UIImagePickerController возвращает неверную ориентацию изображения


Я использую UIImagePickerController, чтобы захватить изображение и затем сохранить его. Однако, когда я пытаюсь изменить его масштаб, значение ориентации, которое я получаю из этого изображения, неверно. Когда я делаю снимок, держа телефон вверх, он дает мне ориентацию влево. Кто-нибудь сталкивался с этой проблемой?

Словарь UIImagePickerController содержит следующую информацию:

{
    UIImagePickerControllerMediaMetadata =     {
        DPIHeight = 72;
        DPIWidth = 72;
        Orientation = 3;
        "{Exif}" =         {
            ApertureValue = "2.970853654340484";
            ColorSpace = 1;
            DateTimeDigitized = "2011:02:14 10:26:17";
            DateTimeOriginal = "2011:02:14 10:26:17";
            ExposureMode = 0;
            ExposureProgram = 2;
            ExposureTime = "0.06666666666666667";
            FNumber = "2.8";
            Flash = 32;
            FocalLength = "3.85";
            ISOSpeedRatings =             (
                125
            );
            MeteringMode = 1;
            PixelXDimension = 2048;
            PixelYDimension = 1536;
            SceneType = 1;
            SensingMethod = 2;
            Sharpness = 1;
            ShutterSpeedValue = "3.910431673351467";
            SubjectArea =             (
                1023,
                767,
                614,
                614
            );
            WhiteBalance = 0;
        };
        "{TIFF}" =         {
            DateTime = "2011:02:14 10:26:17";
            Make = Apple;
            Model = "iPhone 3GS";
            Software = "4.2.1";
            XResolution = 72;
            YResolution = 72;
        };
    };
    UIImagePickerControllerMediaType = "public.image";
    UIImagePickerControllerOriginalImage = "<UIImage: 0x40efb50>";
}

Однако картинка возвращает imageOrientation == 1;

UIImage *picture = [info objectForKey:UIImagePickerControllerOriginalImage];             
6 10

6 ответов:

Я только начал работать над этой проблемой в своем собственном приложении.

Я использовал категория объектами UIImage, что Тревор Хармон созданный для изменения размеров изображения и фиксации его ориентация, объектами UIImage+размер.

Тогда вы можете сделать что-то подобное в -imagePickerController:didFinishPickingMediaWithInfo:

UIImage *pickedImage = [info objectForKey:UIImagePickerControllerEditedImage];
UIImage *resized = [pickedImage resizedImageWithContentMode:UIViewContentModeScaleAspectFit bounds:pickedImage.size interpolationQuality:kCGInterpolationHigh];

Это исправило проблему для меня. Измененное изображение ориентировано правильно визуально, и свойство imageOrientation сообщает UIImageOrientationUp.

Существует несколько версий этого кода масштабирования/изменения размера/обрезки; Я использовал Trevor's, потому что он кажется довольно чистым и включает в себя некоторые другие манипуляторы UIImage, которые я хочу использовать позже.

Это то, что я нашел для решения проблемы ориентации; работает для меня

UIImage *initialImage = [info objectForKey:@"UIImagePickerControllerOriginalImage"];
NSData *data = UIImagePNGRepresentation(self.initialImage);

UIImage *tempImage = [UIImage imageWithData:data];
UIImage *fixedOrientationImage = [UIImage imageWithCGImage:tempImage.CGImage
                                     scale:initialImage.scale
                               orientation:self.initialImage.imageOrientation];
initialImage = fixedOrientationImage;

Вот быстрый фрагмент, который эффективно устраняет проблему:

let orientedImage = UIImage(CGImage: initialImage.CGImage, scale: 1, orientation: initialImage.imageOrientation)!

Я использую следующий код, который я поместил в отдельный объектный файл утилиты image, который имеет кучу других методов редактирования для UIImages:

