您可以将UIImage exif数据复制到缩放的UIImage吗?

时间:2019-03-01 01:46:05

标签: ios uiimage exif

用户正在拍照时,我目前正在抓拍照片:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
   UIImage *image = info[UIImagePickerControllerOriginalImage];

   // create a jpeg
   NSData *jpegData = UIImageJPEGRepresentation(image, 1.0f);

   // write jpeg image to file in app space
   NSString *filePath = 

   // create file path in app space
   [imageData writeToFile:filePath atomically:NO];
}

这很好用,该文件使用其EXIF数据创建了一个jpeg。

现在,我想将图像缩小一些以使其更小。但是,我想保留原始UIImage中存在的部分或全部EXIF数据,然后将其复制到缩放的图像中。

当前缩放图像:

UIImage *scaledImage = [renderer imageWithActions:^(UIGraphicsImageRendererContext*_Nonnull myContext) {
   [image drawInRect:(CGRect) {.origin = CGPointZero, .size = size}];
}];

这可以很好地创建缩放图像,但是其中不包含任何EXIF数据。

是否可以缩放图像并保留原始图像的EXIF数据?我可以从原始图像中获取EXIF数据并将其复制到缩放后的图像吗?

我还使用ALAssetsLibrary搜索了很多答案,现在已弃用了这些答案。似乎替代方法是PhotoKit。哪个状态:

  

在iOS和macOS中,PhotoKit提供了支持构建的类   “照片”应用的照片编辑扩展程序。在iOS和tvOS中,PhotoKit   还可以直接访问由管理的照片和视频资产   照片应用程序。

但是我不使用“照片”应用程序,但是我的图像不是来自本地照片库或icloud,因为我只想将照片存储在我的私人应用程序空间中。

2 个答案:

答案 0 :(得分:0)

请参见This Article

下面是我的实现

