<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Social Media – IMG.LY Blog</title><description>Posts tagged Social Media on the IMG.LY blog.</description><link>https://img.ly/blog/tag/social-media/</link><language>en-us</language><image><url>https://img.ly/apple-touch-icon.png</url><title>Social Media – IMG.LY Blog</title><link>https://img.ly/blog/tag/social-media/</link></image><atom:link href="https://img.ly/blog/tag/social-media/rss.xml" rel="self" type="application/rss+xml"/><generator>Astro</generator><lastBuildDate>Fri, 19 Jun 2026 11:26:06 GMT</lastBuildDate><ttl>60</ttl><item><title>How to Build a TikTok Clone for iOS with Swift &amp; CreativeEditor SDK</title><link>https://img.ly/blog/how-to-build-a-tiktok-clone-for-ios/</link><guid isPermaLink="true">https://img.ly/blog/how-to-build-a-tiktok-clone-for-ios/</guid><description>Learn how to build a TikTok clone for iOS with Swift and CreativeEditor SDK with this step-by-step in-depth tutorial.</description><pubDate>Thu, 30 Mar 2023 11:20:26 GMT</pubDate><content:encoded>&lt;p&gt;Now that TikTok is facing a ban in the US any day now, we better wait in the wings with an alternative ready to go and scoop up those millions of hobby dancers, micro bloggers, and would-be influencers.&lt;/p&gt;
&lt;p&gt;In this article, you’ll learn how to use Swift, SwiftUI, and the IMG.LY CreativeEditor SDK to build a simple iOS app for recording, editing, and viewing short videos. This app features views providing core functionalities similar to making a post in a video-sharing platform like TikTok.&lt;/p&gt;
&lt;p&gt;The editing controller is the central hub. It allows users to capture video clips and enhance their videos by adding filters, stickers, music, and other effects. CreativeEditor SDK calls the overall project a “scene” and the parts (clips, stickers, text, etc.) “blocks”. Once the scene is ready, the user can compose it into a standard video file and export it. Finally, the playback controller showcases the finished projects using Apple’s standard VideoPlayer struct. For recording and editing, the CreativeEditor SDK’s Camera and Video Editor handle the heavy lifting, enabling swift development of a robust app. You can easily extend its features, filters, and creative options as your users demand.&lt;/p&gt;
&lt;p&gt;Follow along to see how to capture video, enhance it, and export the finished product as a polished movie file.&lt;/p&gt;
&lt;h2 id=&quot;setting-up-your-project&quot;&gt;Setting Up Your Project&lt;/h2&gt;
&lt;p&gt;You can try out the TikTok clone by cloning the &lt;a href=&quot;https://github.com/imgly/tiktok-clone-ios-cesdk&quot;&gt;GitHub repository supporting the article&lt;/a&gt;. Otherwise, follow this step-by-step tutorial and learn how to build the TikTok clone with CreativeEditor SDK by yourself.&lt;/p&gt;
&lt;p&gt;To add the CreativeEditor SDK to an Xcode project, include it with your other package dependencies. Use the URL below to add the package, either to your &lt;code&gt;Package.swift&lt;/code&gt; file or using &lt;code&gt;File &gt; Add Packages...&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;https://github.com/imgly/IMGLYUI-swift&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The package includes a number of different frameworks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;IMGLYUI, an umbrella framework of all of the different editors and a camera.&lt;/li&gt;
&lt;li&gt;IMGLYCamera, a standalone camera View. This is the same camera as the editors use.&lt;/li&gt;
&lt;li&gt;IMGLYApparelEditor, IMGLYDesignEditor, IMGLYPostcardEditor, and IMGLYVideoEditor which are four different configurations to support different use cases.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each of these frameworks uses the IMG.LY Engine for image processing. To include them in your project, navigate to the ‘Frameworks, Libraries, and Embedded Content’ section in your app’s General settings. Click the ’+’ button and select the desired frameworks. Initially, consider adding the IMGLYUI package, as it encompasses all other packages. Before releasing your app, review and include only the necessary components to minimize app size and avoid unused code.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Adding a framework to the app&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 590px) 590px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;590&quot; height=&quot;646&quot; src=&quot;https://img.ly/_astro/frameworks_ZpiIEt.webp&quot; srcset=&quot;/_astro/frameworks_ZpiIEt.webp 590w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Once Xcode downloads and resolves the packages, you just need to &lt;code&gt;include IMGLYVideoEditor&lt;/code&gt; in any of the files that will reference the editor in your app. When you’re working with the underlying engine directly you’ll also want to &lt;code&gt;include IMGLYEngine&lt;/code&gt;. You’ll only work with the engine as you start to customize the workflow.&lt;/p&gt;
&lt;h2 id=&quot;asking-for-permissions&quot;&gt;Asking for Permissions&lt;/h2&gt;
&lt;p&gt;Before any app can access the phone’s microphone, camera, documents or photo library, the user must specifically give permission to record audio or video as well as access the user’s Photo library. If your app doesn’t secure these permissions properly before trying to use the camera the app will crash and also probably won’t get through Apple’s app review. In earlier versions of iOS you could develop an app on the Simulator without asking permissions, but always on the device the app will crash. In current versions of iOS the app crashes regardless of platform. The dialogue requesting permissions is a system dialog and looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;permission dialog&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 820px) 820px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;820&quot; height=&quot;453&quot; src=&quot;https://img.ly/_astro/permission1_ZWFkBh.webp&quot; srcset=&quot;/_astro/permission1_1LPnuv.webp 640w, /_astro/permission1_OFysD.webp 750w, /_astro/permission1_ZWFkBh.webp 820w&quot;&gt;&lt;/p&gt;
&lt;p&gt;You do not have the ability to change this dialog. You can supply the reason you are asking for the permission using a key in the &lt;code&gt;info.plist&lt;/code&gt; file in the Xcode project. In the example above “Lets you record videos” is in the &lt;code&gt;info.plist&lt;/code&gt;. For the video camera you will have to ask for video and audio permission. The first step is to add a short message to the user in the &lt;code&gt;info.plist&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Info plist example&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 723px) 723px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;723&quot; height=&quot;102&quot; src=&quot;https://img.ly/_astro/infoplist_FispA.webp&quot; srcset=&quot;/_astro/infoplist_1Jamxn.webp 640w, /_astro/infoplist_FispA.webp 723w&quot;&gt;&lt;/p&gt;
&lt;p&gt;For video the key to add is &lt;code&gt;NSCameraUsageDescription&lt;/code&gt; and for the microphone you need to add &lt;code&gt;NSMicrophoneUsageDescription&lt;/code&gt;. Whenever your app attempts to use the camera, iOS will first check to see if the user has already granted access. If not, it will then display the dialogs using your entries in the &lt;code&gt;info.plist&lt;/code&gt; or crash if you have not provided entries. The user might be surprised by these dialog boxes and may accidentally tap &lt;code&gt;Don&apos;t Allow&lt;/code&gt; if they are trying to quickly launch the camera. It is better practice to set up some kind of onboarding view and secure the permissions before you need them. You might have a view that explains what you are going to ask for and then displays the permission dialog.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;switch&lt;/span&gt;&lt;span&gt; AVCaptureDevice.&lt;/span&gt;&lt;span&gt;authorizationStatus&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt;: .video) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  case&lt;/span&gt;&lt;span&gt; .authorized&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    //the user has authroized permission!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    break&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  case&lt;/span&gt;&lt;span&gt; .denied&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    //the user has previously denied permission!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    //perhaps we should ask them again&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    break&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  case&lt;/span&gt;&lt;span&gt; .restricted&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    //the user cannot grant permission!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    break&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  case&lt;/span&gt;&lt;span&gt; .notDetermined&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    //the user has never been asked for permission&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    //so let&apos;s ask them now&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    AVCaptureDevice.&lt;/span&gt;&lt;span&gt;requestAccess&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt;: .video) { accessGranted &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      if&lt;/span&gt;&lt;span&gt; accessGranted {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        //the user has authorized permission!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      } &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        //the user has denied permission!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  @unknown&lt;/span&gt;&lt;span&gt; default:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    break&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The snippet above lets your app read the permission status for the video camera and ask for permission if it has not been granted. To request access to the microphone pass &lt;code&gt;.audio&lt;/code&gt; to the &lt;code&gt;AVCaptureDevice.authorizationStatus(for:)&lt;/code&gt; and &lt;code&gt;AVCaptureDevice.requestAccess(for:)&lt;/code&gt; functions. The &lt;code&gt;AVCaptureDevice.requestAccess(for:)&lt;/code&gt; command is what displays the system dialog actually requesting access. The &lt;code&gt;accessGranted&lt;/code&gt; variable reports back to your app what the user chose. You can take care of getting the permissions any time but when the CreativeEditor SDK first launches it will attempt to access the camera, so the dialog will appear if the user has not already granted permission.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;.restricted&lt;/code&gt; case is fairly new. In this case, there are policies on the phone that prohibit the user from granting permission to your app. In addition to asking permissions during onboarding, it is good practice to check for permission every time before you attempt to run any code that uses the camera. The user can change permissions using the Settings app on their phone at any time. If the user has denied permissions and you present the video camera anyway, your app will record black video frames and silence on audio tracks.&lt;/p&gt;
&lt;p&gt;In addition to asking for camera and microphone permissions, your app will probably want to access the photos on the user’s phone. You will need to add an entry to the &lt;code&gt;info.plist&lt;/code&gt; for &lt;code&gt;NSPhotoLibraryUsageDescription&lt;/code&gt;. As with the camera and the microphone, the dialog will appear when the Video Editor first attempts access, but you can give your user some ability to grant permission during onboarding. For the user’s photos, you can check the authorization status using&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; status &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; PHPhotoLibrary.&lt;/span&gt;&lt;span&gt;authroizationStatus&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt;: .readWrite)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As with the camera, the photo library has &lt;code&gt;PHPhotoLibrary.requestAuthroization(for: .readWrite)&lt;/code&gt; but instead of just returning a “granted” or “denied” status, this command returns the actual new status. In addition to the status values for the camera, the photo library may return a &lt;code&gt;.limited&lt;/code&gt; status meaning that the user has granted permission to only some of the photos. If the user has chosen to share only some of their photos, Apple provides some views you can present so that the user can manage the photos. Any videos that your app saves to the user’s photo library will always be available when the user has chosen &lt;code&gt;.limited&lt;/code&gt;. You can read more about how to work with permissions and the user’s photo library by reading this Apple article &lt;a href=&quot;https://developer.apple.com/documentation/photokit/delivering-an-enhanced-privacy-experience-in-your-photos-app&quot;&gt;Delivering an Enhanced Privacy Experience in Your Photos App&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;making-video-recordings&quot;&gt;Making Video Recordings&lt;/h2&gt;
&lt;p&gt;The start of a great TikTok is the camera. When our user wants to make a new video clip with our app, they tap on the button at the bottom of the initial screen to start the creation workflow.&lt;/p&gt;
&lt;p&gt;Here there is a decision to make. TikTok and the CreativeEditor SDK can each start with the creation controls and a video preview. When using the CreativeEditor SDK though, you can also start with some video that came from somewhere else. So if you already have some camera code you like, or if you want to start with some video clip from somewhere else, you can insert that into the editor when it launches. You can do that by leveraging the &lt;code&gt;onCreate&lt;/code&gt; modifier of the editor.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; engine &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; EngineSettings&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;license&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;&amp;#x3C;your license code&gt;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                              userID&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;&amp;#x3C;your unique user id&gt;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;VideoEditor&lt;/span&gt;&lt;span&gt;(engine)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  .imgly.&lt;/span&gt;&lt;span&gt;onCreate&lt;/span&gt;&lt;span&gt;({ engine &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    try&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; engine.scene.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;fromVideo&lt;/span&gt;&lt;span&gt;: Bundle.main.&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;forResource&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;dog_water&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;withExtension&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;mov&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    //set other defaults&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the code above, the app initializes an instance of the Video Editor view and then reads the &lt;code&gt;dog_water.mov&lt;/code&gt; file from the app bundle. launches the editor with that.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Starting scene with a dog video&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 480px) 480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;480&quot; height=&quot;1039&quot; src=&quot;https://img.ly/_astro/prepopulated_2uzsKx.webp&quot; srcset=&quot;/_astro/prepopulated_2uzsKx.webp 480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Whether starting with a video or starting with a blank canvas a user can add video clips to their creation using the embedded camera.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;difference between tiktok camera and creativeeditor&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 640px) 640px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;640&quot; height=&quot;674&quot; src=&quot;https://img.ly/_astro/updated_editor_compare_1tFFER.webp&quot; srcset=&quot;/_astro/updated_editor_compare_1tFFER.webp 640w&quot;&gt;&lt;/p&gt;
&lt;p&gt;The image above compares two different camera controllers: the left one from the TikTok app and the right showing the default settings of the MobileCamera, either standalone or within a Video Editor scene. Key controls in each are marked with blue numbers:&lt;/p&gt;
&lt;p&gt;1 - Flip camera button&lt;br&gt;
2 - Flash button&lt;br&gt;
3 - Recording time indicator&lt;br&gt;
4 - Add video and finish buttons&lt;br&gt;
5 - Cancel button&lt;/p&gt;
&lt;p&gt;While the TikTok camera integrates several editing functions during video capture, the Video Editor separates these tasks, focusing the camera purely on recording. Both systems allow users to start and stop video recording to compile a series of clips before moving to the editing phase.&lt;/p&gt;
&lt;h3 id=&quot;configuring-the-camera&quot;&gt;Configuring the Camera&lt;/h3&gt;
&lt;p&gt;The camera used inside of the Video Editor UI isn’t customizable. You have limited options to customize when you use the standalone camera though. You can set the colors of the buttons, helpful if you have a preferred color scheme, and you can set a maximum duration for the video recording allowed.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; config &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; CameraConfiguration&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  recordingColor&lt;/span&gt;&lt;span&gt;: .orange,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  highlightColor&lt;/span&gt;&lt;span&gt;: .blue,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  maxTotalDuration&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;30&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  allowExceedingMaxDuration&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Camera&lt;/span&gt;&lt;span&gt;(engine, &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;: config) { result &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; //handle the recorded video collection&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code above sets the record button to orange while recording and the clip view to orange. There is a maximum duration of 30 seconds for all videos in the collection and the button to save the clips highlighted in blue.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;customized camera&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 480px) 480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;480&quot; height=&quot;1039&quot; src=&quot;https://img.ly/_astro/customcamera_Z2tXDPj.webp&quot; srcset=&quot;/_astro/customcamera_Z2tXDPj.webp 480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;If your app requires further customization, you’ll probably want to make your own camera view and work with the IMG.LY Creative Engine directly.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://img.ly/docs/cesdk/ios/get-started/overview-e18f40/&quot;&gt;documentation website&lt;/a&gt; is a great resource for understanding how much you can add to and customize the IMGLYUI resources and when you’ll need to drop down to the level of the engine.&lt;/p&gt;
&lt;h3 id=&quot;presenting-the-controller&quot;&gt;Presenting the Controller&lt;/h3&gt;
&lt;p&gt;As demonstrated above, both the Video Editor and the Camera are View structures that can be presented directly or through overlays such as overlay or fullScreenCover. However, they are typically enclosed in a NavigationView to utilize the navigation bar for displaying export and other buttons. Therefore, when triggering the Video Editor from a button, it’s crucial to embed it within a NavigationView.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Button&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Edit the Video&quot;&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  isPresented &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; .&lt;/span&gt;&lt;span&gt;fullScreenCover&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;isPresented&lt;/span&gt;&lt;span&gt;: $isPresented) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   NavigationView&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     VideoEditor&lt;/span&gt;&lt;span&gt;(engine)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      //any setup modifiers&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;building-your-creation&quot;&gt;Building Your Creation&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;compare editors&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 640px) 640px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;640&quot; height=&quot;674&quot; src=&quot;https://img.ly/_astro/updated_editor_compare-1_ZncnjS.webp&quot; srcset=&quot;/_astro/updated_editor_compare-1_ZncnjS.webp 640w&quot;&gt;&lt;/p&gt;
&lt;p&gt;After capturing a video, the app displays an editor to complete the creation. The editing tools are in the red circles. TikTok provides about ten different tools on the editing screen. Additionally, TikTok provided some editing tools on the capture screen. The CreativeEditor SDK apps provide a scrolling set of asset libraries along the bottom for items to add to the scene. But when any of the elements of the scene, like your video or an audio clip, are highlighted, the bottom row becomes tools to manipulate that element. The basic Asset Library types are uploads, videos, audio, images, text, shapes, and stickers.&lt;/p&gt;
&lt;p&gt;How to configure and customize each of these tools is beyond the scope of this tutorial. But, a lot of the customization of the assets, fonts, blurs and even filters can be done without code. By design, the CreativeEditor SDK downloads assets from a central server. This is a great way for you to be able to push updated filters, stickers, and other assets to your users without going through the app update process. In the next section, we’ll walk through that and provide some links for further research.&lt;/p&gt;
&lt;h3 id=&quot;configuring-the-editors-assets&quot;&gt;Configuring the Editors Assets&lt;/h3&gt;
&lt;p&gt;The IMG.LY Engine looks for assets for stickers, vector shapes, LUT filters, color filters, color palettes, blurs, and fonts using a URL by default. The design of the system is that you would have your own server supporting your app. However, assets in the app bundle are also accessible by URL, so as long as the assets are in the folder format that the engine expects, it doesn’t matter whether they are local or remote.&lt;/p&gt;
&lt;p&gt;In the &lt;a href=&quot;https://img.ly/docs/cesdk/ios/serve-assets-b0827c/&quot;&gt;documentation for this process&lt;/a&gt; you can find a URL to the default asset bundle. Once you download that bundle you can add it to your app. The bundle is structured much like a regular iOS Assets.catalog with some JSON containing metadata about the asset and a file that provides the actual asset. For some of the assets like filters and vectors, no file is needed as everything can be defined in the JSON.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;asset files and metadata listing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 700px) 700px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;700&quot; height=&quot;656&quot; src=&quot;https://img.ly/_astro/assets_ZLXreD.webp&quot; srcset=&quot;/_astro/assets_21dhby.webp 640w, /_astro/assets_ZLXreD.webp 700w&quot;&gt;&lt;/p&gt;
&lt;p&gt;In the image above, you can see the JSON to describe the ape sticker and the &lt;code&gt;emoji_ape&lt;/code&gt; image file after the IMGLYAssets bundle has been added to our app. You can edit these assets and add your own.&lt;/p&gt;
&lt;p&gt;Once you’re done editing the asset bundle, you can use it instead of the default bundle during the &lt;code&gt;onCreate&lt;/code&gt; modifier like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;VideoEditor&lt;/span&gt;&lt;span&gt;(engine)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  .imgly.&lt;/span&gt;&lt;span&gt;onCreate&lt;/span&gt;&lt;span&gt;({ engine &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     try&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; engine.scene.&lt;/span&gt;&lt;span&gt;load&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt;: VideoEditor.defaultScene)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              // Add asset sources&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     let&lt;/span&gt;&lt;span&gt; bundleURL &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; Bundle.main.&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;forResource&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;IMGLYAssets&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;withExtension&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;bundle&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     try&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; engine.&lt;/span&gt;&lt;span&gt;addDefaultAssetSources&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;baseURL&lt;/span&gt;&lt;span&gt;: bundleURL)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     try&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; engine.&lt;/span&gt;&lt;span&gt;addDemoAssetSources&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;sceneMode&lt;/span&gt;&lt;span&gt;: engine.scene.&lt;/span&gt;&lt;span&gt;getMode&lt;/span&gt;&lt;span&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       withUploadAssetSources&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     try&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; engine.asset.&lt;/span&gt;&lt;span&gt;addSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;TextAssetSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;engine&lt;/span&gt;&lt;span&gt;: engine))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  })&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the code above, we create a blank &lt;code&gt;scene&lt;/code&gt; using &lt;code&gt;VideoEditor.defaultScene&lt;/code&gt; static method. Then set a URL to point to the bundle in the app instead of a remote bundle and make that the source of &lt;code&gt;addDefaultAssetSources&lt;/code&gt;. Now our app will use the assets from the bundle.&lt;/p&gt;
&lt;h3 id=&quot;exporting-the-finished-video&quot;&gt;Exporting the Finished Video&lt;/h3&gt;
&lt;p&gt;Once the user has finished with their creation, they tap the share button and the Video Editor composes all of the video, audio, filters, and static items into a single &lt;code&gt;.mp4&lt;/code&gt; file. Then it displays a share sheet. If you’d rather do something different, like save the creation locally so you can play it back, you can override this default behavior.&lt;/p&gt;
&lt;p&gt;In your app, after the &lt;code&gt;.onCreate&lt;/code&gt; modifier, you can define a &lt;code&gt;.onExport&lt;/code&gt; modifier. When the user taps on the share button you can export the video and then save it to the documents directory to playback later.&lt;/p&gt;
&lt;p&gt;In the &lt;a href=&quot;https://img.ly/docs/cesdk/ios/user-interface/events-514b70/&quot;&gt;documentation for modifiers&lt;/a&gt; you can find the source code for the Video Editor’s default behavior. Instead of duplicating it in detail here, we can just summarize and provide a little snippet for our change.&lt;/p&gt;
&lt;p&gt;First, the &lt;code&gt;.onCreate&lt;/code&gt; handler takes an &lt;code&gt;engine&lt;/code&gt; and a &lt;code&gt;eventHandler&lt;/code&gt; parameter. The &lt;code&gt;engine&lt;/code&gt; is the underlying IMG.LY Engine object we’ve been using. The &lt;code&gt;eventHandler&lt;/code&gt; lets us send information back to the Video Editor UI about the progress or any errors.&lt;/p&gt;
&lt;p&gt;In the documentation, there is a helper function to export the video. After it runs it returns the &lt;code&gt;data&lt;/code&gt; of the exported video and a &lt;code&gt;mimeType&lt;/code&gt;, which will be &lt;code&gt;.mp4&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; data: Date, mimeType: MIMEType&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; mode &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; try&lt;/span&gt;&lt;span&gt; mainEngine.scene.&lt;/span&gt;&lt;span&gt;getMode&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;guard&lt;/span&gt;&lt;span&gt; mode &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; .video &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;throw&lt;/span&gt;&lt;span&gt; CallbackError.unknownSceneMode; &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(data, mimeType) &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; try&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; exportVideo&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code in the documentation handles static files from the &lt;code&gt;DesignEditor&lt;/code&gt; as well as videos from the &lt;code&gt;VideoEditor&lt;/code&gt;. The above code makes it so that only video can be exported, since our app only works with video.&lt;/p&gt;
&lt;p&gt;In the &lt;code&gt;exportVideo&lt;/code&gt; function, the code first checks to make sure it has a properly formed &lt;code&gt;scene&lt;/code&gt; object to work with. Then it starts the export using &lt;code&gt;mainEngine.block.exportVideo(_, mimeType:)&lt;/code&gt;. This begins an async throwing stream during the export. The VideoExport objects in the stream are either &lt;code&gt;.progress&lt;/code&gt; or &lt;code&gt;.finished&lt;/code&gt;. When a &lt;code&gt;.progress&lt;/code&gt; object arrives, the &lt;code&gt;exportVideo&lt;/code&gt; function sends an update to the &lt;code&gt;eventHandler&lt;/code&gt; to display in the UI. When the &lt;code&gt;.finished&lt;/code&gt; object arrives, it has an associated object that is the data for the video.&lt;/p&gt;
&lt;p&gt;Now instead of opening the share sheet, we can write the video to the documents directory for the app.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;do&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      guard&lt;/span&gt;&lt;span&gt; let&lt;/span&gt;&lt;span&gt; documentDirectory &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; try?&lt;/span&gt;&lt;span&gt; FileManager.default.&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt;: .documentDirectory, &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt;: .userDomainMask, &lt;/span&gt;&lt;span&gt;appropriateFor&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;nil&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          logger.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Documents directory not found&quot;&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  let&lt;/span&gt;&lt;span&gt; filePath &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; documentDirectory.&lt;/span&gt;&lt;span&gt;appending&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;component&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;UUID&lt;/span&gt;&lt;span&gt;().uuidString)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  try&lt;/span&gt;&lt;span&gt; data.&lt;/span&gt;&lt;span&gt;write&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;to&lt;/span&gt;&lt;span&gt;: filePath)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;catch&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; error &lt;/span&gt;&lt;span&gt;as&lt;/span&gt;&lt;span&gt; NSError) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  logger.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;could not write finished file: &lt;/span&gt;&lt;span&gt;\(error.&lt;/span&gt;&lt;span&gt;localizedDescription&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;eventHandler.&lt;/span&gt;&lt;span&gt;send&lt;/span&gt;&lt;span&gt;(.&lt;/span&gt;&lt;span&gt;exportCompleted&lt;/span&gt;&lt;span&gt; {})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code above takes the &lt;code&gt;data&lt;/code&gt; from the &lt;code&gt;exportVideo&lt;/code&gt; function and writes it to the app’s documents directory, giving it a UUID string value as a filename. Then it updates the UI to let it know the export is done but sends an empty action block.&lt;/p&gt;
&lt;h2 id=&quot;setting-up-a-playback-controller&quot;&gt;Setting Up a Playback Controller&lt;/h2&gt;
&lt;p&gt;For this example app, the playback controller will play any clips in the app’s &lt;code&gt;Documents&lt;/code&gt; directory. Each clip plays on a loop. The user can swipe up to get the next clip and tap to pause or restart the clip. If there are no clips, the user will be encouraged to make a new one.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;screen shot of player&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 963px) 963px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;963&quot; height=&quot;982&quot; src=&quot;https://img.ly/_astro/viewer_Z21kKPe.webp&quot; srcset=&quot;/_astro/viewer_WarKA.webp 640w, /_astro/viewer_2gQt5P.webp 750w, /_astro/viewer_2mRkuK.webp 828w, /_astro/viewer_Z21kKPe.webp 963w&quot;&gt;&lt;/p&gt;
&lt;p&gt;When the video player view appears, the first task is to see if there are any videos to load. Any video files in the Documents directory are assumed to be ready to play.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;func&lt;/span&gt;&lt;span&gt; loadVideos&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //get a handle to the documents directory for this app&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  guard&lt;/span&gt;&lt;span&gt; let&lt;/span&gt;&lt;span&gt; documentDirectory &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; try?&lt;/span&gt;&lt;span&gt; FileManager.default.&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt;: .documentDirectory, &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt;: .userDomainMask, &lt;/span&gt;&lt;span&gt;appropriateFor&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;nil&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt; { logger.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Documents directory not found&quot;&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; let&lt;/span&gt;&lt;span&gt; files &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; try?&lt;/span&gt;&lt;span&gt; FileManager.default.&lt;/span&gt;&lt;span&gt;contentsOfDirectory&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;at&lt;/span&gt;&lt;span&gt;: documentDirectory, &lt;/span&gt;&lt;span&gt;includingPropertiesForKeys&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;nil&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    videos &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; files&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code above reads all of the filenames from the documents directory into a &lt;code&gt;files&lt;/code&gt; array and then assigns that array to a &lt;code&gt;videos&lt;/code&gt; variable.&lt;/p&gt;
&lt;p&gt;Each time the app is launched or the &lt;code&gt;VideoEditor&lt;/code&gt; view is dismissed, the video player view will get the &lt;code&gt;onAppear&lt;/code&gt; message. This is a good place to check for videos using the &lt;code&gt;loadVideos&lt;/code&gt; function. After the videos are loaded, the app can start to play the first one.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;func&lt;/span&gt;&lt;span&gt; setupVideoPlayer&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  guard&lt;/span&gt;&lt;span&gt; let&lt;/span&gt;&lt;span&gt; currentVideo &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; videos.&lt;/span&gt;&lt;span&gt;first&lt;/span&gt;&lt;span&gt; else&lt;/span&gt;&lt;span&gt; {logger.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;No videos to play&quot;&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  self&lt;/span&gt;&lt;span&gt;.shouldHideEmptyDirectoryText &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       let&lt;/span&gt;&lt;span&gt; endMonitor &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; NotificationCenter.default.&lt;/span&gt;&lt;span&gt;publisher&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt;: NSNotification.Name.AVPlayerItemDidPlayToEndTime)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  self&lt;/span&gt;&lt;span&gt;.player &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; AVPlayerItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;: currentVideo)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  self&lt;/span&gt;&lt;span&gt;.currentVideo &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; currentVideo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the code above, we first check to see if there are any video files. If there are, then hide the message about videos and create a new &lt;code&gt;AVPlayerItem&lt;/code&gt; using the &lt;code&gt;URL&lt;/code&gt; of the first video. The &lt;code&gt;endMonitor&lt;/code&gt;, &lt;code&gt;shouldHideEmptyDirectoryText&lt;/code&gt;, and &lt;code&gt;player&lt;/code&gt; are both being watched by the &lt;code&gt;View&lt;/code&gt;. The AVPlayer gets rendered in a regular SwiftUI View.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;VideoPlayer&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;player&lt;/span&gt;&lt;span&gt;: player)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  .&lt;/span&gt;&lt;span&gt;frame&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;width&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;640&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;height&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;360&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  .&lt;/span&gt;&lt;span&gt;onAppear&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    player.&lt;/span&gt;&lt;span&gt;play&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  .&lt;/span&gt;&lt;span&gt;onReceive&lt;/span&gt;&lt;span&gt;(endMonitor) { &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    player.&lt;/span&gt;&lt;span&gt;seek&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;to&lt;/span&gt;&lt;span&gt;: .zero)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    player.&lt;/span&gt;&lt;span&gt;play&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the video reaches the end, it will &lt;code&gt;seek(to: .zero)&lt;/code&gt; which rewinds the video and loops it.&lt;/p&gt;
&lt;p&gt;In the TikTok app, you can advance to the next video by swiping up. Additionally, you can start and stop any video by tapping on the screen. We can add both of those features using gesture recognizers.&lt;/p&gt;
&lt;p&gt;The code for play and pause is attached to a Tap Gesture modifier we can append to the player.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;onTapGesture&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; player.rate &lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; 0.0&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    player.rate &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  } &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    player.rate &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 1.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can just adjust the playback rate. A value of &lt;code&gt;1.0&lt;/code&gt; is a normal speed and &lt;code&gt;0.0&lt;/code&gt; is paused. The player also has a &lt;code&gt;.pause&lt;/code&gt; and &lt;code&gt;.play&lt;/code&gt; methods, but sometimes these seem buggy.&lt;/p&gt;
&lt;p&gt;Swipe is a little more difficult since SwiftUI only has swiping on List items. So we can use a &lt;code&gt;drag&lt;/code&gt; gesture and then evaluate the translations when it’s complete.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;gesture&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    DragGesture&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;minimumDistance&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;3.0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;coordinateSpace&lt;/span&gt;&lt;span&gt;: .local)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        .&lt;/span&gt;&lt;span&gt;onEnded&lt;/span&gt;&lt;span&gt; { value &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            // Check for a vertical, upward swipe with minimal horizontal deviation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          if&lt;/span&gt;&lt;span&gt; abs&lt;/span&gt;&lt;span&gt;(value.translation.width) &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; 100&lt;/span&gt;&lt;span&gt; &amp;#x26;&amp;#x26;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;             value.translation.height &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                // It was an up swipe!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;		viewModel.&lt;/span&gt;&lt;span&gt;advanceVideo&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then advancing the video is a simple matter of refreshing the &lt;code&gt;player&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;func&lt;/span&gt;&lt;span&gt; advanceVideo&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  guard&lt;/span&gt;&lt;span&gt; let&lt;/span&gt;&lt;span&gt; currentVideo &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; self&lt;/span&gt;&lt;span&gt;.currentVideo &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt; { logger.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;No current video.&quot;&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  let&lt;/span&gt;&lt;span&gt; currentIndex &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; videos.&lt;/span&gt;&lt;span&gt;firstIndex&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;of&lt;/span&gt;&lt;span&gt;: currentVideo)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  var&lt;/span&gt;&lt;span&gt; nextVideo &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; videos.&lt;/span&gt;&lt;span&gt;index&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;after&lt;/span&gt;&lt;span&gt;: currentIndex&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; nextVideo &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; videos.&lt;/span&gt;&lt;span&gt;count&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    nextVideo &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  self&lt;/span&gt;&lt;span&gt;.currentvideo &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; videos[nextVideo]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  self&lt;/span&gt;&lt;span&gt;.player &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; AVPlayer&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;self&lt;/span&gt;&lt;span&gt;.currentVideo&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code will get the next file URL from the array of videos. When it reaches the end, it will loop back and get the file at index 0. Then it creates a new player. Because the view is observing that &lt;code&gt;player&lt;/code&gt; variable, it will update with the new video.&lt;/p&gt;
&lt;p&gt;With this view, the user can create new videos by tapping the creation button and swipe to view all of their created videos.&lt;/p&gt;
&lt;h2 id=&quot;where-to-go-from-here&quot;&gt;Where to Go From Here&lt;/h2&gt;
&lt;p&gt;This tutorial has focused on how the CreativeEditor SDK can help you quickly make a video creation app like TikTok. Good next steps would be to further customize the editing tools and build out the network for sharing and tagging videos. Something that is important to consider is the data structure for each video. The iOS system is optimized to read only as much of a video file off of disk as is needed at any moment. Your app should use those optimizations to run faster. So, don’t load the whole video into memory as a &lt;code&gt;Data&lt;/code&gt; object. Your data structures should keep the large video files somehow separate from the much smaller metadata (likes, comments, etc.). Consider storing the &lt;code&gt;URL&lt;/code&gt; or filename of the video in the same object as the likes and comments. This will also allow you to cache video files after they have been downloaded so that you don’t need to redownload them when other data such as comments or number of likes changes.&lt;/p&gt;
&lt;p&gt;Thanks for reading! We hope that you’ve gotten a better understanding for how a tool like the &lt;a href=&quot;https://img.ly/products/creative-sdk/&quot;&gt;CreativeEditor SDK&lt;/a&gt; can bring your ideas to market faster. Feel free to reach out to us with any questions, comments, or suggestions.&lt;/p&gt;
&lt;p&gt;Looking for more video capabilities? Check out our solutions for &lt;a href=&quot;https://img.ly/use-cases/story-reels-short-video-creation/&quot;&gt;Short Video Creation&lt;/a&gt;, and &lt;a href=&quot;https://img.ly/products/video-sdk-mobile/&quot;&gt;Camera SDK&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;To stay in the loop, subscribe to our&lt;/strong&gt; &lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i&quot;&gt;&lt;strong&gt;Newsletter&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;or follow us on&lt;/strong&gt; &lt;a href=&quot;https://www.linkedin.com/company/img.ly&quot;&gt;&lt;strong&gt;LinkedIn&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;and&lt;/strong&gt; &lt;a href=&quot;https://x.com/imgly&quot;&gt;&lt;strong&gt;Twitter&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Walter</dc:creator><media:content url="https://blog.img.ly/2023/03/Build_TikTok_app_iOS_VE-SDK-1.jpg" medium="image"/><category>How-To</category><category>iOS</category><category>Video Editing</category><category>Social Media</category><category>Tech</category><category>Learning</category><category>Tutorial</category></item><item><title>May the Force Trim be with you: A New Feature in VE.SDK</title><link>https://img.ly/blog/new-force-trim-function-for-videoeditor-sdk/</link><guid isPermaLink="true">https://img.ly/blog/new-force-trim-function-for-videoeditor-sdk/</guid><description>Set the minimum and maximum duration of videos with our latest update.</description><pubDate>Tue, 14 Dec 2021 15:01:31 GMT</pubDate><content:encoded>&lt;p&gt;It has been a fantastic year for video editing – the &lt;a href=&quot;https://img.ly/blog/video-composition-audio-support/&quot;&gt;video composition tool and audio support&lt;/a&gt; enhanced our VideoEditor SDK offerings, enabling developers to bring more high-quality features right into your products and apps. Today, we deliver another feature to enhance your developer experience.&lt;/p&gt;
&lt;h2 id=&quot;force-trim&quot;&gt;Force Trim&lt;/h2&gt;
&lt;p&gt;The VideoEditor SDK trim tool allows your users to determine the start and end frame of a video clip, and thus change the duration of their footage. Now you are also able to &lt;strong&gt;enforce a minimum and maximum duration&lt;/strong&gt; of videos.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Set a minimum and/or a maximum duration for users.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1086px) 1086px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1086&quot; height=&quot;1139&quot; src=&quot;https://img.ly/_astro/min-max-length-videos-app-1_30n9P.webp&quot; srcset=&quot;/_astro/min-max-length-videos-app-1_Z2qfAdT.webp 640w, /_astro/min-max-length-videos-app-1_ZikVdt.webp 750w, /_astro/min-max-length-videos-app-1_1qCbwr.webp 828w, /_astro/min-max-length-videos-app-1_ZftVuf.webp 1080w, /_astro/min-max-length-videos-app-1_30n9P.webp 1086w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Additionally, the update allows configuring the &lt;strong&gt;startup behavior&lt;/strong&gt; of your editor. Possible values are &lt;code&gt;always&lt;/code&gt;, &lt;code&gt;ifNeeded&lt;/code&gt;, and &lt;code&gt;silent&lt;/code&gt; (the default).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;always&lt;/code&gt; will always automatically present the composition tool or the trim tool after opening the editor and force your users to change the length of the video(s).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ifNeeded&lt;/code&gt; will only present&lt;br&gt;
 a) the composition tool, if your initial composition is longer than the maximum duration or shorter than the minimum duration, or&lt;br&gt;
 b) the trim tool, if your initial video is longer than the maximum duration.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;silent&lt;/code&gt; will automatically trim the video to the maximum duration without opening any tool.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Find the right set-up for your use-case in our official &lt;strong&gt;documentation&lt;/strong&gt; for &lt;a href=&quot;https://img.ly/docs/vesdk/ios/guides/trim/force-trim/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;iOS&lt;/a&gt; and &lt;a href=&quot;https://img.ly/docs/vesdk/android/features/trim#how-to-enforce-a-minimum-or-maximum-video-length/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;Android&lt;/a&gt;. Once the trim tool is part of your subscription, you are ready to enhance your user experience.&lt;/p&gt;