+ (UIImage*)imageWithImage:(UIImage*)sourceImage scaledToSizeWithSameAspectRatio:(CGSize)targetSize
{
    CGSize imageSize = sourceImage.size;
    CGFloat width = imageSize.width;
    CGFloat height = imageSize.height;
    CGFloat targetWidth = targetSize.width;
    CGFloat targetHeight = targetSize.height;
    CGFloat scaleFactor = 0.0;
    CGFloat scaledWidth = targetWidth;
    CGFloat scaledHeight = targetHeight;
    CGPoint thumbnailPoint = CGPointMake(0.0,0.0);

    if (CGSizeEqualToSize(imageSize, targetSize) == NO) {
        CGFloat widthFactor = targetWidth / width;
        CGFloat heightFactor = targetHeight / height;

        if (widthFactor > heightFactor) {
            scaleFactor = widthFactor; // scale to fit height
        }
        else {
            scaleFactor = heightFactor; // scale to fit width
        }

        scaledWidth  = width * scaleFactor;
        scaledHeight = height * scaleFactor;

        // center the image
        if (widthFactor > heightFactor) {
            thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
        }
        else if (widthFactor < heightFactor) {
            thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
        }
    }

    CGImageRef imageRef = [sourceImage CGImage];
    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
    CGColorSpaceRef colorSpaceInfo = CGImageGetColorSpace(imageRef);

    if (bitmapInfo == kCGImageAlphaNone) {
        bitmapInfo = kCGImageAlphaNoneSkipLast;
    }

    CGContextRef bitmap;

    if (sourceImage.imageOrientation == UIImageOrientationUp || sourceImage.imageOrientation == UIImageOrientationDown) {
        bitmap = CGBitmapContextCreate(NULL, targetWidth, targetHeight, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);

    } else {
        bitmap = CGBitmapContextCreate(NULL, targetHeight, targetWidth, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);

    }

    // In the right or left cases, we need to switch scaledWidth and scaledHeight,
    // and also the thumbnail point
    if (sourceImage.imageOrientation == UIImageOrientationLeft) {
        thumbnailPoint = CGPointMake(thumbnailPoint.y, thumbnailPoint.x);
        CGFloat oldScaledWidth = scaledWidth;
        scaledWidth = scaledHeight;
        scaledHeight = oldScaledWidth;

        CGContextRotateCTM (bitmap, M_PI_2); // + 90 degrees
        CGContextTranslateCTM (bitmap, 0, -targetHeight);

    } else if (sourceImage.imageOrientation == UIImageOrientationRight) {
        thumbnailPoint = CGPointMake(thumbnailPoint.y, thumbnailPoint.x);
        CGFloat oldScaledWidth = scaledWidth;
        scaledWidth = scaledHeight;
        scaledHeight = oldScaledWidth;

        CGContextRotateCTM (bitmap, -M_PI_2); // - 90 degrees
        CGContextTranslateCTM (bitmap, -targetWidth, 0);

    } else if (sourceImage.imageOrientation == UIImageOrientationUp) {
        // NOTHING
    } else if (sourceImage.imageOrientation == UIImageOrientationDown) {
        CGContextTranslateCTM (bitmap, targetWidth, targetHeight);
        CGContextRotateCTM (bitmap, -M_PI); // - 180 degrees
    }

    CGContextDrawImage(bitmap, CGRectMake(thumbnailPoint.x, thumbnailPoint.y, scaledWidth, scaledHeight), imageRef);
    CGImageRef ref = CGBitmapContextCreateImage(bitmap);
    UIImage* newImage = [UIImage imageWithCGImage:ref];

    CGContextRelease(bitmap);
    CGImageRelease(ref);

    return newImage; 
}

А потом я звоню

UIImage *pickedImage = [info objectForKey:UIImagePickerControllerOriginalImage];
        UIImage *fixedOriginal = [ImageUtil imageWithImage:[mediaInfoDict objectForKey:UIImagePickerControllerOriginalImage] scaledToSizeWithSameAspectRatio:pickedImage.size];

В iOS 7 Мне нужен был код, зависящий от UIImage.ориентация изображения для коррекции различных ориентаций. Теперь, в iOS 8.2, когда я выбираю свои старые тестовые изображения из альбома через UIImagePickerController, ориентация будет UIImageOrientationUp для всех изображений. Когда я делаю фотографию (UIImagePickerControllerSourceTypecamera), эти изображения также всегда будут вверх, независимо от ориентации устройства. Так что между этими версиями iOS, очевидно, было исправление, где UIImagePickerController уже поворачивает изображения, если это необходимо. Вы даже можете заметить, что при отображении изображений альбома: в течение доли секунды они будут отображаться в исходной ориентации, прежде чем они появятся в новой ориентации вверх.

Единственное, что сработало для меня, - это снова воспроизвести изображение, которое заставляет правильно ориентироваться.

if (photo.imageOrientation != .up) {
   UIGraphicsBeginImageContextWithOptions(photo.size, false, 1.0);
   let rect = CGRect(x: 0, y: 0, width: photo.size.width, height: photo.size.height);
   photo.draw(in: rect)
   let newImage = UIGraphicsGetImageFromCurrentImageContext()
   UIGraphicsEndImageContext()
   photo = newImage;
}