Migration from v10
Update dependencies#
PhotoEditor SDK requires iOS 13+ and Xcode 14.3.1+ with Swift 5.8+. If you have to use older versions of Swift or support older versions of iOS, please have a look at previous versions.
Swift Package Manager#
Go to your Xcode project Package Dependencies section, make sure that the version policy for the pesdk-ios-build
package includes v11:
Then select File > Packages > Update to Latest Package Versions.
For more details about using Swift Package Manager see the official guide.
CocoaPods#
Your Podfile
should already contain the proper entry:
pod 'PhotoEditorSDK'
To perform the actual update, run the following command:
pod update PhotoEditorSDK --repo-update
During a successful update to v11, you should get a similar output:
Installing PhotoEditorSDK 11.0.0 (was 10.30.0)Installing imglyKit 11.0.0 (was 10.30.0)
For more details about using CocoaPods see the official guide.
Manually#
Download the latest version of the SDK here, then replace ImglyKit.framework
as well as PhotoEditorSDK.framework
in the Frameworks, Libraries, and Embedded Content
section of your target and make sure that the Embed & Sign
option is selected for both of them:
For more details about manual integration see the getting started section.
UIKit#
CameraViewController#
The CameraViewController
now returns its results within a single completionBlock
:
- cameraViewController.completionBlock = { image, url in- // ...- }- cameraViewController.dataCompletionBlock = { data in- // ...- }+ cameraViewController.completionBlock = { result in+ // ...+ }
- [cameraViewController setCompletionBlock:^(UIImage * _Nullable image, NSURL * _Nullable url) {- // ...- }];- [cameraViewController setDataCompletionBlock:^(NSData * _Nullable imageData) {- // ...- }];+ [cameraViewController setCompletionBlock:^(PESDKCameraResult * _Nonnull result) {+ // ...+ }];
The new CameraResult
parameter optionally contains either:
- JPEG
data
along with EXIF information or - the
url
of the recorded video.
It also adds the model
property to be able to pass, e.g., the filter state stored in PhotoEditModel
between the camera and the editor.
There is no UIImage
property in the result. You can still create it from data
using UIImage(data:)
.
To create a Photo
and pass it to the editor, use Photo(data:)
accordingly:
let cameraViewController = CameraViewController()cameraViewController.completionBlock = { [unowned cameraViewController] result inguard let data = result.data else { return }let photo = Photo(data: data)let photoEditViewController = PhotoEditViewController(photoAsset: photo)photoEditViewController.delegate = selfcameraViewController.present(photoEditViewController, animated: true, completion: nil)}present(cameraViewController, animated: true, completion: nil)
PhotoEditViewControllerDelegate#
The PhotoEditViewControllerDelegate
uses extensible return types.
See the examples below to integrate the improved result API with your existing code.
Getting the image#
- func photoEditViewController(_ photoEditViewController: PhotoEditViewController, didSave image: UIImage, and data: Data)+ func photoEditViewControllerDidFinish(_ photoEditViewController: PhotoEditViewController, result: PhotoEditorResult)
The first thing you may notice is that the UIImage
parameter was removed. Using UIImage
directly is discouraged as it does not contain EXIF metadata. Please see the export section for more details.
You can still consume the output image directly in UIKit
using UIImage(data:)
.
The PhotoEditorResult
parameter has three inner properties:
output
- stores thedata
parameter with additional metadata (such as the type identifier),status
- indicates which exact path was chosen by the user, whether the input image was processed by our rendering pipeline or just passed without changes. This extends thephotoEditViewController.hasChanges
property.task
- encapsulates the input data (context) passed to the editor.
In most cases, you will store or upload your output image directly from Data
. Then, you will need to replace the previously used data
with result.output.data
inside your delegate methods.
While saving to the filesystem, you can leverage the additional property result.output.uti
to create a file extension:
func photoEditViewControllerDidFinish(_ photoEditViewController: PhotoEditViewController, result: PhotoEditorResult) {guard let uti = result.output.uti, let type = UTType(uti as String) else { return }// Get a reference to the temporary directory and append the filename and extension.let temporaryDirectoryURL = FileManager.default.temporaryDirectory// Append a random filename with an extension matching the output format's UTI.let localURL = temporaryDirectoryURL.appendingPathComponent(UUID().uuidString, conformingTo: type)if FileManager.default.fileExists(atPath: localURL.path) {// Remove the file at the destination if it already exists.try? FileManager.default.removeItem(at: localURL)}// Write image data to `localURL`.try? result.output.data.write(to: localURL)presentingViewController?.dismiss(animated: true, completion: nil)}
Error handling#
- func photoEditViewControllerDidFailToGeneratePhoto(_ photoEditViewController: PhotoEditViewController)+ func photoEditViewControllerDidFail(_ photoEditViewController: PhotoEditViewController, error: PhotoEditorError)
The PhotoEditorError
is passed to provide different fallback paths, as well as debugging possibilities.
You can query the error object for its reason
and optional underlyingError
properties:
func photoEditViewControllerDidFail(_ photoEditViewController: PhotoEditViewController, error: PhotoEditorError) {// There was an error generating the photo.print(error.localizedDescription)switch error.reason {case .inputImageNotFound:()case .renderingFailed:()default:()}// Dismissing the editor.presentingViewController?.dismiss(animated: true, completion: nil)}
Starting the rendering (optional)#
There is also a new optional method that you can implement to perform additional validation of the input task
and interrupt the rendering process if necessary:
func photoEditViewControllerShouldStart(_ photoEditViewController: PhotoEditViewController, task: PhotoEditorTask) -> Bool {true}
SwiftUI#
Working with SwiftUI PhotoEditor
you are already familiar with PhotoEditorResult
as well as with the onDidSave
and onDidFail
modifiers. The new version provides a consistent API with its UIKit counterpart so that you can reuse the same straightforward patterns in your closures.
Camera#
< markdownPath="../../shared/migration/camera_swiftui.mdxThere is no
UIImageproperty in the result, you can still create it from
datausing
UIImage(data:)`.
PhotoEditor#
Getting the image#
.onDidSave { result in// ...}
The onDidSave
modifier type did not change, but the PhotoEditorResult
itself is extended.
In most cases, you will store or upload your output image directly from Data
. Then, you will need to replace result.data
with result.output.data
inside your closures.
For more details about consuming the results, see the getting the image section for UIKit.
Error handling#
- .onDidFail {+ .onDidFail { error in
The onDidFail
modifier passes the actual PhotoEditorError
that can be handled accordingly:
.onDidFail { error in// There was an error generating the photo.print("Editor finished with error: \(error.localizedDescription)")switch error.reason {case .inputImageNotFound:()case .renderingFailed:()default:()}}
Starting the rendering (optional)#
There is also a new optional modifier that you can implement to perform additional validation of the input task
and interrupt the rendering process if necessary:
.onShouldStart { task intrue}
Explicit use of AssetCatalog#
< markdownPath="../../shared/migration/asset_catalog.mdx`
IMGLY extension namespace#
< markdownPath="../../shared/migration/namespacing.mdx`