使用ImageIO保留EXIF信息的图片

使用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进行压缩得到的图片更小一些,这需要根据项目而定采用哪种方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值