iOS圖片方向調整後導致Exif、Gps信息丟失

背景:圖片方向錯誤

我們在iOS開發中會碰到一個問題,就是圖片在相冊裏顯示是正確的,但獲取到後自己展示卻是錯誤的,這是因爲手機橫屏拍照的時候,圖片的朝向信息不是豎直的,我們可以用mac看到圖片的如下信息:

通過UIImage的imageOrientation也可以獲取到,相冊之所以是正確的,是因爲相冊在顯示的時候判斷了方向,做了處理。

上網搜,有很多轉化圖片朝向的方法,與本次的問題無關,這裏就不介紹了。

 

問題出現:

有一天,我們碰到一個需求,圖片不僅僅用於展示,還要上傳服務器,所以我們按照網上的方法把NSData先轉化爲UIImage,然後拿到方向後做變換,最終通過UIImageJPEGRepresentation/UIImagePNGRepresentation轉化成NSData。看起來一切正常,突然,服務器說,你給我的圖片中的GPS和EXIF信息怎麼沒了?

通過研究,發現從相冊中拿到的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];
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章