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

问题描述 投票:-1回答:2

我正在拍摄用户拍照时的照片:

- (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提供了支持为Photos应用构建照片编辑扩展的类。在iOS和tvOS中,PhotoKit还可以直接访问由照片应用管理的照片和视频资产。

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

ios uiimage exif
2个回答
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
    }
}
```

0
投票

使用UIImagePickerController从摄像头捕获的元数据到达UIImagePickerControllerMediaMetadata键下的info字典。可以使用ImageIO框架将其复制到另一个UIImage的数据中(您需要使用import ImageIO)。我的代码是Swift,但它使用Objective-C Cocoa类和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

© www.soinside.com 2019 - 2024. All rights reserved.