0 Replies
      Latest reply on Oct 22, 2018 9:24 PM by UIKid
      UIKid Level 1 Level 1 (0 points)

        I'm trying to figure out how to revert edits from within my photo editing extension.

         

        The documentation for PHContentEditingController mentions that if you return `true` from the canHandle(_:) method, you are passed an editing input that contains the original, unmodified asset and a set of adjustments to "reconstruct" its current state so that you can "change the adjustments or revert them". However, it is not clear to me how to go around "reverting" the edits successfully.

         

        I am reusing my photo editing code (a view controller that adopts PHContentEditingController) from both the extension and the container app (which supports the same editing functionality, against photo assets picked by the user from the Library).

         

        In the case of the app extension, the methods of the PHContentEditingController protocol are called by the Photos app's own editing session as per the usual flow recommended by the docs and sample code for Photo Editing Extensions.

         

        In the case of the container app, I first obtain a PHAsset from UIImagePickerController, and then run code like this:

         

        let options = PHContentEditingInputRequestOptions()
        options.canHandleAdjustmentData = { (adjustmentData) in
            return workViewController.canHandle(adjustmentData)
        }
        
        asset.requestContentEditingInput(with: options, completionHandler: { [weak self] (input, options) in
            guard let this = self else {
                 return
            }
            guard let editingInput = input else {
                // alert user and abort
                return
            }
            workViewController.asset = asset
            workViewController.startContentEditing(with: editingInput, placeholderImage: editingInput.displaySizeImage!)
            this.present(UINavigationController(rootViewController: workViewController), animated: true, completion: nil)
        })

         

        (basically creating a PHContentEditingInput and manually calling the protocol's method myself)

         

        My editing UI is such that you can apply an effect to the image, adjust its parameters, and "clear" it too (resetting the image to its initial state).

        I would like to be able to do this when editing images that have adjustment data from previous edits.

         

        I have discovered that, at least in the case of the container app, if I implement the protocol finish method like this:

         

        public func finishContentEditing(completionHandler: @escaping (PHContentEditingOutput?) -> Void) {
            guard let editingInput = self.editingInput, let inputURL = editingInput.fullSizeImageURL else {
                return completionHandler(nil) // (shouldn't happen)
            }
        
            if editingInput.adjustmentData != nil && hasUnsavedEdits == false {
                // We began with adjustment data present but no
                // edits now; this means "REVERT": 
        
                completionHandler(nil)
                return
            }
            
            // (...save resulting image...)

         

        The user will be prompted for authorization to revert the photo library asset, instead of modifying it (as is the case when passing an actual PHContentEditingOutput object to the completion handler). This is very nice because, from the calling side, I can handle both cases with the same code, regardless of whether the PHContentEditingOutput? argument of the completion handler is nil or not:

         

        workViewController.finishContentEditing(completionHandler: {(output) in
            let library = PHPhotoLibrary.shared()
            library.performChanges({
                let request = PHAssetChangeRequest(for: self.asset)
                request.contentEditingOutput = output // non-nil causes "Modify" prompt; nil causes "Revert" prompt.
        
            }, completionHandler: {(didSave, error) in
                if let error = error {
                    // (handle error)
                    
                } else if didSave {
                    // (handle success)
                } else {
                    // (handle user cancellation)
                }
            })
        })

        However, the above method fails in the app extension case: When attempting to finish an editing session by tapping the "Done" button on an image with all edits removed, and returning nil as the editing output, I get the common "Unable to Save Changes" error alert.

         

        What is the right way to revert an image (i.e., save it in its original state, with no adjustment data) from a photo editing extension?