```
import ImageIO

public struct ImageMetadataNamespace {
    /// The schema namespace URI(eg. http://ns.adobe.com/exif/1.0/)
    public var scheme: CFString
    /// The preferred schema namespace prefix(eg. exif)
    public var prefix: CFString

    public init(scheme: CFString, prefix: CFString) {
        self.scheme = scheme
        self.prefix = prefix
    }
}

public extension ImageMetadataNamespace {

    /// Dublin Core(URI="http://purl.org/dc/elements/1.1/" Prefix="dc").
    public static let dc = ImageMetadataNamespace(scheme: kCGImageMetadataNamespaceDublinCore, prefix: kCGImageMetadataPrefixDublinCore)

    /// Exchangeable Image File format, Exif 2.2 or earlier(URI="http://ns.adobe.com/exif/1.0/" Prefix="exif").
    public static let exif = ImageMetadataNamespace(scheme: kCGImageMetadataNamespaceExif, prefix: kCGImageMetadataPrefixExif)

    /// EXIF Auxiliary(URI="http://ns.adobe.com/exif/1.0/aux/" Prefix="aux").
    public static let exifAux = ImageMetadataNamespace(scheme: kCGImageMetadataNamespaceExifAux, prefix: kCGImageMetadataPrefixExifAux)

    /// Exif 2.21 or later(URI="http://cipa.jp/exif/1.0/" Prefix="exifEX").
    public static let exifEX = ImageMetadataNamespace(scheme: kCGImageMetadataNamespaceExifEX, prefix: kCGImageMetadataPrefixExifEX)

    /// International Press Telecommunications Council, IPTC Core(URI="http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/" Prefix="Iptc4xmpCore").
    public static let iptc = ImageMetadataNamespace(scheme: kCGImageMetadataNamespaceIPTCCore, prefix: kCGImageMetadataPrefixIPTCCore)

    /// IPTC Extension(URI="http://iptc.org/std/Iptc4xmpExt/2008-02-29/" Prefix="Iptc4xmpExt").
    @available(iOS 11.3, *)
    public static let iptcExtension = ImageMetadataNamespace(scheme: kCGImageMetadataNamespaceIPTCExtension, prefix: kCGImageMetadataPrefixIPTCExtension)

    /// Photoshop(URI="http://ns.adobe.com/photoshop/1.0/" Prefix="photoshop").
    public static let photoshop = ImageMetadataNamespace(scheme: kCGImageMetadataNamespacePhotoshop, prefix: kCGImageMetadataPrefixPhotoshop)

    /// Tagged Image File Format, TIFF Rev. 6.0(URI="http://ns.adobe.com/tiff/1.0/" Prefix="tiff").
    public static let tiff = ImageMetadataNamespace(scheme: kCGImageMetadataNamespaceTIFF, prefix: kCGImageMetadataPrefixTIFF)

    /// Extensible Metadata Platform Basic(URI="http://ns.adobe.com/xap/1.0/" Prefix="xmp").
    public static let xmpBasic = ImageMetadataNamespace(scheme: kCGImageMetadataNamespaceXMPBasic, prefix: kCGImageMetadataPrefixXMPBasic)

    /// Extensible Metadata Platform Rights(URI="http://ns.adobe.com/xap/1.0/rights/" Prefix="xmpRights").
    public static let xmpRights = ImageMetadataNamespace(scheme: kCGImageMetadataNamespaceXMPRights, prefix: kCGImageMetadataPrefixXMPRights)
}

/// About detail tutorial for ImageIO, you can refer below website:
/// http://www.qingpingshan.com/rjbc/ios/214889.html
public final class ImageMetadataVistor {

    public enum SaveError: Error {
        case unsupportedImageFormat
        case destinationFileNotFound
        case writeMetadataToFileFailed
    }

    private var mutableMetadata: CGMutableImageMetadata
    private var imageSource: CGImageSource

    public init(imageSource: CGImageSource) {
        self.imageSource = imageSource
        if let originalMetadata = CGImageSourceCopyMetadataAtIndex(imageSource, 0, nil) {
            mutableMetadata = CGImageMetadataCreateMutableCopy(originalMetadata)!
        } else {
            mutableMetadata = CGImageMetadataCreateMutable()
        }
    }

    public convenience init(image: UIImage) {
        let imageData = image.jpegData(compressionQuality: 1.0)!
        let source = CGImageSourceCreateWithData(imageData as CFData, nil)
        self.init(imageSource: source!)
    }

    /// If image file not exist, or image is invalid, creating ImageMetadataVistor will fail.
    public convenience init?(imageFileURL: URL) {
        guard let source = CGImageSourceCreateWithURL(imageFileURL as CFURL, nil) else {
            return nil
        }
        self.init(imageSource: source)
    }

    /// If imageData is invalid, creating ImageMetadataVistor will fail.
    public convenience init?(imageData: Data) {
        guard let source = CGImageSourceCreateWithData(imageData as CFData, nil) else {
            return nil
        }
        self.init(imageSource: source)
    }


    /// Set metadata for image using property dictionary.
    ///
    /// - Parameters:
    ///   - propertyName: The name of a metadata property.
    ///   - value: The value of a metadata property.
    ///   - propertyDictionary: The property dictionary which the given property name belongs to.
    /// - Returns: The result of setting metadata.
    func setMetadata(forProperty propertyName: CFString, value: CFTypeRef, propertyDictionary: ImagePropertyDictionary) -> Bool {
        return CGImageMetadataSetValueMatchingImageProperty(mutableMetadata, propertyDictionary.name, propertyName, value)
    }


    /// Set metadata for image using metata tag.
    ///
    /// - Parameters:
    ///   - propertyName: The name of a metadata property.
    ///   - value: The value of a metadata property.
    ///   - valueType: The data type of value.
    ///   - namespace: The namespace info which the given property name belongs to.
    /// - Returns: The result of setting metadata.
    func setMetadata(forProperty propertyName: CFString, value: CFTypeRef, valueType: CGImageMetadataType, namespace: ImageMetadataNamespace) -> Bool {
        guard let tag = CGImageMetadataTagCreate(namespace.scheme, namespace.prefix, propertyName, valueType, value) else {
            return false
        }
        let propertyPath = getPropertyPath(prefix: namespace.prefix, propertyName: propertyName)
        return CGImageMetadataSetValueWithPath(mutableMetadata, nil, propertyPath, tag)
    }

    func getProperties() -> ImageProperties? {
        if let rawValue = CGImageSourceCopyProperties(imageSource, nil) as? [CFString: Any] {
            return ImageProperties(rawValue: rawValue)
        }
        return nil
    }

    /// Save image and metadata to the specified image file url.
    func saveImageAndMetadata(toFile fileURL: URL) throws  {
        guard let type = CGImageSourceGetType(imageSource) else {
            throw SaveError.unsupportedImageFormat
        }

        guard let destination = CGImageDestinationCreateWithURL(fileURL as CFURL, type, 1, nil) else {
            throw SaveError.destinationFileNotFound
        }

        let cgImage = CGImageSourceCreateImageAtIndex(imageSource, 0, nil)
        CGImageDestinationAddImageAndMetadata(destination, cgImage!, mutableMetadata, nil)

        guard CGImageDestinationFinalize(destination) else {
            throw SaveError.writeMetadataToFileFailed
        }
    }
}

fileprivate extension ImageMetadataVistor {

    func getPropertyPath(prefix: CFString, propertyName: CFString) -> CFString {
        return "\(prefix):\(propertyName)" as CFString
    }
}
```

答案 1 :(得分:0)

使用UIImagePickerController进行摄像头捕获的元数据到达UIImagePickerControllerMediaMetadata键下的info字典。可以使用ImageIO框架将其复制到另一个UIImage的数据中(您将需要import ImageIO)。我的代码是Swift,但是它使用了Objective-C可可类和ImageIO C函数,因此您应该可以轻松地将其转换为Objective-C:

let jpeg = im!.jpegData(compressionQuality:1) // im is the new UIImage
let src = CGImageSourceCreateWithData(jpeg as CFData, nil)!
let data = NSMutableData()
let uti = CGImageSourceGetType(src)!
let dest = CGImageDestinationCreateWithData(data as CFMutableData, uti, 1, nil)!
CGImageDestinationAddImageFromSource(dest, src, 0, m) // m is the metadata
CGImageDestinationFinalize(dest)

此后,data是图像im的数据以及捕获中的元数据m