更新UIImage方向元数据?

时间:2013-01-28 00:22:08

标签: ios nsdictionary

基本任务:更新与UIImage关联的元数据的EXIF方向属性。我的问题是我不知道所有EXIF信息中的orientation属性。


复杂的背景:我正在更改imagePickerController:didFinishPickingMediaWithInfo:返回的图片的方向,所以我想我还需要在使用writeImageToSavedPhotosAlbum:(CGImageRef)imageRef metadata:(NSDictionary *)metadata保存图片之前更新元数据

换句话说,除非我更改它,否则metaData将包含旧/初始方向,因此是错误的。我改变方向的原因是因为它在我运行Core Image面部检测程序时不停地绊倒我。使用前置摄像头在人像模式下使用iPhone(设备)拍照时,方向为UIImageOrientationRight(3)。如果我重写图像使方向为UIImageOrientationUp(0),我会得到良好的人脸检测结果。作为参考,重写图像的例程如下。

整个相机方向的东西我觉得很混乱,我似乎正在深入挖掘所有这一切的代码洞。我查看了帖子(hereherehere。根据这篇文章(https://stackoverflow.com/a/3781192/840992):

  

“相机实际上是风景原生的,所以当你开始或不起作用时   当你拍摄时,你会拍摄风景照片,然后向左或向右拍照   纵向图片(取决于您如何握住设备)。“

......这完全令人困惑。如果以上情况属实,我认为我应该使用前置摄像头获得UIImageOrientationLeftMirroredUIImageOrientationRightMirrored的方向。而这一切都无法解释为什么CIDetector未能通过选择器返回的处女图像。

我正在接近这个屁股,但我似乎无法面向......


-(UIImage *)normalizedImage:(UIImage *) thisImage
{
    if (thisImage.imageOrientation == UIImageOrientationUp) return thisImage;

    UIGraphicsBeginImageContextWithOptions(thisImage.size, NO, thisImage.scale);
    [thisImage drawInRect:(CGRect){0, 0, thisImage.size}];
    UIImage *normalizedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return normalizedImage;
}

2 个答案:

答案 0 :(得分:23)

看看我的回答:
Force UIImagePickerController to take photo in portrait orientation/dimensions iOS

associated project on github(您不需要运行项目,只需查看自述文件)。

它更关注阅读而不是编写元数据 - 但它包含了一些关于Apple的imageOrientation和相应的方向'Exif'元数据的注释。

这也许值得一读 Captured photo automatically rotated during upload in IOS 6.0 or iPhone

有两种不同的常数编号约定来表示图像方向。

  1. 在TIFF / IPTC图像元数据标签中使用的kCGImagePropertyOrientation常量
  2. UIImage imageOrientation属性使用的UIImageOrientation常量。
  3. iPhone原生相机方向为横向左侧(右侧有主页按钮)。原始像素尺寸始终反映这一点,旋转标记用于正确定位图像的显示方向。

    Apple            UIImage.imageOrientation     TIFF/IPTC kCGImagePropertyOrientation
    
    iPhone native     UIImageOrientationUp    = 0  =  Landscape left  = 1  
    rotate 180deg     UIImageOrientationDown  = 1  =  Landscape right = 3  
    rotate 90CCW      UIImageOrientationLeft  = 2  =  Portrait  down  = 8  
    rotate 90CW       UIImageOrientationRight = 3  =  Portrait  up    = 6  
    

    UIImageOrientation 4-7映射到kCGImagePropertyOrientation 2,4,5,7 - 这些是镜像对应物。

    UIImage从底层的kCGImagePropertyOrientation标志派生它的imagerOrientation属性 - 这就是它是一个只读属性的原因。这意味着只要您获得正确的元数据标记,imageOrientation就会正确跟随。但是,如果您正在阅读数字以应用变换,则需要知道您正在查看哪些数字。

答案 1 :(得分:5)

从我的世界中收集到一些关于这一点的痛苦:

背景: Core Image人脸检测失败,似乎与使用featuresInImage:options:并使用UIImage.imageOrientation属性作为参数有关。将图像调整为无旋转且未镜像,检测工作正常,但直接从相机检测传入图像失败。

嗯...... UIImage.imageOrientation 不同而不是图像的实际方向。

换句话说......

UIImage* tmpImage = [self.imageInfo objectForKey:UIImagePickerControllerOriginalImage];
printf("tmpImage.imageOrientation: %d\n", tmpImage.imageOrientation);

报告值为3或UIImageOrientationRight,而使用UIImagePickerControllerDelegate方法返回的元数据...

   NSMutableDictionary* metaData = [[tmpInfo objectForKey:@"UIImagePickerControllerMediaMetadata"] mutableCopy];
   printf(" metaData orientation    %d\n", [[metaData objectForKey:@"Orientation"] integerValue]);

报告值为6或UIImageOrientationLeftMirrored

我认为现在似乎很明显,UIImage.imageOrientation是一个显示方向 出现,由源图像方向设备确定回转。 (我可能在这里错了)由于显示方向与实际图像数据不同,使用它会导致CIDetector失败。啊。

我确信所有这些对于液体图形用户界面等都是非常好的和重要的目的。但是对我来说这是太多了,因为所有CIDetector坐标也将在原始图像方向上制作CALayer画病了。因此,对于后人,这里是如何更改元数据的Orientation属性和其中包含的图像。然后可以使用此元数据将图像保存到cameraRoll。

<强>解决方案

// NORMALIZE IMAGE
UIImage* tmpImage = [self normalizedImage:[self.imageInfo objectForKey:UIImagePickerControllerOriginalImage]];
NSMutableDictionary * tmpInfo =[self.imageInfo mutableCopy];
NSMutableDictionary* metaData = [[tmpInfo objectForKey:@"UIImagePickerControllerMediaMetadata"] mutableCopy];

[metaData setObject:[NSNumber numberWithInt:0] forKey:@"Orientation"];
[tmpInfo setObject:tmpImage forKey:@"UIImagePickerControllerOriginalImage"];
[tmpInfo setObject:metaData forKey:@"UIImagePickerControllerMediaMetadata"];

self.imageInfo = tmpInfo;