在 iPhone 的照片库中写入 UIImage 以及元数据(EXIF、GPS、TIFF)
我正在开发一个项目,其要求是: - 用户将通过应用程序打开相机 - 捕获图像后,一些数据将附加到捕获图像的元数据中。 我浏览过一些论坛。我尝试编写这个逻辑。我想,我已经达到了这一点,但是缺少一些东西,因为我无法看到附加到图像的元数据。 我的准则是:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)dictionary
{
[picker dismissModalViewControllerAnimated:YES];
NSData *dataOfImageFromGallery = UIImageJPEGRepresentation (image,0.5);
NSLog(@"Image length: %d", [dataOfImageFromGallery length]);
CGImageSourceRef source;
source = CGImageSourceCreateWithData((CFDataRef)dataOfImageFromGallery, NULL);
NSDictionary *metadata = (NSDictionary *) CGImageSourceCopyPropertiesAtIndex(source, 0, NULL);
NSMutableDictionary *metadataAsMutable = [[metadata mutableCopy]autorelease];
[metadata release];
NSMutableDictionary *EXIFDictionary = [[[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyExifDictionary]mutableCopy]autorelease];
NSMutableDictionary *GPSDictionary = [[[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyGPSDictionary]mutableCopy]autorelease];
if(!EXIFDictionary)
{
//if the image does not have an EXIF dictionary (not all images do), then create one for us to use
EXIFDictionary = [NSMutableDictionary dictionary];
}
if(!GPSDictionary)
{
GPSDictionary = [NSMutableDictionary dictionary];
}
//Setup GPS dict -
//I am appending my custom data just to test the logic……..
[GPSDictionary setValue:[NSNumber numberWithFloat:1.1] forKey:(NSString*)kCGImagePropertyGPSLatitude];
[GPSDictionary setValue:[NSNumber numberWithFloat:2.2] forKey:(NSString*)kCGImagePropertyGPSLongitude];
[GPSDictionary setValue:@"lat_ref" forKey:(NSString*)kCGImagePropertyGPSLatitudeRef];
[GPSDictionary setValue:@"lon_ref" forKey:(NSString*)kCGImagePropertyGPSLongitudeRef];
[GPSDictionary setValue:[NSNumber numberWithFloat:3.3] forKey:(NSString*)kCGImagePropertyGPSAltitude];
[GPSDictionary setValue:[NSNumber numberWithShort:4.4] forKey:(NSString*)kCGImagePropertyGPSAltitudeRef];
[GPSDictionary setValue:[NSNumber numberWithFloat:5.5] forKey:(NSString*)kCGImagePropertyGPSImgDirection];
[GPSDictionary setValue:@"_headingRef" forKey:(NSString*)kCGImagePropertyGPSImgDirectionRef];
[EXIFDictionary setValue:@"xml_user_comment" forKey:(NSString *)kCGImagePropertyExifUserComment];
//add our modified EXIF data back into the image’s metadata
[metadataAsMutable setObject:EXIFDictionary forKey:(NSString *)kCGImagePropertyExifDictionary];
[metadataAsMutable setObject:GPSDictionary forKey:(NSString *)kCGImagePropertyGPSDictionary];
CFStringRef UTI = CGImageSourceGetType(source);
NSMutableData *dest_data = [NSMutableData data];
CGImageDestinationRef destination = CGImageDestinationCreateWithData((CFMutableDataRef) dest_data, UTI, 1, NULL);
if(!destination)
{
NSLog(@"--------- Could not create image destination---------");
}
CGImageDestinationAddImageFromSource(destination, source, 0, (CFDictionaryRef) metadataAsMutable);
BOOL success = NO;
success = CGImageDestinationFinalize(destination);
if(!success)
{
NSLog(@"-------- could not create data from image destination----------");
}
UIImage * image1 = [[UIImage alloc] initWithData:dest_data];
UIImageWriteToSavedPhotosAlbum (image1, self, nil, nil);
}
请帮助我做到这一点并得到一些积极的东西。 看最后一行,我是否保存了带有元数据的图像? 此时图像已保存,但我附加到图像的元数据并未保存。
提前致谢。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
Apple 更新了解决此问题的文章(技术问答 QA1622)。如果您使用的是较旧版本的 Xcode,您可能仍然会看到这篇文章,或多或少,运气不好,如果不对图像数据进行低级解析,您将无法做到这一点。
https://developer.apple.com/library/ios/#qa /qa1622/_index.html
我在那里修改了代码,如下所示:
我从中调用了
图像选择器的委托方法。
我使用辅助方法(改编自 GusUtils)从某个位置构建 GPS 元数据字典:
到目前为止在 iOS4 和 iOS5 设备上运行良好。
更新:和 iOS6/iOS7 设备。我使用以下代码构建了一个简单的项目:
https://github.com/5teev/MetaPhotoSave
Apple has updated their article addressing this issue (Technical Q&A QA1622). If you're using an older version of Xcode, you may still have the article that says, more or less, tough luck, you can't do this without low-level parsing of the image data.
https://developer.apple.com/library/ios/#qa/qa1622/_index.html
I adapted the code there as follows:
and I call this from
which is the delegate method for the image picker.
I use a helper method (adapted from GusUtils) to build a GPS metadata dictionary from a location:
So far this is working well for me on iOS4 and iOS5 devices.
Update: and iOS6/iOS7 devices. I built a simple project using this code:
https://github.com/5teev/MetaPhotoSave
函数:
UIImageWriteToSavePhotosAlbum
仅写入图像数据。您需要阅读 ALAssetsLibrary
你最终要调用的方法是:
The function:
UIImageWriteToSavePhotosAlbum
only writes the image data.You need to read up on the ALAssetsLibrary
The method you ultimately want to call is:
对于任何来这里尝试使用应用中的相机拍照并将图像文件与 GPS 元数据保存到相机胶卷的人,我有一个使用 照片 API 自ALAssetsLibrary 自 iOS 9.0 起已弃用。
正如 rickster 在这个答案中提到的,Photos API 不会直接将位置数据嵌入到即使您设置了新资源的 .location 属性,JPG 图像文件也是如此。
给定 CMSampleBuffer 示例缓冲区
buffer
、一些 CLLocationlocation
,并使用 Morty 的建议< /a> 使用CMSetAttachments
为了避免重复图像,我们可以执行以下操作。扩展 CLLocation 的gpsMetadata
方法可以在此处找到。savePhoto
方法如下。请注意,方便的addResource:with:data:options
方法仅在 iOS 9 中可用。如果您支持早期的 iOS 并希望使用 Photos API,则必须创建一个临时文件,然后如果您希望正确嵌入 GPS 元数据 (PHAssetChangeRequest.creationRequestForAssetFromImage:atFileURL
),请从该 URL 处的文件创建资产。仅设置 PHAsset 的 .location 不会将新元数据嵌入到实际文件本身中。旁白:
如果您只想将带有 GPS 元数据的图像保存到临时文件或文档(而不是相机胶卷/照片库)中,则可以跳过使用 Photos API 并直接将 imageData 写入 URL。
For anyone who comes here trying to take a photo with the camera in your app and saving the image file to the camera roll with GPS metadata, I have a Swift solution that uses the Photos API since ALAssetsLibrary is deprecated as of iOS 9.0.
As mentioned by rickster on this answer, the Photos API does not embed location data directly into a JPG image file even if you set the .location property of the new asset.
Given a CMSampleBuffer sample buffer
buffer
, some CLLocationlocation
, and using Morty’s suggestion to useCMSetAttachments
in order to avoid duplicating the image, we can do the following. ThegpsMetadata
method extending CLLocation can be found here.The
savePhoto
method is below. Note that the handyaddResource:with:data:options
method is available only in iOS 9. If you are supporting an earlier iOS and want to use the Photos API, then you must make a temporary file and then create an asset from the file at that URL if you want to have the GPS metadata properly embedded (PHAssetChangeRequest.creationRequestForAssetFromImage:atFileURL
). Only setting PHAsset’s .location will NOT embed your new metadata into the actual file itself.Aside:
If you are just wanting to save the image with GPS metadata to your temporary files or documents (as opposed to the camera roll/photo library), you can skip using the Photos API and directly write the imageData to a URL.
从应用程序中的摄像头捕获的图像获取元数据:
现在将图像与提取的元数据一起保存到库中:
或者想要保存到本地目录
Getting meta data from cam captured image within an application:
now to save image to library with extracted metadata:
or want to save to local directory
我们要解决的问题是:用户刚刚用UIImagePickerController相机拍了一张照片。我们得到的是一个UIImage。既然我们没有 AssetsLibrary 框架,那么当我们将元数据保存到相机胶卷(照片库)中时,如何将元数据折叠到 UIImage 中?
答案(据我所知)是:使用 ImageIO 框架。从 UIImage 中提取 JPEG 数据,将其用作源并将其和元数据字典写入目标,并将目标数据作为 PHAsset 保存到相机胶卷中。
在此示例中,
im
是 UIImage,meta
是元数据字典:测试的好方法(也是常见的用例)是从 UIImagePickerController 接收照片元数据通过
UIImagePickerControllerMediaMetadata
键委托info
字典,并在我们将其保存到照片库时将其折叠到 PHAsset 中。The problem we are trying to solve is: the user has just taken a picture with the UIImagePickerController camera. What we get is a UIImage. How do we fold metadata into that UIImage as we save it into the camera roll (photo library), now that we don't have the AssetsLibrary framework?
The answer (as far as I can make out) is: use the ImageIO framework. Extract the JPEG data from the UIImage, use it as a source and write it and the metadata dictionary into the destination, and save the destination data as a PHAsset into the camera roll.
In this example,
im
is the UIImage andmeta
is the metadata dictionary:A good way to test — and a common use case — is to receive the photo metadata from the UIImagePickerController delegate
info
dictionary thru theUIImagePickerControllerMediaMetadata
key and fold it into the PHAsset as we save it into the photo library.有许多处理图像和元数据的框架。
资产框架已弃用,并由照片库框架取代。如果你实现了
AVCapturePhotoCaptureDelegate
来拍摄照片,你可以这样做:元数据是字典的字典,你必须参考CGImageProperties。
我在此处写了有关此主题的文章。
There are many frameworks that deals with image and metadata.
Assets Framework is deprecated, and replaced by Photos Library framework. If you implemented
AVCapturePhotoCaptureDelegate
to capture photos, you can do so:The metadata is a dictionary of dictionaries, and you have to refer to CGImageProperties.
I wrote about this topic here.
这是 @matt 答案的细微变化。
以下代码仅使用一个 CGImageDestination,更有趣的是允许在 iOS11+ 上以 HEIC 格式保存。
请注意,在添加图像之前,压缩质量已添加到元数据中。 0.8大致是原生相机保存的压缩质量。
Here is a slight variation of @matt answer.
The following code use only one CGImageDestination and more interesting allow to save in HEIC format on iOS11+.
Notice that the compression quality is added to the metadata before adding the image. 0.8 is roughly the compression quality of native camera save.