&lt;h3 id=&quot;frameworks&quot;&gt;Frameworks&lt;/h3&gt;
&lt;p&gt;Of course, our &lt;a href=&quot;https://img.ly/docs/vesdk/quickstarts/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=announcements&quot;&gt;wrappers&lt;/a&gt; for &lt;strong&gt;Flutter, Cordova&lt;/strong&gt; and &lt;strong&gt;React Native&lt;/strong&gt; have been updated to support force trim.&lt;/p&gt;
&lt;h3 id=&quot;built-to-build&quot;&gt;Built to Build&lt;/h3&gt;
&lt;p&gt;Force Trim will come in handy for use cases, such as social media stories and posts, that have been popularly limited to bite size 15 or 60 seconds by widely loved apps – see TikTok or Instagram. Adopting a ready-to-use solution like &lt;a href=&quot;https://img.ly/products/video-sdk/&quot;&gt;VideoEditor SDK&lt;/a&gt; will set you straight onto your path of creating equally beautiful apps by saving you resources and streamlining your process.&lt;/p&gt;
&lt;h3 id=&quot;a-sleek-user-experience&quot;&gt;A Sleek User Experience&lt;/h3&gt;
&lt;p&gt;Newly in is the interactive and animated timeline, that now elegantly adjusts to the trimming process.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Runs like butter: an interactive and animated timeline&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1280px) 1280px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://img.ly/_astro/video-editor-SDK-timeline-trim_Zq9FTB.webp&quot; srcset=&quot;/_astro/video-editor-SDK-timeline-trim_hFCNo.webp 640w, /_astro/video-editor-SDK-timeline-trim_v09gO.webp 750w, /_astro/video-editor-SDK-timeline-trim_Z1NV0b.webp 828w, /_astro/video-editor-SDK-timeline-trim_Zgg9YQ.webp 1080w, /_astro/video-editor-SDK-timeline-trim_Zq9FTB.webp 1280w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Aware of how time-consuming and costly app development can be for you, our team is committed to delivering more features to enhance your developer experience. &lt;strong&gt;Feel free to reach out to us on &lt;a href=&quot;https://twitter.com/imgly&quot;&gt;Twitter&lt;/a&gt; with any questions, comments, or suggestions!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Thank you for reading, and happy development!&lt;/p&gt;</content:encoded><dc:creator>Neslihan</dc:creator><media:content url="https://blog.img.ly/2021/12/trim-videos-app-videoapp.png" medium="image"/><category>Release Notes</category><category>Video Editor</category><category>App Development</category><category>Social Media</category><category>Videos</category><category>Company</category></item><item><title>Elbi transforms creative user engagement to help people worldwide</title><link>https://img.ly/blog/elbi-transforms-creative-user-engagement-to-help-people-worldwide-ec7e46b082ed/</link><guid isPermaLink="true">https://img.ly/blog/elbi-transforms-creative-user-engagement-to-help-people-worldwide-ec7e46b082ed/</guid><description>A Charity app for content creation and micro-donations</description><pubDate>Wed, 24 Oct 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;Elbi Digital:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Founded 2014&lt;/li&gt;
&lt;li&gt;Based in the UK&lt;/li&gt;
&lt;li&gt;Social enterprise that helps people to connect with charity organizations and do good with micro-donations and content creation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Requirements:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A robust hybrid image editing solution at the core of the app for easy content creation&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Results:&lt;/strong&gt; Easy and seamless content creation with Photos, Doodles, and motivational messages&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;Elbi&lt;/em&gt; app aims to connect people with charity organizations and beneficiaries alike and facilitate the social engagement and donation process. Users can support charity organizations via a “Love Button” with micro-donations and get creative for selected good causes. If users don’t donate directly, they can help fundraise money with their content. To enable their users to produce motivating and exceptional content, &lt;em&gt;Elbi&lt;/em&gt; had to provide them with a powerful creative tool. “Our app has photo-editing at the very core of its experience and the editor has been invaluable in making that vision happen. There are no other tools on the market up to the quality of &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt;, so it was an easy choice to have it be at the heart of &lt;em&gt;Elbi&lt;/em&gt;,” says Toby Green former lead developer at &lt;em&gt;Elbi&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;For the previous version of the &lt;em&gt;Elbi&lt;/em&gt; app, the team built their own creative tool that worked with iOS only. When they decided to reforge their app, the team at &lt;em&gt;Elbi&lt;/em&gt; wanted to follow a different approach. “When we rebuilt the app we wanted it to be a hybrid solution and not only iOS like the previous one, so we abandoned our existing solution and were looking for an existing library. I spent a lot of time researching photo editing tools and did a feasibility study on all the available editors and PhotoEditor SDK came top of the list” says Toby Green.&lt;/p&gt;
&lt;p&gt;With the PhotoEditor SDK the developers at &lt;em&gt;Elbi&lt;/em&gt; were able to swiftly rebuild their app “We would never have been able to do this so quickly without the editor” says Green, “the documentation was great so it was very easy to get it all up and running and the support was incredibly patient and helpful. They always responded quickly and were happy to spend time resolving even difficult-to-track-down issues”. The SDK seamlessly integrates into the app providing an intuitive solution for &lt;em&gt;Elbi&lt;/em&gt;’s content creation section. “It really looks like it’s part of the product,” says Toby Green.&lt;/p&gt;
&lt;p&gt;“The product is a 10/10; it is the best hybrid tool available. And in general, I would say one of the finest teams I’ve ever worked with; they’ve been very supportive with regards to custom support, adding functionalities and discussing integration and they helped us getting everything working 100%,” concludes Toby Green. With the PhotoEditor SDK &lt;em&gt;Elbi&lt;/em&gt; facilitates the charitable engagement of its users and helps people all around the globe to do good on the go.&lt;/p&gt;</content:encoded><dc:creator>Felix</dc:creator><category>Photography</category><category>Social Media</category><category>Charity</category><category>Case Study</category><category>Case Studies</category></item><item><title>Case Study: W | Bear &amp; PhotoEditor SDK</title><link>https://img.ly/blog/case-study-w-bear-photoeditor-sdk-10f06eb8cb14/</link><guid isPermaLink="true">https://img.ly/blog/case-study-w-bear-photoeditor-sdk-10f06eb8cb14/</guid><description>Building a social environment for the LGBT community</description><pubDate>Mon, 17 Sep 2018 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://wbear.lgbt/?utm_source=Case%20Study%20PhotoEditor%20SDK&quot;&gt;W | Bear&lt;/a&gt; is the first global photo and video blogging social community for gay men. The free app allows its users to post pictures and videos to a personal feed, express their creativity and connect with like-minded bears. The blogging community provides a safe place where people can build and shape a social environment, chat, flirt and date. W | Bear was created and developed by the private and public cloud solution provider gNetLabs. We sat together with Xavier Nicolle, CEO at gNetLabs to talk about the vision behind W | Bear, time to market and providing users with tailored assets to amplify engagement.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;“W | Bear is aimed at the bear subculture of the LGBT community. People express themselves, their story and their life through photos and videos. Our users are very happy with the app. 18 months after the release we reached around 150.000 users worldwide, which is beyond our expectation and it’s getting faster and faster. We get a lot of positive reactions and amazing feedback from users that tell us, that our application helped them to gain more self-esteem and to better integrate into the community,” Xavier Nicolle says.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 300px) 300px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;300&quot; height=&quot;533&quot; src=&quot;https://img.ly/_astro/1-vQ6biYxXWoVjVrO12DT4iA_Z2rduG2.webp&quot; srcset=&quot;/_astro/1-vQ6biYxXWoVjVrO12DT4iA_Z2rduG2.webp 300w&quot;&gt;&lt;/p&gt;
&lt;p&gt;As pictures were going to be a vital part of the Instagram like photo blogging application (to this day, more than 2 million pictures and videos have been posted on the app), the folks at gNetLabs started exploring options as their CEO explains: “Time to market was critical for us, and we were kind of in a rush to develop the app. From our background as a hosting company, we’d usually develop and host everything ourselves, however, due to time problems, that wasn’t a viable option regarding the photo editing functionalities. So, we jumped into &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt; to save time, really liked it and eventually kept it. The features and pricing perfectly fit our needs, the integration was straightforward, and the SDK is of great quality and open enough for fine-tuning. On top of that, unlike Adobe Creative SDK for example, it is not linked to any other service. And that is exactly what we were looking for, a piece of software that we could simply plug in that isn’t linked to a service that we don’t need.”&lt;/p&gt;
&lt;p&gt;To offer the best experience possible with &lt;a href=&quot;https://www.wbear.lgbt/?utm_source=Case%20Study%20PhotoEditor%20SDK&quot;&gt;W | Bear&lt;/a&gt;, the folks at gNetLabs pay close attention to how people engage with the app and its features. “Our users mostly work with stickers, frames, and overlays when editing their pictures,” Xavier Nicolle says, “so, bearing that in mind, we want to provide more content and assets that are tailored for the community so our users will hopefully make more use of the editor. Currently, we’re working together with artists that develop stickers that we’re going to introduce using the SDK.”&lt;/p&gt;
&lt;p&gt;But it doesn’t stop with W | Bear, as Xavier Nicolle describes the vision behind the community: “W | Bear is the first piece of a larger social network we want to develop that is dedicated and aimed at the whole LGBT community. We’re going to release more applications using the same technology as W | Bear to address more subcultures. On top of that, there are going to be corresponding websites for each app, so the user will be able to find the same functionalities and tools across all platforms.”&lt;/p&gt;
&lt;p&gt;*&lt;strong&gt;*Thanks for reading! To stay in the loop, subscribe to our&lt;/strong&gt; &lt;a href=&quot;https://photoeditorsdk.us13.list-manage.com/subscribe?u=dc9f652839dbb620d14d6d28d&amp;#x26;id=04a306e4b2&quot;&gt;&lt;strong&gt;Newsletter&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;.**&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Felix</dc:creator><media:content url="https://blog.img.ly/2020/04/image-34.png" medium="image"/><category>Photography</category><category>Social Media</category><category>LGBTQ</category><category>Case Study</category><category>Mobile App Development</category><category>Case Studies</category></item><item><title>Case Study: Dirico &amp; PhotoEditor SDK</title><link>https://img.ly/blog/case-study-dirico-photoeditor-sdk-bf306f04f34d/</link><guid isPermaLink="true">https://img.ly/blog/case-study-dirico-photoeditor-sdk-bf306f04f34d/</guid><description>On orchestrating social media and content marketing </description><pubDate>Wed, 04 Jul 2018 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://dirico.io/&quot;&gt;dirico.io&lt;/a&gt; is a piece of software that unifies the social media and content marketing workflow from research and planning over creation to publishing. In doing that, dirico.io helps marketing teams to better organize and ensures a perfectly orchestrated communication at all times. We sat together with Marcus Burk, Head of Marketing at dirico.io, to discuss how they use the &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt; to provide their users with seamlessly integrated photo editing and branding features.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;“With dirico.io, we follow an all in one approach,” says Marcus Burk, “that means that our tool covers the complete workflow starting with the inspiration for content ideas, over planning, creation, and scheduling to publishing. And just as text is vital to content, images like infographics or pictures for social media are also an incredibly important medium. So, we’ve been looking for a solution that basically could substitute Photoshop in many ways. I’m very happy that we are using the PhotoEditor SDK, it is a great and innovative product. One can see the development that img.ly made as well as the advancement of the SDK over the last years. I believe that it is one of the easiest to use and most powerful editors on the market and the integration possibilities into our solution are awesome.”&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1000px) 1000px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1000&quot; height=&quot;494&quot; src=&quot;https://img.ly/_astro/1-az4mEYK9y0TzpJjNXslYCg_Z12W9Gx.webp&quot; srcset=&quot;/_astro/1-az4mEYK9y0TzpJjNXslYCg_Z1oDWY5.webp 640w, /_astro/1-az4mEYK9y0TzpJjNXslYCg_2gmIAW.webp 750w, /_astro/1-az4mEYK9y0TzpJjNXslYCg_Z2vkzzj.webp 828w, /_astro/1-az4mEYK9y0TzpJjNXslYCg_Z12W9Gx.webp 1000w&quot;&gt;&lt;/p&gt;
&lt;p&gt;The users of dirico.io mostly work with the editor for social media images. Here, a few features and tools of the SDK come in quite handy as Marcus Burk explains: “The fact that you can import and save assets like for example a company logo with a transparent background is a great feature for branding on social media. We recently enabled the photo roll tool of the SDK so the user can choose pictures from a stock library and then edit them in the editor. So, now it’s possible to create completely new content right off the bat. You’d just have to choose an image from the stock library, edit it and then apply your logo to it. Our users are really excited about that feature once they realize how easy it is and look forward to saving time.”&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt; is a great and helpful tool to adjust pictures directly in the browser.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;247GRAD started out as a social media marketing agency. To facilitate their daily routines, they created the Facebook CMS TABMAKER in 2011. Later in coordination with the social media departments of their clients they created 247GRAD CONNECT (formerly PUBLISHER) for in-house use. To tackle the challenges of content marketing, they then expanded the functionalities of their tool and introduced it to the public. 247GRAD CONNECT evolved into dirico.io, a full-fledged social media and content marketing solution for agencies and enterprises of every size. To create this feature-rich experience the developers at 247GRAD Labs had to rely on robust, well-documented software with hassle-free integration, such as the &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt; as Marcus Burk explains: “Our developers told me that they love the fact that everything is well documented and that there are example integrations for various frameworks. And regarding support, we’re happy that we have people that we can directly talk to and that are motivated to work together when there are any issues or questions.”&lt;/p&gt;
&lt;p&gt;*&lt;strong&gt;*Thanks for reading! To stay in the loop, subscribe to our&lt;/strong&gt; &lt;a href=&quot;https://photoeditorsdk.us13.list-manage.com/subscribe?u=dc9f652839dbb620d14d6d28d&amp;#x26;id=04a306e4b2&quot;&gt;&lt;strong&gt;Newsletter&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;.**&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Felix</dc:creator><media:content url="https://blog.img.ly/downloaded_images/Case-Study--Dirico---PhotoEditor-SDK/1-o-xI9IHwokiYplX9nUmyzA.png" medium="image"/><category>Content Marketing</category><category>Case Study</category><category>Social Media</category><category>Marketing</category><category>Communication</category><category>Case Studies</category></item><item><title>Case Study: Vapiano &amp; PhotoEditor SDK</title><link>https://img.ly/blog/case-study-vapiano-photoeditor-sdk-7f335ecc6ac7/</link><guid isPermaLink="true">https://img.ly/blog/case-study-vapiano-photoeditor-sdk-7f335ecc6ac7/</guid><description>Restaurant experience gone App </description><pubDate>Thu, 24 Aug 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The German casual dining restaurant chain &lt;a href=&quot;https://vapiano.com/&quot;&gt;Vapiano&lt;/a&gt; facilitates and streamlines their customer’s visits with a feature-rich app that lets its users: check in at the restaurant, order beverages and desserts from their seat, pay after their visit, collect loyalty points, browse the menu, save favorite dishes, locate the nearest subsidiary and even create images for social media postings.&lt;/p&gt;
&lt;p&gt;With 180 restaurants in 31 countries, Vapiano is one of the biggest fast-casual dining chains around. Especially at lunchtime and early evening hours each restaurant wines and dines plenty of hungry customers, with Vapiano’s current approach (ordering at the counter, receiving the meal, finding a table and after that checking out on a regular register) that sometimes resulted in long lines and consequently frustration among their guests. With the Vapiano app, that is a thing of the past as the visit can almost solely be handled by the app from check-in to check-out. As Vapiano’s target audience is very photography and social media affine, their app holds another gem for their users to play around with. When taking a picture of themselves and their food in a Vapiano restaurant, the users can directly add Vapiano stickers to their pictures and then post them online. Said feature was realized by &lt;a href=&quot;https://mobilabsolutions.com/&quot;&gt;MobiLab Solutions&lt;/a&gt; utilizing the &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt;. We sat down with Max Afflerbach and Robert Rabe of MobiLab Solutions GmbH to talk about their experiences with PhotoEditor SDK.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 800px) 800px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;800&quot; height=&quot;686&quot; src=&quot;https://img.ly/_astro/1-lH2pCjVBFT4HH2MKY6yF3Q_1LBv8g.webp&quot; srcset=&quot;/_astro/1-lH2pCjVBFT4HH2MKY6yF3Q_Z1p42nx.webp 640w, /_astro/1-lH2pCjVBFT4HH2MKY6yF3Q_LL6J.webp 750w, /_astro/1-lH2pCjVBFT4HH2MKY6yF3Q_1LBv8g.webp 800w&quot;&gt;&lt;/p&gt;
&lt;p&gt;“Vapiano’s vision regarding the photo feature is to spread their brand, enhance brand recognition and broaden the brand’s visibility,” Max Afflerbach, Chief Customer Officer at MobiLab Solutions explains. “Basically, they wanted to provide their guests with a tool that facilitates what they’re already doing when dining at Vapiano, that is taking pictures of their food and then uploading them to Snapchat, Instagram, Facebook, you name it. And so, we came up with a built-in branding feature that uses custom stickers.”&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“…on StackOverflow or Quora, &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt; is listed and praised as the only real alternative to Aviary”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As they were on a schedule and didn’t have the time to develop the feature themselves the folks at MobiLab started searching for a third-party solution. “We’ve been looking for an SDK that does exactly what we imagined the feature to be capable of, namely taking a picture, adding assets and then exporting it,” says Robert Rabe, iOS developer at MobiLab Solutions. “We first considered Adobe Creative SDK because it is the best-known SDK in that field. However, it lacked a crucial feature for us that PhotoEditor SDK luckily has and that is the possibility to upload custom stickers,” says Max Afflerbach. “Also,” Rabe adds, “we weren’t 100% sure whether this whole thing would work without the user having to log into the Adobe Cloud.” “When you’re searching for other image processing SDKs on StackOverflow or Quora, PhotoEditor SDK is listed and praised as the only real alternative to Aviary. And besides, there aren’t exactly a lot of SDKs out there that cover both iOS and Android. So, that wasn’t a tough decision at all,” Afflerbach explains.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 800px) 800px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;800&quot; height=&quot;686&quot; src=&quot;https://img.ly/_astro/1-ReYFlxaZFXGtSClTwKYlRw_Z2bRyNU.webp&quot; srcset=&quot;/_astro/1-ReYFlxaZFXGtSClTwKYlRw_ZilXvM.webp 640w, /_astro/1-ReYFlxaZFXGtSClTwKYlRw_17tOXu.webp 750w, /_astro/1-ReYFlxaZFXGtSClTwKYlRw_Z2bRyNU.webp 800w&quot;&gt;&lt;/p&gt;
&lt;p&gt;From the initial decision to work with PhotoEditor SDK until the feature was finished and ready for rollout, only a short period passed as Rabe explains: “Working with the SDK is really straightforward. The implementation is fast, and it’s all well documented. The SDK is a powerful tool and holds a lot of features with a great many possibilities. Setting up the feature exactly as we wanted it to be didn’t take longer than three working days tops. And if we had any issues or questions, we had no problems whatsoever getting in touch with the folks at PhotoEditor SDK which is really nice.”&lt;/p&gt;
&lt;p&gt;“I really like the product, it’s working very well, and especially the communication with the PhotoEditor SDK team was highly pleasant,” Robert Rabe concludes. “Working together with the team of &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt; was super easygoing, the few requests and inquiries we had were answered quickly, and the technical licensing was a cinch as well. We are delighted with the product, the integration was very simple, and our developers are happy, I guess you couldn’t ask for more from an agency’s perspective,” Max Afflerbach adds.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thanks for reading! To stay in the loop, subscribe to our &lt;a href=&quot;https://photoeditorsdk.us13.list-manage.com/subscribe?u=dc9f652839dbb620d14d6d28d&amp;#x26;id=04a306e4b2&quot;&gt;Newsletter&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Felix</dc:creator><media:content url="https://blog.img.ly/2020/04/image-41.png" medium="image"/><category>Android App Development</category><category>iOS App Development</category><category>Social Media</category><category>Mobile Photography</category><category>Case Study</category><category>Case Studies</category></item></channel></rss>