首页 > 解决方案 > 照片编辑扩展 - 将图像还原为原始图像

问题描述

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

为了重用代码,我有一个视图控制器类,它采用了所需的PHContentEditingController协议,我将它子类化为应用程序扩展的主界面和容器应用程序的“工作屏幕”。


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

另一方面,在容器应用程序上,我首先PHAsset通过类获取一个实例UIImagePickerController,然后直接在我的“工作”视图控制器上手动启动编辑会话,如下所示:

// '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...
        }
    })
})

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

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

但是,这仅在从容器应用程序运行时有效。如果我从扩展程序中尝试相同的技巧(即,加载包含以前编辑的图像,重置它们,然后点击“完成”),我会收到可怕的“无法保存更改”消息......


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

标签: iosphotosframework

解决方案


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

当用户从照片扩展 UI 中点击“完成”并且图像没有应用编辑(因为用户重置以前的编辑,或者没有对全新图像应用任何更改),从内部执行以下操作 finishContentEditing(completionHandler:)

  1. 创建完全没有可见变化的调整数据(“无效效果”)并将其存档为Data.

  2. PHAdjustmentData使用上面的“空效果”数据创建一个实例,formatVersionformatIdentifier正确设置。

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

  4. inputURL从编辑输入的属性中读取未修改的图像,并将其未修改PHContentEditingOutput地写入实例renderedContentURL属性指定的 url 。

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

结果:图像以其原始状态保存(未应用效果),并且不会出现警报或错误。

缺点:库资源仍处于“已编辑”状态(因为我们传递了非零编辑输出和调整数据,没有其他选择),所以下次用户尝试从 Photos.app 编辑它时,红色将出现“还原”按钮:

在此处输入图像描述

但是,选择“还原”会导致图像数据没有可见的变化(呃!),这可能会让用户感到困惑。

——

更新

我检查了内置的“标记”扩展做了什么:

在此处输入图像描述

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


推荐阅读