2016-12-15 15 views
6

Tôi gặp sự cố khi cập nhật siêu dữ liệu của hình ảnh và lưu lại hình ảnh đó vào thư viện Ảnh. Mọi thứ hoạt động ngoại trừ siêu dữ liệu hình ảnh sau khi bị thay đổi đã thiếu các mục nhập trước đó và tôi không nhận được bất kỳ lỗi nào thao tác hình ảnh hoặc thực thi khối thay đổi thư viện ảnh. Ngoài ra, từ điển trước khi nó được viết trở lại vào hình ảnh trông giống như bản gốc cộng với từ điển của tôi trong trình gỡ rối.Thiếu siêu dữ liệu hình ảnh khi lưu hình ảnh được cập nhật vào PhotoKit

Câu hỏi của tôi là:

  1. Tôi đang làm gì sai có thể gây ra viết lại tính hiện trở lại với dữ liệu bổ sung để quét sạch những gì đang có?
  2. Có cách nào tốt hơn, kinh điển hơn để thực hiện việc này không? Có vẻ như rất nhiều cơ chế cập nhật một số dữ liệu meta trong một hình ảnh. Nó có vẻ giống như Những gì mọi người khác đang làm.

EDIT:

Trước khi tất cả các Exif và Tiff giá trị tiết kiệm có mặt. Đây là toàn bộ các siêu dữ liệu sau khi lưu vào hình ảnh bằng cách sử dụng mã bên dưới:

["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;}] 

Mã, tất cả trong Swift 3, thử nghiệm trên iOS 10.1

Các công việc cơ bản là:

// 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 ... ... 

các phương pháp helper cho công việc là:

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 
} 

Ngoài ra asGPSMetaData là một phần mở rộng trên CLLocation hơn là một phiên bản Swift 3 của this Gist

Trả lời

5

Nó chỉ ra rằng nó không phải là thao tác của hình ảnh hoặc siêu dữ liệu với CoreGraphics, đó là một vấn đề mà tôi bỏ qua:

  1. Xây dựng một UIImage từ dữ liệu có chứa EXIF ​​hoặc dữ liệu GPS loại bỏ dữ liệu ... trên thực tế, nó loại bỏ nhất các dữ liệu meta trừ một bộ cốt lõi của dữ liệu kích thước JFIF và (khi sử dụng JPEG). Nó có ý nghĩa trong hồi tưởng khi đại diện nội bộ của họ sẽ chỉ là dữ liệu thô. Tuy nhiên, tôi không tìm thấy bất kỳ tuyên bố rõ ràng nào về siêu dữ liệu trong tài liệu.
  2. Với điểm trước, hai cách chính để có được một dữ liệu (hình ảnh với siêu dữ liệu) đối tượng vào thư viện hình ảnh đã được một trong hai để viết nó vào một tập tin tạm thời và đọc nó với PHAssetChangeRequest::creationRequestForAssetFromImage(atFileURL:) hoặc sử dụng PHAssetCreationRequest::forAsset tạo một yêu cầu sáng tạo và sau đó sử dụng PHAssetCreationRequest::addResource(with:data:options:) để thêm dữ liệu dưới dạng ảnh. Tôi đã chọn cái sau vì nó ít di chuyển các phần .

Vì vậy, tôi đoán tất cả những điều đó sẽ thay thế tốt đẹp, ngắn gọn ALAssetsLibrary::writeImage(toSavedPhotosAlbum:metadata:completionBlock:).

Sự thay đổi khối cuối cùng cho thư viện Ảnh rốt cuộc là thế này:

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 ... 
+0

đúng - tính đến ngày hôm nay, UIImage không lưu giữ metadata. Tài liệu sẽ được cập nhật ngay để phản ánh điều này. – Bobjt

+0

Vẫn không có cách nào có thể cho uiimage để bảo vệ siêu dữ liệu? Nó có thể âm thanh không liên quan nhưng nó không, trần với tôi. Tôi có một ứng dụng ảnh sử dụng GPUImage, khi tôi sử dụng hình ảnh đầu vào như ảnh chụp màn hình của điện thoại, nó làm biến dạng hình ảnh nhưng khi sử dụng hình ảnh đầu vào như ảnh chụp bằng cam của điện thoại, nó sẽ không làm biến dạng nó, tôi đã nhận thấy ảnh chụp màn hình không bảo vệ siêu dữ liệu nhưng bức ảnh máy ảnh làm, bất kỳ cách nào để sửa chữa nó? @Ray Pendergraph –

+0

Tôi không chắc chắn điều này có thể là "cố định" vì nó không phải là một lỗi thực sự. Một UIImage thực sự chỉ là biểu diễn bộ nhớ của một hình ảnh cho iOS (không được ghi chép một cách rõ ràng, nhưng không phải là một sự tách biệt không phổ biến với các khung công tác UI) và như vậy sẽ không mang bất kỳ siêu dữ liệu nào với nó. Đây là lý do tại sao bạn sẽ phải sử dụng tài sản để lấy dữ liệu. Ảnh chụp màn hình cũng có dữ liệu Exif (không có dữ liệu GPS). –

Các vấn đề liên quan