我想在临时文件夹中保存一些元数据更改的图像,而不重新编码实际的图像数据。
我发现能够执行此操作的唯一方法是ALAssetsLibrary/writeImageDataToSavedPhotosAlbum:metadata:completionBlock:,但是,此方法会将图像保存到照片库。相反,我想将图像保存到临时文件夹(例如通过电子邮件共享它,而不填充照片库)。
我尝试过使用CGImageDestinationRef
(CGImageDestinationAddImageFromSource),但它只能使用解码图像创建,这意味着它在保存时会重新编码(测试时,像素字节看起来不同)。
除了使用CGImageDestinationRef
之外,iOS还有其他可以保存图像数据和元数据的方法/类吗?对于变通方法的建议也会受到欢迎。
答案 0 :(得分:13)
这是iOS SDK令人沮丧的问题。首先,我建议提交enhancement request。
现在,这是一个潜在的解决方法:如果ALAsset是由您创建的(即,其editable
属性为YES
),那么您基本上可以读取数据,使用元数据写入,再次读取,保存到磁盘,然后使用原始元数据进行写入。
此方法将避免创建重复的图像。
请阅读//评论,因为我为了简洁而省略了一些内容(比如构建元数据字典):
ALAsset* asset; //get your asset, don't use this empty one
if (asset.editable) {
// get the source data
ALAssetRepresentation *rep = [asset defaultRepresentation];
Byte *buffer = (Byte*)malloc(rep.size);
// add error checking here
NSUInteger buffered = [rep getBytes:buffer fromOffset:0.0 length:rep.size error:nil];
NSData *sourceData = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES];
// make your metadata whatever you want
// you should use actual metadata, not a blank dictionary
NSDictionary *metadataDictionary = [NSDictionary dictionary];
// these are __weak to avoid creating an ARC retain cycle
NSData __weak *originalData = sourceData;
NSDictionary __weak *originalMetadata = [rep metadata];
[asset setImageData:sourceData
metadata:metadataDictionary
completionBlock:^(NSURL *assetURL, NSError *error) {
//now get your data and write it to file
if (!error) {
//get your data...
NSString *assetPath = [assetURL path];
NSData *targetData = [[NSFileManager defaultManager] contentsAtPath:assetPath];
//...write to file...
NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentPath = [searchPaths lastObject];
NSURL *fileURL = [NSURL fileURLWithPath:documentPath];
[targetData writeToURL:fileURL atomically:YES];
//...and put it back the way it was
[asset setImageData:originalData metadata:originalMetadata completionBlock:nil];
} else {
// handle error on setting data
NSLog(@"ERROR: %@", [error localizedDescription]);
}
}];
} else {
// you'll need to make a new ALAsset which you have permission to edit and then try again
}
正如您所看到的,如果您不拥有ALAsset,则需要创建一个,这会将照片添加到用户的库中,这正是您想要避免的。但是,正如您可能已经猜到的那样,即使您的应用程序创建了ALAsset,也无法从用户的照片库中删除ALAsset。 (随意提交另一个增强请求。)
因此,如果照片/图片是在您的应用中创建的,那么这对您有用。
但如果没有,它将创建一个用户必须删除的附加副本。
唯一的选择是自己解析NSData,这将是一个痛苦。我知道没有开源库可以填补iOS SDK中的这个空白。
答案 1 :(得分:2)
试试这个:
- (void)saveImage: (UIImage*)image
{
if (image != nil)
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* path = [documentsDirectory stringByAppendingPathComponent:
@"test.png" ];
NSData* data = UIImagePNGRepresentation(image);
[data writeToFile:path atomically:YES];
}
}
- (UIImage*)loadImage
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* path = [documentsDirectory stringByAppendingPathComponent:
@"test.png" ];
UIImage* image = [UIImage imageWithContentsOfFile:path];
[self sendAction:path];
return image;
}
答案 2 :(得分:2)
除了iphone-exif和Aaron的回答,你可能还想看看the libexif c library。
另见HCO23的回答 How to write or modify EXIF data for an existing image on the filesystem, without loading the image?
(@ HCO23在iOS项目中使用了libexif)。
值得注意的是,应用程序商店中的许多“专业”元数据编辑应用程序似乎都是通过创建sidecar / xmp文件来解决这个问题。