Unable to add IPTC section to captured Photo metadata

0

Here is what my App does -

  1. Capture an image (using AVFoundation APIs)
  1. Add a new metadata tag to it (using AVCapture FileDataRepresentation())
  1. Save it to the iPhone's Photo Library (using PHPhotoLibrary creationRequest)

I'm stuck in 2) because the newly added metadata is ignored and does not show up in the saved image. The metadata I'm trying to add is a new 'IPTC' section with a 'Keywords' key, value pair. The IPTC section does not exist in the originally captured photo's metadata. Trying to modify an existing section such as an Exif keyword works just fine.

The specific problem seems to be the Data returned by the fileDataRepresentation(with: AVCapturePhotoFileDataRepresentationCustomizer) -> Data? with my Customizer function passed in. A print inside the AVCapturePhotoFileDataRepresentationCustomizer shows the IPTC dict is correctly created. (See below)

A print of the photo.metadata after the fileDataRepresentation() is called does not show it though.

I'm at my wits end! Any pointers are greatly appreciated :)


class PhotoCaptureProcessor : NSObject {
//The data resulting from the photo capture
private var photoData: Data?

//The tagName to add to IPTC Keywords
private var tagName : String

//Process the Captured photo
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
        ...
        
        if let error = error {
            print("Error capturing photo: \(error)")
        } else {
            //Write the metadata to the photo data
             self.photoData = photo.fileDataRepresentation(with: PSFileDataRepresentationCustomizer(tagName: tagName))

             //Print metedata Dict after change
             print(photo.metaData)
        }
        ...
}

//Save the photo to Photo Library with the modified metadata
func photoOutput(_ output: AVCapturePhotoOutput, didFinishCaptureFor resolvedSettings: AVCaptureResolvedPhotoSettings, error: Error?) {

...
        
        guard let photoData = photoData else {
            print("No photo data resource")
            didFinish()
            return
        }
        
        //The localIdentifier for the saved photo
        var imageIdentifier: String?
        
        PHPhotoLibrary.requestAuthorization { status in
            ...
                //Save the photo
                PHPhotoLibrary.shared().performChanges({
                    
                    let options = PHAssetResourceCreationOptions()
                    let creationRequest = PHAssetCreationRequest.forAsset()
                    options.uniformTypeIdentifier = self.requestedPhotoSettings.processedFileType.map { $0.rawValue }
                    
                    let placeholder = creationRequest.placeholderForCreatedAsset
                    imageIdentifier = placeholder?.localIdentifier
                    
                    
                    //Add the photoAsset to the Photo library
                    creationRequest.addResource(with: .photo, data: photoData, options: options)
                        
                    //Now add the photo to the album
                    let request = PHAssetCollectionChangeRequest(for: album)
                    request?.addAssets([placeholder!] as NSArray)
                    
                    ...
                    }
                    
                }, completionHandler: { success, error in
                    ...
                }
                )
            } else {
                self.didFinish()
            }
        }
    }

}

//The Customizer for fileDataRepresentation that adds the metadata to the photo Data
class PSFileDataRepresentationCustomizer: NSObject, AVCapturePhotoFileDataRepresentationCustomizer {
    
    let tagName : String
    
    init(tagName : String) {
        self.tagName = tagName
        super.init()
    }
    
    public func replacementMetadata(for photo: AVCapturePhoto) -> [String : Any]? {
        return getDict(avFoundationMetadata: photo.metadata as NSDictionary) as! [String : Any]
        
    }
    
    func getDict(avFoundationMetadata: NSDictionary)->NSMutableDictionary {
     
        let inDict: NSMutableDictionary = (avFoundationMetadata).mutableCopy() as! NSMutableDictionary
        var iptc = inDict[kCGImagePropertyIPTCDictionary] as? [CFString: Any] ?? [:]
        
        iptc[kCGImagePropertyIPTCKeywords] = String(tagName)

        inDict[kCGImagePropertyIPTCDictionary] = iptc
        
        //Print Dict Before
        print(inDict)
        
        return inDict
    }
}


//Print Dict Before shows the Keywords added

{
    DPIHeight = 72;
    DPIWidth = 72;
    Orientation = 6;
    kCGImageDestinationICCProfile = {length = 548, bytes = 0x00000224 6170706c 04000000 6d6e7472 ... 000003dc 0000c06e };
    "{Exif}" =     {
        ...
    };
    "{IPTC}" =     {
        Keywords = laptop;
    };
    "{MakerApple}" =     {
    ...
}

//Print Dict After does not

ios
swift
photo
avcapture
iptc
asked on Stack Overflow Nov 6, 2020 by Simi B • edited Nov 6, 2020 by Simi B

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0