una sincronizar metadatos lightroom importar imagen copiar archivo agregar ios swift3 core-graphics photosframework

ios - sincronizar - metadatos lightroom



Faltan metadatos de imagen al guardar la imagen actualizada en PhotoKit (1)

Resultó que no se trataba de la manipulación de la imagen o los metadatos con CoreGraphics, sino de un par de cosas que pasé por alto:

  1. La construcción de un UIImage a partir de datos que contienen datos EXIF ​​o GPS elimina esos datos ... de hecho, elimina la mayoría de los metadatos excepto un conjunto básico de JFIF y datos de tamaño (cuando se usa JPEG). Tiene sentido en retrospectiva ya que su representación interna sería solo datos brutos. Sin embargo, no encontré ninguna declaración explícita sobre los metadatos en los documentos.
  2. Dado el punto anterior, las dos formas principales de obtener un objeto de Datos (imagen con metadatos) en la biblioteca de Fotos era escribirlo en un archivo temporal y leerlo con PHAssetChangeRequest::creationRequestForAssetFromImage(atFileURL:) o usar PHAssetCreationRequest::forAsset para crear una solicitud de creación y luego usar PHAssetCreationRequest::addResource(with:data:options:) para agregar los datos como una foto. Elegí este último ya que tenía menos partes móviles.

Así que supongo que todo eso reemplaza al ALAssetsLibrary::writeImage(toSavedPhotosAlbum:metadata:completionBlock:) .

El bloque de cambio final para la biblioteca de Fotos terminó siendo este:

var assetID: String? PHPhotoLibrary.shared().performChanges({ let creationRequest = PHAssetCreationRequest.forAsset() creationRequest.addResource(with: .photo, data: imageWithMetaData as Data, options: nil) creationRequest.location = clLocation assetID = creationRequest.placeholderForCreatedAsset?.localIdentifier }) { success, error in ...

Tengo problemas para actualizar los metadatos de una imagen y guardarlos en la biblioteca de Fotos. Todo funciona, excepto que los metadatos de la imagen después de su modificación tienen entradas faltantes que estaban allí antes y no estoy recibiendo ningún error manipulando la imagen o ejecutando el bloque de cambio de la biblioteca de fotos. Además, el diccionario antes de que se vuelva a escribir en la imagen se ve como el original más mi diccionario en el depurador.

Mis preguntas son:

  1. ¿Qué estoy haciendo mal que podría volver a escribir las propiedades existentes con datos adicionales para eliminar lo que hay allí?
  2. ¿Hay alguna forma mejor y más canónica para hacer esto? Parece una gran cantidad de mecánicos actualizar algunos metadatos en una imagen. Simplemente parece lo que todo el mundo está haciendo.

EDITAR:

Antes del guardado, todos los valores de Exif y Tiff están presentes. Esta es la totalidad de los metadatos después de guardar en las fotos usando el siguiente código:

["PixelHeight": 2448, "PixelWidth": 3264, "{Exif}": { ColorSpace = 1; PixelXDimension = 3264; PixelYDimension = 2448;}, "Depth": 8, "ProfileName": sRGB IEC61966-2.1, "Orientation": 1, "{TIFF}": { Orientation = 1;}, "ColorModel": RGB, "{JFIF}": { DensityUnit = 0; JFIFVersion = ( 1, 0, 1 ); XDensity = 72; YDensity = 72;}]

El código, todo en Swift 3, prueba en iOS 10.1

El flujo de trabajo básico es:

// Get a mutable copy of the existing Exif meta let mutableMetaData = getMutableMetadataFrom(imageData: data) // Check to see if it has the {GPS} entry, if it does just exit. if let _ = mutableMetaData[kCGImagePropertyGPSDictionary as String] { callback(imageAsset, true, nil) return } // Add the {GPS} tag to the existing metadata let clLocation = media.location!.asCLLocation() mutableMetaData[kCGImagePropertyGPSDictionary as String] = clLocation.asGPSMetaData() // Attach the new metadata to the existing image guard let newImageData = attach(metadata: mutableMetaData, toImageData: data) else { callback(imageAsset, false, nil) return } let editingOptions = PHContentEditingInputRequestOptions() imageAsset.requestContentEditingInput(with: editingOptions) { editingInput, info in guard let editingInput = editingInput else { return } let library = PHPhotoLibrary.shared() let output = PHContentEditingOutput(contentEditingInput: editingInput) output.adjustmentData = PHAdjustmentData(formatIdentifier: "Project", formatVersion: "0.1", data: "Location Adjustment".data(using: .utf8)!) do { try newImageData.write(to: output.renderedContentURL, options: [.atomic]) } catch { callback(imageAsset, false, error) return } library.performChanges({ let changeRequest = PHAssetChangeRequest(for: imageAsset) changeRequest.location = clLocation changeRequest.contentEditingOutput = output }, completionHandler: { success, error in ... ...

Los métodos auxiliares para el flujo de trabajo son:

func attach(metadata: NSDictionary, toImageData imageData:Data) -> Data? { guard let imageDataProvider = CGDataProvider(data: imageData as CFData), let cgImage = CGImage(jpegDataProviderSource: imageDataProvider, decode: nil, shouldInterpolate: true, intent: .defaultIntent), let newImageData = CFDataCreateMutable(nil, 0), let type = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, "image/jpg" as CFString, kUTTypeImage), let destination = CGImageDestinationCreateWithData(newImageData, (type.takeRetainedValue()), 1, nil) else { return nil } CGImageDestinationAddImage(destination, cgImage, metadata as CFDictionary) CGImageDestinationFinalize(destination) guard let newProvider = CGDataProvider(data: newImageData), let newCGImage = CGImage(jpegDataProviderSource: newProvider, decode: nil, shouldInterpolate: false, intent: .defaultIntent) else { return nil } return UIImageJPEGRepresentation(UIImage(cgImage: newCGImage), 1.0) } func getMutableMetadataFrom(imageData data : Data) -> NSMutableDictionary { let imageSourceRef = CGImageSourceCreateWithData(data as CFData, nil) let currentProperties = CGImageSourceCopyPropertiesAtIndex(imageSourceRef!, 0, nil) let mutableDict = NSMutableDictionary(dictionary: currentProperties!) return mutableDict }

También asGPSMetaData es una extensión de CLLocation que parece una versión de Swift 3 de este Gist