IOS:写EXIF到ImageData不反映,除非我将数据附加到从ImageData

时间:2016-09-16 10:42:23

标签: ios objective-c iphone swift exif

我正在开发相机应用程序。我想追加DateTimeOriginal& DateTimeDigitized为exif元数据。我已经创建了Swift类来获取和保存Exif。

import ImageIO

extension NSData {

    func exifNSDict() -> NSDictionary? {
        return _exifCFDict() as NSDictionary?
    }

    func exifCFDict() -> CFDictionaryRef? {
        return _exifCFDict()
    }

    func imageNSUTI() -> NSString? {
        return _imageUTI() as NSString?
    }

    func imageCFUTI() -> CFStringRef? {
        return _imageUTI()
    }

    func appendExif(exif: CFDictionaryRef) -> NSData? {
        return _appendExif(exif)
    }
}

//MARK: - Private

extension NSData {

    private func _exifCFDict() -> CFDictionaryRef? {

        //1.(a) Create original image source ref
        let imageSource: CGImageSourceRef? =      CGImageSourceCreateWithData(self, nil)

        if imageSource == nil {
            return nil
        }

        //1.(b) Get image properties
        let imageProperties: CFDictionaryRef? = CGImageSourceCopyPropertiesAtIndex(imageSource!, 0, nil)

        if imageProperties == nil {
            return nil
        }

        //1.(b) Get original exif
        let dictKey = unsafeBitCast(kCGImagePropertyExifDictionary, UnsafePointer<Void>.self)
        let exif: CFDictionaryRef? = unsafeBitCast(CFDictionaryGetValue(imageProperties, dictKey), CFDictionaryRef.self)

        if exif == nil {
            return nil
        }

        return exif
    }

    private func _imageUTI() -> CFStringRef? {

        let imageSource: CGImageSourceRef? = CGImageSourceCreateWithData(self, nil)

        if imageSource == nil {
            return nil
        }

        let imageUTI: CFStringRef? = CGImageSourceGetType(imageSource!)

        return imageUTI
    }

    private func _appendExif(exif: CFDictionaryRef) -> NSData? {

        //writing both original image data and mutable exif back to a destination
        let imageSource: CGImageSourceRef? = CGImageSourceCreateWithData(self, nil)

        if imageSource == nil {
            return nil
        }

        let imageUTI: CFStringRef? = CGImageSourceGetType(imageSource!)

        if imageUTI == nil {
            return nil
        }

        //3. create a mutable data object to which the originalImageData and exif dictionary will be written.
        let finalCombinedData = NSMutableData()

        //4. create a destination object where the whole thing needs to be written
        let destination : CGImageDestinationRef? = CGImageDestinationCreateWithData(finalCombinedData, imageUTI!, 1, nil)

        if destination == nil {
            return nil
        }

        //5. This is the actual method that does the writing.
        CGImageDestinationAddImageFromSource(destination!, imageSource!, 0, exif);

        //6. Commit the writing
        let success = CGImageDestinationFinalize(destination!);

        if !success {//error
            return nil
        }

        return finalCombinedData.copy() as? NSData
    }
}

现在我可以通过调用exifCFDict

来获取exif
CFDictionaryRef exif = [imageData exifCFDict];

然后我从这个CFDictionaryRef创建了一个MutableCFDictionaryRef,并为kCGImagePropertyExifDateTimeOriginal和kCGImagePropertyExifDateTimeDigitized附加了如下值:

1.(b) Convert original exif to mutable exif                                                            
CFMutableDictionaryRef mutableExif = CFDictionaryCreateMutableCopy(NULL, 0, exif);
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
                                                         [formatter setDateFormat:@"yyyy:MM:dd HH:mm:ss"];
NSString *nowDateStr = [formatter stringFromDate:[[NSDate alloc] init]];
CFDictionarySetValue(mutableExif, kCGImagePropertyExifDateTimeOriginal, (__bridge const void *)nowDateStr);
CFDictionarySetValue(mutableExif, kCGImagePropertyExifDateTimeDigitized, (__bridge const void *)nowDateStr);

我可以在可变副本中看到kCGImagePropertyExifDateTimeOriginal和kCGImagePropertyExifDateTimeDigitized。 然后我尝试通过调用上面类别中的appendExif函数将这个可变字典写入imageData。

//append exif to originalImageData
NSData *imageDataWithExif = [imageData appendExif:mutableExif];

然而,当我试图从imageDataWithExif获取exif时,我意识到kCGImagePropertyExifDateTimeOriginal&amp;缺少kCGImagePropertyExifDateTimeDigitized。所有其他信息都存在。

经过一番打击和尝试后,我找到了解决方法。如果不是为exif创建一个可变副本,我只是附加了kCGImagePropertyExifDateTimeDigitized&amp; kCGImagePropertyExifDateTimeOriginal to原始Exif从Image Data中获取,然后如果我将此原始exif传递给appendExif函数,则kCGImagePropertyExifDateTimeOriginal和kCGImagePropertyExifDateTimeDigitized将出现在新的imageData中。

CFDictionarySetValue(exif, kCGImagePropertyExifDateTimeOriginal, (__bridge const void *)nowDateStr);
CFDictionarySetValue(exif, kCGImagePropertyExifDateTimeDigitized, (__bridge const void *)nowDateStr);

//append exif to originalImageData
NSData *imageDataWithExif = [imageData exif];

这解决了我现在的问题,但这种解决方法让我感到困惑。

  • 如何将键值附加到CFDictionaryRef?
  • 为什么除非我传递从图像数据中获取的原始exif字典对象,否则我对字典的更改将被忽略。

P.S。我对IOS开发还很陌生。

0 个答案:

没有答案
相关问题