照片编辑扩展 - 将图像还原为原始图像

Photo Editing Extension - Revert Image to Original

我正在为 iOS 开发照片编辑扩展程序,捆绑在提供相同照片编辑功能的容器应用程序中。

为了重用代码,我有一个视图控制器 class 采用了所需的 PHContentEditingController 协议,我将其子class编辑为同时用作应用程序扩展,以及作为容器应用程序的 "working screen"。


在编辑扩展中, 控制器的方法由照片应用程序的编辑会话调用,如 Apple 文档和各种教程中所述可以在网上找到。

在容器应用上,另一方面,我首先通过UIImagePickerController class,然后直接在我的 "work" 视图控制器上手动启动编辑会话,如下所示:

// 'work' is my view controller which adopts
// `PHContentEditingController`. 'workNavigation'
// embeds it.

let options = PHContentEditingInputRequestOptions()
options.canHandleAdjustmentData = { (adjustmentData) in
    return work.canHandle(adjustmentData)
}

asset.requestContentEditingInput(with: options, completionHandler: { [weak self] (input, options) in
    // (Called on the Main thread on iOS 10.0 and above)
    guard let this = self else {
        return
    }
    guard let editingInput = input else {
        return
    }
    work.asset = asset
    work.startContentEditing(with: editingInput, placeholderImage: editingInput.displaySizeImage!)
    this.present(workNavigation, animated: true, completion: nil)
})

当用户完成编辑时,工作视图控制器调用finishContentEditing(completionHandler:自身来完成会话:

self.finishContentEditing(completionHandler: {(output) in
    // nil output results in "Revert" prompt.
    // non-nil output results in "Modify" prompt. 

    let library = PHPhotoLibrary.shared()
    library.performChanges({
        let request = PHAssetChangeRequest(for: self.asset)
        request.contentEditingOutput = output

    }, completionHandler: {(didSave, error) in
        if let error = error {
            // handle error...

        } else if didSave {
            // proceed after saving...

        } else {
            // proceed after cancellation...
        }
    })
})

在编辑会话中,用户可以 'clear' 以前的编辑作为 调整数据 传递,有效地将图像恢复到其原始状态。 我注意到,如果我通过使用 nil 作为参数(而不是有效的 PHContentEditingOutput 对象)调用传递给 finishContentEditing(completionHandler:) 的完成处理程序来完成编辑,照片框架将提示用户 "revert" 图像而不是 "modifying" 它:

func finishContentEditing(completionHandler: @escaping (PHContentEditingOutput?) -> Void) {

    guard let editingInput = self.editingInput, let inputURL = editingInput.fullSizeImageURL else {
        return completionHandler(nil)
    }

    if editingInput.adjustmentData != nil && hasUnsavedEdits == false {
        // We began with non-nil adjustment data but now have 
        // no outstanding edits - means REVERT:

        return completionHandler(nil)
    }

    // (...proceed with writing output to url...)

但是,这仅在容器应用程序 运行 时有效。 如果我在 扩展 中尝试相同的技巧(即加载包含先前编辑的图像,重置它们,然后点击 'Done')我收到可怕的 "Unable to Save Changes" 消息...


从照片编辑扩展程序中恢复以前对图像的编辑的正确方法是什么?

几个月后,仍然没有答案,所以我不情愿地采用了这个解决方法(这仍然比错误警报更可取):

当用户从照片扩展 UI 中点击 "Done" 并且图像没有应用任何编辑时(因为用户重置了以前的编辑,或者没有对图像应用任何更改)全新图像),从 finishContentEditing(completionHandler:):

中执行以下操作
  1. 创建完全没有可见变化的调整数据 ("null effect") 并将其存档为 Data.

  2. 使用上面的 "null effect" 数据创建一个 PHAdjustmentData 实例,正确设置 formatVersionformatIdentifier

  3. 从会话开始时传递的编辑输入创建一个PHContentEditingOutput实例(像往常一样),并设置上面创建的调整数据。

  4. 从编辑输入inputURL属性中读取未修改的图片,未修改写入[=84] =] 由 PHContentEditingOutput 实例的 renderedContentURL 属性.

  5. 指定
  6. 调用 completionHandler 块,传递编辑输出实例(正常)。

结果:图像以原始状态保存(未应用任何效果),未出现任何警报或错误。

缺点:库资源保持在'edited'状态(因为我们通过了非nil编辑输出和调整数据,没有其他选择),所以下次用户尝试从 Photos.app 编辑它时,红色的 'Revert' 按钮将会出现:

然而,选择 'revert' 导致图像数据 无可见变化 (呃!),这可以是让用户感到困惑。

——

更新

我检查了内置“标记”扩展的功能:

...这与我上面的解决方法一致,所以我想这是最好的办法了。