<?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>App Development – IMG.LY Blog</title><description>Posts tagged App Development on the IMG.LY blog.</description><link>https://img.ly/blog/tag/app-development/</link><language>en-us</language><image><url>https://img.ly/apple-touch-icon.png</url><title>App Development – IMG.LY Blog</title><link>https://img.ly/blog/tag/app-development/</link></image><atom:link href="https://img.ly/blog/tag/app-development/rss.xml" rel="self" type="application/rss+xml"/><generator>Astro</generator><lastBuildDate>Tue, 09 Jun 2026 09:48:31 GMT</lastBuildDate><ttl>60</ttl><item><title>CE.SDK v1.44 Release Notes</title><link>https://img.ly/blog/creative-editor-sdk-v-1-44-0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v-1-44-0-release-notes/</guid><description>Create dynamic content with ease – with multiple clips per track for video editing. Customize your Android Editor with Canvas UI to match your workflow. </description><pubDate>Thu, 06 Feb 2025 07:31:00 GMT</pubDate><content:encoded>&lt;p&gt;Welcome to &lt;strong&gt;CE.SDK v1.44&lt;/strong&gt;! This release brings a range of updates designed to enhance your editing workflow across platforms. Enjoy more vibrant and true-to-life visuals with expanded P3 color support on iOS and Android. On the web, streamline your editing process with the new ability to add multiple clips per track, making timeline management more efficient.&lt;/p&gt;
&lt;p&gt;Let’s dive into the updates!&lt;/p&gt;
&lt;h2 id=&quot;simplify-your-video-editing-workflow&quot;&gt;&lt;strong&gt;Simplify Your Video Editing Workflow&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-44/multiple-clips.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Add &lt;strong&gt;multiple clips to a single track&lt;/strong&gt; on your video timeline! With CE.SDK video editing for the &lt;strong&gt;web&lt;/strong&gt;, you can insert video clips, text, overlays, and more on one track—resulting in a more organized and efficient workspace.&lt;/p&gt;
&lt;p&gt;This update empowers you to create richer, more dynamic sequences while keeping your timeline neat and easy to navigate.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Maximize Efficiency&lt;/strong&gt;&lt;br&gt;
Simplicity and speed are key. By reducing the need for multiple tracks, this feature helps users to work smarter and faster—allowing them to focus on creative storytelling and deliver engaging content.&lt;/p&gt;
&lt;p&gt;Get started with our Video Editing for Web &lt;a href=&quot;https://img.ly/docs/cesdk/js/prebuilt-solutions/video-editor-9e533a/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;get-vibrant-colors-with-p3wide-gamut-support&quot;&gt;&lt;strong&gt;Get Vibrant Colors with P3/Wide Gamut Support&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/p3-color-support_suVsV.webp&quot; srcset=&quot;/_astro/p3-color-support_2ahnAp.webp 640w, /_astro/p3-color-support_ZeByaQ.webp 750w, /_astro/p3-color-support_2uXPdA.webp 828w, /_astro/p3-color-support_1oTSrF.webp 1080w, /_astro/p3-color-support_VcTWN.webp 1280w, /_astro/p3-color-support_suVsV.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Unlock a broader color range with &lt;strong&gt;P3 color space&lt;/strong&gt; support on &lt;strong&gt;iOS&lt;/strong&gt; and &lt;strong&gt;Android&lt;/strong&gt; devices. This enhancement ensures your designs and content are more vibrant, accurate, and true to life—giving you richer color options for all your projects.&lt;/p&gt;
&lt;p&gt;Set up color spaces with our documentation for &lt;a href=&quot;https://img.ly/docs/cesdk/ios/open-the-editor/uri-resolver-36b624/?language=swift&amp;#x26;platform=ios&amp;#x26;ref=img.ly#editorapicheckp3support/?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/cesdk/android/open-the-editor/uri-resolver-36b624/?language=kotlin&amp;#x26;platform=android&amp;#x26;ref=img.ly#working-in-different-color-spaceshttps://img.ly/docs/cesdk/engine/api/editor-utils?language=swift&amp;#x26;platform=ios#editorapicheckp3support/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;Android&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;tailor-the-android-canvas-menu-to-your-workflows&quot;&gt;Tailor the Android Canvas Menu to Your Workflows&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Customize the Canvas menu in your Android Editor.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1080px) 1080px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1080&quot; height=&quot;1080&quot; src=&quot;https://img.ly/_astro/canvas-menu-android_13989F.webp&quot; srcset=&quot;/_astro/canvas-menu-android_1n3lUT.webp 640w, /_astro/canvas-menu-android_1XULNH.webp 750w, /_astro/canvas-menu-android_1Pdizt.webp 828w, /_astro/canvas-menu-android_13989F.webp 1080w&quot;&gt;&lt;/p&gt;
&lt;p&gt;💡 The Canvas menu appears when you select a design block, letting you edit its settings, like duplicating a selected image.&lt;/p&gt;
&lt;p&gt;Building on mobile configuration introduced in our &lt;a href=&quot;https://img.ly/blog/creative-editor-sdk-v-1-43-0-release-notes/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;last release&lt;/a&gt;, we’ve extended customization to the editor Canvas Menu for Android. This update gives you full control over how the menu and its items appear and behave in the editor:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Customization&lt;/strong&gt;: Configure visibility, transition effects, and decoration. Adjust the style of the divider between buttons.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Item List Control&lt;/strong&gt;: Modify, add, reorder, or hide menu items.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flexible Button and Divider Configuration&lt;/strong&gt;: Adjust button appearance, functionality, and divider styles to match your design requirements.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;More customizations will be available soon, including for iOS.&lt;br&gt;
Explore the &lt;a href=&quot;https://img.ly/docs/cesdk/android/user-interface/customization/canvas-menu-0d2b5b/&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;improvements&quot;&gt;Improvements&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Switch the Editor Language without Restarting&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/switch-language-sdk_2fgOhx.webp&quot; srcset=&quot;/_astro/switch-language-sdk_1TDR5H.webp 640w, /_astro/switch-language-sdk_ZeLDos.webp 750w, /_astro/switch-language-sdk_1WzYOW.webp 828w, /_astro/switch-language-sdk_ZveCJ9.webp 1080w, /_astro/switch-language-sdk_Z1F4XCL.webp 1280w, /_astro/switch-language-sdk_2fgOhx.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Easily switch languages in our web editor without restarting it. This update lets you update the UI language instantly via API, streamlining localization. Check our &lt;a href=&quot;https://img.ly/docs/cesdk/js/user-interface/localization-508e20/?ref=img.ly#i18n-apihttps://img.ly/docs/cesdk/engine/api/editor-utils?language=kotlin&amp;#x26;platform=android#working-in-different-color-spaceshttps://img.ly/docs/cesdk/engine/api/editor-utils?language=swift&amp;#x26;platform=ios#editorapicheckp3support/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;documentation&lt;/a&gt;, and translate right away!&lt;/p&gt;
&lt;h2 id=&quot;upcoming&quot;&gt;Upcoming&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Record Reactions to Videos on Android&lt;/strong&gt;&lt;br&gt;
We’re excited to announce that Reactions will soon be available on Android. Already live in CE.SDK on iOS, this feature—popularized by platforms like TikTok and Instagram—allows users to capture and share their real-time responses to videos. Enhance engagement and provide content creators with immediate, interactive feedback, making your video content even more dynamic.&lt;/p&gt;
&lt;p&gt;View the &lt;a href=&quot;https://img.ly/docs/cesdk/changelog/#v1440--february-6th-2025&quot;&gt;Changelog&lt;/a&gt;. Thanks for reading!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3,000+ creative professionals gain early access to new features and updates—don’t miss out, and&lt;/strong&gt; &lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i?ref=img.ly&quot;&gt;&lt;strong&gt;subscribe&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;to our newsletter.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Neslihan</dc:creator><media:content url="https://blog.img.ly/2025/02/creative-editor-sdk-1-44.jpg" medium="image"/><category>Release Notes</category><category>CE.SDK</category><category>Creative Editing</category><category>App Development</category><category>Android App Development</category></item><item><title>CE.SDK v1.33 Release Notes</title><link>https://img.ly/blog/creative-editor-sdk-v-1-33-0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v-1-33-0-release-notes/</guid><description>Explore new mobile design and photo editor configurations, plugins for UI customization, voiceover capabilities, and more.</description><pubDate>Thu, 29 Aug 2024 12:08:57 GMT</pubDate><content:encoded>&lt;p&gt;Welcome to the latest update of CE.SDK! We are bringing you new features that enhance your app’s creative capabilities and user experience. This release includes Configurations for a Design Editor or Photo Editor on iOS and Android, Plugins, Voiceover Capabilities, and more.&lt;/p&gt;
&lt;p&gt;With this release, you can:&lt;/p&gt;
&lt;h2 id=&quot;integrate-a-design-editor-on-ios-and-android&quot;&gt;Integrate a Design Editor on iOS and Android&lt;/h2&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-33/page-management-cesdk.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Get started with our new Design Editor configuration for iOS and Android. The out-of-the-box package is designed for easy creation and management of multipage designs.&lt;/p&gt;
&lt;p&gt;Users can switch between editing and the page overview mode to review and adjust their work.&lt;/p&gt;
&lt;p&gt;Keep the design process straightforward and efficient: the editor features a dock at the bottom, offering convenient access to essential tools like adding text, images, stickers, and uploading new assets. Additionally, you can insert a photo directly from your camera.&lt;/p&gt;
&lt;h3 id=&quot;key-features&quot;&gt;&lt;strong&gt;Key Features&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Page Management&lt;/strong&gt;&lt;br&gt;
Create and manage your design pages within a template. It’s easy to create fun carousel posts, as seen on Instagram and LinkedIn, or create a series. Head to the ‘Pages’ icon on the top right bar. In the page overview, you can create, duplicate, and edit a page. Lastly, you can change the order of pages by moving them up and down.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Image Settings&lt;/strong&gt;&lt;br&gt;
Selecting an image lets you fine-tune adjustment settings, and add filters, effects, or blur. Easily crop, straighten, rotate, or flip images.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://apps.apple.com/us/app/img-ly-design-editor/id1672991141&quot;&gt;Try the Design Editor Configuration on iOS&lt;/a&gt; and &lt;a href=&quot;https://play.google.com/store/apps/details?id=ly.img.cesdk.catalog&amp;#x26;pli=1&quot;&gt;Android&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;use-plugins-to-customize-ui-and-add-quick-actions&quot;&gt;Use Plugins to Customize UI and Add Quick Actions&lt;/h2&gt;
&lt;p&gt;We’re excited to introduce the first part of our plugin release for CE.SDK on the web: with this release, you can tailor the editor’s UI elements, reorder components, and add quick actions like &lt;strong&gt;background removal.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;grafik.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1886px) 1886px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1886&quot; height=&quot;1289&quot; src=&quot;https://img.ly/_astro/plugins-customize-UI_Z1V1dcA.webp&quot; srcset=&quot;/_astro/plugins-customize-UI_Z1VSlKa.webp 640w, /_astro/plugins-customize-UI_1qIha2.webp 750w, /_astro/plugins-customize-UI_XGkYN.webp 828w, /_astro/plugins-customize-UI_ZBDlJC.webp 1080w, /_astro/plugins-customize-UI_Z1fvfbb.webp 1280w, /_astro/plugins-customize-UI_Z1uBYIU.webp 1668w, /_astro/plugins-customize-UI_Z1V1dcA.webp 1886w&quot;&gt;&lt;/p&gt;
&lt;p&gt;We’ve enabled extension points within key areas of the UI: the Canvas, Navigation bar, Inspector Bar, Dock, and Canvas Menu. Modify the appearance of existing features, register new components, and integrate quick actions. For example, you can add a “Background Removal” button directly in the Canvas Menu or create complex interactions like custom cut-out lines.&lt;/p&gt;
&lt;p&gt;For more details on this first batch release and the upcoming plugins, please read our dedicated &lt;a href=&quot;https://img.ly/blog/plugin-release-part-1-customizing-the-ui-quick-actions/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;article&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;add-voiceovers-to-videos-on-ios&quot;&gt;Add Voiceovers to Videos on iOS&lt;/h2&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-33/voice-over.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Add voiceover tracks directly within your mobile app, making your projects more dynamic and engaging. Whether creating a tutorial, narrating a slideshow, or adding commentary to a video, this feature allows you to seamlessly record, edit, and integrate voiceovers.&lt;/p&gt;
&lt;p&gt;The popular feature, as enjoyed on TikTok and Instagram, is a staple for content creation and adds a personal touch to video creations.&lt;/p&gt;
&lt;p&gt;To get started, navigate to “Add Audio”, select “Voiceover” section and start recording. You can preview the recording, re-record it, and add more audio, such as music. Adjust the audio levels for a balanced background track.&lt;/p&gt;
&lt;p&gt;Try recording a voiceover with our Demo App for &lt;a href=&quot;https://apps.apple.com/us/app/img-ly-design-editor/id1672991141&quot;&gt;iOS&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;integrate-a-photo-editor-for-ios-and-android&quot;&gt;Integrate a Photo Editor for iOS and Android&lt;/h2&gt;
&lt;p&gt;Our new &lt;strong&gt;Photo Editor Configuration&lt;/strong&gt; is designed to offer an intuitive, out-of-the-box solution that bundles a range of key photo editing capabilities. Enhance individual photos, add text and shapes, or apply filters—this configuration is a kick-start to provide high-quality photo editing for iOS and Android with CE.SDK.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-33/photo-editor-cesdk.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;h3 id=&quot;key-features-1&quot;&gt;Key Features&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Crop, Resize&lt;/strong&gt;&lt;br&gt;
Crop, straighten, flip, resize, and rotate your photos.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adjustments&lt;/strong&gt;&lt;br&gt;
Fine-tune your photos by adjusting brightness, contrast, and other key settings, ensuring your images look their best.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Text, Shapes, and Stickers&lt;/strong&gt;&lt;br&gt;
Enhance your photos by adding and customizing text, shapes, and stickers. Whether you’re creating eye-catching titles, intricate shapes, or playful stickers—our configuration gives you the flexibility to adjust fonts, font colors, sizes, and positions to perfectly match your vision.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Effects, Filters, Blur, Blending Modes&lt;/strong&gt;&lt;br&gt;
Transform your images with fun effects, blur, and filters. Apply overlays to add depth and texture to your photos by adjusting blend modes and opacity to achieve the perfect effect.&lt;/p&gt;
&lt;p&gt;Additionally, use our range of photo filters to set the mood, from warm and nostalgic tones to vibrant, modern effects, giving your images a distinctive and professional look.&lt;/p&gt;
&lt;p&gt;Check our &lt;a href=&quot;https://img.ly/docs/cesdk/ios/prebuilt-solutions/photo-editor-42ccb2/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;documentation&lt;/a&gt; to get started with our photo editor configuration, or &lt;a href=&quot;https://apps.apple.com/us/app/img-ly-design-editor/id1672991141&quot;&gt;try the photo editor on iOS&lt;/a&gt; and &lt;a href=&quot;https://play.google.com/store/apps/details?id=ly.img.cesdk.catalog&amp;#x26;pli=1&quot;&gt;Android&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;improvements&quot;&gt;Improvements&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Preview Audio on iOS and Android&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-33/prev-audio.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;We’ve made it easier to select the perfect audio clip for your projects. Listen to audio tracks directly within the interface before adding them to your video. Tap the play button of an audio clip in the asset library to preview it, and adjust your audio clip within the timeline.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Resize Pages&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-33/resizable-pages-short.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Resize pages in your web editor by simply grabbing corners and side handles, moving beyond the limitations of input fields or preset format sizes. This intuitive resizing integrates seamlessly with other adjustments, such as image cropping, ensuring a smooth workflow. Enable or disable this behavior as needed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Create Rounded Corners&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-33/rounded-corners-short.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;You can now easily create rounded corners for images on the web, iOS and Android. Within your designs, you can add a sleek and modern touch to your projects.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Drag and Select Multiple Elements&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-33/drag-select.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;You can now click and drag with your mouse to draw a selection rectangle, instantly selecting all blocks within the covered area. This feature saves you time and effort, working with complex templates.&lt;/p&gt;
&lt;p&gt;Thanks for reading! Don’t hesitate to &lt;a href=&quot;https://img.ly/forms/contact-sales?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;reach out&lt;/a&gt; if you have any questions or need assistance.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Over 3,000 creative professionals gain early access to our new features, demos, and updates—don’t miss out, and&lt;/strong&gt; &lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i&quot;&gt;&lt;strong&gt;subscribe&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;to our newsletter.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Please note that these release notes also include improvements from previous versions.&lt;/em&gt;&lt;/p&gt;</content:encoded><dc:creator>Neslihan</dc:creator><media:content url="https://blog.img.ly/2024/08/cesdk-1-32-133-imgly.png" medium="image"/><category>Release Notes</category><category>App Development</category><category>iOS App Development</category><category>Android App Development</category><category>Design Editor</category></item><item><title>Designing A Timeline For Mobile Video Editing</title><link>https://img.ly/blog/designing-a-timeline-for-mobile-video-editing/</link><guid isPermaLink="true">https://img.ly/blog/designing-a-timeline-for-mobile-video-editing/</guid><description>When we brought our desktop-class video editing capabilities to iOS, we learned some interesting lessons along the way. In this article, we’ll share the key user experience learnings from our design and development process.</description><pubDate>Tue, 20 Aug 2024 13:08:58 GMT</pubDate><content:encoded>&lt;p&gt;This article documents the most surprising insights from our journey building timeline user interface. We’ll explore everything from overcoming usability challenges, visualizing data, prioritizing information, and refining touch interactions.&lt;/p&gt;
&lt;p&gt;IMG.LY’s CE.SDK for iOS now comes with a &lt;a href=&quot;https://img.ly/showcases/cesdk/video-ui/ios&quot;&gt;native video editor&lt;/a&gt;, built from scratch in SwiftUI. I was responsible for coding and polishing the timeline user interface, working with both our design team and our cross-platform engine team. When I started implementing the timeline, we had the basic design concept sketched out in Figma. However, for an advanced UI like this, nothing beats rapid prototyping and iteration between design and development to make it &lt;em&gt;feel&lt;/em&gt; right.&lt;/p&gt;
&lt;h2 id=&quot;i-visualizing-time&quot;&gt;I. Visualizing Time&lt;/h2&gt;
&lt;p&gt;Timelines are a well-known convention, at least to modern humans. Timelines show durations in time as segments in space, distributed along the horizontal axis, with multiple tracks for things that happen in parallel. This is a simple yet effective way of representing moments in time visually. As obvious as it may seem today, this flavor of data visualization first appeared only 250 years ago. One of the earliest known examples is Joseph Priestley’s &lt;a href=&quot;https://en.wikipedia.org/wiki/A_Chart_of_Biography&quot;&gt;&lt;em&gt;A Chart of Biography&lt;/em&gt;&lt;/a&gt;, published in 1765. Here is Priestley’s &lt;em&gt;A New Chart of History&lt;/em&gt; from 1769, which is even more impressive:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Joseph Priestley, Public domain, via Wikimedia Commons&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 2000px) 2000px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;2000&quot; height=&quot;1399&quot; src=&quot;https://img.ly/_astro/A_New_Chart_of_History_s_Z11Q3oT.webp&quot; srcset=&quot;/_astro/A_New_Chart_of_History_s_Z1A1imS.webp 640w, /_astro/A_New_Chart_of_History_s_ZQ4nwl.webp 750w, /_astro/A_New_Chart_of_History_s_Z1RL1mX.webp 828w, /_astro/A_New_Chart_of_History_s_Zdfq9n.webp 1080w, /_astro/A_New_Chart_of_History_s_1uxfeA.webp 1280w, /_astro/A_New_Chart_of_History_s_1sCwTW.webp 1668w, /_astro/A_New_Chart_of_History_s_Z11Q3oT.webp 2000w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Video editing timelines are built on this exact principle of mapping time to space: A digital video composition consists of tracks for simultaneous audio and video layers. These tracks contain individual clips that can be rearranged, trimmed, and transformed. Navigating the video’s time dimension is as easy as scrolling left and right. The tracks and clips serve as landmarks for orientation, forming the mental model of what the video composition &lt;em&gt;is&lt;/em&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Timelines map time to space&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/embed/cKcksLW95-Y?feature=oembed&quot;&gt;https://www.youtube.com/embed/cKcksLW95-Y?feature=oembed&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;horizontal-direction&quot;&gt;Horizontal Direction&lt;/h3&gt;
&lt;p&gt;Modern iOS user interfaces appear flipped in right-to-left languages: the buttons and controls are in different horizontal positions. The layout follows the reading direction of the language. Even the familiar drill-down navigation animates to the left when drilling deeper into the hierarchy, and the &lt;em&gt;Back&lt;/em&gt; button sits in the upper right corner, its chevron pointing to the right. So, naturally, one of the first things we checked was whether timelines should run right-to-left in writing systems like Arabic or Hebrew. According to a trustworthy source, this is not the case: we found an old version of Apple’s developer guides stating that &lt;a href=&quot;https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/SupportingRight-To-LeftLanguages/SupportingRight-To-LeftLanguages.html&quot;&gt;editor timelines in software are universally left-to-right&lt;/a&gt;, even if the surrounding interface layout is flipped by the operating system for right-to-left system languages.&lt;/p&gt;
&lt;h3 id=&quot;cognitive-load-vs-discoverability&quot;&gt;Cognitive Load vs. Discoverability&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;Variations of clip heights within our video 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;1280&quot; src=&quot;https://img.ly/_astro/timeline_heights-s-1_Zf1XyL.webp&quot; srcset=&quot;/_astro/timeline_heights-s-1_loE2x.webp 640w, /_astro/timeline_heights-s-1_1N9hmK.webp 750w, /_astro/timeline_heights-s-1_ZPCwAb.webp 828w, /_astro/timeline_heights-s-1_PsMHu.webp 1080w, /_astro/timeline_heights-s-1_Zf1XyL.webp 1280w&quot;&gt;&lt;/p&gt;
&lt;p&gt;When designing our video timeline, we experimented with both the size of the clips and with the dimensions of the timeline itself. How much can you fit on a screen before it looks cluttered? How large can the controls be without being clumsy and inefficient? The only way to find out is to try it out right on the device.&lt;/p&gt;
&lt;p&gt;Hiding features in dropdown menus is easy. Banishing them to separate screens is even easier. But hiding functionality hurts discoverability. Out of sight, out of mind. We think user interfaces in productivity apps should be the opposite. They should prioritize &lt;a href=&quot;https://blog.codinghorror.com/information-density-and-dr-bronner/&quot;&gt;high information density&lt;/a&gt; and avoid extra navigation steps as much as possible.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1200px) 1200px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1200&quot; height=&quot;538&quot; src=&quot;https://img.ly/_astro/timeline-density_Z1v9BvG.webp&quot; srcset=&quot;/_astro/timeline-density_Ze8fWQ.webp 640w, /_astro/timeline-density_1xRR1T.webp 750w, /_astro/timeline-density_Z1EYVqv.webp 828w, /_astro/timeline-density_UKvMA.webp 1080w, /_astro/timeline-density_Z1v9BvG.webp 1200w&quot;&gt;&lt;/p&gt;
&lt;p&gt;We increased the density of the toolbar that sits below the timeline: Our goal was to make all the important features easily accessible, despite the small screen. We achieved this by changing the single floating &lt;em&gt;Add&lt;/em&gt; button from the initial designs to a more granular set of buttons to add specific asset types, like stickers and text. This not only increases efficiency for frequent users, it also makes the capabilities of the video editor more obvious and approachable.&lt;/p&gt;
&lt;h3 id=&quot;adaptive-height&quot;&gt;Adaptive Height&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;Left: Small timeline in an empty scene. Right: Large timeline in a complex scene.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 2000px) 2000px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;2000&quot; height=&quot;2089&quot; src=&quot;https://img.ly/_astro/scenes-empty-full-s_Zq9sal.webp&quot; srcset=&quot;/_astro/scenes-empty-full-s_Z1wkWJX.webp 640w, /_astro/scenes-empty-full-s_26v1Ib.webp 750w, /_astro/scenes-empty-full-s_ZosLXG.webp 828w, /_astro/scenes-empty-full-s_Z2nAm3m.webp 1080w, /_astro/scenes-empty-full-s_V3mUA.webp 1280w, /_astro/scenes-empty-full-s_Z1blOTE.webp 1668w, /_astro/scenes-empty-full-s_Zq9sal.webp 2000w&quot;&gt;&lt;/p&gt;
&lt;p&gt;As space is at a premium on a small screen, we wanted to make the video preview as large as possible. We decided to allow the user to collapse the timeline at any time to focus on the video canvas. And even without manually minimizing the timeline, it doesn’t waste space: the timeline adjusts its height to fit snugly around its contents. It only grows as you add more clips.&lt;/p&gt;
&lt;h3 id=&quot;units-and-scale&quot;&gt;Units and Scale&lt;/h3&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/building-a-timeline/zoom-levels.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;The numeric scale is an essential part of any timeline. It helps you see the &lt;em&gt;in&lt;/em&gt; and &lt;em&gt;out&lt;/em&gt; time of a clip at a glance, and the permanently visible ruler makes changes in the zoom level easy to understand. We added dots as subdivisions between the ruler’s numeric labels, which gives it a nice tool-like character. At full zoom—when the ruler shows 5-second intervals—we decided to use four dots in between, so there is one dot for each second. We think this detail adds a welcome sense of precision.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/building-a-timeline/clip-label.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;The clips themselves have a duration label when they are selected. If the duration is below 10, you get a fractional digit (e.g., 4.2s). For the ruler, we went with the same short format (5s, 10s, 30s, etc.) for all values below one minute, and the technical format (1:00, 1:30, etc.) for the rest. Of course, we use iOS’s built-in &lt;a href=&quot;https://swiftbysundell.com/articles/formatting-numbers-in-swift/&quot;&gt;number formatters&lt;/a&gt; to get properly formatted and localized strings for our labels.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/building-a-timeline/ruler-rounding.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;An important detail for the label that shows the current playback timecode: The seconds must always be rounded down. If the playhead sits between two seconds, the lower number must be displayed until the playhead crosses the indicator for the higher second. Simple rounding to the nearest integer would be confusing, because it doesn’t match our expectations when dealing with timelines. Five seconds do not count as five seconds until they have elapsed in their entirety.&lt;/p&gt;
&lt;h2 id=&quot;ii-manipulating-time&quot;&gt;II. Manipulating Time&lt;/h2&gt;
&lt;p&gt;What &lt;em&gt;looks&lt;/em&gt; good is not guaranteed to &lt;em&gt;feel&lt;/em&gt; good when you interact with it. A video editor timeline is more than just a visualization; it’s also a user interface. As such, it should be self-explanatory and provide constant feedback as the user manipulates it.&lt;/p&gt;
&lt;h3 id=&quot;fingertip-sized&quot;&gt;Fingertip-sized&lt;/h3&gt;
&lt;p&gt;The clips must be large enough to be easy to touch and at the same time detailed enough to give a decent overview. The size that can be easily tapped by most people &lt;a href=&quot;https://www.nngroup.com/articles/touch-target-size/&quot;&gt;is around one square centimeter&lt;/a&gt;, which matches the 44 × 44 pt default size of iPhone system controls. Our testing showed that we could go a little smaller. Editing video is a focused task, so the tap targets don’t need to be as robust as for tasks that happen while you, say, run for the bus. And all user interfaces should be scalable for accessibility anyhow, so we didn’t hard-code any sizes and we also made the dimensions adjustable. And, speaking of adapting to individual user needs: of course, all the text labels in our timeline are &lt;a href=&quot;https://developer.apple.com/documentation/uikit/scaling-fonts-automatically&quot;&gt;automatically scaled&lt;/a&gt; depending on your device settings.&lt;/p&gt;
&lt;h3 id=&quot;handles&quot;&gt;Handles&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;Hit area of timeline handles&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1179px) 1179px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1179&quot; height=&quot;438&quot; src=&quot;https://img.ly/_astro/hit-area_Z1THQer.webp&quot; srcset=&quot;/_astro/hit-area_Z1Qmzes.webp 640w, /_astro/hit-area_JoIVh.webp 750w, /_astro/hit-area_Z1I3V8z.webp 828w, /_astro/hit-area_Z1VwXEK.webp 1080w, /_astro/hit-area_Z1THQer.webp 1179w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Selected clips in the timeline get a bold blue frame with large handles on either side. These handles are used to trim the clip’s length. For comfortable tapping and dragging, the handles must be larger than their visual size. In fact, we made the hit area more than twice as wide as the visual appearance suggests.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Triangular indents on trim handles&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 500px) 500px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;500&quot; height=&quot;500&quot; src=&quot;https://img.ly/_astro/triangle_Z1UocRe.webp&quot; srcset=&quot;/_astro/triangle_Z1UocRe.webp 500w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Early on in our design process, we realized that the trim handles had to sit on the outside of the clip, extending beyond the left and right edge. This made it hard to see the clip’s actual size, so we added little grooves: little triangular indents that point to the start and end of the selected clip.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/building-a-timeline/clip-trim-bounce.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Some clips in the timeline can be extended to any duration, like text or stickers. Other clips have a finite footage duration, like video and audio clips. To make this difference visible, clips with a finite footage duration reveal a ghost outline in the background while they are resized, featuring &lt;a href=&quot;https://en.wikipedia.org/wiki/Marching_ants&quot;&gt;marching ants&lt;/a&gt;. The handle icon changes from an outward-pointing chevron to a vertical line when the clip can’t be made longer.&lt;/p&gt;
&lt;h3 id=&quot;scrolling-and-zooming&quot;&gt;Scrolling and Zooming&lt;/h3&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/building-a-timeline/scroll-zoom.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;A rather invisible detail was one of the trickiest things to get right: the coordination of all the different finger gestures on the timeline.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Horizontal Scrolling:&lt;/strong&gt; Timeline scrolls horizontally to move in time.&lt;br&gt;
&lt;strong&gt;Vertical Scrolling:&lt;/strong&gt; Timeline scrolls vertically providing room for tracks.&lt;br&gt;
&lt;strong&gt;Clip Movement:&lt;/strong&gt; Dragging horizontally on a selected clip moves it.&lt;br&gt;
&lt;strong&gt;Duration Adjustment:&lt;/strong&gt; Dragging the trim handles adjusts the clip’s duration.&lt;br&gt;
&lt;strong&gt;Pinch-to-Zoom:&lt;/strong&gt; Pinching with two fingers changes the zoom level of the visualization.&lt;/p&gt;
&lt;p&gt;All these gestures must behave as expected and not interfere with each other. We found it unexpectedly difficult to fine-tune and harmonize these interactions with pure SwiftUI, so we used some proven legacy iOS techniques to get it right. If you’re interested in the technical details of our solution with &lt;code&gt;SwiftUIIntrospect&lt;/code&gt; and &lt;code&gt;UIGestureRecognizers&lt;/code&gt;, check the &lt;a href=&quot;https://github.com/imgly/IMGLYUI-swift/tree/main/Sources/IMGLYEditor/Timeline/TimelineView&quot;&gt;source code&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;snapping&quot;&gt;Snapping&lt;/h3&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/building-a-timeline/snapping.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Video editing must feel precise, even on a small screen. When you trim or move clips, they should snap to other clips, to the playhead, and to the start and the end of the timeline. To show which position the selected clip snaps to, we designed animated dotted lines. We use the iPhone’s haptic engine to provide subtle feedback for snapping, which really helps to make the interaction feel natural—like a notch snapping into a detent. Something that we didn’t get right at first: Snapping should only respect those snapping points that are currently visible in the viewport. Of course! Otherwise, a partially visible clip may snap to something offscreen, which is very confusing.&lt;/p&gt;
&lt;h3 id=&quot;scrubbing-preview&quot;&gt;Scrubbing Preview&lt;/h3&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/building-a-timeline/scrubbing.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;For editing a video clip to feel precise, you need to be able to see exactly &lt;em&gt;where&lt;/em&gt; you’re trimming. But the playback position in our mobile timeline can’t change while you’re trimming, because that would mean scrolling the timeline—which would move the very clip you’re trimming. The trim preview needs to be independent of the composition’s playback position. We solved this by adding a temporary overlay with its own playback time to the canvas. When you start dragging one of the handles on either side of the clip, the overlay shows the exact trim position of the video clip. When you release, the preview returns to the playback position.&lt;/p&gt;
&lt;h2 id=&quot;try-it-out&quot;&gt;Try it out!&lt;/h2&gt;
&lt;p&gt;“The only way to experience an experience is to experience it,” said interaction designer Bill Moggridge, and we couldn’t agree more! If you’re curious how our new video timeline &lt;em&gt;feels&lt;/em&gt;, &lt;a href=&quot;https://apps.apple.com/en/app/img-ly-design-editor/id1672991141&quot;&gt;download our iOS app&lt;/a&gt; and try editing your own videos in our brand-new timeline experience.&lt;/p&gt;
&lt;p&gt;If you’re a developer, check out &lt;a href=&quot;https://img.ly/docs/cesdk/ios/starterkits/video-editor-e1nlor/&quot;&gt;the video editor documentation&lt;/a&gt;. With IMG.LY’s SDK, you can add all of these video editing capabilities to your own apps in a breeze.&lt;/p&gt;</content:encoded><dc:creator>Frank</dc:creator><media:content url="https://blog.img.ly/2024/08/build-a-timeline-video-app-s.jpg" medium="image"/><category>App Development</category><category>UI/UX</category><category>Video Editing</category><category>Insights</category></item><item><title>Background Removal in the Browser Using ONNX Runtime with WebGPU</title><link>https://img.ly/blog/browser-background-removal-using-onnx-runtime-webgpu/</link><guid isPermaLink="true">https://img.ly/blog/browser-background-removal-using-onnx-runtime-webgpu/</guid><description>Achieve 20x Faster Background Removal in the Browser</description><pubDate>Tue, 11 Jun 2024 16:26:17 GMT</pubDate><content:encoded>&lt;p&gt;TL;DR: Using ONNX Runtime with WebGPU and WebAssembly leads to 20x speedup over multi-threaded and 550x speedup over single-threaded CPU performance. Thus achieving interactive speeds for state-of-the-art background removal directly in the browser.&lt;/p&gt;
&lt;p&gt;Removing background from an image is a typical job to be done in creative editing. We have come a long way from manually knocking out the background from an image to full automation with Neural Networks.&lt;/p&gt;
&lt;p&gt;Most state-of-the-art background removal solutions work by offloading the task to the server with a GPU as it was simply infeasible to run the NN on the client.&lt;/p&gt;
&lt;p&gt;However, running background removal directly in the browser offers several advantages over server-side processing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reduced server load and infrastructure costs by offloading heavy lifting to the client.&lt;/li&gt;
&lt;li&gt;Enhanced scalability by distributing the workload across client devices.&lt;/li&gt;
&lt;li&gt;Easier compliance with data protection and security policies by not transferring data across a network to a server.&lt;/li&gt;
&lt;li&gt;Offline processing without needing a reliable internet connection.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It caters to a wide range of use cases, including but not limited to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;E-commerce applications&lt;/em&gt; that need to remove backgrounds from product images in real time.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Image editing applications&lt;/em&gt; that require background removal capabilities for enhancing user experience.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Web-based graphic design tools&lt;/em&gt; that aim to simplify the creative process with in-browser background removal.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In general, two factors influence the feasibility of running background removal directly on the client.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The execution performance, and&lt;/li&gt;
&lt;li&gt;the download size of the Neural Network.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The performance or overall runtime is the major factor to be useful in interactive applications, if a user has to wait several minutes or hours for a neural network to execute, this is in many cases far too long in terms of good user experience. From experience, there are three factors to consider.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The initial first-time execution. The major factor is that neural networks come with the drawback of generally being several MB to GB in size, thus the time to download the neural network into the browser cache is considerable. In subsequent browser page reloads this has no impact anymore.&lt;/li&gt;
&lt;li&gt;The neural network or session initialization time, cannot be cached and has to run with every reload of the page in the browser.&lt;/li&gt;
&lt;li&gt;The neural network or session inference time, largely depends on the longest path inside the neural network and most importantly the execution time of each operator in the neural network.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;towards-real-time-background-removal-in-the-browser&quot;&gt;Towards Real-time Background Removal in the Browser&lt;/h3&gt;
&lt;p&gt;Neural networks are commonly trained in frameworks like PyTorch, which is a neural network library for Python, as such not usable directly in the browser. The best option to run neural networks directly in the browser is converting the neural network into the &lt;strong&gt;Open Neural Network Exchange (ONNX)&lt;/strong&gt; format, which is a widely supported standardized format by Microsoft used extensively in the industry.&lt;/p&gt;
&lt;p&gt;These ONNX-formatted neural networks can then be reconverted into a platform-specific format or directly executed by a supported runtime.&lt;/p&gt;
&lt;p&gt;The ONNX Runtime by Microsoft is a high-performance inference engine designed to run ONNX models across various platforms and languages. One notable feature is &lt;a href=&quot;https://onnxruntime.ai/docs/tutorials/web/build-web-app.html&quot;&gt;ONNX Runtime Web&lt;/a&gt;, which allows JavaScript developers to execute ONNX models directly in the browser. ONNX Runtime Web offers several execution providers for hardware acceleration. For instance, its WebAssembly execution provider enhances CPU execution performance using multiple Web Workers and SIMD instructions.&lt;/p&gt;
&lt;p&gt;More importantly, starting from version 1.7.0, ONNX Runtime Web includes official support for the WebGPU execution provider. WebGPU is a modern web API that enables developers to utilize GPU power for high-performance computations, offering a significant performance boost over CPU-based in-browser machine learning. WebGPU support has been available by default since Chrome 113 and Edge 113 on Mac, Windows, and ChromeOS, and Chrome 121 on Android. For the latest browser support updates, you can track them &lt;a href=&quot;https://github.com/gpuweb/gpuweb/wiki/Implementation-Status&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;implementation-details&quot;&gt;Implementation Details&lt;/h3&gt;
&lt;p&gt;For the implementation of the open-source package &lt;a href=&quot;https://github.com/imgly/background-removal-js&quot;&gt;@imgly/background-removal-js&lt;/a&gt;, we started the journey with a neural network implementation in PyTorch written in Python. The network was then converted to ONNX. You can see our &lt;a href=&quot;https://img.ly/showcases/cesdk/background-removal/web&quot;&gt;live showcase&lt;/a&gt; here.&lt;/p&gt;
&lt;p&gt;The original model was using 32-bit floating point (fp32) precision, which is fine, but results in a file size of 168 MB after converting it to ONNX. As mentioned earlier, the size of the network has a large impact on perceived first-time execution performance as the download time tends to be longer than the execution time, but more to that later.&lt;/p&gt;
&lt;p&gt;To reduce the size of the model, we converted the model to use fp16 (16-bit floating point) and QUINT8 (Quantized 8-bit) datatypes. Thus, effectively reducing the size to half (84MB) and a fourth (42MB) of the original size. Additionally to the download size, the operators used will be converted corresponding to the datatype and different data types and depending on the hardware may lead to speed improvements or even deteriorating due to specialized hardware being used or not being present.&lt;/p&gt;
&lt;p&gt;Note, that while that sounds great, the conversion has a potential negative impact on the quality of the output as we are removing information in the neural networks and since we are working with images, artifacts might become visible and the quality of the resulting background mask is reduced.&lt;/p&gt;
&lt;h2 id=&quot;evaluation&quot;&gt;Evaluation&lt;/h2&gt;
&lt;p&gt;When dealing with neural networks in the browser we can identify three different scenarios&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;First Use&lt;/li&gt;
&lt;li&gt;First Run&lt;/li&gt;
&lt;li&gt;Consecutive Runs&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first-use scenario occurs when the web application is started the first time. The neural network has to be downloaded from the server into the browser sandbox, as neural networks are several 10-1000 MB in size this is not neglectable.&lt;/p&gt;
&lt;p&gt;The first run assumes that the neural network is already present in the browser cache, however, when the neural network ought to be used, the network has to initialize before execution.&lt;/p&gt;
&lt;p&gt;In consecutive runs, the neural network is already in memory and the execution time is largely determined by the neural network depth and operators only.&lt;/p&gt;
&lt;h3 id=&quot;first-use--neural-network-download&quot;&gt;First Use – Neural Network Download&lt;/h3&gt;
&lt;p&gt;While download or time is a large factor in the first-time execution time, this is largely dependent on the available network bandwidth, as such it is not part of the evaluation but in order to get an idea here are the expected download times for the fp32 (168MB) and fp16 (84MB) neural network subject to various common network bandwidth:&lt;/p&gt;






























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Network Bandwidth&lt;/th&gt;&lt;th&gt;Filesize&lt;/th&gt;&lt;th&gt;Download Time&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;10 Mbps&lt;/td&gt;&lt;td&gt;84 MB&lt;/td&gt;&lt;td&gt;67s s&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;100 Mbps&lt;/td&gt;&lt;td&gt;84 MB&lt;/td&gt;&lt;td&gt;6.7 s&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1 Gbps&lt;/td&gt;&lt;td&gt;84 MB&lt;/td&gt;&lt;td&gt;0.67 s&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;10 Gbps&lt;/td&gt;&lt;td&gt;84 MB&lt;/td&gt;&lt;td&gt;0.067&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;






























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Network Bandwidth&lt;/th&gt;&lt;th&gt;Filesize&lt;/th&gt;&lt;th&gt;Download Time&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;10 Mbps&lt;/td&gt;&lt;td&gt;168 MB&lt;/td&gt;&lt;td&gt;134.4 s&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;100 Mbps&lt;/td&gt;&lt;td&gt;168 MB&lt;/td&gt;&lt;td&gt;13.4 s&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1 Gbps&lt;/td&gt;&lt;td&gt;168 MB&lt;/td&gt;&lt;td&gt;1.34 s&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;10 Gbps&lt;/td&gt;&lt;td&gt;168 MB&lt;/td&gt;&lt;td&gt;0.13 s&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Based on the assumption that the median download bandwidth is ~100 Mbps, we see that it’s in the 5-15 second range.&lt;/p&gt;
&lt;h3 id=&quot;first-run--neural-network-initialization--compilation&quot;&gt;First Run – Neural Network Initialization / Compilation&lt;/h3&gt;
&lt;p&gt;Before the neural network can be executed it has to be initialized. Initialization includes several execution provider-specific steps. Most prominent are the time to upload or convert the data to the execution provider and execution provider-specific ONNX graph optimization passes. This all adds to the first run experience. We have evaluated the average session initialization time for the CPU (WASM) and WebGPU provider on a MacBook Pro 13” from 2024 with an Apple M3 Max 16 cores to get an idea of the general impact on first run execution time:&lt;/p&gt;






























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Device&lt;/th&gt;&lt;th&gt;Datatype&lt;/th&gt;&lt;th&gt;Session Initialization Time&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;CPU (WASM)&lt;/td&gt;&lt;td&gt;fp32&lt;/td&gt;&lt;td&gt;~320ms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CPU (WASM)&lt;/td&gt;&lt;td&gt;fp16&lt;/td&gt;&lt;td&gt;~320ms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;WebGPU&lt;/td&gt;&lt;td&gt;fp32&lt;/td&gt;&lt;td&gt;~400ms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;WebGPU&lt;/td&gt;&lt;td&gt;fp16&lt;/td&gt;&lt;td&gt;~200ms&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Note, that session initialization is not negligible and adds significant runtime overhead and might be subject to additional optimization possibilities like caching the optimized model.&lt;/p&gt;
&lt;h3 id=&quot;consecutive-runs--neural-network-execution&quot;&gt;Consecutive Runs – Neural Network Execution&lt;/h3&gt;
&lt;p&gt;Independent of the download and initialization time, we evaluated different execution providers on a MacBook Pro 13” from 2024 with an Apple M3 Max 16 cores. While this is top-end consumer hardware, the general trends will probably apply to various hardware configurations. As a reference, we choose the single thread performance with the neural network running on the CPU with 1 worker thread and SIMD disabled.&lt;/p&gt;













































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Device&lt;/th&gt;&lt;th&gt;SIMD&lt;/th&gt;&lt;th&gt;Threads&lt;/th&gt;&lt;th&gt;Datatype&lt;/th&gt;&lt;th&gt;Session Runtime&lt;/th&gt;&lt;th&gt;Speedup&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;CPU (WASM)&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;fp32&lt;/td&gt;&lt;td&gt;~53000 ms&lt;/td&gt;&lt;td&gt;1.0 x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CPU (WASM)&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;16&lt;/td&gt;&lt;td&gt;fp32&lt;/td&gt;&lt;td&gt;~6300 ms&lt;/td&gt;&lt;td&gt;8.4 x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CPU (WASM)&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;fp32&lt;/td&gt;&lt;td&gt;~15000 ms&lt;/td&gt;&lt;td&gt;3.5 x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CPU (WASM)&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;16&lt;/td&gt;&lt;td&gt;fp32&lt;/td&gt;&lt;td&gt;~2000 ms&lt;/td&gt;&lt;td&gt;26.5 x&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The data above reveals that running the neural network without any acceleration such as SIMD and threading in the browser results in almost 53s runtime, and as such is for most interactive use cases too slow to use. Due to the optimizations of the ONNX Runtime that uses SIMD and threads, we can achieve an overall speedup of roughly ~26 times compared to the baseline performance. Thus decreasing the session runtime to around 2s and making it usable for interactive applications.&lt;/p&gt;
&lt;p&gt;As mentioned before, we neglected the download time and size of the network. Leveraging the fp16 model compression, we re-ran the benchmarks and got similar results as before, but with half the bandwidth required to download the network for the first time application. The general visual performance of the fp16 and fp32 is similar or visually not perceivable. The quint8 model led to artifacts and as such unusable for visual processing, thus we excluded from the following benchmark.&lt;/p&gt;













































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Device&lt;/th&gt;&lt;th&gt;SIMD&lt;/th&gt;&lt;th&gt;Threads&lt;/th&gt;&lt;th&gt;Datatype&lt;/th&gt;&lt;th&gt;Session Runtime&lt;/th&gt;&lt;th&gt;Speedup&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;CPU (WASM)&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;fp16&lt;/td&gt;&lt;td&gt;~55000 ms&lt;/td&gt;&lt;td&gt;1.0 x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CPU (WASM)&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;16&lt;/td&gt;&lt;td&gt;fp16&lt;/td&gt;&lt;td&gt;~7300 ms&lt;/td&gt;&lt;td&gt;7.2 x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CPU (WASM)&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;td&gt;fp16&lt;/td&gt;&lt;td&gt;~15000 ms&lt;/td&gt;&lt;td&gt;3.5 x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CPU (WASM)&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;16&lt;/td&gt;&lt;td&gt;fp16&lt;/td&gt;&lt;td&gt;~2300 ms&lt;/td&gt;&lt;td&gt;23.9 x&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The results are a little worse than the fp32 version, which might be because the fp16 datatype has no direct specialized hardware in modern CPUs like the M3 Max CPU, and as such additional fp16 to fp32 conversion operations have to be performed.&lt;/p&gt;
&lt;p&gt;Our final benchmark measures the WebGPU performance, which led to the following impressive results. To have a fair comparison and understanding of the impact of the WebGPU technology, we compare it with the best CPU version with 16 threads and SIMD enabled with the fp32 model, which was around ~2 s.&lt;/p&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Device&lt;/th&gt;&lt;th&gt;SIMD&lt;/th&gt;&lt;th&gt;Threads&lt;/th&gt;&lt;th&gt;Datatype&lt;/th&gt;&lt;th&gt;Session Runtime&lt;/th&gt;&lt;th&gt;Speedup&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;WebGPU&lt;/td&gt;&lt;td&gt;Not applicable&lt;/td&gt;&lt;td&gt;Not applicable&lt;/td&gt;&lt;td&gt;fp32&lt;/td&gt;&lt;td&gt;~120ms&lt;/td&gt;&lt;td&gt;16.6 x&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;WebGPU&lt;/td&gt;&lt;td&gt;Not applicable&lt;/td&gt;&lt;td&gt;Not applicable&lt;/td&gt;&lt;td&gt;fp16&lt;/td&gt;&lt;td&gt;~100ms&lt;/td&gt;&lt;td&gt;20.0 x&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The WebGPU performance varies around &lt;strong&gt;16 to 20 x&lt;/strong&gt; improvements over the best CPU execution time. The GPU has specialized hardware for fp16 instructions, as such the model performs better than the fp32 model. Also, note that the session initialization time is also reduced due to half the required bandwidth to upload the network data to the GPU.&lt;/p&gt;
&lt;p&gt;Therefore, the first run of the network will take ~300 ms and consecutive runs will be ~100 ms, leading to near real-time performance in the browser.&lt;/p&gt;
&lt;p&gt;Note, that the WebGPU performance is an astonishing &lt;strong&gt;550 times faster&lt;/strong&gt; than the single thread, with no SIMD performance.&lt;/p&gt;
&lt;p&gt;Try the live implementation in our &lt;a href=&quot;https://img.ly/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=background-removal-onnx&quot;&gt;background removal showcase&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;WebGPU is a major leap in establishing the browser as a factor to be reckoned with as a true Application platform. With &lt;a href=&quot;https://IMG.LY/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=background-removal-onnx&quot;&gt;IMG.LY&lt;/a&gt;, we are striving to leverage modern technology to make design tools accessible, this includes on-device execution, on-premise, but also on-cloud execution of design tools leveraging neural networks.&lt;/p&gt;
&lt;p&gt;As a next step, we will port background removal to all our supported platforms, ONNX Runtime seems the best choice, as it is already available for all the potential platforms we support.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/onnx/bg-removal.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Furthermore, we are evaluating the feasibility of in-browser background removal for videos to be included with our video-editing suits.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://img.ly/showcases/cesdk/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=background-removal-onnx&quot;&gt;Try our tools today&lt;/a&gt; to see how we help bring unique creative editing experiences to any application. Or &lt;a href=&quot;https://img.ly/forms/contact-sales/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=background-removal-onnx&quot;&gt;contact us&lt;/a&gt; to discuss your project.&lt;/p&gt;</content:encoded><dc:creator>Daniel</dc:creator><dc:creator>Emma</dc:creator><media:content url="https://blog.img.ly/2024/06/onnx-runtime-imgly.jpg" medium="image"/><category>Plugin</category><category>App Development</category><category>Image Processing</category><category>Insights</category></item><item><title>Unleash Creativity with CE.SDK’s New Plugin System</title><link>https://img.ly/blog/img-ly-sdk-plugin-system/</link><guid isPermaLink="true">https://img.ly/blog/img-ly-sdk-plugin-system/</guid><description>Teaser: Our new Plugin System empowers customization and creativity with one-click features, smart design tools, and generative AI.</description><pubDate>Mon, 03 Jun 2024 08:42:25 GMT</pubDate><content:encoded>&lt;p&gt;At IMG.LY, we have always believed that a superb design editor should be effortlessly customizable and extensible. We are thrilled to roll out a brand-new Plugin system for CE.SDK in the upcoming months—to take creative editing and feature development to the next level.&lt;/p&gt;
&lt;p&gt;Starting with one-click features like background removal or vectorizers, smart design tools like QR codes or subtitle generators, and deeply interactive features like generative AI for text and images; all these tools can be used or built by customers soon.&lt;/p&gt;
&lt;p&gt;Additionally, our upcoming Plugin system will bring you unparalleled autonomy by making feature development for our SDK accessible and offering extensive options to reconfigure our editor’s UI.&lt;/p&gt;
&lt;p&gt;Start exploring our Plugin System rollout now to immediately benefit from upcoming features.&lt;/p&gt;
&lt;h2 id=&quot;built-for-modification&quot;&gt;Built for Modification&lt;/h2&gt;
&lt;p&gt;Let’s dive deep into some of the opportunities CE.SDK plugins help unlock.&lt;/p&gt;
&lt;h3 id=&quot;unlocking-the-ai-revolution&quot;&gt;Unlocking the AI Revolution&lt;/h3&gt;
&lt;p&gt;While the AI transformation is already fully underway, much of the tech is still not very accessible to product builders, often requiring deep technical knowledge to get started. At the same time, AI features become significantly more valuable when integrated with other editing functionalities in workflows or automation. With our plugins, we aim to make it effortless to leverage innovation and put it to use.&lt;/p&gt;
&lt;h3 id=&quot;boosting-customer-autonomy&quot;&gt;Boosting Customer Autonomy&lt;/h3&gt;
&lt;p&gt;Key to our success is providing maximum flexibility and autonomy to our customers about product decisions. Ultimately, you shouldn’t depend on our product roadmap; rather, you should be able to add features when you like. While our SDKs are already highly configurable, plugins allow tailoring the whole user experience not only on a look &amp;#x26; feel level but through custom functionalities and editing experiences.&lt;/p&gt;
&lt;h3 id=&quot;accelerate-product-expansion&quot;&gt;Accelerate Product Expansion&lt;/h3&gt;
&lt;p&gt;Many ecosystems witnessed explosive growth in added value to the user after releasing plugin mechanisms. Currently, only IMG.LY core developers can contribute to the SDK. We have started to extend this to solution engineers and even designers on our team who don’t have much knowledge of the inner workings of the SDK. Ultimately, we will push this more and more into a community of contributors, making the community’s innovation accessible to everyone.&lt;/p&gt;
&lt;h2 id=&quot;key-concepts&quot;&gt;Key Concepts&lt;/h2&gt;
&lt;p&gt;Three important concepts have driven the development of our Plugins:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Customizable Menu Bars&lt;/strong&gt;&lt;br&gt;
We are extending our API so that it allows easy hooking into various parts of the UI. Our editor has key components like the inspector, toolbar, and on-canvas menu. These are now all accessible through an API, so you can hook your feature anywhere in the editor.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Easily hook your features anywhere in the editor.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1920px) 1920px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1920&quot; height=&quot;1080&quot; src=&quot;https://img.ly/_astro/key-concept-plugins-sdk-1_Z7C57k.webp&quot; srcset=&quot;/_astro/key-concept-plugins-sdk-1_Z1cMp6H.webp 640w, /_astro/key-concept-plugins-sdk-1_1mLpHS.webp 750w, /_astro/key-concept-plugins-sdk-1_1vy6cU.webp 828w, /_astro/key-concept-plugins-sdk-1_Z2cAeFG.webp 1080w, /_astro/key-concept-plugins-sdk-1_Z13AeBp.webp 1280w, /_astro/key-concept-plugins-sdk-1_2dEjpa.webp 1668w, /_astro/key-concept-plugins-sdk-1_Z7C57k.webp 1920w&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UI Building Blocks to Provide Consistency&lt;/strong&gt;&lt;br&gt;
To reach a high level of consistency and speed up time for development, we will be providing out-of-the-box UI components such as buttons, sliders, text inputs, etc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Escape Hatches&lt;/strong&gt;&lt;br&gt;
From experience, we know that sometimes unique functionality needs unique solutions, so we have added escape hatches to add custom elements via HTML whenever needed.&lt;/p&gt;
&lt;h2 id=&quot;what-can-you-build-with-our-plugin-system&quot;&gt;What Can You Build with our Plugin System?&lt;/h2&gt;
&lt;p&gt;Let’s explore some potential use cases of the plugin system.&lt;/p&gt;
&lt;h3 id=&quot;custom-actions&quot;&gt;Custom Actions&lt;/h3&gt;
&lt;p&gt;Adding custom actions is a great option to make simple third-party APIs accessible within the editor. This can be &lt;strong&gt;one-click edits&lt;/strong&gt; such as background removal, vectorizers, or auto-enhancement for images. You can also add custom actions for text in combination with Large Language Models (LLM) to provide features like autocorrection and improved writing, etc.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/plugin-release/background-removal-plugin-sdk.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;h3 id=&quot;custom-tools&quot;&gt;Custom Tools&lt;/h3&gt;
&lt;p&gt;Some custom functionality will require more than just a single button, e.g., to &lt;strong&gt;generate AI images&lt;/strong&gt;, background patterns, QR codes, or maps. In these cases, you’ll require sliders, text input, drop-downs, and many other UI elements. With plugins, you can easily create panels with your own UI to bring any custom tool to life.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/plugin-release/ai-generator-plugin-sdk.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;h3 id=&quot;custom-assets--presets&quot;&gt;Custom Assets &amp;#x26; Presets&lt;/h3&gt;
&lt;p&gt;Apart from building custom tools, you can also bundle and group effects into presets and make them accessible in a custom panel. This is especially useful to simplify the design process or create standard design components: for example, providing beautiful text presets will enable your users to create instantly great text designs without any design knowledge.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Bundle presets or sticker packs for a stylish, simple design process.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1920px) 1920px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1920&quot; height=&quot;1080&quot; src=&quot;https://img.ly/_astro/custom-bundles-sdk-s_Z2eX5Wk.webp&quot; srcset=&quot;/_astro/custom-bundles-sdk-s_wWPTG.webp 640w, /_astro/custom-bundles-sdk-s_WbFjy.webp 750w, /_astro/custom-bundles-sdk-s_Zx5C9.webp 828w, /_astro/custom-bundles-sdk-s_Z1MpguG.webp 1080w, /_astro/custom-bundles-sdk-s_1RCU0T.webp 1280w, /_astro/custom-bundles-sdk-s_Z1MVQn1.webp 1668w, /_astro/custom-bundles-sdk-s_Z2eX5Wk.webp 1920w&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;custom-libraries&quot;&gt;&lt;strong&gt;Custom Libraries&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Integrate third-party libraries, such as Unsplash, Getty Images, Pexels, or your own.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/plugin-release/photo-library-sdk-unsplash.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;h3 id=&quot;custom-editor-behavior&quot;&gt;Custom Editor Behavior&lt;/h3&gt;
&lt;p&gt;Some of our customers asked us how they could move a functionality from one place in the editor to another. Let’s say you wish to move the function ‘move to front’ from the inspector to the canvas menu. This is not a problem! You can do this by using the internal API endpoints of our editor.&lt;/p&gt;
&lt;p&gt;As for custom editor behavior, you can do far more than just move functionality. Here is a demo of layer lists we built as a plugin.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/plugin-release/layer-list-editor-sdk.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;h3 id=&quot;custom-user-feedback&quot;&gt;Custom User Feedback&lt;/h3&gt;
&lt;p&gt;Additionally, you can enhance the canvas with overlays, which are useful for providing alerts, instructions, or feedback directly on the canvas.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Provide instant design feedback to users, such as cut-off text or images.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1920px) 1920px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1920&quot; height=&quot;1080&quot; src=&quot;https://img.ly/_astro/custom-user-notification-design-feedback-1_Z1dtpGM.webp&quot; srcset=&quot;/_astro/custom-user-notification-design-feedback-1_1qQrVb.webp 640w, /_astro/custom-user-notification-design-feedback-1_yfu3B.webp 750w, /_astro/custom-user-notification-design-feedback-1_Z2ctvGd.webp 828w, /_astro/custom-user-notification-design-feedback-1_1CxUVl.webp 1080w, /_astro/custom-user-notification-design-feedback-1_29zsPe.webp 1280w, /_astro/custom-user-notification-design-feedback-1_Z81FNb.webp 1668w, /_astro/custom-user-notification-design-feedback-1_Z1dtpGM.webp 1920w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;whats-next&quot;&gt;What’s Next&lt;/h2&gt;
&lt;p&gt;We are now rolling out Plugins and building an initial set of features through Plugins ourselves—available for the web first, and mobile SDKs will follow. Keep your eyes peeled for our next releases and don’t hesitate to &lt;a href=&quot;https://img.ly/forms/contact-sales&quot;&gt;get in touch&lt;/a&gt; with us to learn more about plugins, and how your product benefits from integration without losing time and resources.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thank you for reading. Join 3,000+ creative professionals—&lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i&quot;&gt;subscribe&lt;/a&gt; to our newsletter for updates on new features, plugins, early access, and more!&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Daniel</dc:creator><dc:creator>Eray</dc:creator><media:content url="https://blog.img.ly/2024/05/plugin-sdk-design-img-ly-s.jpg" medium="image"/><category>Plugin</category><category>App Development</category><category>Design Editor</category><category>Company</category></item><item><title>CE.SDK v1.25 Release Notes</title><link>https://img.ly/blog/creative-editor-sdk-v-1-25-0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v-1-25-0-release-notes/</guid><description>Recolor images, such as T-shirt mockups, remove green screen backgrounds, and preview audio directly in your app. </description><pubDate>Tue, 07 May 2024 11:43:59 GMT</pubDate><content:encoded>&lt;p&gt;Welcome to the latest update from our team! Since our &lt;a href=&quot;https://img.ly/blog/creative-editor-sdk-v-1-23-0-release-notes/&quot;&gt;last release&lt;/a&gt;, we have been working to bring more creative capabilities to your app and improve user experience. With this release, you can:&lt;/p&gt;
&lt;h2 id=&quot;recolor-images-like-t-shirt-mockups&quot;&gt;Recolor Images like T-shirt Mockups&lt;/h2&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-25/recolor-images-editor-sdk.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Replace colors in any image with our new recoloring feature. Select a color you want to change, choose its replacement, and apply the changes. Recoloring is ideal for tasks like altering the color of specific elements, such as t-shirts in product photos.&lt;/p&gt;
&lt;p&gt;Simply choose your image, navigate to Effects, and select “Recolor”. Choose the color you want to change (Source Color), and the color you want to replace it with (Target Color). For a more refined result, adjust “Smoothness”, “Color Match”, and “Brightness Match”.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-25/recoloring_androids.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;This feature is available on &lt;strong&gt;Web&lt;/strong&gt;, &lt;strong&gt;Android&lt;/strong&gt;, and &lt;strong&gt;iOS&lt;/strong&gt; platforms.&lt;/p&gt;
&lt;p&gt;Check our &lt;a href=&quot;https://img.ly/docs/cesdk/js/filters-and-effects/add-c796ba/&quot;&gt;documentation&lt;/a&gt; on filters and effects to learn more.&lt;/p&gt;
&lt;h2 id=&quot;create-transparency-with-a-green-screen&quot;&gt;Create Transparency with a Green Screen&lt;/h2&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-25/green-screen-video-sdk.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Easily make green screen backgrounds transparent in your &lt;strong&gt;images&lt;/strong&gt; and &lt;strong&gt;videos on the Web,&lt;/strong&gt; and for images on &lt;strong&gt;Android and iOS&lt;/strong&gt;. Our Green Screen Effect is tailored to identify and eliminate green backdrops—or any other color you specify. Perfect for content creators and videographers who need to isolate subjects without manually editing backgrounds.&lt;/p&gt;
&lt;p&gt;Select an image or video clip with a color background you wish to remove. Then choose “Green Screen” in the Effects, and our effect handles the rest. Fine-tune the effect to your liking.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-25/greenscreen_android.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;h2 id=&quot;user-interface-improvements&quot;&gt;User Interface Improvements&lt;/h2&gt;
&lt;p&gt;In our latest update, we’ve focused on enhancing the usability and functionality of our interface. Here’s what’s new:&lt;/p&gt;
&lt;h3 id=&quot;audio-preview&quot;&gt;Audio Preview&lt;/h3&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-25/audio-preview-web-video-sdk.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Choosing the right audio clip is now easier with our new Audio Preview feature. Preview audio clips directly within the interface and make the perfect selection for your projects.&lt;/p&gt;
&lt;h3 id=&quot;selection-frame-improvements&quot;&gt;Selection Frame Improvements&lt;/h3&gt;
&lt;p&gt;We’ve upgraded our selection frames with new icons, hover effects, enhanced drag functionality, and shadow rendering. These improvements make manipulating elements within our platform more intuitive and visually appealing. Whether you’re rearranging components or resizing elements, our refined handling ensures a smoother interaction.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Please note that these release notes also include improvements from v1.24.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thanks for reading. Join over 3000 specialists with powerful apps, and&lt;/strong&gt; &lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i&quot;&gt;&lt;strong&gt;subscribe&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;to our newsletter. We keep you in the loop with brand-new features, early access, and updates.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Neslihan</dc:creator><media:content url="https://blog.img.ly/2024/05/creative-sdk-1-25.jpg" medium="image"/><category>Release Notes</category><category>CE.SDK</category><category>Video Editing</category><category>Design Editor</category><category>App Development</category></item><item><title>CE.SDK v1.19 Release Notes</title><link>https://img.ly/blog/creative-editor-sdk-v1-19-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v1-19-release-notes/</guid><description>Explore unified editing of your graphic blocks, new showcases, and an exciting announcement for video!</description><pubDate>Fri, 22 Dec 2023 14:26:48 GMT</pubDate><content:encoded>&lt;p&gt;Since our last release, we’ve been crafting new features to empower your users’ creative journey. Today, we’re thrilled to introduce CE.SDK v1.19! With this release, you can:&lt;/p&gt;
&lt;h3 id=&quot;unify-design-power-with-block-unification&quot;&gt;Unify Design Power with Block Unification&lt;/h3&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-19/block-unification_1-19-videofills.mp4&quot; controls muted playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Introducing Block Unification for CE.SDK on Mobile and Web—a feature that simplifies design versatility. Videos, images, shapes, and stickers now seamlessly come together as one Graphic Block, easily modified within a unified inspector. All supported settings for your selected block, including strokes, filters, and adjustments, are conveniently displayed in a single, user-friendly space.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Unified Graphic Block&lt;/strong&gt;&lt;br&gt;
Experience a singular Graphic Block supporting diverse fills (images, videos, colors, gradients) and shapes. Switch fill types (video, image, color) effortlessly, enabling dynamic designs in one place.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Easy Fine-Tuning&lt;/strong&gt;&lt;br&gt;
Block Unification integrates effects, filters, adjustments, and blur uniformly across all design elements. Elevate your designs with precision and consistency.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A Treat for Users and Developers&lt;/strong&gt;&lt;br&gt;
For developers, Block Unification means streamlined code maintenance. The consolidation of design blocks into one Graphic Block simplifies development, allowing more focus on crafting exceptional design experiences with IMG.LY.&lt;/p&gt;
&lt;h3 id=&quot;enhance-interaction-with-mouse-wheel-support&quot;&gt;Enhance Interaction with Mouse Wheel Support&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;mousewheel.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/mousewheel_ZdLdi7.webp&quot; srcset=&quot;/_astro/mousewheel_2evOYG.webp 640w, /_astro/mousewheel_1btqKu.webp 750w, /_astro/mousewheel_Z1mpLwI.webp 828w, /_astro/mousewheel_1aUQbe.webp 1080w, /_astro/mousewheel_t4NVy.webp 1280w, /_astro/mousewheel_ZdLdi7.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;In our latest update, our engine now directly registers mouse wheel events on the canvas, eliminating the need for manual camera manipulation. This seamless integration brings a host of new features, including smooth zooming, centered around the cursor, and support for pinch gestures on multitouch trackpads. Enjoy a more intuitive and unified interaction experience across various inputs, simplifying and enriching your design process.&lt;/p&gt;
&lt;h3 id=&quot;migrate-to-cesdk-v119&quot;&gt;Migrate to CE.SDK v1.19&lt;/h3&gt;
&lt;p&gt;The structural changes of CE.SDK v1.19 bring a more composable and powerful editing experience. To benefit from our new features, and to attain to licensing changes, head to our &lt;a href=&quot;https://img.ly/docs/cesdk/js/upgrade-4f8715/&quot;&gt;documentation on migrating to v.1.19&lt;/a&gt; for an easy transition.&lt;/p&gt;
&lt;p&gt;Wait. There’s more. As we explore the extensive capabilities of our SDK, we’re unveiling new showcases to demonstrate your possibilities. Plus, stick around until the end for an exciting announcement that will elevate your video creation experience!&lt;/p&gt;
&lt;h3 id=&quot;new-showcase-automated-resizing&quot;&gt;New Showcase: Automated Resizing&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;Scale your marketing materials across all platforms with automated sizes.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/automated_Z1or62o.webp&quot; srcset=&quot;/_astro/automated_1UVbIY.webp 640w, /_astro/automated_1iPdUS.webp 750w, /_astro/automated_1uk67P.webp 828w, /_astro/automated_DqpQ8.webp 1080w, /_astro/automated_2a5INP.webp 1280w, /_astro/automated_Z1or62o.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;In our new live &lt;a href=&quot;https://img.ly/showcases/cesdk/automated-resizing/web&quot;&gt;showcase&lt;/a&gt; for web, effortlessly generate size variations of your designs and seamlessly &lt;strong&gt;scale your&lt;/strong&gt; &lt;strong&gt;marketing materials across platforms&lt;/strong&gt;. The automated resizing feature empowers you to easily leverage marketing materials without requiring the involvement of a design team, ensuring efficiency and adaptability.&lt;/p&gt;
&lt;h3 id=&quot;new-showcase-version-history&quot;&gt;New Showcase: Version History&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;Keep track! Version History monitors changes made to your design.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/history_Z1I9vf0.webp&quot; srcset=&quot;/_astro/history_1suucg.webp 640w, /_astro/history_ZuG7lP.webp 750w, /_astro/history_1T8alE.webp 828w, /_astro/history_Z1gpSmo.webp 1080w, /_astro/history_Z1uhGNc.webp 1280w, /_astro/history_Z1I9vf0.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Discover the convenience of Version History, enabling you to monitor changes made to each design and seamlessly restore past versions when needed. Explore our straightforward &lt;a href=&quot;https://img.ly/showcases/cesdk/version-history/web&quot;&gt;Version History&lt;/a&gt; showcase for a practical design experience.&lt;/p&gt;
&lt;h3 id=&quot;outlook-offer-tiktok-inspired-video-editing&quot;&gt;Outlook: Offer TikTok-Inspired Video Editing&lt;/h3&gt;
&lt;p&gt;Video remains the reigning champion for attracting and retaining your audience. Yet, building a video editor from the ground up is a pain.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-19/HD_IMGLY-SDK_141223-0.mp4&quot; controls playsinline poster=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-19/thumb-vcc.jpg&quot;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;To simplify your journey and save valuable time and resources, we are excited to unveil a groundbreaking SDK for creating captivating short-form videos in January 2024!&lt;/p&gt;
&lt;p&gt;Empower your users to arrange video, audio, text, and graphics seamlessly on a sleek video timeline. Our new camera introduces popular features like Voiceover, Zoom, Tap to Record, and more. Plus, bring the beloved Split Screen Modes for Reactions and Duets, akin to TikTok and Instagram!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://share.hsforms.com/1mrIXiBbURn6sMqYgZG9c6A1hk3i&quot;&gt;Be the first to access our new IMG.LY SDK—join our waitlist now!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thanks for reading!&lt;/strong&gt; &lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i&quot;&gt;&lt;strong&gt;Subscribe&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;to our newsletter to stay in the loop with the latest news and updates.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Neslihan</dc:creator><media:content url="https://blog.img.ly/2023/12/v119.jpg" medium="image"/><category>Release Notes</category><category>CE.SDK</category><category>Video Editing</category><category>Design Editor</category><category>App Development</category><category>Mobile App Development</category></item><item><title>CE.SDK v1.17 Release Notes</title><link>https://img.ly/blog/creative-editor-sdk-v_1_17_0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v_1_17_0-release-notes/</guid><description>Discover more about our new WebP Support, Seamless Android Video Capture, and Editing!</description><pubDate>Tue, 17 Oct 2023 12:48:42 GMT</pubDate><content:encoded>&lt;p&gt;In the ever-evolving landscape of app development, staying ahead of the curve is crucial. Since our &lt;a href=&quot;https://img.ly/blog/creative-editor-sdk-v_1_16_0-release-notes/&quot;&gt;last release&lt;/a&gt;, we’ve been crafting new features to empower your users’ creative journey. Today, we’re thrilled to introduce CE.SDK v1.17. With this release, you can:&lt;/p&gt;
&lt;h2 id=&quot;support-webp-file-formats&quot;&gt;Support WebP File Formats&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;webp.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/webp_ZihMfY.webp&quot; srcset=&quot;/_astro/webp_WMgHq.webp 640w, /_astro/webp_Zktgcw.webp 750w, /_astro/webp_ZaozQq.webp 828w, /_astro/webp_lWaNa.webp 1080w, /_astro/webp_1OGgA.webp 1280w, /_astro/webp_ZihMfY.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Interfaces: Engine&lt;br&gt;
Platforms: All&lt;/p&gt;
&lt;p&gt;We’re delighted to announce that our editor now supports WebP images, delivering you an array of benefits. WebP is gaining popularity for its unique ability to strike the perfect balance between high image quality and smaller file sizes. This means your visuals will look stunning while optimizing website performance.&lt;/p&gt;
&lt;h2 id=&quot;capture-and-export-videos-with-camera-for-android&quot;&gt;&lt;strong&gt;Capture and Export Videos with Camera for Android&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;android-camera-clips.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/android-camera-1_1QwCnP.webp&quot; srcset=&quot;/_astro/android-camera-1_SXytg.webp 640w, /_astro/android-camera-1_Z1uUni0.webp 750w, /_astro/android-camera-1_1eF16r.webp 828w, /_astro/android-camera-1_Z2hfyrm.webp 1080w, /_astro/android-camera-1_2keARH.webp 1280w, /_astro/android-camera-1_1QwCnP.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Interfaces: Engine&lt;br&gt;
Platforms: Android&lt;/p&gt;
&lt;p&gt;Video content creation has become the lifeblood of today’s app ecosystem. Social entertainment, user-generated content, and the demand for immersive experiences have transformed the way we engage with audiences.&lt;/p&gt;
&lt;p&gt;We’re excited to introduce &lt;strong&gt;Camera Recording for Android&lt;/strong&gt;, seamlessly integrating your live camera preview with our engine’s extensive capabilities. This means you can apply a wide range of effects, strokes, and drop shadows to your live camera feed, all while ensuring it harmoniously blends into the composition of your scene.&lt;/p&gt;
&lt;p&gt;This feature allows you to seamlessly capture, edit, and export high-quality videos directly within your applications. Whether you’re building a social platform, a video editing app, or a storytelling tool, this feature will redefine your users’ video creation experience. Learn how to use your camera in our Engine for Android in our &lt;a href=&quot;https://img.ly/docs/cesdk/android/import-media/capture-from-camera/record-video-47819b/&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Stay tuned for more exciting updates and the &lt;strong&gt;full reveal&lt;/strong&gt;: CE.SDK v1.17 is just the beginning of a new era in app-driven video content.&lt;/p&gt;
&lt;p&gt;Thank you for being a part of this journey with us. Subscribe to our &lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i&quot;&gt;newsletter&lt;/a&gt; to ensure you never miss out on updates! &lt;strong&gt;?&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Neslihan</dc:creator><media:content url="https://blog.img.ly/2023/10/white-label-editor-1_17.jpg" medium="image"/><category>Release Notes</category><category>Android</category><category>App Development</category></item><item><title>CE.SDK v1.16 Release Notes</title><link>https://img.ly/blog/creative-editor-sdk-v_1_16_0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v_1_16_0-release-notes/</guid><description>Keep it colorful! This release brings CMYK and color library support. We also enhanced web touch gestures. Find out more.</description><pubDate>Tue, 26 Sep 2023 14:26:37 GMT</pubDate><content:encoded>&lt;p&gt;It’s getting colorful! Since &lt;a href=&quot;https://img.ly/blog/creative-editor-sdk-v_1_15_0-release-notes/&quot;&gt;our last release&lt;/a&gt;, we’ve been busy crafting new features and enhancements to empower your user’s creative journey. We are excited to announce that CE.SDK v1.16 is now available.&lt;/p&gt;
&lt;p&gt;With this release, you can:&lt;/p&gt;
&lt;h2 id=&quot;maintain-color-consistency-with-cmyk--libraries&quot;&gt;Maintain Color Consistency with CMYK &amp;#x26; Libraries&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Interfaces:&lt;/strong&gt; Engine, Editor&lt;br&gt;
&lt;strong&gt;Platforms:&lt;/strong&gt; Web&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-16/color-cmyk-pantone-naptone.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;We understand the importance of precise color reproduction and the need for brand consistency. That’s why we’re enhancing your editing experience with greater color control.&lt;/p&gt;
&lt;p&gt;You can now seamlessly integrate &lt;strong&gt;CMYK and Pantone color spaces,&lt;/strong&gt; along with other customized color libraries, including &lt;strong&gt;your brand’s unique colors&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This ensures that your designs not only meet but exceed expectations across all mediums, delivering a consistent and visually engaging experience. It also helps eliminate color inconsistencies and product returns, while ensuring color accuracy.&lt;/p&gt;
&lt;p&gt;Learn more about adding color libraries to CE.SDK in our &lt;a href=&quot;https://img.ly/docs/cesdk/js/colors/create-color-palette-7012e0/&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;improve-web-interaction-with-touch-gestures&quot;&gt;Improve Web Interaction with Touch Gestures&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Offer enhanced cross-device editor interaction, including multitouch gestures like pinching and zooming.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/web-gestures-multitouch_ZmKIw4.webp&quot; srcset=&quot;/_astro/web-gestures-multitouch_Qxp6d.webp 640w, /_astro/web-gestures-multitouch_iwaoR.webp 750w, /_astro/web-gestures-multitouch_15RP4N.webp 828w, /_astro/web-gestures-multitouch_2aoYLz.webp 1080w, /_astro/web-gestures-multitouch_Z1DgVhd.webp 1280w, /_astro/web-gestures-multitouch_ZmKIw4.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Interfaces:&lt;/strong&gt; Engine, Editor&lt;br&gt;
&lt;strong&gt;Platforms:&lt;/strong&gt; Web&lt;/p&gt;
&lt;p&gt;With this update, we’re bringing a more interactive and responsive experience to our web applications. Let your users experience seamless &lt;strong&gt;multitouch interactions&lt;/strong&gt;, even on mobile web. This ensures that the content and functionality of our web applications remain accessible and user-friendly across various devices.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thank you for reading! Never miss out on updates and&lt;/strong&gt; &lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i&quot;&gt;&lt;strong&gt;subscribe&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;to our newsletter.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Neslihan</dc:creator><media:content url="https://blog.img.ly/2023/10/1-16.jpg" medium="image"/><category>Release Notes</category><category>Creative Editing</category><category>CMYK</category><category>Print</category><category>Design Editor</category><category>Cross-Platform</category><category>App Development</category></item><item><title>CE.SDK v1.14 Release Notes</title><link>https://img.ly/blog/creative-editor-sdk-v_1_14_0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v_1_14_0-release-notes/</guid><description>Experience faster thumbnails for video, enhanced placeholders, macOS support, and more! </description><pubDate>Fri, 25 Aug 2023 15:37:00 GMT</pubDate><content:encoded>&lt;p&gt;Since &lt;a href=&quot;https://img.ly/blog/creative-editor-sdk-v_1_13_0-release-notes/&quot;&gt;our last release&lt;/a&gt;, we’ve been hard at work developing new features and improvements to enhance your creative editing experience. We are excited to announce that CE.SDK v1.14 is now available!&lt;/p&gt;
&lt;p&gt;With this release, you can:&lt;/p&gt;
&lt;h2 id=&quot;generate-thumbnails-fast-for-smooth-performance&quot;&gt;Generate Thumbnails Fast for Smooth Performance&lt;/h2&gt;
&lt;p&gt;Interfaces: Engine&lt;br&gt;
Platforms: All&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-14/thumbnail-improved.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;We have made significant enhancements to the way video thumbnails are generated, resulting in a smoother and more efficient workflow. Our intelligent engine now renders thumbnails seamlessly across multiple frames, ensuring there are no delays or interruptions while you work. Instead of slow JPEG compression, we have implemented a faster method using raw pixel buffers that maintain high-quality results.&lt;/p&gt;
&lt;p&gt;If you’re using web applications, the thumbnail width adapts to fit your screen, providing a seamless and enjoyable user experience. Additionally, our dynamic thumbnail generation adjusts based on the size of your clips and zoom level, optimizing resources and improving overall performance.&lt;/p&gt;
&lt;h2 id=&quot;enhance-templating-with-improved-placeholders&quot;&gt;Enhance Templating with Improved Placeholders&lt;/h2&gt;
&lt;p&gt;Interfaces: Engine, Editor&lt;br&gt;
Platforms: All&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/placeholder-images.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Introducing an enhanced placeholder behavior for text and image content, allowing for seamless editing and replacement. With the new &lt;code&gt;PlaceholderBehavior&lt;/code&gt; concept, you can define whether a block should initially look and behave as a placeholder or allow editing/replacement. This feature provides a smooth editing experience for users and offers flexibility for template designers to differentiate between placeholder and desired content.&lt;/p&gt;
&lt;h2 id=&quot;bring-creative-editing-to-your-macos-app&quot;&gt;Bring Creative Editing to Your macOS App&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Bring creative editing to your macOS app with CE.SDK.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/macOS_Z2iunHV.webp&quot; srcset=&quot;/_astro/macOS_2uXTJb.webp 640w, /_astro/macOS_Rmfii.webp 750w, /_astro/macOS_Z2okYll.webp 828w, /_astro/macOS_1QoMw8.webp 1080w, /_astro/macOS_Zdxi5T.webp 1280w, /_astro/macOS_Z2iunHV.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;We’re excited to announce the addition of macOS platform support to our lineup. Extend your application’s reach to macOS users and provide a seamless editing experience across different platforms. Get started, and &lt;strong&gt;initialize our engine in your macOS app&lt;/strong&gt; with our &lt;a href=&quot;https://img.ly/docs/cesdk/macos/overview-8cc730/&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;expand-editing-capabilities-macos--catalyst-binding&quot;&gt;Expand Editing Capabilities: macOS &amp;#x26; Catalyst Binding&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Initialize CE.SDK&amp;#39;s engine in your iOS app, and bring creative editing to your users.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/catalyst_Z1zzDyb.webp&quot; srcset=&quot;/_astro/catalyst_Z16zs6Q.webp 640w, /_astro/catalyst_1SieDm.webp 750w, /_astro/catalyst_20b6IL.webp 828w, /_astro/catalyst_1izTD3.webp 1080w, /_astro/catalyst_2oAGVT.webp 1280w, /_astro/catalyst_Z1zzDyb.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;With this new feature, we provide a comprehensive solution for developers looking to enhance their iOS applications with our CE.SDK’s editing capabilities. Learn how to initialize our creative engine in your iOS app in our &lt;a href=&quot;https://img.ly/docs/cesdk/mac-catalyst/overview-8cc730/&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thank you for reading! Never miss out on updates and&lt;/strong&gt; &lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i&quot;&gt;&lt;strong&gt;subscribe&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;to our newsletter.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Neslihan</dc:creator><media:content url="https://blog.img.ly/2023/09/ce-sdk_1-14-2.jpg" medium="image"/><category>Release Notes</category><category>Video Editing</category><category>Creative Editor</category><category>CE.SDK</category><category>macOS</category><category>App Development</category></item><item><title>IMG.LY Announces Open Source JavaScript Library for In-Browser Background Removal</title><link>https://img.ly/blog/announcing-imgly-background-removal/</link><guid isPermaLink="true">https://img.ly/blog/announcing-imgly-background-removal/</guid><description>Seamlessly remove backgrounds in-browser with ease. Empower your creativity and protect data privacy. Learn how!</description><pubDate>Wed, 28 Jun 2023 11:38:49 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;UPDATE October 2023&lt;/strong&gt;: We’ve recently introduced Node.js support for the &lt;a href=&quot;https://www.npmjs.com/package/@imgly/background-removal&quot;&gt;@imgly/background-removal&lt;/a&gt; npm package. This enhancement enables you to remove backgrounds from images not only in the user’s browser but also on your server. This opens up the potential for batch processing and allows you to bypass memory constraints, especially for larger images.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Just before the summer lull engulfs us all, we have something exciting to share! We are thrilled to announce the release of &lt;a href=&quot;https://www.npmjs.com/package/@imgly/background-removal&quot;&gt;@imgly/background-removal&lt;/a&gt;, an innovative npm package that empowers developers to seamlessly remove backgrounds from images directly in the browser.&lt;/p&gt;
&lt;p&gt;Gone are the days of relying on server-side processing or sacrificing data privacy. With IMG.LY’s Background Removal, you can now harness the power of in-browser background removal with ease. Let’s dive into the key features that make this library truly exceptional:&lt;/p&gt;
&lt;h3 id=&quot;in-browser-background-removal&quot;&gt;In-Browser Background Removal&lt;/h3&gt;
&lt;p&gt;Our one-of-a-kind solution performs the entire background removal process directly in the user’s browser, eliminating the need for additional server costs. By leveraging the computing power of the local device, users can enjoy a fast and efficient background removal process that streamlines their workflow.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/bg-removal-javascript-open-source.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;h3 id=&quot;data-protection&quot;&gt;Data Protection&lt;/h3&gt;
&lt;p&gt;Rest assured that your images and sensitive information remain secure within your own devices. As IMG.LY’s Background Removal runs entirely in the browser, there are no data transfers to external servers, ensuring robust data privacy and alleviating any concerns you may have.&lt;/p&gt;
&lt;p&gt;You can experience it in action on our &lt;a href=&quot;https://img.ly/showcases/cesdk/web/background-removal/web&quot;&gt;background removal showcase&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;seamless-integration-with-imglys-cesdk&quot;&gt;Seamless Integration with IMG.LY’s CE.SDK&lt;/h3&gt;
&lt;p&gt;IMG.LY’s Background Removal seamlessly integrates with IMG.LY’s CE.SDK, making it easier than ever to incorporate powerful in-browser image matting and background removal capabilities into your projects. Boost your creative endeavors with this intuitive integration.&lt;/p&gt;
&lt;p&gt;The Neural Network (ONNX model) and WebAssembly (WASM) files used by IMG.LY’s Background Removal are hosted on UNPKG, making them readily available for download to all users of the library. However, if you prefer to host the data on your own servers, our library also supports custom asset serving. The choice is yours!&lt;/p&gt;
&lt;p&gt;Background removal is often the first step in any creative workflow involving image composition. Whether you are developing e-commerce applications that need real-time background removal, enhancing user experience in image editing applications, or simplifying the creative process with web-based graphic design tools, IMG.LY’s Background Removal is your go-to solution.&lt;/p&gt;
&lt;h3 id=&quot;empower-yourself-with-imglys-background-removal&quot;&gt;Empower Yourself with IMG.LY’s Background Removal&lt;/h3&gt;
&lt;p&gt;Whether you are a professional developer or a hobbyist, this open source JavaScript library empowers you to deliver impressive applications and services with ease. Join the growing community of developers who are revolutionizing the way background removal is done.&lt;/p&gt;
&lt;p&gt;Get started with @imgly/background-removal today by visiting &lt;a href=&quot;https://www.npmjs.com/package/@imgly/background-removal&quot;&gt;our official npm package page&lt;/a&gt; and &lt;a href=&quot;https://github.com/imgly/background-removal-js/&quot;&gt;our GitHub repository&lt;/a&gt;. You’ll find comprehensive documentation, examples, and everything you need to unlock the full potential of in-browser background removal.&lt;/p&gt;
&lt;h3 id=&quot;update-nodejs-support&quot;&gt;Update: Node.js Support&lt;/h3&gt;
&lt;p&gt;We have just shipped &lt;a href=&quot;https://www.npmjs.com/package/@imgly/background-removal-node&quot;&gt;Node.js support&lt;/a&gt; for the &lt;a href=&quot;https://www.npmjs.com/package/@imgly/background-removal&quot;&gt;@imgly/background-removal&lt;/a&gt; npm package. In addition to the users’ browser, you can now remove backgrounds from images on your server, making it possible to perform batch processing or bypass memory constraints for larger images.&lt;/p&gt;
&lt;p&gt;Thank you for your support, and we can’t wait to see the incredible projects you’ll create with IMG.LY’s Background Removal. Stay tuned for more updates and enhancements as we continue to improve and expand this powerful library. Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Don’t forget to &lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i&quot;&gt;subscribe&lt;/a&gt; to our newsletter to stay in the loop with the latest news and updates.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Jan</dc:creator><media:content url="https://blog.img.ly/2023/06/bg-removal.jpg" medium="image"/><category>Photo Editing</category><category>App Development</category><category>Photo Editor</category><category>JavaScript</category><category>OpenSource</category><category>Background Removal</category><category>Company</category></item><item><title>IMG.LY Partners with Soundstripe to Infuse Video Editing with Epic Royalty-Free Music &amp; SFX</title><link>https://img.ly/blog/img-ly-partners-with-soundstripe/</link><guid isPermaLink="true">https://img.ly/blog/img-ly-partners-with-soundstripe/</guid><description>Elevated storytelling and captivating viewers is everything: unlock the ultimate video editing experience with this integration.</description><pubDate>Wed, 24 May 2023 07:31:24 GMT</pubDate><content:encoded>&lt;p&gt;We are excited to announce our exciting new partnership with Soundstripe, the leading provider of royalty-free music for video creators. Our VideoEditor SDK now features a seamless integration with Soundstripe, offering users access to a vast collection of over &lt;strong&gt;9,000 hand-curated songs&lt;/strong&gt; from &lt;strong&gt;150+ musicians&lt;/strong&gt;, along with an extensive library of &lt;strong&gt;70,000 sound effects&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/soundstripe_2.mp4&quot; controls playsinline poster=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/integrate-soundstripe-into-app.jpg&quot;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Starting from version 11, our &lt;a href=&quot;https://img.ly/products/video-sdk&quot;&gt;VideoEditor SDK&lt;/a&gt; now comes pre-equipped with a seamless Soundstripe integration, as detailed in our &lt;a href=&quot;https://img.ly/docs/vesdk/ios/guides/audio-overlays/custom-overlays/soundstripe-integration/#soundstripe-api&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;streamlining-music-licensing-for-digital-platforms&quot;&gt;Streamlining Music Licensing for Digital Platforms&lt;/h3&gt;
&lt;p&gt;Finding the right music for digital platforms hasn’t been easy. Music licensing complexities and the challenge of finding high-quality tracks that align with your brand standards can be overwhelming.&lt;/p&gt;
&lt;p&gt;But now, with our &lt;a href=&quot;https://www.soundstripe.com/blogs/how-to-use-soundstripe-video-0&quot;&gt;partnership with Soundstripe&lt;/a&gt;, you can effortlessly enhance your app with royalty-free music and video editing.&lt;/p&gt;
&lt;p&gt;Our mission has always been to provide the ultimate toolkit for building captivating creative experiences, and video editing plays a central role in achieving this. We recognize the significant role that music plays in video storytelling, as it has the power to evoke emotions, set the mood, tone, and atmosphere, and greatly influence the pacing and energy of a video. With Soundstripe’s diverse range of over 50 genres, your users will have no trouble finding the perfect track to complement their visual narrative.&lt;/p&gt;
&lt;h3 id=&quot;effortless-music-selection&quot;&gt;Effortless Music Selection&lt;/h3&gt;
&lt;p&gt;We have developed an &lt;strong&gt;intuitive search&lt;/strong&gt; interface that allows users to explore music by &lt;strong&gt;title, genre, and description&lt;/strong&gt; effortlessly. Once users have found their desired song, they can easily position any section of the track over their video. Furthermore, we are delighted to provide every one of our customers with seven complimentary sample songs, allowing them to get a taste of the fantastic library available. To unlock the full audio library, simply head over to Soundstripe and &lt;a href=&quot;https://www.soundstripe.com/enterprise-licensing&quot;&gt;request an API key&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We are eagerly looking forward to working closely with Soundstripe to deliver the most exceptional video editing experience on the market. We invite you to try out &lt;a href=&quot;https://img.ly/video-sdk&quot;&gt;VideoEditor SDK&lt;/a&gt; in your Android or iOS app and witness the transformative impact it will have on your users’ creativity. Together, we can take your video editing capabilities to new heights.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thanks for reading! Stay ahead of the curve with our newsletter and &lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i&quot;&gt;sign up&lt;/a&gt; now!&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Jan</dc:creator><media:content url="https://blog.img.ly/2023/06/soundstripe-app.jpg" medium="image"/><category>Video App</category><category>Royalty-Free Music</category><category>App Development</category><category>Mobile App Development</category><category>Video Editing</category><category>Company</category></item><item><title>CE.SDK v1.11 Release</title><link>https://img.ly/blog/creative-editor-sdk-v_1_11_0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v_1_11_0-release-notes/</guid><description>Elevate your editing game with new features: Cutout Lines for Stickers and Shapes, Advanced Text Settings, and more. Discover the possibilities now!</description><pubDate>Tue, 16 May 2023 15:37:49 GMT</pubDate><content:encoded>&lt;p&gt;We are introducing CE.SDK v1.11! Elevate your editing game with new features like Cutout Lines, Advanced Text Styling, HEVC/H.265 codec, and transparent video support. We’ve also improved asset resource management, and added user interfaces to enhance your template creation and editing workflow. See how CE.SDK v1.11 can bring your creative vision to life.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;With this release, you can:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create Cutout Stickers and Shapes&lt;/li&gt;
&lt;li&gt;Choose Letter Cases&lt;/li&gt;
&lt;li&gt;Keep Font Size Consistent in Templates&lt;/li&gt;
&lt;li&gt;Enhance and Highlight Text&lt;/li&gt;
&lt;li&gt;Ensure Effortless Layouting with Alignment Options&lt;/li&gt;
&lt;li&gt;Support More Video Codecs&lt;/li&gt;
&lt;li&gt;Use Less Memory&lt;/li&gt;
&lt;li&gt;Enjoy Smoother Editing&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;create-cutout-stickers-and-shapes&quot;&gt;Create Cutout Stickers and Shapes&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Interfaces&lt;/strong&gt;: API, Default UI, Advanced UI&lt;br&gt;
&lt;strong&gt;Platforms:&lt;/strong&gt; Web, Server, iOS, Android&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;CutOuts_UI.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/CutOuts_UI-1_Z1tfgS5.webp&quot; srcset=&quot;/_astro/CutOuts_UI-1_Z2cgTFN.webp 640w, /_astro/CutOuts_UI-1_22p3pU.webp 750w, /_astro/CutOuts_UI-1_Z28Jas0.webp 828w, /_astro/CutOuts_UI-1_Z1qzUyO.webp 1080w, /_astro/CutOuts_UI-1_15aXb1.webp 1280w, /_astro/CutOuts_UI-1_Z1tfgS5.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;We are excited to announce that CE.SDK now supports &lt;strong&gt;cutout lines&lt;/strong&gt;, which includes a new type of block that enables users to create these lines and perform cutout line combinations. A future update will allow dynamic generation of such lines for existing blocks. This feature is based on the technology used for named/spot colors and is available for use with a range of printers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Create Cutout and Adjust Offset&lt;/strong&gt;&lt;br&gt;
By providing precise control over the offset, we enable print businesses to ensure accurate and high-quality output for their users. Empower your users to create designs with exceptional precision, perfect for applications like stickers.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Effortlessly create cutout lines, and adjust their offset as seen here in our Default UI.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/cutout_01-1_Z2aVFxS.webp&quot; srcset=&quot;/_astro/cutout_01-1_Z1GlzAz.webp 640w, /_astro/cutout_01-1_ZEXXD1.webp 750w, /_astro/cutout_01-1_Z1PJwlq.webp 828w, /_astro/cutout_01-1_ZkJWAo.webp 1080w, /_astro/cutout_01-1_1hffkk.webp 1280w, /_astro/cutout_01-1_Z2aVFxS.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Combine Cutout Shapes (Boolean Operations)&lt;/strong&gt;&lt;br&gt;
These boolean operations provide designers with the ability to manipulate and combine Cutout shapes in various ways, enabling the creation of complex designs and precise control over the final output.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Union: Combines two or more shapes into a single shape, creating a merged outline of the combined areas.&lt;/li&gt;
&lt;li&gt;Subtract: Removes one shape from another, resulting in a new shape formed by subtracting the overlapping region.&lt;/li&gt;
&lt;li&gt;Intersect: Creates a new shape that represents the overlapping area between two or more shapes.&lt;/li&gt;
&lt;li&gt;Exclude: Achieve artistic flair by excluding the overlapping area between shapes, resulting in a unique and captivating composition.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&quot;Combine cutout lines, perfect for custom shapes like stickers.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/cutout_02-1_Z12u8CF.webp&quot; srcset=&quot;/_astro/cutout_02-1_Z1E6Ub9.webp 640w, /_astro/cutout_02-1_ZCJjdA.webp 750w, /_astro/cutout_02-1_Z1NuQV0.webp 828w, /_astro/cutout_02-1_MGzjO.webp 1080w, /_astro/cutout_02-1_2pGMfx.webp 1280w, /_astro/cutout_02-1_Z12u8CF.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Visit our documentation on &lt;a href=&quot;https://img.ly/docs/cesdk/js/stickers-and-shapes/create-cutout-384be3/&quot;&gt;using cutouts&lt;/a&gt; to get started.&lt;/p&gt;
&lt;h3 id=&quot;choose-letter-cases&quot;&gt;Choose Letter Cases&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Interfaces&lt;/strong&gt;: API, Advanced UI, Default UI&lt;br&gt;
&lt;strong&gt;Platforms:&lt;/strong&gt; Web, iOS, Android, Server&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Simplify the design process by selecting a letter case.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/cases-1_Z6pAOB.webp&quot; srcset=&quot;/_astro/cases-1_2aHljw.webp 640w, /_astro/cases-1_cvIKq.webp 750w, /_astro/cases-1_Z2sQ7l1.webp 828w, /_astro/cases-1_lj130.webp 1080w, /_astro/cases-1_7rcBc.webp 1280w, /_astro/cases-1_Z6pAOB.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;In our &lt;strong&gt;Advanced Text Styling,&lt;/strong&gt; users can now adjust multiple new settings to enhance the visual appeal of their designs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Letter case settings, including uppercase, lowercase, and title case.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Using the new styling settings enhances your design’s visual appeal while reducing implementation time and effort.&lt;/p&gt;
&lt;h3 id=&quot;keep-font-size-consistent-in-templates&quot;&gt;Keep Font Size Consistent in Templates&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Interfaces&lt;/strong&gt;: API, Default UI, Advanced UI&lt;br&gt;
&lt;strong&gt;Platforms:&lt;/strong&gt; Web, iOS, Android, Server&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Perfect for creating templates in our Advanced UI: choose &amp;quot;Auto-size&amp;quot; to allow users to fit as much text in the frame at all times, without breaking the design.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/auto-size-1_Z1fYTGh.webp&quot; srcset=&quot;/_astro/auto-size-1_WxLcx.webp 640w, /_astro/auto-size-1_1XUna6.webp 750w, /_astro/auto-size-1_N9OrG.webp 828w, /_astro/auto-size-1_zbNgd.webp 1080w, /_astro/auto-size-1_2cc1bV.webp 1280w, /_astro/auto-size-1_Z1fYTGh.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;CE.SDK’s new &lt;strong&gt;Automatic Font Size&lt;/strong&gt; feature adjusts font size to fit within text frame constraints, enabling users to create visually appealing designs with ease. For example, a text placeholder for names will now adjust the font size for longer names, ensuring they fit perfectly within a print design. Users can now enter as much text as they need, without worrying about it overflowing out of the designated frame.&lt;/p&gt;
&lt;h3 id=&quot;enhance-and-highlight-text&quot;&gt;Enhance and Highlight Text&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Interfaces&lt;/strong&gt;: API, Advanced UI, Default UI&lt;br&gt;
&lt;strong&gt;Platforms:&lt;/strong&gt; Web, iOS, Android, Server&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;textrun.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/textrun-1_UtjFF.webp&quot; srcset=&quot;/_astro/textrun-1_1FuFvn.webp 640w, /_astro/textrun-1_13oHHh.webp 750w, /_astro/textrun-1_1eSzTe.webp 828w, /_astro/textrun-1_Z26PieJ.webp 1080w, /_astro/textrun-1_ZAaYh2.webp 1280w, /_astro/textrun-1_UtjFF.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Easily manipulate individual segments of text within a text block with &lt;strong&gt;Text Run&lt;/strong&gt;. That means, you can modify the formatting of specific words or phrases, such as font weight and changing colors, without having to manipulate the entire text block. This feature is particularly useful for creating visually appealing text effects or highlighting specific words or phrases within a larger body of text.&lt;/p&gt;
&lt;h3 id=&quot;ensure-effortless-layouting-with-alignment-options&quot;&gt;Ensure Effortless Layouting with Alignment Options&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Interfaces&lt;/strong&gt;: API, Advanced UI, Default UI&lt;br&gt;
&lt;strong&gt;Platforms:&lt;/strong&gt; Web, Server, iOS, Android&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Easily align elements for streamlined layouting.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/align-shirt-1_1YVar6.webp&quot; srcset=&quot;/_astro/align-shirt-1_ZM3FIw.webp 640w, /_astro/align-shirt-1_1vtDEA.webp 750w, /_astro/align-shirt-1_K5eYF.webp 828w, /_astro/align-shirt-1_2jkAOw.webp 1080w, /_astro/align-shirt-1_29CS8j.webp 1280w, /_astro/align-shirt-1_1YVar6.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;We are introducing the &lt;strong&gt;Block Align&lt;/strong&gt; feature, which transforms the editing experience by enabling users to effortlessly align blocks to the page or each other, empowering them to achieve their desired layout with ease. Read our &lt;a href=&quot;https://img.ly/docs/cesdk/js/insert-media/position-and-align-cc6b6a/#alignment&quot;&gt;documentation on Block Alignment&lt;/a&gt; for more details.&lt;/p&gt;
&lt;h3 id=&quot;support-more-codecs-and-transparent-videos&quot;&gt;Support More Codecs and Transparent Videos&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Interfaces&lt;/strong&gt;: All&lt;br&gt;
&lt;strong&gt;Platforms:&lt;/strong&gt; Web&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;HEVC.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/HEVC-1_Z1pW1FI.webp&quot; srcset=&quot;/_astro/HEVC-1_Z1ShWzE.webp 640w, /_astro/HEVC-1_1nVYci.webp 750w, /_astro/HEVC-1_Z1GUF7A.webp 828w, /_astro/HEVC-1_ZxYjSK.webp 1080w, /_astro/HEVC-1_ZYsFhJ.webp 1280w, /_astro/HEVC-1_Z1pW1FI.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;We have added support for hardware-accelerated video decoding of the &lt;strong&gt;HEVC/H.265 codec&lt;/strong&gt;. This new feature will allow users to decode high-quality videos with &lt;strong&gt;better compression and smaller file sizes&lt;/strong&gt;. It enables CE.SDK to handle a wider range of video files with improved efficiency.&lt;/p&gt;
&lt;p&gt;Please note: At the moment, we do not support transparent videos on some major platforms due to a limitation on Windows. However, we’re excited to announce preliminary MOV container support, allowing you to work with a wider range of video files.&lt;/p&gt;
&lt;h3 id=&quot;use-less-memory&quot;&gt;Use Less Memory&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;assetresource.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/assetresource-1_1MIj2c.webp&quot; srcset=&quot;/_astro/assetresource-1_sbgtj.webp 640w, /_astro/assetresource-1_Z1lCtE0.webp 750w, /_astro/assetresource-1_Nmg4O.webp 828w, /_astro/assetresource-1_ZgsD4d.webp 1080w, /_astro/assetresource-1_KCktu.webp 1280w, /_astro/assetresource-1_1MIj2c.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Loading and unloading assets, including images and fonts, has been updated to allow for the unloading of unused items. This &lt;strong&gt;unused asset usage optimization&lt;/strong&gt; frees up memory and reduces the engine’s memory footprint, resulting in more stable and longer editing sessions.&lt;/p&gt;
&lt;h3 id=&quot;smoother-editing&quot;&gt;Smoother Editing&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;Undo-Redo.jpg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1480px) 1480px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1480&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/Undo-Redo-1_Z10dxPT.webp&quot; srcset=&quot;/_astro/Undo-Redo-1_1i4AF2.webp 640w, /_astro/Undo-Redo-1_2jrcCA.webp 750w, /_astro/Undo-Redo-1_18FDUb.webp 828w, /_astro/Undo-Redo-1_OXa6A.webp 1080w, /_astro/Undo-Redo-1_2rXn2j.webp 1280w, /_astro/Undo-Redo-1_Z10dxPT.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;This update &lt;strong&gt;addresses issues with the undo/redo&lt;/strong&gt; stack not being built properly in certain scenarios, which could cause delays in updating the video timeline. With these improvements, users can now benefit from a smoother and more efficient editing experience.&lt;/p&gt;
&lt;p&gt;Thanks for reading. &lt;strong&gt;Visit our&lt;/strong&gt; &lt;a href=&quot;https://img.ly/docs/cesdk/changelog/&quot;&gt;&lt;strong&gt;changelog&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;for more details and start creating with confidence.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Neslihan</dc:creator><media:content url="https://blog.img.ly/2023/05/cesdk-v1_1-1_ReleaseNotes-1.jpg" medium="image"/><category>Release Notes</category><category>App Development</category><category>Cutouts</category><category>Web-to-print</category><category>Design Editor</category></item><item><title>IMG.LY Partners with Getty Images to Revolutionize Image Integration</title><link>https://img.ly/blog/getty-images-partnership/</link><guid isPermaLink="true">https://img.ly/blog/getty-images-partnership/</guid><description>Discover Getty Images Library SDK - the easy-to-use toolkit that integrates image search, licensing, and editing for efficient content creation.</description><pubDate>Wed, 03 May 2023 13:07:31 GMT</pubDate><content:encoded>&lt;p&gt;We are thrilled to announce our latest partnership with Getty Images, the world’s leading provider of images, clips, and illustrations for visual communication. This collaboration has brought forth the &lt;a href=&quot;https://img.ly/partners/getty-images-sdk&quot;&gt;Getty Images Library SDK&lt;/a&gt; - a bridge that seamlessly integrates image searching, licensing, and editing into your application. This revolutionary toolkit grants access to millions of stock images and enables your teams and users to browse, license, and edit images without ever leaving your application or website.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empower your users to unleash their creativity with the Getty Images library&amp;#39;s powerful filtering tool. Let them find the perfect visual match for their content with ease.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 519px) 519px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;519&quot; height=&quot;526&quot; src=&quot;https://img.ly/_astro/image_D8Iyi.webp&quot; srcset=&quot;/_astro/image_D8Iyi.webp 519w&quot;&gt;&lt;/p&gt;
&lt;p&gt;By integrating Getty Images Library SDK into your application, you can save precious resources, streamline your workflows, and ensure legal compliance with a broad range of licensed stock images at your fingertips. Imagine not having to switch between different platforms to search, license, and edit images – all while staying in your application.&lt;/p&gt;
&lt;h3 id=&quot;empower-your-developers-and-users&quot;&gt;Empower your Developers and Users&lt;/h3&gt;
&lt;p&gt;At IMG.LY, we are passionate about delivering powerful editing tools with an intuitive interface, providing a creative outlet for users of all skill levels. Teaming up with Getty Images, we strive to provide a toolkit that empowers content creators to communicate their message in the most efficient and effective way possible, while upholding Getty Images’ commitment to quality and diversity in visual images.&lt;/p&gt;
&lt;p&gt;Designed by developers, for developers, the integration is quick and easy to set up. Once integrated, users can effortlessly browse through images, license the visuals they want, and make quick edits such as cropping or rotating images, all within the same application.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Explore the user-friendly interface of the Getty Images Library SDK editor, designed to seamlessly integrate image searching, licensing, and editing into your application.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 854px) 854px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;854&quot; height=&quot;520&quot; src=&quot;https://img.ly/_astro/getty-images-library-integration-app_ZADacA.webp&quot; srcset=&quot;/_astro/getty-images-library-integration-app_1YOhLQ.webp 640w, /_astro/getty-images-library-integration-app_xDMFe.webp 750w, /_astro/getty-images-library-integration-app_i0Kt7.webp 828w, /_astro/getty-images-library-integration-app_ZADacA.webp 854w&quot;&gt;&lt;/p&gt;
&lt;p&gt;We are excited to share this news and look forward to working with Getty Images to bring tools and empower creative expression!&lt;/p&gt;
&lt;h3 id=&quot;get-started&quot;&gt;Get Started&lt;/h3&gt;
&lt;p&gt;Learn more about the &lt;a href=&quot;https://img.ly/partners/getty-images-sdk&quot;&gt;Getty Images Library SDK&lt;/a&gt;, &lt;a href=&quot;https://img.ly/docs/pesdk/web/guides/getty-library/getting-started/&quot;&gt;how to integrate it&lt;/a&gt;, or contact &lt;a href=&quot;https://www.gettyimages.de/api?utm_source=imgly&amp;#x26;utm_medium=referral&quot;&gt;Getty Images&lt;/a&gt; to obtain a license key.&lt;/p&gt;</content:encoded><dc:creator>Klaudia</dc:creator><media:content url="https://blog.img.ly/2023/05/partnership---getty.jpg" medium="image"/><category>App Development</category><category>Web Application</category><category>Web Development</category><category>Image Editing</category><category>Company</category></item><item><title>How To Resize Images in Flutter</title><link>https://img.ly/blog/how-to-resize-images-in-flutter/</link><guid isPermaLink="true">https://img.ly/blog/how-to-resize-images-in-flutter/</guid><description>Keep it light: resize your application images in Flutter. </description><pubDate>Tue, 27 Sep 2022 15:03:53 GMT</pubDate><content:encoded>&lt;p&gt;Static images are a core part of mobile applications. Usually, you store them in the directory in their original sizes, which requires you to adjust the sizes now and then, depending on where they are displayed. This article discusses how to resize images in Flutter and adjust their width, height, and size with efficient lines of code.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/flutter-resize-images.mp4&quot; controls muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;h3 id=&quot;resizing-methods&quot;&gt;Resizing Methods&lt;/h3&gt;
&lt;p&gt;For image editing tools, Flutter offers an excellent and easy-in-use &lt;code&gt;Boxfit&lt;/code&gt; property that works within the &lt;code&gt;fit&lt;/code&gt; parameter, and you can easily integrate it into your application.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;dart&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;child&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; Image&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;asset&lt;/span&gt;&lt;span&gt;( &lt;/span&gt;&lt;span&gt;&apos;images/pexels.jpg&apos;&lt;/span&gt;&lt;span&gt;, fit&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; BoxFit&lt;/span&gt;&lt;span&gt;.cover)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Depending on your needs, you can choose between multiple attributes. For example, &lt;code&gt;.cover&lt;/code&gt; and &lt;code&gt;.fitHeight&lt;/code&gt; properties are similar when called, and both result in maximum frame coverage. Yet, although the image is widened proportionally, these methods can significantly affect the quality of crop image borders if they overfill. On the contrary, with &lt;code&gt;.fitWidth&lt;/code&gt; or &lt;code&gt;.scaledown&lt;/code&gt;, the asset is resized to the container’s width boundaries, which could be helpful when multiple images are needed to be displayed simultaneously.  If you are dealing with a static image of small size, you can also employ &lt;code&gt;.fill&lt;/code&gt; attribute that helps stretch your assets without cropping any critical information.&lt;/p&gt;
&lt;p&gt;Alternatively, by calling  .scale 0.5 the fit parameter will return you a graphical asset based on the scale you define. Note that any value less than 1 would reduce the image size.&lt;/p&gt;
&lt;h3 id=&quot;adjusting-image-size-with-flutter&quot;&gt;Adjusting Image Size with Flutter&lt;/h3&gt;
&lt;p&gt;Now, let’s look at how Flutter allows applying these image manipulation techniques. The crucial difference from the other frameworks is that in Flutter, images should be stored in a specific folder. In other words, once you upload graphic files, go to the &lt;code&gt;pubspec.yaml&lt;/code&gt; file and add the path to the directory around under &lt;code&gt;assets&lt;/code&gt;(&lt;strong&gt;Note:&lt;/strong&gt; by default the dependencies corresponding to ****&lt;code&gt;assets&lt;/code&gt;are usually placed around 45-46th lines in the code and need to be uncommented first by eliminating # and one space).&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# Don&apos;t forget to define the assets folder in your directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# To do so, find lines 45 - 46 in the **pubspec.yaml** file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# and uncomment the assets section like this:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;assets&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;images/&lt;/span&gt;&lt;span&gt; #Note that this should correspond to the name of your folder&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Alternatively, you can specify the path to each image in the list:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;assets&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;assets/images/your_image.jpg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  - &lt;/span&gt;&lt;span&gt;assets/images/your_image2.jpg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the image is uploaded to Flutter, it seeks to occupy as much size as possible. But let’s presume that we have a “frame” or container that differs in size from the visual asset. One way to see the differences in sizes of both canvases is to color one frame, like color: Colors.indigo. Then we provide Flutter with the size specification and render our image in a child node child: Image.asset(‘images/pexels.jpg’). Thus, now we can see the image is placed inside the frame, and we need only to assign one of the filling methods (for example, fit: BoxFit.cover) discussed above.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;dart&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &apos;package:flutter/cupertino.dart&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &apos;package:flutter/material.dart&apos;&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;void&lt;/span&gt;&lt;span&gt; main&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  runApp&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; ImgApp&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;class&lt;/span&gt;&lt;span&gt; ImgApp&lt;/span&gt;&lt;span&gt; extends&lt;/span&gt;&lt;span&gt; StatelessWidget&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; ImgApp&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;span&gt;Key&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; key}) &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; super&lt;/span&gt;&lt;span&gt;(key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; key);&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;  @override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Widget&lt;/span&gt;&lt;span&gt; build&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BuildContext&lt;/span&gt;&lt;span&gt; context) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; MaterialApp&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      debugShowCheckedModeBanner&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;      home&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; const&lt;/span&gt;&lt;span&gt; ResizePage&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;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; ResizePage&lt;/span&gt;&lt;span&gt; extends&lt;/span&gt;&lt;span&gt; StatelessWidget&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; ResizePage&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;span&gt;Key&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; key}) &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; super&lt;/span&gt;&lt;span&gt;(key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; key);&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;  @override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Widget&lt;/span&gt;&lt;span&gt; build&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BuildContext&lt;/span&gt;&lt;span&gt; context) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; Scaffold&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        appBar&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; AppBar&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          title&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; Text&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;How to Resize Images&apos;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          backgroundColor&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; Color&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0xffe55586&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;        body&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; Center&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            // Enabling the Image Frame&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            child&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; Container&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                color&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; Colors&lt;/span&gt;&lt;span&gt;.indigo, &lt;/span&gt;&lt;span&gt;// To see the difference between the image&apos;s original size and the frame&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                height&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 550&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                width&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 300&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;                // Uploading the Image from Assets&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                child&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; Image&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;asset&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                  &apos;images/pexels.jpg&apos;&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;                  // Resizing the Image to the Frame Size&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                  fit&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; BoxFit&lt;/span&gt;&lt;span&gt;.cover,&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;You can find the associated to this tutorial Git repository ― &lt;a href=&quot;https://github.com/nataliakzm/Resizing_Images_with_Flutter&quot;&gt;here&lt;/a&gt;. Otherwise, run the following command to clone the complete code to your system:&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;git&lt;/span&gt;&lt;span&gt; clone&lt;/span&gt;&lt;span&gt; &amp;#x3C;&lt;/span&gt;&lt;span&gt;https://github.com/nataliakzm/Resizing_Images_with_Flutte&lt;/span&gt;&lt;span&gt;r&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;This article covered Flutter’s approach to the image resizing problem and saw how to use it in practice. However, despite the diversity of suggested methods that could fulfill basic users’ needs, Flutter fails to provide a comfortable integration. Just imagine you are building an app similar to Instagram in its functionality and you need not only upload various images from different assets but also resize them differently. If you want to avoid spending your time writing and maintaining a ton of code, then you may consider using &lt;a href=&quot;https://img.ly/products/photo-sdk?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;PhotoEditor SDK&lt;/a&gt; in your next project.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/photoeditor-sdk-resize-image.mp4&quot; controls muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;PhotoEditor SDK is available for various frameworks: first, read &lt;a href=&quot;https://img.ly/docs/pesdk/flutter/getting-started/integration/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;this article&lt;/a&gt; from &lt;a href=&quot;https://img.ly/docs/pesdk/guides/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;the official documentation&lt;/a&gt; to set up dependencies for your Flutter-based project. You can also follow our guide on how to integrate &lt;a href=&quot;https://img.ly/blog/a-modern-video-editor-sdk-for-your-flutter-app/&quot;&gt;video editor for Flutter&lt;/a&gt; into your app.&lt;/p&gt;
&lt;p&gt;In case you encounter any difficulties with the installation process, don’t hesitate to contact our &lt;a href=&quot;https://img.ly/support?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;support&lt;/a&gt; who will be happy to help you.  Then, as shown in the example below, you can efficiently resize, crop, rotate or flip your visual assets with the &lt;a href=&quot;https://img.ly/docs/pesdk/web/features/transform/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;transform tool&lt;/a&gt;.&lt;/p&gt;</content:encoded><dc:creator>Natalia</dc:creator><media:content url="https://blog.img.ly/2022/09/resize-images-in-flutter-1.png" medium="image"/><category>How-To</category><category>Flutter</category><category>Photo Editing</category><category>App Development</category><category>Framework</category><category>Tutorial</category></item><item><title>How to Crop and Trim Videos in Flutter</title><link>https://img.ly/blog/how-to-crop-and-trim-videos-in-flutter/</link><guid isPermaLink="true">https://img.ly/blog/how-to-crop-and-trim-videos-in-flutter/</guid><description>Create your own video app in Flutter with the free-to-use and open source solution FFmpeg.</description><pubDate>Tue, 27 Sep 2022 08:45:16 GMT</pubDate><content:encoded>&lt;p&gt;If you are looking for a package that crops and trims videos in Flutter, you must have already come across the &lt;a href=&quot;https://pub.dev/packages/video_trimmer&quot;&gt;video_trimmer&lt;/a&gt; Flutter package. This package can trim videos but does not provide video cropping (at least not out-of-the-box). In fact, none of the packages on pub.dev, as of today, allow cropping a video in Flutter. If you have dug deeper, you might have come across FFmpeg — a powerful video editing command line tool, that is not the easiest to get started with. See the &lt;a href=&quot;https://img.ly/blog/ultimate-guide-to-ffmpeg/&quot;&gt;Ultimate Guide to FFmpeg&lt;/a&gt; for help.In this article we will use the FFmpeg library to crop and trim a video in a Flutter project.&lt;/p&gt;
&lt;p&gt;Here is a list of packages that we will be using; &lt;a href=&quot;https://pub.dev/packages/ffmpeg_kit_flutter&quot;&gt;ffmpeg_kit_flutter&lt;/a&gt; package for cropping and trimming videos, the &lt;a href=&quot;https://pub.dev/packages/path_provider&quot;&gt;path_provider&lt;/a&gt; package to get the path to the application or external directory where the video files will be stored, and the &lt;a href=&quot;https://pub.dev/packages/video_player&quot;&gt;video_player&lt;/a&gt; package to play the video preview.&lt;/p&gt;
&lt;p&gt;This article will not cover building any UI for cropping and trimming. But, it will discuss in brief how to crop the video using the video_trimmer library as well. If you want to package this workflow for production, check out our guide on &lt;a href=&quot;https://img.ly/blog/how-to-run-ffmpeg-inside-a-docker-container/&quot;&gt;running FFmpeg inside a Docker container&lt;/a&gt;. Also, you can try out the code used in this article from this &lt;a href=&quot;https://github.com/numerative/flutter_crop_and_trim_video&quot;&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;get-started&quot;&gt;Get Started&lt;/h2&gt;
&lt;p&gt;The end result of this tutorial will be a simple app that would look like the following screenshot.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Create a Flutter app to trim and crop videos easily.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 323px) 323px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;323&quot; height=&quot;700&quot; src=&quot;https://img.ly/_astro/resized_Z1EVmRl.webp&quot; srcset=&quot;/_astro/resized_Z1EVmRl.webp 323w&quot;&gt;&lt;/p&gt;
&lt;p&gt;When you tap the &lt;strong&gt;Save Video&lt;/strong&gt;, the preview will refresh with the cropped and trimmed video replacing the original video. Follow the instructions in this article, and you will be able to develop a similar Flutter app.&lt;/p&gt;
&lt;p&gt;First, let us start by adding dependencies to a new Flutter project.&lt;/p&gt;
&lt;h3 id=&quot;add-dependencies&quot;&gt;Add Dependencies&lt;/h3&gt;
&lt;p&gt;In your project’s &lt;code&gt;pubspec.yaml&lt;/code&gt; file add the following 3 dependencies.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;dependencies&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;  ffmpeg_kit_flutter&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;^4.5.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  path_provider&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;^2.0.11&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  video_player&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;^2.4.6&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, execute &lt;code&gt;flutter pub get&lt;/code&gt; command from the project folder root.&lt;/p&gt;
&lt;h3 id=&quot;set-minimum-sdk-version-and-platform-version&quot;&gt;Set Minimum SDK Version and Platform Version&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;ffmpeg_kit_flutter&lt;/code&gt; plugin runs on Android SDK API level 24+ and iOS SDK 12.1+. Therefore, modify the module level &lt;code&gt;build.gradle&lt;/code&gt; file to declare the &lt;code&gt;minSdkVersion&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;groovy&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;android {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  defaultConfig {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&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;    minSdkVersion &lt;/span&gt;&lt;span&gt;24&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&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&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, modify the &lt;code&gt;Podfile&lt;/code&gt; to declare the minimum global platform.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;# Uncomment this line to define a global platform for your project&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;platform &lt;/span&gt;&lt;span&gt;:ios&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;12.1&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;add-a-video-asset&quot;&gt;Add a Video Asset&lt;/h3&gt;
&lt;p&gt;For simplicity, we will be using a video asset instead of implementing a file picker. Choose a video file you would like to work with or &lt;a href=&quot;https://github.com/numerative/flutter_crop_and_trim_video/raw/main/assets/file1.mp4&quot;&gt;download&lt;/a&gt; this sample video file. Next, copy the video file to a new directory named &lt;code&gt;assets&lt;/code&gt; at the root of your project folder.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Copy your video of choice to your assets folder at the root of your project folder.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 318px) 318px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;318&quot; height=&quot;240&quot; src=&quot;https://img.ly/_astro/file1-mp4-placement_ZVFQb9.webp&quot; srcset=&quot;/_astro/file1-mp4-placement_ZVFQb9.webp 318w&quot;&gt;&lt;/p&gt;
&lt;p&gt;And then reference the video file from the &lt;code&gt;pubspec.yaml&lt;/code&gt; file.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;flutter&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  assets&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;assets/file1.mp4&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Execute &lt;code&gt;flutter pub get&lt;/code&gt; again.&lt;/p&gt;
&lt;p&gt;Having added the required dependencies, let us move on to coding.&lt;/p&gt;
&lt;h3 id=&quot;implement-video-crop-and-trim&quot;&gt;Implement Video Crop and Trim&lt;/h3&gt;
&lt;p&gt;Replace the code in your &lt;code&gt;main.dart&lt;/code&gt; file with the following code in the code block. This will be our starter code.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;dart&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &apos;package:flutter/material.dart&apos;&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;void&lt;/span&gt;&lt;span&gt; main&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  runApp&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; MyApp&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;class&lt;/span&gt;&lt;span&gt; MyApp&lt;/span&gt;&lt;span&gt; extends&lt;/span&gt;&lt;span&gt; StatelessWidget&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; MyApp&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;span&gt;Key&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; key}) &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; super&lt;/span&gt;&lt;span&gt;(key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; key);&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;  // This widget is the root of your application.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  @override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Widget&lt;/span&gt;&lt;span&gt; build&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BuildContext&lt;/span&gt;&lt;span&gt; context) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; MaterialApp&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      title&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &apos;Crop and Trim Demo&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      home&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; const&lt;/span&gt;&lt;span&gt; MyHomePage&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;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; MyHomePage&lt;/span&gt;&lt;span&gt; extends&lt;/span&gt;&lt;span&gt; StatefulWidget&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; MyHomePage&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;span&gt;Key&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; key}) &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; super&lt;/span&gt;&lt;span&gt;(key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; key);&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;  @override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  State&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;MyHomePage&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;createState&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; _MyHomePageState&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;class&lt;/span&gt;&lt;span&gt; _MyHomePageState&lt;/span&gt;&lt;span&gt; extends&lt;/span&gt;&lt;span&gt; State&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;MyHomePage&lt;/span&gt;&lt;span&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  @override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Widget&lt;/span&gt;&lt;span&gt; build&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BuildContext&lt;/span&gt;&lt;span&gt; context) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; Scaffold&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      appBar&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; AppBar&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        title&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; Text&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Flutter Crop and Trim&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;      body&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; Column&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        children&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;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;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;initialize-the-input-player&quot;&gt;Initialize the Input Player&lt;/h3&gt;
&lt;p&gt;Add the following code to the &lt;code&gt;_MyHomePageState&lt;/code&gt; class.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;dart&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &apos;dart:io&apos;&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;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &apos;package:flutter/services.dart&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &apos;package:path_provider/path_provider.dart&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &apos;package:video_player/video_player.dart&apos;&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;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; _MyHomePageState&lt;/span&gt;&lt;span&gt; extends&lt;/span&gt;&lt;span&gt; State&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;MyHomePage&lt;/span&gt;&lt;span&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  late&lt;/span&gt;&lt;span&gt; String&lt;/span&gt;&lt;span&gt; inputPath;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  VideoPlayerController&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; controller;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  String&lt;/span&gt;&lt;span&gt; outputPath &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &quot;&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;  ...&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;  @override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  void&lt;/span&gt;&lt;span&gt; initState&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    super&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;initState&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    copyVideoToApplicationDirectory&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;span&gt;((path) &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      inputPath &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; path;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      controller &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; VideoPlayerController&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;file&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;File&lt;/span&gt;&lt;span&gt;(inputPath));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      await&lt;/span&gt;&lt;span&gt; controller&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;initialize&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      await&lt;/span&gt;&lt;span&gt; controller&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.&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;      setState&lt;/span&gt;&lt;span&gt;(() {});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      outputPath &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; getOutputPath&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 class=&quot;line&quot;&gt;&lt;span&gt;  ///Copy input file to ApplicationStorage Directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ///returns path to copied video&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Future&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;copyVideoToApplicationDirectory&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; filename &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &quot;file1.mp4&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    var&lt;/span&gt;&lt;span&gt; bytes &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; rootBundle.&lt;/span&gt;&lt;span&gt;load&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;assets/file1.mp4&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    String&lt;/span&gt;&lt;span&gt; dir &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; getApplicationDocumentsDirectory&lt;/span&gt;&lt;span&gt;()).path;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    writeToFile&lt;/span&gt;&lt;span&gt;(bytes, &lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;dir&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;filename&lt;/span&gt;&lt;span&gt;&apos;&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;    return&lt;/span&gt;&lt;span&gt; &apos;&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;dir&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;filename&lt;/span&gt;&lt;span&gt;&apos;&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;  ///Write to Path.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Future&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;writeToFile&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ByteData&lt;/span&gt;&lt;span&gt; data, &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; path) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    final&lt;/span&gt;&lt;span&gt; buffer &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; data.buffer;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; File&lt;/span&gt;&lt;span&gt;(path).&lt;/span&gt;&lt;span&gt;writeAsBytes&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        buffer.&lt;/span&gt;&lt;span&gt;asUint8List&lt;/span&gt;&lt;span&gt;(data.offsetInBytes, data.lengthInBytes));&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 &lt;code&gt;copyVideoToApplicationDirectory&lt;/code&gt; method is copying the video from Assets to the Application directory on the phone’s file system. The resulting path is then stored in the &lt;code&gt;inputPath&lt;/code&gt; variable which is then supplied to the FFmpeg command. For large‑scale workloads, you can move this FFmpeg command to &lt;a href=&quot;https://img.ly/blog/how-to-run-ffmpeg-on-aws-spot-instances-for-scalable-low-cost-video-processing/&quot;&gt;AWS Spot Instances&lt;/a&gt;; our AWS guide shows how to configure a cloud environment for scalable video processing.&lt;/p&gt;
&lt;p&gt;Next, add the &lt;code&gt;VideoPlayer&lt;/code&gt; widget to the &lt;code&gt;Column&lt;/code&gt; widget.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;dart&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;body&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; Column&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  children&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;    (controller &lt;/span&gt;&lt;span&gt;!=&lt;/span&gt;&lt;span&gt; null&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; AspectRatio&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        aspectRatio&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; controller&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;.value.aspectRatio,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        child&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; VideoPlayer&lt;/span&gt;&lt;span&gt;(controller&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&gt;&lt;span&gt; const&lt;/span&gt;&lt;span&gt; SizedBox&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run the app and the video should start playing.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;You can now play your video.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 323px) 323px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;323&quot; height=&quot;700&quot; src=&quot;https://img.ly/_astro/resized_screen_2sxrDY.webp&quot; srcset=&quot;/_astro/resized_screen_2sxrDY.webp 323w&quot;&gt;&lt;/p&gt;
&lt;p&gt;In the next step, we will add the FFmpeg command, but before that add the following 2 more methods to the &lt;code&gt;_MyHomePageState&lt;/code&gt; class.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;dart&quot;&gt;&lt;code&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;import&lt;/span&gt;&lt;span&gt; &apos;package:ffmpeg_kit_flutter/ffmpeg_kit.dart&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &apos;package:ffmpeg_kit_flutter/log.dart&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &apos;package:ffmpeg_kit_flutter/return_code.dart&apos;&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;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; _MyHomePageState&lt;/span&gt;&lt;span&gt; extends&lt;/span&gt;&lt;span&gt; State&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;MyHomePage&lt;/span&gt;&lt;span&gt;&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;  /// Output path with a file name where the result will be stored.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Future&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;getOutputPath&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    final&lt;/span&gt;&lt;span&gt; appDirectory &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; Platform&lt;/span&gt;&lt;span&gt;.isAndroid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        ?&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; getExternalStorageDirectory&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; await&lt;/span&gt;&lt;span&gt; getApplicationDocumentsDirectory&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    final&lt;/span&gt;&lt;span&gt; externalPath &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;appDirectory&lt;/span&gt;&lt;span&gt;?.&lt;/span&gt;&lt;span&gt;path&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;/out_file.mp4&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; externalPath;&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;  ///Executes the FFMPEG &lt;/span&gt;&lt;span&gt;[command]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ///Note: Green bar on the right is a Flutter issue. &amp;#x3C;https://github.com/flutter/engine/pull/24888&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ///Should get fixed in a 3.1.0+ stable release &amp;#x3C;https://github.com/flutter/engine/pull/24888#issuecomment-1212374010&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Future&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;ffmpegExecute&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; command) &lt;/span&gt;&lt;span&gt;async&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;    final&lt;/span&gt;&lt;span&gt; session &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; FFmpegKit&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;execute&lt;/span&gt;&lt;span&gt;(command);&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;    final&lt;/span&gt;&lt;span&gt; returnCode &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; session.&lt;/span&gt;&lt;span&gt;getReturnCode&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; (&lt;/span&gt;&lt;span&gt;ReturnCode&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isSuccess&lt;/span&gt;&lt;span&gt;(returnCode)) {&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;      print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Success&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      //Replace the preview video&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      await&lt;/span&gt;&lt;span&gt; controller&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;pause&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      await&lt;/span&gt;&lt;span&gt; controller&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;dispose&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      controller &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; VideoPlayerController&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;file&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;File&lt;/span&gt;&lt;span&gt;(outputPath));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      await&lt;/span&gt;&lt;span&gt; controller&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;initialize&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      await&lt;/span&gt;&lt;span&gt; controller&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.&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;      setState&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;else&lt;/span&gt;&lt;span&gt; if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;ReturnCode&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isCancel&lt;/span&gt;&lt;span&gt;(returnCode)) {&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;      print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Cancel&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;    } &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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Error&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      final&lt;/span&gt;&lt;span&gt; failStackTrace &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; session.&lt;/span&gt;&lt;span&gt;getFailStackTrace&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      print&lt;/span&gt;&lt;span&gt;(failStackTrace);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      List&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Log&lt;/span&gt;&lt;span&gt;&gt; logs &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; session.&lt;/span&gt;&lt;span&gt;getLogs&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; element &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt; logs) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        print&lt;/span&gt;&lt;span&gt;(element.&lt;/span&gt;&lt;span&gt;getMessage&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;    }&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 &lt;code&gt;getOutputPath&lt;/code&gt; method provides the path where the resulting video will be saved. The &lt;code&gt;outputPath&lt;/code&gt; will be passed to the FFmpeg command whereas the &lt;code&gt;ffmpegExecute&lt;/code&gt; method is where the FFmpeg magic takes place.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;ffmpegExecute&lt;/code&gt; method expects a valid FFmpeg &lt;code&gt;String&lt;/code&gt; command. The &lt;code&gt;String&lt;/code&gt; command is then passed to the &lt;code&gt;FFmpegKit.execute&lt;/code&gt; method which returns an instance of &lt;code&gt;FFMpegSession&lt;/code&gt; . It will tell us whether our command was executed successfully or not. If it was not executed successfully, we can extract error logs from it.&lt;/p&gt;
&lt;h3 id=&quot;ffmpeg-execute-command&quot;&gt;FFmpeg Execute Command&lt;/h3&gt;
&lt;p&gt;Add a &lt;code&gt;TextButton&lt;/code&gt; from where the FFmpeg command shall be sent.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;dart&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;TextButton&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  child&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; Text&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;Save Video&apos;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  onPressed&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    //TODO: Call FFMPEG Execute&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;Next, call the following &lt;code&gt;ffmpegExecute&lt;/code&gt; method from the &lt;code&gt;onPressed&lt;/code&gt; property.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;dart&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ffmpegExecute&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;-ss 0:00:15 -to 0:00:45 -y -i &lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;inputPath&lt;/span&gt;&lt;span&gt; -filter:v &quot;crop=320:150&quot; -c:a copy &lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;outputPath&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run the app and tap the &lt;strong&gt;Save Video&lt;/strong&gt; button. You will notice that the player is now playing the new cropped and trimmed video.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;You can now play your cropped and trimmed video!&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 323px) 323px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;323&quot; height=&quot;700&quot; src=&quot;https://img.ly/_astro/flutter_video_app_crop_trim_screen_ZP5gb4.webp&quot; srcset=&quot;/_astro/flutter_video_app_crop_trim_screen_ZP5gb4.webp 323w&quot;&gt;&lt;/p&gt;
&lt;p&gt;If you were able to successfully follow the instructions up till here, it is time to dig a little deeper into the FFmpeg command that we just ran earlier.&lt;/p&gt;
&lt;h3 id=&quot;understanding-the-ffmpeg-command&quot;&gt;Understanding the FFmpeg Command&lt;/h3&gt;
&lt;p&gt;Because command FFmpeg is a command line tool, it expects string-only commands. For this reason, we do not have any dart Classes, Methods, or Parameters to work with that we usually get when working with a dart plugin. Let us dissect the above command line command that is helping us crop and trim a video.&lt;/p&gt;





































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Command&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;-ss 0:00:15&lt;/td&gt;&lt;td&gt;Seeks to position on the input video. The trim starts from this position.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-to 0:00:45&lt;/td&gt;&lt;td&gt;Stops reading at the position in the input video. The trim stops at this position. The total length of the video is 0:02:05.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-y&lt;/td&gt;&lt;td&gt;Overwrite output files. Helpful when the Save Video button is tapped more than once.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-i $inputPath&lt;/td&gt;&lt;td&gt;Input file location. This is the file on which the crop and trim are applied.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-filter:v&lt;/td&gt;&lt;td&gt;Apply a filter to the video stream.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;”crop=320:150”&lt;/td&gt;&lt;td&gt;Apply a crop filter from the center of the video that is 320 pixels wide and 150 pixels tall. The original dimensions of the video were 320 x 240.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-c:a copy $outputPath&lt;/td&gt;&lt;td&gt;Specifies the codec with which the output file must be encoded. Here, copy is a special value to indicate the stream is not to be re-encoded. The a after the colon is a stream specifier for the audio stream.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;That will be either the application directory or the external directory of the application, depending on whether the app is running on iOS or Android.&lt;/p&gt;
&lt;p&gt;You can check out the app’s code and play with it by downloading it from this &lt;a href=&quot;https://github.com/numerative/flutter_crop_and_trim_video&quot;&gt;GitHub Repository&lt;/a&gt;. This project allows you to tweak the duration of the trim and dimensions of the crop, so it has more code, but at the heart of it, it still uses the above FFmpeg command.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Download this app code from the GitHub Repository.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 378px) 378px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;378&quot; height=&quot;700&quot; src=&quot;https://img.ly/_astro/flutter_video_app_crop_trim_info_Z2pzU1G.webp&quot; srcset=&quot;/_astro/flutter_video_app_crop_trim_info_Z2pzU1G.webp 378w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;cropping-using-the-video_trimmer-plugin&quot;&gt;Cropping Using the video_trimmer Plugin&lt;/h2&gt;
&lt;p&gt;As a bonus, here is a tip on how to use the video_trimmer plugin for cropping videos.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://pub.dev/packages/video_trimmer&quot;&gt;video_trimmer&lt;/a&gt; plugin also uses FFmpeg at its core and allows us to pass on an FFmpeg command while saving the video. For this reason, it is an easy task for us to apply the crop to a video using the video_trimmer plugin.&lt;/p&gt;
&lt;p&gt;To do this, pass the following command to the &lt;code&gt;saveTrimmedVideo&lt;/code&gt; method’s &lt;code&gt;ffmpegCommand&lt;/code&gt; parameter as shown in the code block below. The video_trimmer package expects the &lt;code&gt;customVideoFormat&lt;/code&gt; parameter argument when the &lt;code&gt;ffmpegCommand&lt;/code&gt; parameter is used.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;await &lt;/span&gt;&lt;span&gt;_trimmer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    .&lt;/span&gt;&lt;span&gt;saveTrimmedVideo&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        startValue:&lt;/span&gt;&lt;span&gt; _startValue&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        endValue:&lt;/span&gt;&lt;span&gt; _endValue&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        ffmpegCommand:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            &apos;-filter:v &quot;crop=320:150&quot;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        customVideoFormat:&lt;/span&gt;&lt;span&gt; &apos;.mp4&apos;&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;then&lt;/span&gt;&lt;span&gt;((value) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  setState&lt;/span&gt;&lt;span&gt;(() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    _value&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; value;&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;h2 id=&quot;limitations-of-this-approach&quot;&gt;Limitations of this Approach&lt;/h2&gt;
&lt;p&gt;The crop that we are applying is from the center of the frame. The present command would also need starting coordinates to crop a non-center frame.&lt;/p&gt;
&lt;p&gt;The project will need a refined UI for cropping and trimming videos to offer a complete app experience to users. The current approach is miles away from creating that experience.&lt;/p&gt;
&lt;p&gt;But perhaps the most significant limitation is FFmpeg’s &lt;strong&gt;licensing&lt;/strong&gt;. FFmpeg is available with both LGPL and GPL licenses, so you must ensure your project is compatible with those licenses. For many commercial projects, this is a non-starter. Alternatively, you can &lt;a href=&quot;https://img.ly/blog/ffmpeg-on-google-cloud-platform-guide/&quot;&gt;run FFmpeg on Google Cloud Platform&lt;/a&gt;; our GCP tutorial walks you through setup.&lt;/p&gt;
&lt;h2 id=&quot;commercial-alternative&quot;&gt;Commercial Alternative&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://img.ly/docs/vesdk/flutter/getting-started/integration/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;VideoEditor SDK (VE.SDK)&lt;/a&gt; from &lt;a href=&quot;https://img.ly&quot;&gt;IMG.LY&lt;/a&gt; provides powerful video editing features, including cropping and trimming videos in a Flutter project. You will receive staples of video editing, including straightening videos, filters, brightness, color adjustments, and more. Follow our guide to learn how to integrate IMG.LY’s &lt;a href=&quot;https://img.ly/blog/a-modern-video-editor-sdk-for-your-flutter-app/&quot;&gt;video editor for Flutter&lt;/a&gt; into your app.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;While still a complex topic, video manipulation is more attainable to implement on Flutter than on native Android. Nevertheless, FFmpeg is the only open-source, free-to-use option to edit videos on Flutter right now. To automate cropping and trimming across many files or build a transcoding server, see our article on &lt;a href=&quot;https://img.ly/blog/building-a-production-ready-batch-video-processing-server-with-ffmpeg/&quot;&gt;building a production‑ready batch video processing server.&lt;/a&gt;&lt;/p&gt;</content:encoded><dc:creator>Michael H.</dc:creator><media:content url="https://blog.img.ly/2022/09/trim_videos_with_flutter_tutorial.png" medium="image"/><category>How-To</category><category>Flutter</category><category>Video Editor</category><category>App Development</category><category>FFmpeg</category><category>Tutorial</category></item><item><title>How to Remove Backgrounds Using Core ML</title><link>https://img.ly/blog/how-to-remove-backgrounds-using-coreml/</link><guid isPermaLink="true">https://img.ly/blog/how-to-remove-backgrounds-using-coreml/</guid><description>Bring background removal and replacement to your iOS application.</description><pubDate>Tue, 28 Jun 2022 15:26:53 GMT</pubDate><content:encoded>&lt;p&gt;In this tutorial, you will learn how to use machine learning to identify an image background and mask it out. This is particularly useful for making stickers or avatars or adding a fake background to a video call. The process of assigning the pixels in an image to a specific object is called “segmentation”. Apple provides an optimized method with pictures of people in its &lt;a href=&quot;https://developer.apple.com/documentation/vision&quot;&gt;Vision framework&lt;/a&gt;. For performing the same tasks with non-human subjects, you can use the &lt;a href=&quot;https://github.com/tensorflow/models/tree/master/research/deeplab&quot;&gt;DeepLabV3 machine learning model with Core ML&lt;/a&gt;. The code examples in this tutorial have been tested using Xcode 13 and Swift 5. Because of the use of Core ML, Vision, and CoreImage in this tutorial, you should run the demo code on a device, not on the Simulator. An iOS project with the demo code is &lt;a href=&quot;https://github.com/waltertyree/super-eureka&quot;&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Image segmentation is a different process and requires other machine learning models than image recognition. With recognition, the model produces bounding rectangles that the system believes to contain the entire object. With segmentation, the model identifies the actual pixels of the object.&lt;/p&gt;
&lt;p&gt;In this tutorial, you’ll start with an image of your subject. Then you’ll generate a mask for the background using Vision. Finally, you’ll use CoreImage filters to blend the original image, image mask, and the new image background.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;segmentation-process-1&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;666&quot; src=&quot;https://img.ly/_astro/segmentation-process-1_Z2lEfI5.webp&quot; srcset=&quot;/_astro/segmentation-process-1_2i2R9H.webp 640w, /_astro/segmentation-process-1_Z2lEfI5.webp 700w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Whether using the Vision framework alone or supplementing Vision with another Core ML model – the process will be the same:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a Vision request object with some parameters.&lt;/li&gt;
&lt;li&gt;Create a Vision request handler with the image to be processed.&lt;/li&gt;
&lt;li&gt;Process the image with the handler and object.&lt;/li&gt;
&lt;li&gt;Process the results into the final image using CoreImage.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When working with still images, Apple’s CoreImage framework is usually the best option, mainly because of the large number of available filters and the ability to create reusable pipelines that you can run on the CPU or the GPU.&lt;/p&gt;
&lt;h2 id=&quot;using-vision-to-segment-people&quot;&gt;Using Vision to Segment People&lt;/h2&gt;
&lt;p&gt;Without an external model, Vision can only segment documents or people in an image. It is vital to understand that Vision will only identify a pixel in the image as “this pixel is part of a person” or “this pixel is not part of a person.” If an image contains a group of people, Vision will not be able to separate individuals.&lt;/p&gt;
&lt;p&gt;To segment the image, start by creating an instance of a &lt;code&gt;VNGeneratePersonSegmentationRequest&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;var&lt;/span&gt;&lt;span&gt; segmentationRequest &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; VNGeneratePersonSegmentationRequest&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;segmentationRequest.qualityLevel &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; .balanced&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This type of request has a few options you can set. &lt;code&gt;.qualityLevel&lt;/code&gt; can be &lt;code&gt;.fast&lt;/code&gt;, &lt;code&gt;.balanced&lt;/code&gt; or &lt;code&gt;.accurate&lt;/code&gt;. The level of &lt;code&gt;.accurate&lt;/code&gt; is the default. This will determine how closely the mask conforms to the boundaries of the original image. The different levels process at different speeds. The &lt;code&gt;.fast&lt;/code&gt; setting is intended for use in a video so that frames don’t get dropped. Using &lt;code&gt;.balanced&lt;/code&gt; or &lt;code&gt;.accurate&lt;/code&gt; causes noticeable delay in an app processing the image on most devices. Experiment with different settings depending on your needs.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;speed-compare&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;516&quot; src=&quot;https://img.ly/_astro/speed-compare_Z1SlWxp.webp&quot; srcset=&quot;/_astro/speed-compare_ywD9u.webp 640w, /_astro/speed-compare_Z1SlWxp.webp 700w&quot;&gt;&lt;/p&gt;
&lt;p&gt;The output of the segmentation request will be a &lt;code&gt;CVPixelBuffer&lt;/code&gt;. This is a structure that contains information for each pixel of the image. Most of Apple’s video frameworks as well as CoreImage can work with pixel buffers. The default for &lt;code&gt;VNGeneratePersonSegmentationRequest&lt;/code&gt; is a buffer where the color of each pixel is represented by an 8-bit number. Any pixel that Vision thinks contains part of a person will be white and any not-a-person will be black and represented by zero. This will be exactly what you want for generating a mask to work with &lt;code&gt;CIBlendWithMask&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Next, create a &lt;code&gt;VNImageRequestHandler&lt;/code&gt; with the image to be processed. The handler class has a &lt;a href=&quot;https://developer.apple.com/documentation/vision/vnimagerequesthandler&quot;&gt;number of initializers&lt;/a&gt; for different types of data. In this example we will use &lt;code&gt;CGImage&lt;/code&gt;, but you could also start with &lt;code&gt;CIImage&lt;/code&gt;, &lt;code&gt;CVPixelbuffer&lt;/code&gt;, &lt;code&gt;Data&lt;/code&gt;, or others. You can also specify options for the handler. In this tutorial we will not specify any, but one of the options is to pass in a &lt;code&gt;CIContext&lt;/code&gt;. This can help with performance as you can tell your app to do all of the processing with a single context on the GPU using Metal.&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;guard&lt;/span&gt;&lt;span&gt; let&lt;/span&gt;&lt;span&gt; originalCG &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; originalImage&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.cgImage &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;abort&lt;/span&gt;&lt;span&gt;() }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; handler &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; VNImageRequestHandler&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;cgImage&lt;/span&gt;&lt;span&gt;: originalCG)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;try?&lt;/span&gt;&lt;span&gt; handler.&lt;/span&gt;&lt;span&gt;perform&lt;/span&gt;&lt;span&gt;([segmentationRequest])&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; maskPixelBuffer &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  segmentationRequest.results&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;first&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.pixelBuffer &lt;/span&gt;&lt;span&gt;else&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;let&lt;/span&gt;&lt;span&gt; maskImage &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; CGImage.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;pixelBuffer&lt;/span&gt;&lt;span&gt;: maskPixelBuffer)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the code above, the &lt;code&gt;originalImage&lt;/code&gt; (which happens to be a UIImage) gets converted to a CGImage. Then we use the image to initialize a request handler. The &lt;code&gt;VNImageRequestHandler&lt;/code&gt; has a method &lt;code&gt;.perform&lt;/code&gt; which takes an array of all of the Vision requests you want to use to process the image. The &lt;code&gt;.perform&lt;/code&gt; method will not return until all of the requests in the array have been completed. Depending on how you want to structure your code, you can either provide a completion handler to use with each of the requests or just process the results in-line. In this example, we’ll process in-line.&lt;/p&gt;
&lt;p&gt;If the &lt;code&gt;segmentationRequest&lt;/code&gt; found any people in the image, the &lt;code&gt;results&lt;/code&gt; array will contain a &lt;code&gt;.pixelBuffer&lt;/code&gt;. Create the mask we need by converting the &lt;code&gt;pixelBuffer&lt;/code&gt; into a CGImage. To convert to a CGImage, the example uses some helper methods that &lt;a href=&quot;https://github.com/hollance/CoreMLHelpers&quot;&gt;Matthijs Hollemans published to GitHub&lt;/a&gt; specifically for working with Core ML inputs and outputs.&lt;/p&gt;
&lt;p&gt;Now that we have the mask image, use &lt;code&gt;CIFilter&lt;/code&gt; to compose the final image. It will take a few steps. First, resize the new background, mask, and original image to the same size. Then, blend the three images.&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;//Convert main image to a CIImage and get the size&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; mainImage &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; CIImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;cgImage&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;self&lt;/span&gt;&lt;span&gt;.originalImage&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;.cgImage&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;let&lt;/span&gt;&lt;span&gt; originalSize &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; mainImage.extent.&lt;/span&gt;&lt;span&gt;size&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;//Convert the maskimage to CIImage and set the size&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;//to be the same as the original&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; maskCI &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; CIImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;cgImage&lt;/span&gt;&lt;span&gt;: maskImage&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;let&lt;/span&gt;&lt;span&gt; scaleX &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; originalSize.width &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; maskCI.extent.width&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; scaleY &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; originalSize.height &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; maskCI.extent.height&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;maskCI &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; maskCI.&lt;/span&gt;&lt;span&gt;transformed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;by&lt;/span&gt;&lt;span&gt;: .&lt;/span&gt;&lt;span&gt;init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;scaleX&lt;/span&gt;&lt;span&gt;: scaleX, &lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;: scaleY))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;//Convert the new background to a CIImage and set the size&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;//to be the same as the original&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; backgroundUIImage &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; UIImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;named&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;starfield&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;resized&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;to&lt;/span&gt;&lt;span&gt;: originalSize)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; background &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; CIImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;cgImage&lt;/span&gt;&lt;span&gt;: backgroundUIImage.cgImage&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;//Use CIBlendWithMask to combine the three images&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; filter &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; CIFilter&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;CIBlendWithMask&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;filter&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;setValue&lt;/span&gt;&lt;span&gt;(background, &lt;/span&gt;&lt;span&gt;forKey&lt;/span&gt;&lt;span&gt;: kCIInputBackgroundImageKey)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;filter&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;setValue&lt;/span&gt;&lt;span&gt;(mainImage, &lt;/span&gt;&lt;span&gt;forKey&lt;/span&gt;&lt;span&gt;: kCIInputImageKey)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;filter&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;setValue&lt;/span&gt;&lt;span&gt;(maskCI, &lt;/span&gt;&lt;span&gt;forKey&lt;/span&gt;&lt;span&gt;: kCIInputMaskImageKey)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;//Update the UI&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;self&lt;/span&gt;&lt;span&gt;.filteredImageView.&lt;/span&gt;&lt;span&gt;image&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; UIImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ciImage&lt;/span&gt;&lt;span&gt;: filter&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;.outputImage&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above code resizes the images to match the size of the original image and converts them to &lt;code&gt;CIImage&lt;/code&gt;. Many machine learning models commonly resize inputs and outputs. For example, the output of the &lt;code&gt;VNGeneratePersonSegmentationRequest&lt;/code&gt; using the demo image is 384x512.&lt;/p&gt;
&lt;p&gt;Both CIImage and UIImage formats describe an image but do not always have a bitmap representation. That is why each image gets converted to a CGImage first. Though this guarantees that the demo code will work, converting formats makes the code run slower. In your app, you should experiment with different methods to get your images into CIImage format for filtering. Also, the above code uses Matthijs’ &lt;code&gt;resized&lt;/code&gt; helper method to do some of the resizing.&lt;/p&gt;
&lt;p&gt;With everything resized, the &lt;a href=&quot;https://developer.apple.com/documentation/coreimage/ciblendwithmask&quot;&gt;CIBlendWithMask&lt;/a&gt; filter stitches the images together. In place of the black pixels in the mask, the final image will show the background – for white pixels, the foreground. Wherever the mask image has a gray pixel, the final image will blend background and foreground.&lt;/p&gt;
&lt;p&gt;Now let’s see how to use an additional &lt;code&gt;CoreML&lt;/code&gt; model to process images that don’t have a person as the main subject.&lt;/p&gt;
&lt;h2 id=&quot;choosing-a-model&quot;&gt;Choosing a Model&lt;/h2&gt;
&lt;p&gt;Apple provides a number of pre-built models for text and image processing. The DeepLab v3 Machine Learning model can perform segmentation requests on images that have subjects like dogs. You can download it from &lt;a href=&quot;https://developer.apple.com/machine-learning/models/&quot;&gt;Apple directly&lt;/a&gt; or also find it at the &lt;a href=&quot;https://github.com/tensorflow/models/tree/master/research/deeplab&quot;&gt;DeepLab repo on GitHub&lt;/a&gt;. Once you have downloaded the model, add it to your Xcode project the same as any other file. The DeepLab model will recognize people, the same as the &lt;code&gt;VNPersonSegmentationRequest&lt;/code&gt;, but also other objects. This does come at a cost in an increased filesize for your application. You may notice that Apple provides multiple versions of the model of different file sizes. They all perform the same task, but differ in how they represent the output and a few other things.&lt;/p&gt;
&lt;p&gt;Models on Apple’s website are packaged to work with Core ML and Xcode, so you can easily try a different model. The input and output method names will be the same. It is beyond the scope of this tutorial, yet Apple provides tutorials and example scripts on how to convert TensorFlow and other machine learning models to work with Core ML.&lt;/p&gt;
&lt;h3 id=&quot;core-ml-and-xcode&quot;&gt;Core ML and Xcode&lt;/h3&gt;
&lt;p&gt;When you are working with a Core ML model, Xcode provides some convenient tools. Access them by highlighting the name of the model in the File Navigator pane of Xcode. For instance, clicking “Preview” will let you test the model with your data.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;testing-screenshot&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;412&quot; src=&quot;https://img.ly/_astro/testing-screenshot_Z2l2s2a.webp&quot; srcset=&quot;/_astro/testing-screenshot_8v5CS.webp 640w, /_astro/testing-screenshot_Z2l2s2a.webp 700w&quot;&gt;&lt;/p&gt;
&lt;p&gt;You can also use the “Predictions” tab to determine how the input needs to be formatted and what to expect for the output.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;predictions-screenshot&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;355&quot; src=&quot;https://img.ly/_astro/predictions-screenshot_Z1Bf2h7.webp&quot; srcset=&quot;/_astro/predictions-screenshot_Zh7lHX.webp 640w, /_astro/predictions-screenshot_Z1Bf2h7.webp 700w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Here you can see that the DeepLabV3 model expects images to be 513 x 513 and will output a multidimensional array of integers that is 513 x 513 in size.&lt;/p&gt;
&lt;p&gt;Finally, on this screen, you can see an entry for the “Model Class” in the headers. Double-click on the name to jump into the Swift wrapper class for the model to see how to call the model in your code and work with the inputs and outputs.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;model-class&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 418px) 418px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;418&quot; height=&quot;85&quot; src=&quot;https://img.ly/_astro/model-class_1pbhcQ.webp&quot; srcset=&quot;/_astro/model-class_1pbhcQ.webp 418w&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;the-deeplabv3-model&quot;&gt;The DeepLabV3 Model&lt;/h3&gt;
&lt;p&gt;The DeepLab model input will be a color image that is 513 x 513 pixels. The Vision framework will handle resizing the input, but you can provide options on how that resize should work. The DeepLabV3 model has been trained to recognize and segment these items:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;aeroplane&lt;/li&gt;
&lt;li&gt;bicycle&lt;/li&gt;
&lt;li&gt;bird&lt;/li&gt;
&lt;li&gt;boat&lt;/li&gt;
&lt;li&gt;bottle&lt;/li&gt;
&lt;li&gt;bus&lt;/li&gt;
&lt;li&gt;car&lt;/li&gt;
&lt;li&gt;cat&lt;/li&gt;
&lt;li&gt;chair&lt;/li&gt;
&lt;li&gt;cow&lt;/li&gt;
&lt;li&gt;dining table&lt;/li&gt;
&lt;li&gt;dog&lt;/li&gt;
&lt;li&gt;horse&lt;/li&gt;
&lt;li&gt;motorbike&lt;/li&gt;
&lt;li&gt;person&lt;/li&gt;
&lt;li&gt;potted plant&lt;/li&gt;
&lt;li&gt;sheep&lt;/li&gt;
&lt;li&gt;sofa&lt;/li&gt;
&lt;li&gt;train&lt;/li&gt;
&lt;li&gt;tv or monitor&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Anything that the model does not recognize, it will consider a &lt;em&gt;background&lt;/em&gt;. After performing the recognition, the model returns a two-dimensional 513 x 513 array. Each entry in the array corresponds to one pixel in the original 513 x 513 input image. For instance, every pixel in the original image that shows a dog will be represented in the output by a &lt;code&gt;12&lt;/code&gt; in the corresponding array entry. Any pixel that is not a recognized object will be given a &lt;code&gt;0&lt;/code&gt; in the output array to represent a &lt;em&gt;background&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;If the model recognizes multiple objects, there will be multiple numbers in the array. If that is not what you want, you need to make changes to the array before creating the mask. For example, using an image of a dog riding a horse, some entries in the array will be &lt;code&gt;12&lt;/code&gt;, others will be &lt;code&gt;13&lt;/code&gt;, and the rest will be &lt;code&gt;0&lt;/code&gt;. To filter out the horse, you need to loop through the array and change any &lt;code&gt;13&lt;/code&gt;s to &lt;code&gt;0&lt;/code&gt;s.&lt;/p&gt;
&lt;h2 id=&quot;segmentation-with-deeplab&quot;&gt;Segmentation with DeepLab&lt;/h2&gt;
&lt;p&gt;To use the DeepLab model in your code, you again use a request to the Vision framework but this time you can specify a model.&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; MLModelConfiguration&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; segmentationModel &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; try!&lt;/span&gt;&lt;span&gt; DeepLabV3&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;configuration&lt;/span&gt;&lt;span&gt;: config)&lt;/span&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; visionModel &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; try?&lt;/span&gt;&lt;span&gt; VNCoreMLModel&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt;: segmentationModel.model) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  self&lt;/span&gt;&lt;span&gt;.request &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; VNCoreMLRequest&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;model&lt;/span&gt;&lt;span&gt;: visionModel)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  self&lt;/span&gt;&lt;span&gt;.request&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.imageCropAndScaleOption &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; .scaleFill&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 an instance of the DeepLab Core ML object and then initialize a generic &lt;code&gt;VNCoreMLRequest&lt;/code&gt; with its model. The only option we set on the request is to tell it how to modify the image when it resizes it for input.&lt;/p&gt;
&lt;p&gt;Now the code is very similar to the first example.&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; cgImage &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; originalImage&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.cgImage&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; handler &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; VNImageRequestHandler&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;cgImage&lt;/span&gt;&lt;span&gt;: cgImage, &lt;/span&gt;&lt;span&gt;options&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;try?&lt;/span&gt;&lt;span&gt; handler.&lt;/span&gt;&lt;span&gt;perform&lt;/span&gt;&lt;span&gt;([request])&lt;/span&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; observations &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; request.results &lt;/span&gt;&lt;span&gt;as?&lt;/span&gt;&lt;span&gt; [VNCoreMLFeatureValueObservation],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  let&lt;/span&gt;&lt;span&gt; segmentationmap &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; observations.&lt;/span&gt;&lt;span&gt;first&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.featureValue.multiArrayValue {&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; maskUIImage &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; segmentationmap.&lt;/span&gt;&lt;span&gt;image&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;min&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;0.0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;max&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1.0&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;else&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;  applyBackgroundMask&lt;/span&gt;&lt;span&gt;(maskUIImage)&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;Because we are using a generic &lt;code&gt;VNCoreMLRequest&lt;/code&gt; we have to cast the results as &lt;code&gt;VNCoreMLFeatureValueObservation&lt;/code&gt;. The DeepLab model returns a &lt;code&gt;.multiArrayValue&lt;/code&gt; instead of a &lt;code&gt;.pixelBuffer&lt;/code&gt; so we will again rely on the helper methods to convert it to an image. Now that the mask image has been created, applying the background is the same as in the original example.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;dog-in-space-1&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 400px) 400px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;400&quot; height=&quot;519&quot; src=&quot;https://img.ly/_astro/dog-in-space-1_pxayi.webp&quot; srcset=&quot;/_astro/dog-in-space-1_pxayi.webp 400w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;going-further&quot;&gt;Going Further&lt;/h2&gt;
&lt;p&gt;This tutorial focused on still images, yet both the standard Vision segmentation requests and DeepLabV3 allow processing video input as they can work with &lt;code&gt;CVPixelBuffer&lt;/code&gt; and &lt;code&gt;VNSequenceRequestHandler&lt;/code&gt;.&lt;br&gt;
The rest of the process will be almost identical to our example. You will need to finetune the performance, or else you will experience frame drops.&lt;/p&gt;
&lt;p&gt;Apple provides another method for identifying the background and primary subject in a still image: Portrait mode. When a device renders Portrait mode, it takes pictures with all cameras on the device and stitches them together. This way, the depth of field can change, and you can adjust what items are in focus or blurred.&lt;/p&gt;
&lt;p&gt;If the DeepLab model does not cover your subject matter, you can train the DeepLabV3 model to recognize other objects using your own data.&lt;/p&gt;
&lt;p&gt;However, you may consider using SDKs such as &lt;a href=&quot;https://img.ly/products/photo-sdk&quot;&gt;PE.SDK&lt;/a&gt; and &lt;a href=&quot;https://img.ly/products/video-sdk&quot;&gt;VE.SDK&lt;/a&gt;. Enabling background removal for your users is easy — all it takes is a few lines in your configuration as described in the &lt;a href=&quot;https://img.ly/docs/pesdk/ios/guides/background-removal/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;official PE.SDK documentation for iOS&lt;/a&gt; and &lt;a href=&quot;https://img.ly/docs/pesdk/android/guides/background-removal/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;Android&lt;/a&gt;, which adds a control to the photo editor to toggle the setting.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;background-removal-photo-editor-app-pe-sdk-1&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 277px) 277px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;277&quot; height=&quot;600&quot; src=&quot;https://img.ly/_astro/background-removal-photo-editor-app-pe-sdk-1_21B1QF.webp&quot; srcset=&quot;/_astro/background-removal-photo-editor-app-pe-sdk-1_21B1QF.webp 277w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Integrate a fully customizable photo editor with Background Removal into your app with PE.SDK.&lt;/p&gt;
&lt;p&gt;The latest &lt;a href=&quot;https://img.ly/blog/photo-editor-video-editor-sdk-v_10-11-release-notes/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;VE.SDK release&lt;/a&gt; introduced Background Removal for stickers. This feature recognizes people in pictures and removes the background with one tap – no need for manual outlines or masks.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;background-removal-photo-editor-app-pe-sdk-video&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 277px) 277px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;277&quot; height=&quot;600&quot; src=&quot;https://img.ly/_astro/background-removal-photo-editor-app-pe-sdk-video_1flT3l.webp&quot; srcset=&quot;/_astro/background-removal-photo-editor-app-pe-sdk-video_1flT3l.webp 277w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Let your users create beautiful visuals with Sticker Background Removal.&lt;/p&gt;
&lt;p&gt;This feature is available on Android and iOS 15.0 and higher only. See the official documentation for Sticker Background Removal on &lt;a href=&quot;https://img.ly/docs/vesdk/android/guides/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#background-removal&quot;&gt;Android&lt;/a&gt; or &lt;a href=&quot;https://img.ly/docs/vesdk/ios/guides/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#background-removal&quot;&gt;iOS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Using an SDK will simplify and accelerate your app development, as you can save time and resources, and focus on the growth and innovation of your application instead.&lt;/p&gt;
&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this tutorial, you saw how to use Vision and Core ML to segment an image of a person and remove the background. You also saw how to use DeepLab to work with images of non-persons.&lt;/p&gt;
&lt;p&gt;Thanks for reading! We hope that you found this tutorial helpful. Feel free to reach out on &lt;a href=&quot;https://twitter.com/imgly&quot;&gt;Twitter&lt;/a&gt; with any questions, comments, or suggestions.&lt;/p&gt;</content:encoded><dc:creator>Walter</dc:creator><media:content url="https://blog.img.ly/2022/06/background-remove-removal-editor-app-development.png" medium="image"/><category>How-To</category><category>Background Removal</category><category>Machine Learning</category><category>Photo Editing</category><category>App Development</category><category>iOS App Development</category><category>Core ML</category><category>Tutorial</category></item><item><title>PE.SDK and VE.SDK 10 for Android and 11 for iOS Release</title><link>https://img.ly/blog/photo-editor-video-editor-sdk-v_10-11-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/photo-editor-video-editor-sdk-v_10-11-release-notes/</guid><description>This major update brings Background Removal and more to PhotoEditor SDK and VideoEditor SDK.</description><pubDate>Wed, 04 May 2022 12:46:21 GMT</pubDate><content:encoded>&lt;p&gt;We are thrilled to announce the release of PhotoEditor SDK and VideoEditor SDK 10 for Android and 11 for iOS. This new major version is packed with features and improvements.&lt;/p&gt;
&lt;p&gt;This release is adding:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Custom Watermarks&lt;/li&gt;
&lt;li&gt;Background Removal for Photos&lt;/li&gt;
&lt;li&gt;Background Removal for Stickers&lt;/li&gt;
&lt;li&gt;Custom Sticker Libraries&lt;/li&gt;
&lt;li&gt;Giphy Integration&lt;/li&gt;
&lt;li&gt;And More Updates for Android and iOS&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;custom-watermarks&quot;&gt;Custom Watermarks&lt;/h2&gt;
&lt;p&gt;With our new support for custom watermarks, you can add your company logo or any other image to photo and video exports. You can place your watermark in either corner or the center of your photo and video. Additionally, you can specify the size of the watermark and determine its distance from the outline if you choose to place it near a corner. Your users will not be able to remove nor modify the watermark.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Set your Custom Watermark for all exports.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 277px) 277px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;277&quot; height=&quot;600&quot; src=&quot;https://img.ly/_astro/watermark-video-editor-custom-sdk_Z12Y3l4.webp&quot; srcset=&quot;/_astro/watermark-video-editor-custom-sdk_Z12Y3l4.webp 277w&quot;&gt;&lt;/p&gt;
&lt;p&gt;For more details on Custom Watermarks, take a look at our documentation for &lt;a href=&quot;https://img.ly/docs/pesdk/android/customization/watermark/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;Android&lt;/a&gt; or &lt;a href=&quot;https://img.ly/docs/pesdk/ios/customization/watermark/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;iOS&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;background-removal-for-photos&quot;&gt;Background Removal for Photos&lt;/h2&gt;
&lt;p&gt;You have unwaveringly requested this feature: we are excited to offer the automatic removal of backgrounds for static content! Background Removal is fully running &lt;strong&gt;on-device&lt;/strong&gt; and currently specializes in images containing a person only. PE.SDK enables this feature exclusively when it detects a person in the photo.&lt;/p&gt;
&lt;p&gt;The removed background will turn transparent if your selected output supports transparency, such as PNG. In other cases, such as JPG, your background removal will be tinted black.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Integrate Background Removal into your application.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 277px) 277px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;277&quot; height=&quot;600&quot; src=&quot;https://img.ly/_astro/background-removal-photo-editor-app-pe-sdk-1_2jocg8.webp&quot; srcset=&quot;/_astro/background-removal-photo-editor-app-pe-sdk-1_2jocg8.webp 277w&quot;&gt;&lt;/p&gt;
&lt;p&gt;This feature is available on Android and iOS 15.0 and higher only. Easily enable Background Removal for Photos with our &lt;a href=&quot;https://img.ly/docs/pesdk/android/features/background_removal/&quot;&gt;Android guide&lt;/a&gt; or &lt;a href=&quot;https://img.ly/docs/pesdk/ios/features/background_removal/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;iOS guide&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;background-removal-for-stickers&quot;&gt;Background Removal for Stickers&lt;/h2&gt;
&lt;p&gt;A more common use case for automatic background removal is with stickers, so we’ve also added this functionality. Select a sticker including a person and tap the &lt;em&gt;Remove BG&lt;/em&gt; button. Simple!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Let your users create beautiful visuals with Sticker Background Removal.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 277px) 277px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;277&quot; height=&quot;600&quot; src=&quot;https://img.ly/_astro/background-removal-photo-editor-app-pe-sdk-video_2nmAzB.webp&quot; srcset=&quot;/_astro/background-removal-photo-editor-app-pe-sdk-video_2nmAzB.webp 277w&quot;&gt;&lt;/p&gt;
&lt;p&gt;This feature is available on Android and iOS 15.0 and higher only. Easily enable Background Removal for Stickers with our &lt;a href=&quot;https://img.ly/docs/vesdk/android/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#background-removal&quot;&gt;Android documentation&lt;/a&gt; or &lt;a href=&quot;https://img.ly/docs/vesdk/ios/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#background-removal&quot;&gt;iOS documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;custom-sticker-libraries&quot;&gt;Custom Sticker Libraries&lt;/h2&gt;
&lt;p&gt;We wanted to make it easier for you to provide your users with more sticker tool content. So far, you were able to create multiple sticker categories with different stickers that could either be part of your app or stored on a server. Additionally, you could &lt;a href=&quot;https://img.ly/docs/pesdk/ios/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#personal-stickers&quot;&gt;enable our personal stickers feature on iOS&lt;/a&gt; or &lt;a href=&quot;https://img.ly/docs/pesdk/ios/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#personal-stickers&quot;&gt;Android&lt;/a&gt;), giving your users the option to select stickers from their camera roll.&lt;/p&gt;
&lt;p&gt;We have now added more ways to provide your users with stickers.&lt;/p&gt;
&lt;h3 id=&quot;android&quot;&gt;Android&lt;/h3&gt;
&lt;p&gt;You can now create sticker categories that do not present our sticker selection interface, but will instead load any arbitrary Fragment. That gives you complete control over the sticker selection screen, and you can use it to load and display any content. When the user selects any of your stickers, all you have to do is pass it back to the SDK with a callback. Get started with your &lt;a href=&quot;https://img.ly/docs/vesdk/android/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#adding-custom-stickers&quot;&gt;Custom Sticker Library with our Android documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;ios&quot;&gt;iOS&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;You can now create sticker categories that do not present our sticker selection interface, but will instead load any arbitrary view controller that conforms to the &lt;code&gt;StickerCollection&lt;/code&gt; protocol. That gives you complete control over the sticker selection screen, and you can use it to load and display any content. When the user selects any of your stickers, simply pass it back to the SDK using a delegate method.&lt;/li&gt;
&lt;li&gt;Additionally, we’ve created a new &lt;code&gt;StickerProviderCategory&lt;/code&gt; that you can pass any object conforming to the &lt;code&gt;StickerProvider&lt;/code&gt; protocol. This category provides most of the features required to interact with sticker content providers, such as search and pagination. You can use this category to very quickly integrate any sticker service.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Find more information on &lt;a href=&quot;https://img.ly/docs/vesdk/ios/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#custom-sticker-view-controller&quot;&gt;Custom Sticker Libraries in the iOS documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;giphy-integration&quot;&gt;GIPHY Integration&lt;/h2&gt;
&lt;p&gt;This online database and search engine for funny GIFs and beautiful animations is a staple in many social applications. Easily integrate GIPHY into your app:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 277px) 277px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;277&quot; height=&quot;600&quot; src=&quot;https://img.ly/_astro/integrate-giphy-video-editor-photo-sdk_ZNfYn8.webp&quot; srcset=&quot;/_astro/integrate-giphy-video-editor-photo-sdk_ZNfYn8.webp 277w&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;android-1&quot;&gt;Android&lt;/h3&gt;
&lt;p&gt;Using our new Custom Sticker Library, we’ve also created an integration for GIPHY on Android. All you have to do is head over to &lt;a href=&quot;https://developers.giphy.com&quot;&gt;GIPHY&lt;/a&gt;, create your API key, pass it to your &lt;code&gt;GiphySettings&lt;/code&gt; and create a &lt;code&gt;GiphyStickerCategoryItem&lt;/code&gt;. Your users will then immediately have access to all the content GIPHY has to offer.&lt;/p&gt;
&lt;p&gt;For more details, visit our &lt;a href=&quot;https://img.ly/docs/vesdk/android/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#adding-giphy&quot;&gt;documentation on adding GIPHY&lt;/a&gt; for Android.&lt;/p&gt;
&lt;h3 id=&quot;ios-1&quot;&gt;iOS&lt;/h3&gt;
&lt;p&gt;Using the new &lt;code&gt;StickerProviderCategory&lt;/code&gt;, we added GIPHY support on iOS. All you have to do is head over to &lt;a href=&quot;https://developers.giphy.com&quot;&gt;GIPHY&lt;/a&gt;, create your API key, and pass this to the GIPHY sticker category. Your users will then immediately have access to all the content GIPHY has to offer.&lt;/p&gt;
&lt;p&gt;For more details, visit our documentation &lt;a href=&quot;https://img.ly/docs/vesdk/ios/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#giphy&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;more-updates-for-android&quot;&gt;More Updates for Android&lt;/h2&gt;
&lt;p&gt;Additionally, we have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Increased the minimum API level for PhotoEditor SDK from 16 (Android 4) to 21 (Android 5), which ensures support for 98% of all phones in use.&lt;/li&gt;
&lt;li&gt;Added support for headless video exporting.&lt;/li&gt;
&lt;li&gt;Increased video playback stability.&lt;/li&gt;
&lt;li&gt;Fixed a number of issues with degraded audio quality in videos.&lt;/li&gt;
&lt;li&gt;And added the ability to choose a theme at runtime.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;more-updates-for-ios&quot;&gt;More Updates for iOS&lt;/h2&gt;
&lt;p&gt;Additionally, we have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Increased our deployment target from iOS 9 to iOS 13.&lt;/li&gt;
&lt;li&gt;Migrated all usage of OpenGL to Metal.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/vesdk/ios/introduction/migration/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;Added a better result API&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/vesdk/ios/introduction/getting_started/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#swiftui&quot;&gt;Added support for SwiftUI&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Enhanced our video export to display a progress indicator and the option to cancel the export.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;thanks-for-reading-let-us-know-what-you-think-on-twitter-or-stay-in-the-loop-with-our-newsletter&quot;&gt;Thanks for reading! Let us know what you think on &lt;a href=&quot;https://twitter.com/imgly&quot;&gt;Twitter&lt;/a&gt;, or stay in the loop with 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;/h3&gt;</content:encoded><dc:creator>Sascha</dc:creator><media:content url="https://blog.img.ly/2022/05/photo-editor-sdk-video-editor-sdk-background-removal.png" medium="image"/><category>Release Notes</category><category>Photo Editor</category><category>Video Editor</category><category>Android App Development</category><category>iOS App Development</category><category>App Development</category></item><item><title>How To Apply Image Filters in WebGL</title><link>https://img.ly/blog/how-to-add-image-filters-in-webgl/</link><guid isPermaLink="true">https://img.ly/blog/how-to-add-image-filters-in-webgl/</guid><description>Learn everything you need to get started with kernel-based image filters in WebGL.</description><pubDate>Fri, 08 Apr 2022 13:06:16 GMT</pubDate><content:encoded>&lt;p&gt;In this article, you will learn how to apply custom filters to an image in WebGL. You can achieve this goal without using any external library. That is because the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL&quot;&gt;HTML5 &lt;code&gt;canvas&lt;/code&gt;&lt;/a&gt; &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL&quot;&gt;element natively supports WebGL&lt;/a&gt; and does not require the use of plug-ins.&lt;/p&gt;
&lt;p&gt;As we have already covered in &lt;a href=&quot;https://img.ly/blog/tag/html5/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;previous articles&lt;/a&gt;, &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt; is a powerful tool that equips you with everything required to manipulate images. This is true regardless of the use of WebGL. So, you can &lt;a href=&quot;https://img.ly/blog/how-to-apply-filters-in-javascript/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;filter images also without using WebGL&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now, let’s see how to filter images in Vanilla JavaScript with WebGL in your browser. Follow this step-by-step tutorial and learn how to build the following &lt;a href=&quot;https://codesandbox.io/s/how-to-filter-an-image-in-webgl-forked-zkgccv&quot;&gt;demo&lt;/a&gt;:&lt;/p&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/how-to-filter-an-image-in-webgl-forked-zkgccv?fontsize=14&amp;#x26;hidenavigation=1&amp;#x26;theme=dark&quot; title=&quot;How To Filter an Image in WebGL (forked)&quot; allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot; sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;getting-started-with-webgl&quot;&gt;Getting Started with WebGL&lt;/h2&gt;
&lt;p&gt;If you are not familiar with &lt;a href=&quot;https://get.webgl.org/&quot;&gt;WebGL&lt;/a&gt;, you need to learn a few things before approaching it. To build an application in WebGL, start with the following three concepts.&lt;/p&gt;
&lt;h3 id=&quot;1-textures&quot;&gt;1. Textures&lt;/h3&gt;
&lt;p&gt;Keep in mind that to draw an image in WebGL you have to use a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Using_textures_in_WebGL&quot;&gt;texture&lt;/a&gt;. To use a texture, WebGL requires you to define the texture coordinates. These coordinates go from 0.0 to 1.0, regardless of the texture size.&lt;/p&gt;
&lt;h3 id=&quot;2-vertex-shader&quot;&gt;2. Vertex shader&lt;/h3&gt;
&lt;p&gt;The vertex shader is a function you have to write in &lt;a href=&quot;https://www.khronos.org/opengl/wiki/OpenGL_Shading_Language&quot;&gt;GLSL&lt;/a&gt; that is in charge of computing the vertex positions. Thanks to it, WebGL can &lt;a href=&quot;https://en.wikipedia.org/wiki/Rasterisation&quot;&gt;rasterize&lt;/a&gt; the draw primitives, which include points, lines, and triangles. When rasterizing these primitives, WebGL calls another user-defined function called fragment shader. In other words, WebGL interpolates the values provided in the vertex shader function while it draws each pixel using the fragment shader function execution.&lt;/p&gt;
&lt;h3 id=&quot;3-fragment-shader&quot;&gt;3. Fragment shader&lt;/h3&gt;
&lt;p&gt;The fragment shader is a function you have to write in GLSL whose goal is to generate a color for each pixel of the draw primitive currently being drawn. This function has little info per pixel, but you can provide it with everything required by using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Data#varyings&quot;&gt;&lt;code&gt;varyings&lt;/code&gt;&lt;/a&gt; variables. These allow you to pass values from the vertex shader function to the fragment shader function.&lt;/p&gt;
&lt;h2 id=&quot;filtering-images-with-kernels-in-webgl-with-canvas&quot;&gt;Filtering Images with Kernels in WebGL with &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;There are many ways to filter images, but the most common one involves the &lt;a href=&quot;https://en.wikipedia.org/wiki/Convolution&quot;&gt;convolution operation&lt;/a&gt;. This is because when used on images, convolution applies a filter by taking the weighted sum of a square of pixels and assigning the resulting value to the current pixel. This logic is applied to every pixel the image consists of. Therefore, you can now imagine why convolution is one of the most relevant concepts when it comes to image processing.&lt;/p&gt;
&lt;p&gt;The coefficients used to perform the weighted sum come from a matrix called &lt;a href=&quot;https://en.wikipedia.org/wiki/Kernel%5F(image_processing)&quot;&gt;&lt;em&gt;kernel&lt;/em&gt;&lt;/a&gt;. The kernel represents the filter you want to apply through the convolution operation. So, by changing the kernel, the resulting image will change accordingly. Some kernels are more useful than others and can be used for blurring, sharpening, performing edge detection, and other operations. You can find a list of the most popular &lt;a href=&quot;https://en.wikipedia.org/wiki/Kernel%5F(image_processing)#Details&quot;&gt;kernels on Wikipedia&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now, let’s see how to implement kernel image filtering in WebGL.&lt;/p&gt;
&lt;p&gt;Clone the &lt;a href=&quot;https://github.com/Tonel/how-to-filter-an-image-in-webgl-imgly&quot;&gt;GitHub repository that supports this article&lt;/a&gt; with the following command:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;git clone https://github.com/Tonel/how-to-filter-an-image-in-webgl-imgly&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Additionally, try the demo application by launching &lt;code&gt;how-to-filter-an-image-in-webgl-imgly/index.html&lt;/code&gt; in your browser.&lt;/p&gt;
&lt;p&gt;Otherwise, you can find the JavaScript function taking care of implementing the filter logic in WebGL below:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; filterImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;canvas&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;originalImage&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;kernel&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // assuming the kernel is a square matrix&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; kernelSize&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; Math.&lt;/span&gt;&lt;span&gt;sqrt&lt;/span&gt;&lt;span&gt;(kernel.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; gl&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; canvas.&lt;/span&gt;&lt;span&gt;getContext&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;webgl&apos;&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;  // clearing the canvas&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;clearColor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;clear&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;COLOR_BUFFER_BIT&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;  const&lt;/span&gt;&lt;span&gt; vertexShaderSource&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;  attribute vec2 position;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  varying vec2 v_coordinate;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  void main() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl_Position = vec4(position, 0, 1);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    v_coordinate = gl_Position.xy * 0.5 + 0.5;&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&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; fragmentShaderSource&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;  precision mediump float;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // the varible defined in the vertex shader above&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  varying vec2 v_coordinate;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  uniform vec2 imageSize;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  uniform sampler2D u_texture;&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;  void main() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    vec2 position = vec2(v_coordinate.x, 1.0 - v_coordinate.y);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    vec2 onePixel = vec2(1, 1) / imageSize;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    vec4 color = vec4(0);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    mat3 kernel = mat3(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      ${&lt;/span&gt;&lt;span&gt;kernel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;,&apos;&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&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // implementing the convolution operation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    for(int i = 0; i &amp;#x3C; ${&lt;/span&gt;&lt;span&gt;kernelSize&lt;/span&gt;&lt;span&gt;}; i++) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      for(int j = 0; j &amp;#x3C; ${&lt;/span&gt;&lt;span&gt;kernelSize&lt;/span&gt;&lt;span&gt;}; j++) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // retrieving the sample position pixel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        vec2 samplePosition = position + vec2(i - 1 , j - 1) * onePixel;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // retrieving the sample color&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        vec4 sampleColor = texture2D(u_texture, samplePosition);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        sampleColor *= kernel&lt;/span&gt;&lt;span&gt;\[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;\]&lt;/span&gt;&lt;span&gt;[j];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        color += sampleColor;&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;    color.a = 1.0;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl_FragColor = color;&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&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; vertexShader&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; compileShader&lt;/span&gt;&lt;span&gt;(gl, gl.&lt;/span&gt;&lt;span&gt;VERTEX_SHADER&lt;/span&gt;&lt;span&gt;, vertexShaderSource);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; fragmentShader&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; compileShader&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;FRAGMENT_SHADER&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    fragmentShaderSource&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;  // iniziailing the program&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; program&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; createProgram&lt;/span&gt;&lt;span&gt;(gl, vertexShader, fragmentShader);&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;  const&lt;/span&gt;&lt;span&gt; positionAttributeLocation&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; gl.&lt;/span&gt;&lt;span&gt;getAttribLocation&lt;/span&gt;&lt;span&gt;(program, &lt;/span&gt;&lt;span&gt;&apos;position&apos;&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;  const&lt;/span&gt;&lt;span&gt; imageSizeLocation&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; gl.&lt;/span&gt;&lt;span&gt;getUniformLocation&lt;/span&gt;&lt;span&gt;(program, &lt;/span&gt;&lt;span&gt;&apos;imageSize&apos;&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;  // binding the position buffer to positionBuffer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; positionBuffer&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; gl.&lt;/span&gt;&lt;span&gt;createBuffer&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;bindBuffer&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;ARRAY_BUFFER&lt;/span&gt;&lt;span&gt;, positionBuffer);&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;  // using the program defined above&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;useProgram&lt;/span&gt;&lt;span&gt;(program);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // enabling the texcoord attribute&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;enableVertexAttribArray&lt;/span&gt;&lt;span&gt;(positionAttributeLocation);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // setting up the size of the image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;uniform2f&lt;/span&gt;&lt;span&gt;(imageSizeLocation, canvas.width, canvas.height);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // telling positionAttributeLocation how to retrieve data out of positionBuffer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;vertexAttribPointer&lt;/span&gt;&lt;span&gt;(positionAttributeLocation, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;FLOAT&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;0&lt;/span&gt;&lt;span&gt;, &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;  // provide the texture coordinates&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;bufferData&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;ARRAY_BUFFER&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    new&lt;/span&gt;&lt;span&gt; Float32Array&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;]),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;STATIC_DRAW&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;  // loading the original image as a texture&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; texture&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; gl.&lt;/span&gt;&lt;span&gt;createTexture&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  texture.image &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; Image&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;  // setting the anonymous mode&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // Learn more about it here:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/crossOrigin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  texture.image.crossOrigin &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  texture.image.src &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; originalImage.src;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  texture.image.&lt;/span&gt;&lt;span&gt;onload&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;bindTexture&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;TEXTURE_2D&lt;/span&gt;&lt;span&gt;, texture);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // setting the parameters to be able to render any image,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // regardless of its size&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;texParameteri&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;TEXTURE_2D&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;TEXTURE_WRAP_S&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;CLAMP_TO_EDGE&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;texParameteri&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;TEXTURE_2D&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;TEXTURE_WRAP_T&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;CLAMP_TO_EDGE&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;texParameteri&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;TEXTURE_2D&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;TEXTURE_MAG_FILTER&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;NEAREST&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;texParameteri&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;TEXTURE_2D&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;TEXTURE_MIN_FILTER&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;NEAREST&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // loading the original image as a texture&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;texImage2D&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      gl.&lt;/span&gt;&lt;span&gt;TEXTURE_2D&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&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;      gl.&lt;/span&gt;&lt;span&gt;RGBA&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      gl.&lt;/span&gt;&lt;span&gt;RGBA&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      gl.&lt;/span&gt;&lt;span&gt;UNSIGNED_BYTE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      texture.image&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;    gl.&lt;/span&gt;&lt;span&gt;drawArrays&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;TRIANGLES&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;6&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 class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; compileShader&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;gl&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;shaderSource&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; shader&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; gl.&lt;/span&gt;&lt;span&gt;createShader&lt;/span&gt;&lt;span&gt;(type);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;shaderSource&lt;/span&gt;&lt;span&gt;(shader, shaderSource);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;compileShader&lt;/span&gt;&lt;span&gt;(shader);&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;  const&lt;/span&gt;&lt;span&gt; outcome&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; gl.&lt;/span&gt;&lt;span&gt;getShaderParameter&lt;/span&gt;&lt;span&gt;(shader, gl.&lt;/span&gt;&lt;span&gt;COMPILE_STATUS&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; (outcome &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;    // logging the error message on failure&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;getShaderInfoLog&lt;/span&gt;&lt;span&gt;(shader));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;deleteShader&lt;/span&gt;&lt;span&gt;(shader);&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;  return&lt;/span&gt;&lt;span&gt; shader;&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;function&lt;/span&gt;&lt;span&gt; createProgram&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;gl&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;vertexShader&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;fragmentShader&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; program&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; gl.&lt;/span&gt;&lt;span&gt;createProgram&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;attachShader&lt;/span&gt;&lt;span&gt;(program, vertexShader);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;attachShader&lt;/span&gt;&lt;span&gt;(program, fragmentShader);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;linkProgram&lt;/span&gt;&lt;span&gt;(program);&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;  const&lt;/span&gt;&lt;span&gt; outcome&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; gl.&lt;/span&gt;&lt;span&gt;getProgramParameter&lt;/span&gt;&lt;span&gt;(program, gl.&lt;/span&gt;&lt;span&gt;LINK_STATUS&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; (outcome &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;    // logging the error message on failure&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;getProgramInfoLog&lt;/span&gt;&lt;span&gt;(program));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;deleteProgram&lt;/span&gt;&lt;span&gt;(program);&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;  return&lt;/span&gt;&lt;span&gt; program;&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 &lt;code&gt;filterImage()&lt;/code&gt; function is where the magic happens. It takes the following three parameters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;canvas&lt;/code&gt;: an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element&quot;&gt;&lt;code&gt;Element&lt;/code&gt;&lt;/a&gt; object representing an HTML &lt;code&gt;canvas&lt;/code&gt; element&lt;/li&gt;
&lt;li&gt;&lt;code&gt;originalImage&lt;/code&gt;: an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element&quot;&gt;&lt;code&gt;Element&lt;/code&gt;&lt;/a&gt; object representing an HTML &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img&quot;&gt;&lt;code&gt;img&lt;/code&gt;&lt;/a&gt; element&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kernel&lt;/code&gt;: an array containing the values of the kernel to use in the convolution operation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first part of the function takes care of extracting the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext&quot;&gt;&lt;code&gt;WebGLRenderingContext&lt;/code&gt;&lt;/a&gt; object representing a three-dimensional rendering context from the &lt;code&gt;canvas&lt;/code&gt;  element. Then, the vertex shader and fragment shader functions are defined as strings written in GLSL. Next, they are compiled and finally used to create a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebGLProgram&quot;&gt;WebGL program&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The last part of the function creates a texture starting from the original image passed as a parameter and passes it to the &lt;code&gt;WebGLRenderingContext&lt;/code&gt; to produce the final result. This represents the filtered image and is finally displayed by the browser in the &lt;code&gt;canvas&lt;/code&gt; element.&lt;/p&gt;
&lt;p&gt;The results produced by the &lt;code&gt;filterImage()&lt;/code&gt; function depend on the kernel chosen, as you can verify by playing with the live demo you can find at the beginning of the article.&lt;/p&gt;
&lt;p&gt;Et voilà! You just learned how to filter images in WebGL!&lt;/p&gt;
&lt;h2 id=&quot;final-considerations&quot;&gt;Final Considerations&lt;/h2&gt;
&lt;p&gt;As shown above, you can filter images with WebGL in Vanilla JavaScript with a hundred lines. At the same time, this cannot be considered an easy task to achieve. The reason is that getting into WebGL takes time and effort. Plus, you have to learn how to use GLSL to write the vertex shader and the fragment shader functions. So, things can get more complicated than expected.&lt;/p&gt;
&lt;p&gt;Plus, you learned how to perform non-complex filters, but several filtering techniques are complex and do not involve the convolution operation. That also means that implementing them can be challenging and result in inefficient algorithms.&lt;/p&gt;
&lt;p&gt;To avoid a headache, you should consider a complete and all-in-one solution like &lt;a href=&quot;https://img.ly/products/photo-sdk?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;PhotoEditor SDK&lt;/a&gt;. Commercial solutions make things easier and shield you from all difficulties, offering features that would be complex, time-consuming, and challenging to implement. That is particularly true when it comes to using WebGL, which is &lt;a href=&quot;https://img.ly/docs/pesdk/web/introduction/migration-guide/#canvas-renderer/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;PhotoEditor SDK’s main renderer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You will be able to harness WebGL’s power without writing a single line of GLSL or knowing about its existence. WebGL will be used behind the scene for you! Keep also in mind that you would not be alone, since developers at &lt;a href=&quot;https://img.ly/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;IMG.LY&lt;/a&gt; are happy to provide support.&lt;/p&gt;
&lt;h2 id=&quot;filtering-images-with-photoeditor-sdk&quot;&gt;Filtering Images With PhotoEditor SDK&lt;/h2&gt;
&lt;p&gt;Read the article from &lt;a href=&quot;https://img.ly/docs/pesdk/guides/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;the official documentation&lt;/a&gt; to learn &lt;a href=&quot;https://img.ly/docs/pesdk/web/guides/umd/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;how to get started&lt;/a&gt; with &lt;a href=&quot;https://img.ly/products/photo-sdk&quot;&gt;PhotoEditor SDK&lt;/a&gt; in HTML and Vanilla JavaScript. In detail, the &lt;a href=&quot;https://img.ly/docs/pesdk/web/features/filters/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;Filters&lt;/a&gt; feature gives you more than 60 high-quality filters to play with. Achieve the following result with a few clicks:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;PE.SDK ships with stunning preset filters for aesthetic photo creations.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 600px) 600px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;600&quot; height=&quot;321&quot; src=&quot;https://img.ly/_astro/add-image-filters-webGL-1_1apHk1.webp&quot; srcset=&quot;/_astro/add-image-filters-webGL-1_1apHk1.webp 600w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Check out this feature on the &lt;a href=&quot;https://img.ly/products/photo-sdk/demo&quot;&gt;PhotoEditor SDK demo page&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this article, we looked at how to filter an image in WebGL with the HTML &lt;code&gt;canvas&lt;/code&gt; element. Implementing a feature allowing users to filter images through a kernel-based approach in WebGL involves only a dozen of lines of code. However, understanding how WebGL works and coding in GLSL cannot be considered easy tasks.&lt;/p&gt;
&lt;p&gt;As a result, you might want to avoid dealing with WebGL entirely. In this case, consider a commercial and easy-to-adopt solution using WebGL behind the scene – such as &lt;a href=&quot;https://img.ly/products/photo-sdk?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;PhotoEditor SDK&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks for reading! We hope that you found this article helpful. 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;/p&gt;</content:encoded><dc:creator>Antonello</dc:creator><media:content url="https://blog.img.ly/2022/04/add-filter-image-webgl.png" medium="image"/><category>How-To</category><category>Photo Editing</category><category>Web Development</category><category>App Development</category><category>Photo Editor</category><category>Photo Filter</category><category>Tech</category><category>Tutorial</category></item><item><title>CE.SDK v1.4.0 Release</title><link>https://img.ly/blog/ce-sdk-v140-release/</link><guid isPermaLink="true">https://img.ly/blog/ce-sdk-v140-release/</guid><description>Enhance your user experience with an improved library system, easy UI translation and more.</description><pubDate>Tue, 22 Feb 2022 12:34:56 GMT</pubDate><content:encoded>&lt;p&gt;Six weeks have passed since our &lt;a href=&quot;https://img.ly/blog/ce-sdk-v1-3-0-release-notes/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;last release&lt;/a&gt;, where we shipped our new and improved default UI, Placeholders, and a preview for our new Dashboard.&lt;/p&gt;
&lt;p&gt;This time, we focused heavily on making content discovery and provisioning better for you and your customers, as well as automation and API-driven design. Our release includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Custom Asset Libraries &amp;#x26; Management&lt;/li&gt;
&lt;li&gt;Internationalization&lt;/li&gt;
&lt;li&gt;Headless Mode &amp;#x26; APIs&lt;/li&gt;
&lt;li&gt;Other&lt;/li&gt;
&lt;li&gt;Outlook on upcoming releases&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;asset-libraries--management&quot;&gt;Asset Libraries &amp;#x26; Management&lt;/h2&gt;
&lt;p&gt;With this release, we improve our library system and overall usability. CE.SDK 1.4.0 introduces a new toolbar to let your users quickly access their favorite images, shapes, stickers, or text assets.&lt;/p&gt;
&lt;p&gt;Even more importantly, we added a General Asset Source API that allows you to add any external library sources you like. This way, you can provide custom assets to your users, such as images, stickers, or anything else.&lt;br&gt;
Check out our &lt;a href=&quot;https://img.ly/docs/cesdk/js/import-media-4e3703/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;Documentation on Custom Asset Source Integration&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A new user toolbar to the left - for quick library access. Use the General Asset Source API for external libraries.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1408px) 1408px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1408&quot; height=&quot;792&quot; src=&quot;https://img.ly/_astro/ce-sdk-design-editor-v140_1cQ66o.webp&quot; srcset=&quot;/_astro/ce-sdk-design-editor-v140_15HV7q.webp 640w, /_astro/ce-sdk-design-editor-v140_Z1oTmQU.webp 750w, /_astro/ce-sdk-design-editor-v140_Z1g7GmS.webp 828w, /_astro/ce-sdk-design-editor-v140_Z1YrsWH.webp 1080w, /_astro/ce-sdk-design-editor-v140_ZPrsSq.webp 1280w, /_astro/ce-sdk-design-editor-v140_1cQ66o.webp 1408w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;internationalization-i18n&quot;&gt;Internationalization (i18n)&lt;/h2&gt;
&lt;p&gt;CE.SDK now supports the easy translation of the default UI into any language, including full i18n support. We ship with English and German locales, but have successfully tested it with other languages.&lt;br&gt;
Learn more about &lt;a href=&quot;https://img.ly/docs/cesdk/js/user-interface/localization-508e20/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;adding translations to CE.SDK in our Documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;headless-mode--apis&quot;&gt;Headless Mode &amp;#x26; APIs&lt;/h2&gt;
&lt;p&gt;We are finally extending CE.SDK with a full headless mode that is usable without a user interface in a browser. You can use it to load, modify, and export scene templates programmatically without the need for any user interaction. Use it to create previews of your scenes with custom user content without opening the editor, or export your designs in multiple resolutions on demand.&lt;/p&gt;
&lt;h3 id=&quot;included-apis&quot;&gt;Included APIs&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Scene API&lt;/em&gt;&lt;/strong&gt; lets you create, load, save, or export scenes to a rasterized image format.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Block API&lt;/strong&gt; lets you create, read, update and delete any item (so-called &lt;em&gt;blocks&lt;/em&gt;) in the scene; modifying properties like position, size, or content is guaranteed easy.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Layouts API&lt;/strong&gt; lets you use advanced layout capabilities: choose from modes like absolute positioning, relative positioning in percent relative to the parent, or even auto layout. An even auto-layout lets you auto-adapt the size of a block according to its parent size and siblings.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;other&quot;&gt;Other&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Snapping now works with multiple selected items.&lt;/li&gt;
&lt;li&gt;Slider input values now allow manual input to give you more control.&lt;/li&gt;
&lt;li&gt;Easy asset library access in the UI.&lt;/li&gt;
&lt;li&gt;Changing content in Preview Mode to preview your template settings does not alter your template anymore.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;upcoming&quot;&gt;Upcoming&lt;/h2&gt;
&lt;p&gt;We are currently working hard to improve the overall CE.SDK Editor experience for you and your customers. That includes adding features like strokes, gradients, grouping, but also improving the rendering performance to create more complex designs. Additionally, we are improving asset discovery within the editor.&lt;/p&gt;
&lt;p&gt;Excitingly, we are working hard to bring our &lt;a href=&quot;https://img.ly/products/video-sdk/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;VE.SDK video features&lt;/a&gt; to CE.SDK! In the near future, you can use videos and animated GIFs inside any template and export short videos from within CE.SDK for Web.&lt;/p&gt;
&lt;h3 id=&quot;thanks-for-reading-to-stay-in-the-loop-with-our-latest-articles-and-case-studies-subscribe-to-our-newsletter&quot;&gt;Thanks for reading! To stay in the loop with our latest articles and case studies, 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;/h3&gt;</content:encoded><dc:creator>Daniel</dc:creator><media:content url="https://blog.img.ly/2022/02/CE-SDK-design-editor-1-4-0-javascript.png" medium="image"/><category>Release Notes</category><category>Design Editor</category><category>Web Development</category><category>Photo Editor</category><category>App Development</category></item></channel></rss>