您的位置:首页 > 其它

使用ImageIO保留EXIF信息的图片

2016-01-14 14:24 381 查看

使用ImageIO上传保留EXIF信息的图片

相信大多数项目中需要上传图片,但是从相机中取到的图片再上传到服务器,一般的项目就是直接用
NSData *data = UIImageJPEGRepresentation(image, 1)
把图片压缩转换成DATA进行上传。然而在转成UIImage的时候,会把图片的EXIF一些信息自动隐藏,所以别人拿到你的图片别人是看不到这些信息的。所以我就在网上找到了以下的方法,主要借助ImageIO框架,先写入本地再进行上传。

stack overflow原文

ALAssetRepresentation *image_Representation = [asset defaultRepresentation];
// create a buffer to hold image data
uint8_t *buffer = (Byte *)malloc(image_Representation.size);
NSUInteger length = [image_Representation getBytes:buffer fromOffset:0.0 length:image_Representation.size error:nil];
if (length != 0) {
// buffer -> NSData object; free buffer afterwards
NSData *adata = [[NSData alloc] initWithBytesNoCopy:buffer length:image_Representation.size freeWhenDone:YES];
// identify image type (jpeg, png, RAW file, ...) using UTI hint
float compression = 0.0;
int orientation = 4;
NSDictionary *sourceOptionsDict = @{(__bridge id)kCGImageSourceTypeIdentifierHint:[image_Representation UTI],
(__bridge id)kCGImageDestinationLossyCompressionQuality: (__bridge id)CFNumberCreate(NULL, kCFNumberFloatType, &compression),
(__bridge id)kCGImagePropertyOrientation:(__bridge id)CFNumberCreate(NULL, kCFNumberIntType, &orientation),
(__bridge id)kCGImagePropertyHasAlpha:(__bridge id)kCFBooleanTrue};
// create CGImageSource with NSData
CGImageSourceRef sourceRef = CGImageSourceCreateWithData((__bridge CFDataRef)adata, (__bridge CFDictionaryRef)sourceOptionsDict);
// get imagePropertiesDictionary
CFDictionaryRef imagePropertiesDictionary = CGImageSourceCopyPropertiesAtIndex(sourceRef,0, NULL);

// get exif data
CFDictionaryRef exif = (CFDictionaryRef)CFDictionaryGetValue(imagePropertiesDictionary, kCGImagePropertyExifDictionary);
NSDictionary *exif_dict = (__bridge NSDictionary*)exif;
NSLog(@"exif_dict: %@",exif_dict);
// save image WITH meta data
CGImageRef imageRef = CGImageSourceCreateImageAtIndex(sourceRef, 0, imagePropertiesDictionary);
//存入本地
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSURL *fileURL = nil;
if (![[sourceOptionsDict objectForKey:@"kCGImageSourceTypeIdentifierHint"] isEqualToString:@"public.tiff"]) {
fileURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@.%@",
documentsDirectory,
@"myimage",
[[[sourceOptionsDict objectForKey:@"kCGImageSourceTypeIdentifierHint"] componentsSeparatedByString:@"."] objectAtIndex:1]
]];
CGImageDestinationRef dr = CGImageDestinationCreateWithURL ((__bridge CFURLRef)fileURL,
(__bridge CFStringRef)[sourceOptionsDict objectForKey:@"kCGImageSourceTypeIdentifierHint"],
1,
NULL
);
CGImageDestinationAddImage(dr, imageRef, imagePropertiesDictionary);
CGImageDestinationFinalize(dr);
CFRelease(dr);

NSData *imageData = [NSData dataWithContentsOfURL:fileURL];
//                        NSLog(@"%lu",(unsigned long)imageData.length);
[blockSelf.selectedPhotos addObject:imageData];

}else {
NSLog(@"no valid kCGImageSourceTypeIdentifierHint found …");
}
// clean up
CFRelease(imageRef);
CFRelease(imagePropertiesDictionary);
CFRelease(sourceRef);
}else {
NSLog(@"image_representation buffer length == 0");
}


然而你会发现这里比原文多了一点。

原图太大,上传辣么大的图,慢,费流量,所以需要就原图进行压缩。如果想要对原图进行压缩,就需要在
sourceOptionsDict
这个字典中添加
kCGImageDestinationLossyCompressionQuality
这个KEY对应的VALUE为
CFNumber
此值0.0~1.0.如此添加之后,我以为就OK了,然而并没有什么卵用,原图是多大,压缩后还是多大。思前想后,我觉得一定是一些属性对压缩产生了冲突,于是我就查阅了苹果官方文档,发现没什么大的改变,也就是字典那的一些转换。那就用官方的试试…

ALAssetRepresentation *image_Representation = [asset defaultRepresentation];
float compression = 0; // 压缩比例
int orientation = 1; // 方向
CFStringRef myKeys[4];
CFTypeRef   myValues[4];
CFDictionaryRef myOptions = NULL;
myKeys[0] = kCGImagePropertyOrientation;
myValues[0] = CFNumberCreate(NULL, kCFNumberIntType, &orientation);
myKeys[1] = kCGImagePropertyHasAlpha;
myValues[1] = kCFBooleanTrue;
myKeys[2] = kCGImageDestinationLossyCompressionQuality;
myValues[2] = CFNumberCreate(NULL, kCFNumberFloatType, &compression);
myKeys[3] = kCGImageSourceTypeIdentifierHint;
myValues[3] = (__bridge CFTypeRef)([image_Representation UTI]);
myOptions = CFDictionaryCreate( NULL, (const void **)myKeys, (const void **)myValues, 4,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

//创建DATA
uint8_t *buffer = (Byte *)malloc(image_Representation.size);
NSUInteger length = [image_Representation getBytes:buffer fromOffset:0.0 length:image_Representation.size error:nil];
NSData *adata = [[NSData alloc] initWithBytesNoCopy:buffer length:image_Representation.size freeWhenDone:YES];
/*********构建CGImageRef*******/
//CGImageSourceCreateWithData
CGImageSourceRef sourceRef = CGImageSourceCreateWithData((__bridge CFDataRef)adata, myOptions);
CFDictionaryRef imagePropertiesDictionary = CGImageSourceCopyPropertiesAtIndex(sourceRef,0, NULL);
CGImageRef imageRef = CGImageSourceCreateImageAtIndex(sourceRef, 0, imagePropertiesDictionary);
/*********构建文件URL*******/
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *imageType = [(__bridge NSDictionary *)myOptions objectForKey:@"kCGImageSourceTypeIdentifierHint"];
NSURL *fileURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@.%@",
documentsDirectory,
@"myimage",
[[imageType componentsSeparatedByString:@"."] objectAtIndex:1]
]];
[blockSelf writeCGImage:imageRef toURL:fileURL withType:(__bridge CFStringRef)(imageType) andOptions:myOptions];

- (void)writeCGImage: (CGImageRef) image toURL: (NSURL*) url withType: (CFStringRef) imageType andOptions: (CFDictionaryRef) options
{

CGImageDestinationRef myImageDest = CGImageDestinationCreateWithURL((CFURLRef)url, imageType, 1, NULL);//此处NULL不能为nil,否则图片为空
CGImageDestinationAddImage(myImageDest, image, options);
CGImageDestinationFinalize(myImageDest);
CFRelease(myImageDest);
}


如此改变之后,就成功的压缩了图片,上传的时候直接取到图片转成Data然后进行上传。

然而对比了使用ImageIO与使用UIImage的方法之后会发现,还是使用
UIImageJPEGRepresentation
进行压缩得到的图片更小一些,这需要根据项目而定采用哪种方式。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: