Можете ли вы скопировать данные exif UIImage в масштабированный UIImage? - PullRequest
0 голосов
/ 01 марта 2019

В настоящее время я получаю фотографию, когда пользователь делает снимок:

- (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];
}

Это прекрасно работает, файл создается в формате JPEG с данными EXIF.

Теперь я хотел бынемного уменьшить изображение, чтобы сделать его немного меньше.Однако я хотел бы сохранить некоторые или все данные EXIF, которые существовали в исходном UIImage, и скопировать их в масштабированное изображение.

В настоящее время масштабирование изображения:

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 также предоставляет прямой доступ к фото и видео активам, управляемым приложением Photos.

Однако я не использую приложение Photos, мое изображение не поступает из локальной библиотеки фотографийили icloud, поскольку я хочу сохранить фотографию только в своем личном пространстве приложения.

Ответы [ 2 ]

0 голосов
/ 01 марта 2019

Метаданные из захвата камеры с использованием UIImagePickerController поступают в словарь info под ключом UIImagePickerControllerMediaMetadata.Его можно скопировать в данные для другого UIImage с помощью каркаса ImageIO (вам потребуется 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 из захвата.

0 голосов
/ 01 марта 2019

см. Эта статья .

Ниже моя реализация

```
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
    }
}
```
...