iOS图片方向调整后导致Exif、Gps信息丢失

背景:图片方向错误

我们在iOS开发中会碰到一个问题,就是图片在相册里显示是正确的,但获取到后自己展示却是错误的,这是因为手机横屏拍照的时候,图片的朝向信息不是竖直的,我们可以用mac看到图片的如下信息:

iOS图片方向调整后导致Exif、Gps信息丢失_第1张图片

通过UIImage的imageOrientation也可以获取到,相册之所以是正确的,是因为相册在显示的时候判断了方向,做了处理。

上网搜,有很多转化图片朝向的方法,与本次的问题无关,这里就不介绍了。

 

问题出现:

有一天,我们碰到一个需求,图片不仅仅用于展示,还要上传服务器,所以我们按照网上的方法把NSData先转化为UIImage,然后拿到方向后做变换,最终通过UIImageJPEGRepresentation/UIImagePNGRepresentation转化成NSData。看起来一切正常,突然,服务器说,你给我的图片中的GPS和EXIF信息怎么没了?

iOS图片方向调整后导致Exif、Gps信息丢失_第2张图片

通过研究,发现从相册中拿到的NSData是包含ExIf和Gps的,但是转化成UIImage后,就丢失了这些信息。。于是就想把原始NSData中的这些信息提起出来,再追加到处理完方向的NSData中。上网搜了很多方法,发现都不是很完美,不是内存泄漏就是到处摘抄的。贴一下最终参考了很多资料并bugfix后的方法吧。

CF对象一定要注意内存管理问题,需要手动释放!

CFRelease空指针会崩溃,一定需要判断下,我们要谨慎细微才能提高自己的代码质量,毕竟客户端线上Crash要比服务端难受很多!另外一个好习惯就是release完就把指针置空: CFRelease(p); p = nil,我这里没做,对自己要求高的同学可以补上。

/**
 * @brief 将图片原始数据中的Gps和Exif信息添加到新数据中
 * @param origin 从相册获取到的原始数据,包含了exif和gps信息
 * @param newData 进行过方向修正的图片数据
 */
- (NSData *)appendMetaDataFromOrigin:(NSData *)origin toNewData:(NSData *)newData {
    if (!origin || !newData) {
        return newData;
    }

    CGImageSourceRef originSouceRef = CGImageSourceCreateWithData((__bridge CFDataRef)origin, NULL);
    if (!originSouceRef) {
        return newData;
    }

    CFDictionaryRef imageInfoRef = CGImageSourceCopyPropertiesAtIndex(originSouceRef, 0, NULL);
    // originRef release
    CFRelease(originSouceRef);
    
    if (!imageInfoRef) {
        return newData;
    }
    // 原始的exif/gps信息,getValue不需要release
    CFDictionaryRef gpsInfoRef = CFDictionaryGetValue(imageInfoRef, kCGImagePropertyGPSDictionary);
    CFDictionaryRef exifInfoRef = CFDictionaryGetValue(imageInfoRef, kCGImagePropertyExifDictionary);
    
    NSMutableData *newImageData = [[NSMutableData alloc] init];

    CGImageSourceRef newSourceRef = CGImageSourceCreateWithData((__bridge CFDataRef)newData, NULL);
    if (newSourceRef) {

        CFDictionaryRef newDataInfoRef = CGImageSourceCopyPropertiesAtIndex(newSourceRef, 0, NULL);
        if (newDataInfoRef) {

            CFMutableDictionaryRef newDataMutableInfo  = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, newDataInfoRef);
            if (newDataMutableInfo) {

                if (gpsInfoRef) {
                    CFDictionarySetValue(newDataMutableInfo, kCGImagePropertyGPSDictionary, gpsInfoRef);
                }
                if (exifInfoRef) {
                    CFDictionarySetValue(newDataMutableInfo, kCGImagePropertyExifDictionary, exifInfoRef);
                }

                CFStringRef uti = CGImageSourceGetType(newSourceRef);
                
                CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)newImageData, uti, 1, NULL);
                if (destination) {
                    CGImageDestinationAddImageFromSource(destination, newSourceRef, 0, newDataMutableInfo);
                    CGImageDestinationFinalize(destination);
                    CFRelease(destination);
                }
                CFRelease(newDataMutableInfo);
            }
            // newDataInfoRef release
            CFRelease(newDataInfoRef);
        }
        // newDataRef release
        CFRelease(newSourceRef);
    }
    
    // imageInfoRef release
    CFRelease(imageInfoRef);
    
    return [newImageData copy];
}

 

你可能感兴趣的:(IOS,Swift)