<?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>Android App Development – IMG.LY Blog</title><description>Posts tagged Android App Development on the IMG.LY blog.</description><link>https://img.ly/blog/tag/android-app-development/</link><language>en-us</language><image><url>https://img.ly/apple-touch-icon.png</url><title>Android App Development – IMG.LY Blog</title><link>https://img.ly/blog/tag/android-app-development/</link></image><atom:link href="https://img.ly/blog/tag/android-app-development/rss.xml" rel="self" type="application/rss+xml"/><generator>Astro</generator><lastBuildDate>Tue, 09 Jun 2026 09:48:33 GMT</lastBuildDate><ttl>60</ttl><item><title>CE.SDK v1.73 Release Notes</title><link>https://img.ly/blog/creative-editor-sdk-v-1-73-0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v-1-73-0-release-notes/</guid><description>v1.73 brings Starter Kits to iOS &amp; Android, giving you full ownership of your mobile editor config. Plus SVG export across platforms.</description><pubDate>Tue, 21 Apr 2026 13:29:35 GMT</pubDate><content:encoded>&lt;p&gt;v1.73 is a mobile-focused release. The main act is our new architectural foundation for iOS and Android: Starter Kits give you full ownership of your editor configuration. On the engine side, CE.SDK now supports SVG export across all platforms.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;own-your-mobile-editor--not-just-the-config&quot;&gt;Own Your Mobile Editor — Not Just the Config&lt;/h2&gt;
&lt;p&gt;The old model was simple: drop in a solution component (PhotoEditor, VideoEditor, DesignEditor), pass a license key, ship. For most teams, that was exactly the right starting point. Fast to integrate, zero configuration overhead, a full editor running in your app within hours.&lt;/p&gt;
&lt;p&gt;As products matured, though, teams needed more. Deeper customization. Granular control over behaviors. An editor that felt like theirs.&lt;/p&gt;
&lt;p&gt;That’s what &lt;strong&gt;Starter Kits for Mobile&lt;/strong&gt; addresses.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Set up fast, customize, and own your code - now for iOS &amp;amp;#x26; Android&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;857&quot; src=&quot;https://img.ly/_astro/starter-kits-design-editor-video-apparel-mobile-ios-android_Zuekpc.webp&quot; srcset=&quot;/_astro/starter-kits-design-editor-video-apparel-mobile-ios-android_hid7x.webp 640w, /_astro/starter-kits-design-editor-video-apparel-mobile-ios-android_1fMlOs.webp 750w, /_astro/starter-kits-design-editor-video-apparel-mobile-ios-android_14DV9O.webp 828w, /_astro/starter-kits-design-editor-video-apparel-mobile-ios-android_Z2opymo.webp 1080w, /_astro/starter-kits-design-editor-video-apparel-mobile-ios-android_ZEa6Mt.webp 1280w, /_astro/starter-kits-design-editor-video-apparel-mobile-ios-android_Z2tuMOW.webp 1668w, /_astro/starter-kits-design-editor-video-apparel-mobile-ios-android_Zuekpc.webp 2000w&quot;&gt;&lt;/p&gt;
&lt;p&gt;The prebuilt solution components are replaced by a single &lt;code&gt;Editor&lt;/code&gt; entry point and a set of Starter Kits: complete, working editor projects for each use case that live in your codebase, not ours. Set it up in minutes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For your product, this means:&lt;/strong&gt; you can adapt the editor to fit your product, not the other way around.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Everything Is In Your Code Now&lt;/strong&gt;&lt;br&gt;
Each Starter Kit is a real editor project — not a thin config wrapper. Every toolbar item, every callback, every loading phase is written out explicitly in files you own.&lt;/p&gt;
&lt;p&gt;That means your team can read the integration, review changes to it, and understand exactly what the editor does and why. No more hunting through SDK internals to figure out why something behaves the way it does.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SDK Updates Stop Touching Your UI&lt;/strong&gt;&lt;br&gt;
Previously, updating CE.SDK could introduce new buttons, changed defaults, or different menus without you asking for them. Your QA had to catch it.&lt;/p&gt;
&lt;p&gt;That dynamic is reversed now. Engine improvements, bug fixes, and performance gains come through updates as before. But your editor UI stays exactly where you left it. New features arrive as optional building blocks, documented and ready when you want them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No More Customization Ceiling&lt;/strong&gt;&lt;br&gt;
The old configuration APIs had a line between what you could change and what you couldn’t. Starter Kits remove that line entirely. You can restructure initialization, inject custom logic between loading phases, and build workflows specific to your product.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If you can see it in the code, you can change it.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If none of the five kits match your needs, the &lt;code&gt;Editor&lt;/code&gt; view accepts raw configuration directly.&lt;/p&gt;
&lt;h3 id=&quot;migration&quot;&gt;Migration&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;This is a breaking change on both iOS and Android. Migration guides cover every change with before-and-after examples.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;→ &lt;a href=&quot;https://img.ly/docs/cesdk/android/to-v1-73-ab14fb/&quot;&gt;Android Migration Guide&lt;/a&gt;&lt;br&gt;
→ &lt;a href=&quot;https://img.ly/docs/cesdk/ios/to-v1-73-ab14fb/&quot;&gt;iOS Migration Guide&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;starter-kit-repositories&quot;&gt;Starter Kit Repositories&lt;/h3&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Editor&lt;/th&gt;&lt;th&gt;iOS (Swift)&lt;/th&gt;&lt;th&gt;Android (Kotlin)&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Photo&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://github.com/imgly/starterkit-photo-editor-ios&quot;&gt;GitHub&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://github.com/imgly/starterkit-photo-editor-android&quot;&gt;GitHub&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Design&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://github.com/imgly/starterkit-design-editor-ios&quot;&gt;GitHub&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://github.com/imgly/starterkit-design-editor-android&quot;&gt;GitHub&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Video&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://github.com/imgly/starterkit-video-editor-ios&quot;&gt;GitHub&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://github.com/imgly/starterkit-video-editor-android&quot;&gt;GitHub&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Postcard&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://github.com/imgly/starterkit-postcard-editor-ios&quot;&gt;GitHub&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://github.com/imgly/starterkit-postcard-editor-android&quot;&gt;GitHub&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Apparel&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://github.com/imgly/starterkit-apparel-editor-ios&quot;&gt;GitHub&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://github.com/imgly/starterkit-apparel-editor-android&quot;&gt;GitHub&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&quot;export-vector-designs-as-svg&quot;&gt;Export Vector Designs as SVG&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/svg-export_sXlp.webp&quot; srcset=&quot;/_astro/svg-export_Z1Gawc7.webp 640w, /_astro/svg-export_2kYdnC.webp 750w, /_astro/svg-export_ZcTYTA.webp 828w, /_astro/svg-export_1pb2OK.webp 1080w, /_astro/svg-export_Hk0A5.webp 1280w, /_astro/svg-export_sXlp.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Until now, users working with vector content in CE.SDK had no path to get that content out as a vector file. CE.SDK v1.73 adds SVG export via the &lt;code&gt;image/svg+xml&lt;/code&gt; MIME type.&lt;/p&gt;
&lt;p&gt;Text is exported as vector paths for consistent rendering across environments regardless of font availability. Drop shadows, blur, effects, and embedded raster images are rasterized and included as embedded images within the SVG output.&lt;/p&gt;
&lt;p&gt;→ &lt;a href=&quot;https://img.ly/docs/cesdk/engine/guides/export-blocks/&quot;&gt;Exporting Blocks Engine Guide&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;changelog&quot;&gt;Changelog&lt;/h2&gt;
&lt;p&gt;See the &lt;a href=&quot;https://img.ly/docs/cesdk/changelog/v1-73-0/&quot;&gt;full changelog&lt;/a&gt; for the complete list.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Thanks for building with IMG.LY.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Join 3,000+ creative professionals who get early access to new features and updates—&lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i?ref=img.ly&quot;&gt;subscribe&lt;/a&gt;.&lt;/p&gt;</content:encoded><dc:creator>Neslihan</dc:creator><media:content url="https://blog.img.ly/2026/04/creative-sdk-imgly-173-release-notes-android-ios-design-video-photo-editor-integrate.jpg" medium="image"/><category>Release Notes</category><category>Android App Development</category><category>iOS App Development</category></item><item><title>CE.SDK v1.48 Release Notes</title><link>https://img.ly/blog/creative-editor-sdk-v-1-48-0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v-1-48-0-release-notes/</guid><description>We’re expanding UI customization for CE.SDK on Android—now you can tailor the navigation bar to match your brand and streamline your design workflows.</description><pubDate>Tue, 08 Apr 2025 12:13:35 GMT</pubDate><content:encoded>&lt;p&gt;This release makes it easier than ever to tailor the Android editing experience to your brand. Customize the navigation bar to guide your users seamlessly and create an interface that feels uniquely yours.&lt;/p&gt;
&lt;p&gt;Let’s jump in:&lt;/p&gt;
&lt;h2 id=&quot;match-your-navigation-bar-with-your-design--logic&quot;&gt;Match Your Navigation Bar With Your Design &amp;#x26; Logic&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Customize your Navigation Bar in your Editor for Android.&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;2000&quot; src=&quot;https://img.ly/_astro/navigation-bar-customize-android-ce_SDK_ZlFfI4.webp&quot; srcset=&quot;/_astro/navigation-bar-customize-android-ce_SDK_ZzTchm.webp 640w, /_astro/navigation-bar-customize-android-ce_SDK_ZSL2Wg.webp 750w, /_astro/navigation-bar-customize-android-ce_SDK_ZPpwKD.webp 828w, /_astro/navigation-bar-customize-android-ce_SDK_LL6Aj.webp 1080w, /_astro/navigation-bar-customize-android-ce_SDK_vQyjX.webp 1280w, /_astro/navigation-bar-customize-android-ce_SDK_2hUPw9.webp 1668w, /_astro/navigation-bar-customize-android-ce_SDK_ZlFfI4.webp 2000w&quot;&gt;&lt;/p&gt;
&lt;p&gt;You now have more control over customizing the navigation bar on &lt;strong&gt;Android&lt;/strong&gt;, ensuring that it reflects your brand and optimizes user flows.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key Features:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Add Custom Buttons&lt;/strong&gt;: You can add custom buttons to the navigation bar, to give users quick access to frequently used actions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rearrange Buttons:&lt;/strong&gt; Arrange buttons in your navigation bar.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integrate Custom Components&lt;/strong&gt;: Customize the navigation bar by integrating unique elements that fit your app’s design and functionality.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These updates allow you to fully tailor the mobile editing experience to your specific needs.&lt;/p&gt;
&lt;p&gt;💡 Did you know? In our previous update, we introduced customizability for the &lt;a href=&quot;https://img.ly/docs/cesdk/android/user-interface/customization/dock-cb916c/&quot;&gt;dock&lt;/a&gt; and &lt;a href=&quot;https://img.ly/docs/cesdk/android/user-interface/customization/inspector-bar-8ca1cd/&quot;&gt;inspector&lt;/a&gt; bar on Android—laying the foundation for more UI personalization.&lt;/p&gt;
&lt;p&gt;We’re continuing that momentum by giving you full control over the navigation bar, ensuring that every part of your mobile editing experience can align with your product’s workflow.&lt;/p&gt;
&lt;p&gt;Start customizing your navigation bar with our &lt;a href=&quot;https://img.ly/docs/cesdk/android/user-interface/customization/navigation-bar-4e5d39/&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;upcoming&quot;&gt;Upcoming&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Enjoy Vibrant HDR Videos&lt;/strong&gt;&lt;br&gt;
CE.SDK will support loading HDR videos on iOS, converting them to SDR on the fly for accurate and vibrant color representation—without the need for time-consuming transcoding.&lt;/p&gt;
&lt;p&gt;Previously, HDR videos needed to be transcoded with delays—especially with large 4K videos. Soon, HDR content is processed &lt;em&gt;instantly&lt;/em&gt;. Videos appear with correct color fidelity right away, making the editing experience more fluid and visually accurate for users.&lt;/p&gt;
&lt;p&gt;This enhancement will remove friction in the editing workflow and lets your users start working with their content immediately. By offering a smoother, higher-quality experience, your app can boost user engagement and retention.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;View all bug fixes and changes in the &lt;a href=&quot;https://img.ly/docs/cesdk/changelog/#v1480--april-1st-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/04/creative-editor-sdk-1-48.jpg" medium="image"/><category>Release Notes</category><category>CE.SDK</category><category>Android App Development</category><category>HDR</category></item><item><title>CE.SDK v1.45 Release Notes</title><link>https://img.ly/blog/creative-editor-sdk-v-1-45-0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v-1-45-0-release-notes/</guid><description>Create, Engage &amp; Build Seamlessly! This release brings Reactions to Android. Record authentic responses to a video. </description><pubDate>Tue, 25 Feb 2025 14:11:57 GMT</pubDate><content:encoded>&lt;p&gt;Welcome to &lt;strong&gt;CE.SDK v1.45!&lt;/strong&gt; We’re expanding creative possibilities and refining the editing experience. &lt;strong&gt;Reactions&lt;/strong&gt; are now available on Android, enabling users to record, edit, and personalize real-time responses.&lt;/p&gt;
&lt;p&gt;We also introduce improvements like smoother development with TypeScript and better text rendering across languages.&lt;/p&gt;
&lt;p&gt;These solutions help creators and developers work smarter, engage better, and deliver high-quality content.&lt;/p&gt;
&lt;h2 id=&quot;record-reactions-to-videos-on-android&quot;&gt;Record Reactions to Videos on Android&lt;/h2&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-45/reactions-video-sdk-imgly-ce-sdk.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Now available on &lt;strong&gt;Android&lt;/strong&gt;, the popular &lt;strong&gt;Reactions&lt;/strong&gt; feature lets users record and add their real-time responses to videos.&lt;/p&gt;
&lt;p&gt;This is a must-have for engagement-driven content, mirroring interactions on platforms like TikTok and Instagram. Reactions have become a key element of personal branding and connecting with other creators on social media. With Reactions, users can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Connect with their audience&lt;/strong&gt;—duet, respond to trends, or join conversations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Add a personal touch&lt;/strong&gt;—react to fan art, viral moments, or inspiring videos.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Show thought leadership&lt;/strong&gt;—comment on user questions, industry news, or niche topics.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Increase reach&lt;/strong&gt;—boost visibility and interaction.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monetize content&lt;/strong&gt;—sell products and showcase collaborations.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Reactions make content creation fast, easy, and personal.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-45/timeline-video-editor-sdk-android.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;With our shipped UI, users can select a &lt;strong&gt;vertical or horizontal layout&lt;/strong&gt; to record their reaction video, then &lt;strong&gt;customize&lt;/strong&gt; it with text, filters, adjustments, and more.&lt;/p&gt;
&lt;p&gt;It’s easy to crop, trim, and further adjust your video clip—providing a flexible starting point for seamless editing.&lt;/p&gt;
&lt;p&gt;Try the &lt;a href=&quot;https://play.google.com/store/apps/details?id=ly.img.cesdk.catalog&amp;#x26;hl=gsw&quot;&gt;live demo&lt;/a&gt; and enable Reactions for Android with our &lt;a href=&quot;https://img.ly/docs/cesdk/android/import-media/capture-from-camera/camera-configuration-46afd0/&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;improvements&quot;&gt;Improvements&lt;/h2&gt;
&lt;h3 id=&quot;ensure-text-rendering-across-languages&quot;&gt;Ensure Text Rendering Across Languages&lt;/h3&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-45/font-fallback-sdk.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;When a glyph is unavailable in the selected font, CE.SDK automatically falls back to a configurable default font. This prevents localization issues and ensures seamless text rendering, perfect for your global projects.&lt;/p&gt;
&lt;h3 id=&quot;simplify-development-with-complete-typescript-support&quot;&gt;Simplify Development with Complete TypeScript Support&lt;/h3&gt;
&lt;p&gt;We’ve improved TypeScript support by exposing previously missing types used in our UI APIs. This enhancement, based on user feedback, reduces complexity and ensures smoother development workflows.&lt;/p&gt;
&lt;p&gt;View the &lt;a href=&quot;https://img.ly/docs/cesdk/changelog/#v1450--february-19th-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-45-imgly.jpg" medium="image"/><category>Release Notes</category><category>Android App Development</category><category>Reactions</category><category>CE.SDK</category></item><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.43 Release Notes</title><link>https://img.ly/blog/creative-editor-sdk-v-1-43-0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v-1-43-0-release-notes/</guid><description>Customize your Android Editor to fit your workflow! Easily rearrange the dock and inspector for a more efficient, responsive editing experience.</description><pubDate>Mon, 03 Feb 2025 12:20:13 GMT</pubDate><content:encoded>&lt;p&gt;Welcome to CE.SDK v1.43! This update brings you enhanced customization tools, allowing you to tailor the interface of your Android Editor to fit your workflow. With new possibilities for mobile configurations, you’ll enjoy a more flexible and responsive user experience. Let’s dive into what’s new!&lt;/p&gt;
&lt;h2 id=&quot;shape-your-interface-around-your-workflow&quot;&gt;Shape Your Interface Around Your Workflow&lt;/h2&gt;
&lt;p&gt;We’re excited to introduce powerful new ways to customize your &lt;strong&gt;Editor on Android&lt;/strong&gt;. Easily configure your dock and inspector—giving you the flexibility to design a more personalized, responsive user experience!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1980px) 1980px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1980&quot; height=&quot;960&quot; src=&quot;https://img.ly/_astro/docks-inspector_JwYvg.webp&quot; srcset=&quot;/_astro/docks-inspector_bEJv8.webp 640w, /_astro/docks-inspector_27DgES.webp 750w, /_astro/docks-inspector_Z1vXPFr.webp 828w, /_astro/docks-inspector_Zo5jBk.webp 1080w, /_astro/docks-inspector_Z1vEFrp.webp 1280w, /_astro/docks-inspector_Z1MA4Ia.webp 1668w, /_astro/docks-inspector_JwYvg.webp 1980w&quot;&gt;&lt;/p&gt;
&lt;p&gt;💡 The &lt;strong&gt;dock&lt;/strong&gt; is where you keep essential tools for quick access, while the &lt;strong&gt;inspector&lt;/strong&gt; provides detailed controls and settings for the selected item. What’s New:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rearrange Your Dock&lt;/strong&gt;&lt;br&gt;
Move and remove dock items freely while keeping your custom settings intact, like button height.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Smart Custom Buttons&lt;/strong&gt;&lt;br&gt;
For a more responsive workflow, add buttons that dynamically appear, change, or disappear based on your workflow—adapting to selected tools or active tasks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Real-Time Updates&lt;/strong&gt;&lt;br&gt;
The dock updates in real-time, instantly reflecting changes to icons or visibility and adapting seamlessly to your workflow.&lt;/p&gt;
&lt;p&gt;More customization options are coming soon! This update will be available on iOS shortly. Get started with our docs for &lt;a href=&quot;https://img.ly/docs/cesdk/android/user-interface/customization/inspector-bar-8ca1cd/?ref=img.ly#inspectorbaritem-configuration/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;Inspector&lt;/a&gt; and &lt;a href=&quot;https://img.ly/docs/cesdk/android/user-interface/customization/dock-cb916c/?ref=img.ly#dock-configuration/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;Dock Configuration&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;control-how-images-fit-into-blocks&quot;&gt;Control How Images Fit into Blocks&lt;/h2&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-43/image-fill.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;This web feature is perfect for customizing how images appear in designs and templates, allowing for more precise control. With &lt;strong&gt;Fill&lt;/strong&gt; &lt;strong&gt;Mode&lt;/strong&gt; for images, you can choose from three options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Crop&lt;/strong&gt;: Resizes and may crop the image to fill the block.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cover&lt;/strong&gt;: The image fully covers the block while remaining centered both vertically and horizontally.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fit&lt;/strong&gt;: Scales the image to fit within the block without cropping, leaving space if necessary.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Control this via API, with details in our &lt;a href=&quot;https://img.ly/docs/cesdk/js/edit-image/transform/crop-f67a47/&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;upcoming&quot;&gt;Upcoming&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Streamline Your Video Editing Workflow&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-43/multiclips.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Our next release makes web video creation smoother than ever! You will be able to add &lt;strong&gt;multiple video clips&lt;/strong&gt; within a single track on your timeline, keeping your workspace organized and efficient. No more juggling extra tracks—just a clean, intuitive editing experience that lets you focus on bringing your vision to life.&lt;/p&gt;
&lt;p&gt;View the &lt;a href=&quot;https://img.ly/docs/cesdk/changelog/#v1430--january-21st-2025/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&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-43.jpg" medium="image"/><category>Release Notes</category><category>Creative Editor</category><category>Android App Development</category></item><item><title>CE.SDK v1.39 Release Notes</title><link>https://img.ly/blog/creative-editor-sdk-v-1-39-0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v-1-39-0-release-notes/</guid><description>Capture high-quality videos using our Android Camera UI and add polished text designs with customizable backgrounds!</description><pubDate>Tue, 10 Dec 2024 10:23:38 GMT</pubDate><content:encoded>&lt;p&gt;This release introduces powerful new features to take your app’s content creation capabilities to the next level. With the new &lt;strong&gt;Camera UI for Android&lt;/strong&gt;, users can now capture high-quality videos directly within your app, making content creation smoother than ever.&lt;/p&gt;
&lt;p&gt;This update also brings enhancements like color backgrounds for text, helping users add a professional touch to their designs.&lt;/p&gt;
&lt;h2 id=&quot;capture-videos-on-android&quot;&gt;Capture Videos on Android&lt;/h2&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-39/android-camera-ui-sdk-imgly.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Easily integrate video recording capabilities into your Android app: our new Camera UI for Android empowers users to capture high-quality videos directly within your app, streamlining the content creation process. With intuitive controls and customizable settings, it’s designed to fit seamlessly into your app’s workflow.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&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;1126&quot; src=&quot;https://img.ly/_astro/android-camera-UI-sdk-imgly_1KEz56.webp&quot; srcset=&quot;/_astro/android-camera-UI-sdk-imgly_1wimxE.webp 640w, /_astro/android-camera-UI-sdk-imgly_Z1ArzRj.webp 750w, /_astro/android-camera-UI-sdk-imgly_k7LDs.webp 828w, /_astro/android-camera-UI-sdk-imgly_Z2BwqL.webp 1080w, /_astro/android-camera-UI-sdk-imgly_ZfowGp.webp 1280w, /_astro/android-camera-UI-sdk-imgly_ZdIRv.webp 1668w, /_astro/android-camera-UI-sdk-imgly_1KEz56.webp 2000w&quot;&gt;&lt;/p&gt;
&lt;p&gt;If you’re already using our &lt;strong&gt;Video Editor for Android&lt;/strong&gt;, which includes a sleek timeline editor, you can easily enhance functionality by adding clips and selecting ‘Camera’ to record new footage directly into your timeline.&lt;/p&gt;
&lt;p&gt;With the Android Camera UI, your users can create engaging video content without requiring additional tools, keeping them fully engaged within your app.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Get started today:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dive into 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;/li&gt;
&lt;li&gt;Explore the feature in our &lt;a href=&quot;https://img.ly/showcases/cesdk/default-ui/android?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;Demo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;add-backgrounds-to-text&quot;&gt;&lt;strong&gt;Add Backgrounds to Text&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-39/background-text-design-SDK-imgly.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Apply solid color backgrounds to text. Additionally, adjust padding and rounded corners of your text background. This new feature ensures readability and adds a polished, professional touch to your designs. By elevating text design, your app helps users create visually compelling content that stands out.&lt;/p&gt;
&lt;p&gt;Try customizing text in our &lt;a href=&quot;https://img.ly/showcases/cesdk/default-ui/web?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;Demo&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;upcoming&quot;&gt;Upcoming&lt;/h2&gt;
&lt;p&gt;Our next release is right around the corner, which includes &lt;strong&gt;React Native &amp;#x26; Expo&lt;/strong&gt; Support. Get ready for more upcoming tools and even better developer experience:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reimagining Our Documentation&lt;/strong&gt;&lt;br&gt;
We’re revamping our documentation to deliver a superior developer experience. With improved structure, searchability and an AI-friendly design, our new docs will cater to both developers and their AI tools of choice. Our documentation will be further optimized for clarity, structure, and accessibility, making navigation, integration and creation easier than ever.&lt;/p&gt;
&lt;p&gt;View the complete &lt;a href=&quot;https://img.ly/docs/cesdk/changelog/#v1390--november-12th-2024&quot;&gt;Changelog&lt;/a&gt;. Thanks for reading!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Over 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/2024/12/camera-sdk-android-ios-imgly.jpg" medium="image"/><category>Release Notes</category><category>CE.SDK</category><category>Android App Development</category></item><item><title>CE.SDK Video Editor Now Available on Android</title><link>https://img.ly/blog/ce-sdk-video-editor-now-available-on-android/</link><guid isPermaLink="true">https://img.ly/blog/ce-sdk-video-editor-now-available-on-android/</guid><description>Integrate a fully-customizable Video Editor into your Android App with CE.SDK.</description><pubDate>Tue, 22 Oct 2024 11:44:02 GMT</pubDate><content:encoded>&lt;p&gt;We are excited to announce the release of CE.SDK’s video editing and video content creation tools for Android!&lt;/p&gt;
&lt;p&gt;After the successful iOS launch, CE.SDK’s professional video editing capabilities are now available for Android. Whether your app focuses on social media, e-commerce, or marketing technology, CE.SDK enables users to create high-quality videos directly within your app.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-36/uncompressed/Android-crop-split-trim.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;h2 id=&quot;getting-started&quot;&gt;Getting Started&lt;/h2&gt;
&lt;p&gt;Getting up and running with an instance of the CE.SDK video editor for Android is easy.&lt;/p&gt;
&lt;p&gt;After downloading your license (get your trial license here) from your dashboard, simply &lt;a href=&quot;https://img.ly/docs/cesdk/android/prebuilt-solutions/video-editor-9e533a/&quot;&gt;invoke &lt;code&gt;VideoEditor&lt;/code&gt; as composable function, Activity or Fragment.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;our-video-editing-backstory&quot;&gt;Our Video Editing Backstory&lt;/h2&gt;
&lt;p&gt;Since we launched VideoEditor SDK almost ten years ago, we have seen an astounding range of creative and unique use cases of our SDK in customer projects. From Cameo connecting celebrities and their fans in new ways, over Multibrain supercharging their users marketing campaigns with editable video content, to &lt;a href=&quot;https://zigazoo.com/&quot;&gt;Zigazoo&lt;/a&gt; powering video content within their social network for kids while putting safety and parental control first.&lt;/p&gt;
&lt;p&gt;Since then, millions of users have experienced IMG.LY’s VideoEditor SDK through our customers’ products, shaping how they expect to interact with and modify videos. Continuous feedback from both our customers and their users has also influenced the way we approach video interface design, helping us refine and innovate along the way.&lt;/p&gt;
&lt;p&gt;Our goal was to combine the reliability and robustness of the VideoEditor SDK with true cross-platform compatibility and the flexibility to meet diverse needs. By applying the lessons we’ve learned, we aimed to deliver an exceptional video editing user experience straight out of the box. We described how those learnings shaped the &lt;a href=&quot;https://img.ly/blog/designing-a-timeline-for-mobile-video-editing/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=androidvideo&quot;&gt;design of the mobile video editing interface.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;key-capabilities&quot;&gt;Key Capabilities&lt;/h2&gt;
&lt;p&gt;With CE.SDK’s sleek timeline interface, your Android users can now take their video editing from simple transforms and adjustments to complex composition and multi-track editing:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Timeline-Based Editing&lt;/strong&gt;&lt;br&gt;
Split, trim, arrange video and audio tracks. Position elements such as images and stickers on the timeline and control their duration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Multi-Track Editing&lt;/strong&gt;&lt;br&gt;
Work with multiple video and audio tracks, allowing for complex composition.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Transform &amp;#x26; Enhance&lt;/strong&gt;&lt;br&gt;
Crop, flip, rotate, and use presets for common video formats. Add filters, effects, blur and essential adjustments.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Customizable Templates&lt;/strong&gt;&lt;br&gt;
Create and import templates using our web video editor, to jumpstart your users’ video composition and designs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Asset Integration&lt;/strong&gt;&lt;br&gt;
Integrate your own asset libraries for audio tracks, sound effects, images, and more.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cross-platform Interoperability&lt;/strong&gt;&lt;br&gt;
CE.SDK’s video capabilities extends across iOS, Android and the Web, enabling cross-platform applications to offer seamless video editing capabilities. Users can edit and save work in progress and pick up on any device.&lt;/p&gt;
&lt;p&gt;Check out the &lt;a href=&quot;https://img.ly/showcases/cesdk/video-ui/android?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=androidvideo&quot;&gt;showcase app for an interactive demo&lt;/a&gt; of these features.&lt;/p&gt;
&lt;h2 id=&quot;customization&quot;&gt;Customization&lt;/h2&gt;
&lt;p&gt;The ability to tailor the video editor to your app’s particular use case has been a front and center concern in its development.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/android/configuration-2c1c3d/&quot;&gt;&lt;strong&gt;UI Customization&lt;/strong&gt;&lt;/a&gt;: While theming is currently limited to &lt;code&gt;dark&lt;/code&gt; and &lt;code&gt;light&lt;/code&gt; model, future releases will introduce more flexible theming, allowing you to modify the look and feel of the editor to match your app’s branding. Furthermore, we expose &lt;strong&gt;callbacks&lt;/strong&gt; that make it possible to hook into editor events and &lt;strong&gt;overlays&lt;/strong&gt; for custom dialogues.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/android/create-video-c41a08/&quot;&gt;&lt;strong&gt;Configure Video Presets&lt;/strong&gt;&lt;/a&gt;: You can configure the editor to create video presets based on your users’ needs. For instance, you may want to fix the video’s aspect ratio or optimize for certain resolutions, depending on the target platform.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/android/use-templates/apply-template-35c73e/&quot;&gt;&lt;strong&gt;Video Templates&lt;/strong&gt;&lt;/a&gt;: With the CE.SDK video editor web UI, you can create an unlimited number of video templates, such as collages, text designs, and animations, providing your users with professional-quality starting points for their video designs.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/android/import-media/asset-panel/customize-c9a4de/&quot;&gt;&lt;strong&gt;Assets&lt;/strong&gt;&lt;/a&gt;: Provide custom filters, fonts, and stickers to enhance the user experience. For niche apps, this can be an excellent way to engage users by offering content that feels unique to your community.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;ideal-for-social-media-ecommerce-and-marketing-tech-apps&quot;&gt;Ideal for Social Media, Ecommerce, and Marketing Tech Apps&lt;/h2&gt;
&lt;p&gt;CE.SDK’s new Android video editing capabilities are perfect for a variety of use cases, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/use-cases/story-reels-short-video-creation&quot;&gt;&lt;strong&gt;Social Media Applications&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;:&lt;/strong&gt; The CE.SDK video editor for Android excels at short-form video, ideal for social media applications, whether your users are publishing to other networks or you run a network yourself.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/industries/e-commerce&quot;&gt;&lt;strong&gt;Ecommerce&lt;/strong&gt;&lt;/a&gt;: Allow your users to create engaging product showcases, ads, and promotional videos, testimonials or reviews.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/industries/marketing-tech&quot;&gt;&lt;strong&gt;Marketing Tech Platforms&lt;/strong&gt;&lt;/a&gt;: Users can leverage our versatile templating to easily create polished social media and marketing graphics from within your app.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;whats-next&quot;&gt;What’s Next?&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Camera UI: Record videos on Android.&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;988&quot; src=&quot;https://img.ly/_astro/camera-UI-Android-1_1FyMRS.webp&quot; srcset=&quot;/_astro/camera-UI-Android-1_ZjEi38.webp 640w, /_astro/camera-UI-Android-1_Z743FA.webp 750w, /_astro/camera-UI-Android-1_ZYwhh4.webp 828w, /_astro/camera-UI-Android-1_8a3zG.webp 1080w, /_astro/camera-UI-Android-1_19mjIs.webp 1280w, /_astro/camera-UI-Android-1_1FyMRS.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;This Android release is just the beginning! We are about to launch a &lt;strong&gt;Camera UI&lt;/strong&gt; for Android and are working on more advanced template creation features. So stay tuned.&lt;br&gt;
To see some of these features in action, check out our iOS demo, where the next phase of innovation is unfolding.&lt;/p&gt;
&lt;h2 id=&quot;get-started&quot;&gt;Get Started&lt;/h2&gt;
&lt;p&gt;Explore our &lt;a href=&quot;https://img.ly/showcases/cesdk/video-ui/android?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=androidvideo&quot;&gt;Video UI Showcase&lt;/a&gt; and &lt;a href=&quot;https://img.ly/docs/cesdk/android/prebuilt-solutions/video-editor-9e533a/&quot;&gt;Documentation for Android&lt;/a&gt; to discover how CE.SDK can streamline your content creation projects and make Android video editing easier than ever.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Over 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&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>Jan</dc:creator><media:content url="https://blog.img.ly/2024/10/android-video-editor-sdk-imgly-creative-editor_s.jpg" medium="image"/><category>Android</category><category>Android App Development</category><category>Creative Editor</category><category>Video Editing</category><category>Video Editor</category></item><item><title>CE.SDK v1.36 Release Notes</title><link>https://img.ly/blog/creative-editor-sdk-v-1-36-0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v-1-36-0-release-notes/</guid><description>Bring Animation to your web application and edit videos on Android.</description><pubDate>Tue, 08 Oct 2024 09:52:59 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 the highly requested Animations for Web and our Video Timeline for Android.&lt;/p&gt;
&lt;p&gt;Let’s dive in!&lt;/p&gt;
&lt;h2 id=&quot;animate-on-the-web&quot;&gt;Animate On The Web&lt;/h2&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-36/uncompressed/animations-sdk-title.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;We’re introducing animation support for our Video Editor for the web. With this update, you can now apply various animations, such as blur, zoom, and slide, to elements directly within the editor.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Animate and Fine-Tune Settings&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-36/uncompressed/fine-tune-animations.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Select a ‘block’ on your canvas — that includes images, videos, text, shapes, and stickers. Then choose from twelve &lt;strong&gt;in-and-out&lt;/strong&gt; animations or nine &lt;strong&gt;loop&lt;/strong&gt; animations. Lastly, fine-tune your selected animation, by tweaking the properties, for custom movement and transition.&lt;/p&gt;
&lt;p&gt;Get started with our animation &lt;a href=&quot;https://img.ly/docs/cesdk/js/animation/overview-6a2ef2/&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;edit-videos-on-android&quot;&gt;Edit Videos on Android&lt;/h2&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-36/uncompressed/Android-crop-split-trim.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;We are proud to launch our video editing and content creation tools for Android, following our tried and tested iOS launch. Get started with a fully customizable UI for video editing:&lt;/p&gt;
&lt;p&gt;Now Android users can crop, split, trim, and compose videos. Add multiple elements—videos, photos, stickers, and more—to a &lt;strong&gt;timeline&lt;/strong&gt; to create engaging content. Editing options like filters, effects, and audio tracks turn it into a one-stop solution for video creation.&lt;/p&gt;
&lt;p&gt;Integrate your custom asset library for stock photos, videos, stickers, and music.&lt;/p&gt;
&lt;p&gt;With customizable video formats, users can create content for specific platforms like Instagram and TikTok. Whether it’s stories or Ultra HD, the canvas auto-adjusts, making it easy to tailor videos for any need.&lt;/p&gt;
&lt;p&gt;Explore our &lt;a href=&quot;https://img.ly/showcases/cesdk/video-ui/android?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;Android Showcase&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;explore-new-showcases&quot;&gt;Explore New Showcases&lt;/h2&gt;
&lt;p&gt;Explore our latest solutions.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://img.ly/showcases/cesdk/photo-editor-ui/web?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;&lt;strong&gt;Photo Editor UI (Web)&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
Integrate and customize a powerful photo editor for your web apps. With background removal, cropping, adjustments, and filters, users can enhance their photos easily.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://img.ly/showcases/cesdk/psd-template-import/web?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;&lt;strong&gt;Photoshop Template Importer&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
Import Photoshop templates into CE.SDK while preserving key design elements like positioning, rotation, images, and text. Bulk importing is also supported for larger projects.&lt;/p&gt;
&lt;h2 id=&quot;upcoming&quot;&gt;Upcoming&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Camera UI for Android&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;988&quot; src=&quot;https://img.ly/_astro/camera-UI-Android_1CM8TJ.webp&quot; srcset=&quot;/_astro/camera-UI-Android_fHrD4.webp 640w, /_astro/camera-UI-Android_XdTJx.webp 750w, /_astro/camera-UI-Android_Z1lzOAb.webp 828w, /_astro/camera-UI-Android_2d2oXa.webp 1080w, /_astro/camera-UI-Android_2k7vEz.webp 1280w, /_astro/camera-UI-Android_1CM8TJ.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;We’re committed to expanding our out-of-the-box solutions for Android, including our upcoming Camera UI. Check out our &lt;a href=&quot;https://img.ly/showcases/cesdk/video-ui/ios?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;iOS demo&lt;/a&gt; to see it already in action. These enhancements will further enrich the content creation experience for your Android users. Stay tuned for more updates.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;React Native Support&lt;/strong&gt;&lt;br&gt;
We’re excited to announce that CE.SDK React Native support is on the way for both iOS and Android. Developers will be able to get started with React Native by integrating our fully customizable editor UIs for video, photo, and design editing, just like in &lt;a href=&quot;https://img.ly/blog/creativeeditor-sdk-now-supports-flutter-mobile/?utm_source=imgly&amp;#x26;utm_medium=releasenotes&quot;&gt;Flutter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Animate Text&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-36/uncompressed/text-ani.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;With the CE.SDK v1.36 animation release, you can already animate entire text blocks. For instance, you can slide in or fade out text. However, to create more intricate animations of letters, we are excited to announce a dedicated text animation release for web soon.&lt;/p&gt;
&lt;p&gt;View the full CE.SDK v1.36 &lt;a href=&quot;https://img.ly/docs/cesdk/changelog/#v1360--september-30th-2024&quot;&gt;Changelog&lt;/a&gt;. Thanks for reading! We are happy 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;support you&lt;/a&gt; with any questions you have.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Over 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&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/2024/10/creative-editor-sdk-1-36-1.jpg" medium="image"/><category>Release Notes</category><category>Creative Editing</category><category>Animation</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>Elegant Event Handling in Kotlin - A Refactoring Walkthrough</title><link>https://img.ly/blog/kotlin-code-refactoring-for-peak-performance/</link><guid isPermaLink="true">https://img.ly/blog/kotlin-code-refactoring-for-peak-performance/</guid><description>Unlock peak performance in Kotlin code with these expert refactoring tips.</description><pubDate>Fri, 29 Sep 2023 07:00:53 GMT</pubDate><content:encoded>&lt;p&gt;In the world of software development, code refactoring is the hero that rescues us from tangled and inefficient code. In this article, we’ll embark on an adventure to revamp Kotlin code handling diverse events. Our mission? To enhance performance and style, making the code sleeker, more maintainable, and a joy to work with.&lt;/p&gt;
&lt;h2 id=&quot;what-we-aim-to-achieve&quot;&gt;What We Aim to Achieve&lt;/h2&gt;
&lt;p&gt;On this journey to transform Kotlin event handling, our goal is to refine our code to be more efficient, readable, and maintainable. We’re introducing a variety of improvements, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Replacing a convoluted &lt;code&gt;when&lt;/code&gt; statement with a &lt;code&gt;HashMap&lt;/code&gt; for lightning-fast (O(1)) performance.&lt;/li&gt;
&lt;li&gt;Infusing syntactic sweetness with inline functions and &lt;a href=&quot;https://kotlinlang.org/docs/inline-functions.html#reified-type-parameters&quot;&gt;reified&lt;/a&gt; type parameters.&lt;/li&gt;
&lt;li&gt;Employing delegated properties for cleaner dependency injection.&lt;/li&gt;
&lt;li&gt;Adhering to the Single Responsibility Principle by enabling multiple specialized event handler functions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;step-1-the-starting-line&quot;&gt;Step 1: The Starting Line&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;sven2244_a_playful_abstract_artwork_that_represents_the_complex_6e9491ff-8203-4ae2-9a5e-52025e4010be.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1856px) 1856px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1856&quot; height=&quot;656&quot; src=&quot;https://img.ly/_astro/2_1H0FvJ.webp&quot; srcset=&quot;/_astro/2_Z2e3gQ7.webp 640w, /_astro/2_2dHdPv.webp 750w, /_astro/2_ZB5tWb.webp 828w, /_astro/2_Z1Ro7yX.webp 1080w, /_astro/2_Qgvw5.webp 1280w, /_astro/2_NDMYj.webp 1668w, /_astro/2_1H0FvJ.webp 1856w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Our adventure begins with a glance at the original code. This codebase manages a variety of block events through a function named &lt;code&gt;handleBlockEvent&lt;/code&gt; and an event handler function called &lt;code&gt;onEvent&lt;/code&gt;. Let’s unveil the original code:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;open&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; onEvent&lt;/span&gt;&lt;span&gt;(event: &lt;/span&gt;&lt;span&gt;Event&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;    handleBlockEvent&lt;/span&gt;&lt;span&gt;(engine, &lt;/span&gt;&lt;span&gt;getBlockForEvents&lt;/span&gt;&lt;span&gt;(), &lt;/span&gt;&lt;span&gt;checkNotNull&lt;/span&gt;&lt;span&gt;(assetsRepo.fontFamilies.&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;getOrThrow&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;fun&lt;/span&gt;&lt;span&gt; handleBlockEvent&lt;/span&gt;&lt;span&gt;(engine: &lt;/span&gt;&lt;span&gt;Engine&lt;/span&gt;&lt;span&gt;, block: &lt;/span&gt;&lt;span&gt;DesignBlock&lt;/span&gt;&lt;span&gt;, fontFamilyMap: &lt;/span&gt;&lt;span&gt;Map&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;FontFamilyData&lt;/span&gt;&lt;span&gt;&gt;, event: &lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    when&lt;/span&gt;&lt;span&gt; (event) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        BlockEvent.OnDelete &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; engine.&lt;/span&gt;&lt;span&gt;delete&lt;/span&gt;&lt;span&gt;(block)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        BlockEvent.OnBackward &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; engine.&lt;/span&gt;&lt;span&gt;sendBackward&lt;/span&gt;&lt;span&gt;(block)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        BlockEvent.OnDuplicate &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; engine.&lt;/span&gt;&lt;span&gt;duplicate&lt;/span&gt;&lt;span&gt;(block)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        BlockEvent.OnForward &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; engine.&lt;/span&gt;&lt;span&gt;bringForward&lt;/span&gt;&lt;span&gt;(block)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        BlockEvent.ToBack &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; engine.&lt;/span&gt;&lt;span&gt;sendToBack&lt;/span&gt;&lt;span&gt;(block)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        BlockEvent.ToFront &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; engine.&lt;/span&gt;&lt;span&gt;bringToFront&lt;/span&gt;&lt;span&gt;(block)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        BlockEvent.OnChangeFinish &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; engine.editor.&lt;/span&gt;&lt;span&gt;addUndoStep&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        is&lt;/span&gt;&lt;span&gt; BlockEvent.OnChangeBlendMode &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; onChangeBlendMode&lt;/span&gt;&lt;span&gt;(engine, block, event.blendMode)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        is&lt;/span&gt;&lt;span&gt; BlockEvent.OnChangeOpacity &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;setOpacity&lt;/span&gt;&lt;span&gt;(block, event.opacity)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        is&lt;/span&gt;&lt;span&gt; BlockEvent.OnChangeFillColor &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; onChangeFillColor&lt;/span&gt;&lt;span&gt;(engine, block, event.color)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // and so on...&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;sealed&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt; BlockEvent&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;Event&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    object&lt;/span&gt;&lt;span&gt; OnChangeFinish&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    object&lt;/span&gt;&lt;span&gt; OnForward&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    object&lt;/span&gt;&lt;span&gt; OnBackward&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    object&lt;/span&gt;&lt;span&gt; OnDuplicate&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    object&lt;/span&gt;&lt;span&gt; OnDelete&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    object&lt;/span&gt;&lt;span&gt; ToFront&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    object&lt;/span&gt;&lt;span&gt; ToBack&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    data&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt; OnChangeBlendMode&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; blendMode: &lt;/span&gt;&lt;span&gt;BlendMode&lt;/span&gt;&lt;span&gt;) : &lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    data&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt; OnChangeOpacity&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; opacity: &lt;/span&gt;&lt;span&gt;Float&lt;/span&gt;&lt;span&gt;) : &lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    data&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt; OnChangeFillColor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; color: &lt;/span&gt;&lt;span&gt;Color&lt;/span&gt;&lt;span&gt;) : &lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // and so on...&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;To use the original code, you’d typically call the &lt;code&gt;onEvent&lt;/code&gt; function with a specific event:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;onEvent&lt;/span&gt;&lt;span&gt;(BlockEvent.&lt;/span&gt;&lt;span&gt;OnChangeFillColor&lt;/span&gt;&lt;span&gt;(Color.RED))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This would then trigger the &lt;code&gt;handleBlockEvent&lt;/code&gt; function to deal with the event at hand. Now, let’s embark on our first refactoring adventure.&lt;/p&gt;
&lt;h2 id=&quot;step-2-unveiling-hashmaps-and-payloads-for-peak-performance&quot;&gt;Step 2: Unveiling HashMaps and Payloads for Peak Performance&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;sven2244_an_abstract_image_ofa_futuristic_cityscape_with_neon-l_fbda2c5b-b80f-430b-9f00-609ceecc1292.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1856px) 1856px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1856&quot; height=&quot;656&quot; src=&quot;https://img.ly/_astro/3_ZK0M1r.webp&quot; srcset=&quot;/_astro/3_Z2iStzt.webp 640w, /_astro/3_28R179.webp 750w, /_astro/3_ZFUGFx.webp 828w, /_astro/3_JLxGM.webp 1080w, /_astro/3_Z1AJW16.webp 1280w, /_astro/3_Z1DmExR.webp 1668w, /_astro/3_ZK0M1r.webp 1856w&quot;&gt;&lt;/p&gt;
&lt;p&gt;In our first act of refactoring, we introduce a trusty &lt;code&gt;HashMap&lt;/code&gt; to map each event type to its corresponding action. This heroic move eliminates the need for the convoluted &lt;code&gt;when&lt;/code&gt; statement, making our code more efficient. We also unveil a payload mechanism to convey essential data to the event handlers.&lt;/p&gt;
&lt;p&gt;Behold the refactored code:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;abstract&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt; EventsHandler&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Payloads&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    val&lt;/span&gt;&lt;span&gt; fillPayload: (&lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;Payloads&lt;/span&gt;&lt;span&gt;) -&gt; &lt;/span&gt;&lt;span&gt;Unit&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;    abstract&lt;/span&gt;&lt;span&gt; val&lt;/span&gt;&lt;span&gt; payloadCache: &lt;/span&gt;&lt;span&gt;Payloads&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    private&lt;/span&gt;&lt;span&gt; val&lt;/span&gt;&lt;span&gt; eventMap &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; mutableMapOf&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;KClass&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;out Event&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;, Payloads.(event: &lt;/span&gt;&lt;span&gt;Event&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Unit&lt;/span&gt;&lt;span&gt;&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;    fun&lt;/span&gt;&lt;span&gt; handleEvent&lt;/span&gt;&lt;span&gt;(event: &lt;/span&gt;&lt;span&gt;Event&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        eventMap[event::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;]?.&lt;/span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            it.&lt;/span&gt;&lt;span&gt;invoke&lt;/span&gt;&lt;span&gt;(payloadCache.&lt;/span&gt;&lt;span&gt;also&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;fillPayload&lt;/span&gt;&lt;span&gt;(it) }, event)&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;    operator&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; &amp;#x3C;&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;Event&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(event: &lt;/span&gt;&lt;span&gt;KClass&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span&gt; EventType&lt;/span&gt;&lt;span&gt;&gt;, lambda: &lt;/span&gt;&lt;span&gt;Payloads&lt;/span&gt;&lt;span&gt;.(event: &lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Unit) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        eventMap[event] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; lambda &lt;/span&gt;&lt;span&gt;as&lt;/span&gt;&lt;span&gt; Payloads.(event: &lt;/span&gt;&lt;span&gt;Event&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Unit&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; BlockEventsHandler&lt;/span&gt;&lt;span&gt;(fillPayload: (&lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;BlockEventsHandler&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Payloads&lt;/span&gt;&lt;span&gt;) -&gt; &lt;/span&gt;&lt;span&gt;Unit&lt;/span&gt;&lt;span&gt;) : &lt;/span&gt;&lt;span&gt;EventsHandler&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BlockEventsHandler&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Payloads&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;fillPayload&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    class&lt;/span&gt;&lt;span&gt; Payloads&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        lateinit&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt; engine: &lt;/span&gt;&lt;span&gt;Engine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        lateinit&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt; block: &lt;/span&gt;&lt;span&gt;DesignBlock&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        lateinit&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt; fontFamilyMap: &lt;/span&gt;&lt;span&gt;Map&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;FontFamilyData&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;    override&lt;/span&gt;&lt;span&gt; val&lt;/span&gt;&lt;span&gt; payloadCache: &lt;/span&gt;&lt;span&gt;Payloads&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; Payloads&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;    init&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        it[BlockEvent.OnDelete::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { engine.&lt;/span&gt;&lt;span&gt;delete&lt;/span&gt;&lt;span&gt;(block) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        it[BlockEvent.OnBackward::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { engine.&lt;/span&gt;&lt;span&gt;sendBackward&lt;/span&gt;&lt;span&gt;(block) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        it[BlockEvent.OnDuplicate::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { engine.&lt;/span&gt;&lt;span&gt;duplicate&lt;/span&gt;&lt;span&gt;(block) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        it[BlockEvent.OnForward::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { engine.&lt;/span&gt;&lt;span&gt;bringForward&lt;/span&gt;&lt;span&gt;(block) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        it[BlockEvent.ToBack::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { engine.&lt;/span&gt;&lt;span&gt;sendToBack&lt;/span&gt;&lt;span&gt;(block) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        it[BlockEvent.ToFront::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { engine.&lt;/span&gt;&lt;span&gt;bringToFront&lt;/span&gt;&lt;span&gt;(block) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        it[BlockEvent.OnChangeFinish::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { engine.editor.&lt;/span&gt;&lt;span&gt;addUndoStep&lt;/span&gt;&lt;span&gt;() }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        it[BlockEvent.OnChangeBlendMode::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;onChangeBlendMode&lt;/span&gt;&lt;span&gt;(engine, block, it.blendMode) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        it[BlockEvent.OnChangeOpacity::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { engine.block.&lt;/span&gt;&lt;span&gt;setOpacity&lt;/span&gt;&lt;span&gt;(block, it.opacity) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        it[BlockEvent.OnChangeFillColor::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;onChangeFillColor&lt;/span&gt;&lt;span&gt;(engine, block, it.color) }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // and so on...&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;private&lt;/span&gt;&lt;span&gt; val&lt;/span&gt;&lt;span&gt; blockEventHandler &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; BlockEventsHandler&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    it.engine &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; engine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    it.block &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; getBlockForEvents&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    it.fontFamilyMap &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; checkNotNull&lt;/span&gt;&lt;span&gt;(assetsRepo.fontFamilies.&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;getOrThrow&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;open&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; onEvent&lt;/span&gt;&lt;span&gt;(event: &lt;/span&gt;&lt;span&gt;Event&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;    blockEventHandler.&lt;/span&gt;&lt;span&gt;handleEvent&lt;/span&gt;&lt;span&gt;(event)&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;a-performance-boost&quot;&gt;A Performance Boost&lt;/h3&gt;
&lt;p&gt;By harnessing the power of a &lt;code&gt;HashMap&lt;/code&gt;, we’ve turbocharged our event handling. The time complexity for handling an event is now a lightning-fast (O(1)), a monumental improvement over the (O(n)) time complexity of the ponderous &lt;code&gt;when&lt;/code&gt; statement. While our payload mechanism adds a dollop of syntactic sugar. It enables us to bundle all the necessary data into a single object, making our code more legible and maintainable.&lt;/p&gt;
&lt;p&gt;? Note: Using a HashMap instead of a large when() statement provides a significant performance improvement. It can be up to 40 to 150 times faster. However, explaining the details would exceed the scope of this blog post. Therefore, I will cover it, along with other Kotlin performance puzzles, in a future blog post.&lt;/p&gt;
&lt;p&gt;While the refactored code remains as simple as before:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;onEvent&lt;/span&gt;&lt;span&gt;(BlockEvent.&lt;/span&gt;&lt;span&gt;OnChangeFillColor&lt;/span&gt;&lt;span&gt;(Color.RED))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This still triggers the &lt;code&gt;handleEvent&lt;/code&gt; method in &lt;code&gt;BlockEventsHandler&lt;/code&gt;, which in turn performs the appropriate action based on the event type. The &lt;code&gt;BlockEvent&lt;/code&gt; itself is a data object containing all event details, and it serves as the lambda parameter.&lt;/p&gt;
&lt;h3 id=&quot;a-note-on-payloads&quot;&gt;A Note on Payloads&lt;/h3&gt;
&lt;p&gt;The payload creation is a dynamic lambda function that’s executed each time an event is handled. This ensures that all variables not part of the event are consistently up-to-date. Given that we’re dealing with a single thread per event handler, caching the payload is entirely secure.&lt;/p&gt;
&lt;h2 id=&quot;step-3-adding-syntactic-sweetness-with-infix-functions&quot;&gt;Step 3: Adding Syntactic Sweetness with Infix Functions&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;sven2244_an_abstract_composition_resembling_a_candy_store_fille_894e8c68-0a37-4ad0-adc8-c313db1c29da.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1856px) 1856px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1856&quot; height=&quot;656&quot; src=&quot;https://img.ly/_astro/4_1R9Sfj.webp&quot; srcset=&quot;/_astro/4_Z2nIGiP.webp 640w, /_astro/4_241NnM.webp 750w, /_astro/4_ZKKToT.webp 828w, /_astro/4_Z1HeTPo.webp 1080w, /_astro/4_11pIfE.webp 1280w, /_astro/4_XN0HS.webp 1668w, /_astro/4_1R9Sfj.webp 1856w&quot;&gt;&lt;/p&gt;
&lt;p&gt;In our next act, we elevate our syntax to a new level of expressiveness and readability. We introduce an infix function called &lt;code&gt;to&lt;/code&gt;, allowing us to map an event class to its corresponding action elegantly.&lt;/p&gt;
&lt;p&gt;Witness the updated code:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;abstract&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt; EventsHandler&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Payloads&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    val&lt;/span&gt;&lt;span&gt; fillPayload: (&lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;Payloads&lt;/span&gt;&lt;span&gt;) -&gt; &lt;/span&gt;&lt;span&gt;Unit&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;    infix&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; &amp;#x3C;&lt;/span&gt;&lt;span&gt;Payloads&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;Event&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;KClass&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;out EventType&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;to&lt;/span&gt;&lt;span&gt;(lambda: &lt;/span&gt;&lt;span&gt;Payloads&lt;/span&gt;&lt;span&gt;.(event: &lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Unit) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        eventMap[event] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; lambda &lt;/span&gt;&lt;span&gt;as&lt;/span&gt;&lt;span&gt; Payloads.(event: &lt;/span&gt;&lt;span&gt;Event&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Unit&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;    // ... (rest of the code remains the same)&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; BlockEventsHandler&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    manager: &lt;/span&gt;&lt;span&gt;EventsManager&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    override&lt;/span&gt;&lt;span&gt; val&lt;/span&gt;&lt;span&gt; fillPayload: (&lt;/span&gt;&lt;span&gt;cache&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;TextBlockEventsHandler&lt;/span&gt;&lt;span&gt;) -&gt; &lt;/span&gt;&lt;span&gt;Unit&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;) : &lt;/span&gt;&lt;span&gt;EventsHandler&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;TextBlockEventsHandler&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;manager&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    lateinit&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt; engine: &lt;/span&gt;&lt;span&gt;Engine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    lateinit&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt; block: &lt;/span&gt;&lt;span&gt;DesignBlock&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    lateinit&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt; fontFamilyMap: &lt;/span&gt;&lt;span&gt;Map&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;FontFamilyData&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 class=&quot;line&quot;&gt;&lt;span&gt;    init&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        BlockEvent.OnDelete::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            engine.&lt;/span&gt;&lt;span&gt;delete&lt;/span&gt;&lt;span&gt;(block)&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;        BlockEvent.OnBackward::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            engine.&lt;/span&gt;&lt;span&gt;sendBackward&lt;/span&gt;&lt;span&gt;(block)&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;        BlockEvent.OnDuplicate::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            engine.&lt;/span&gt;&lt;span&gt;duplicate&lt;/span&gt;&lt;span&gt;(block)&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;        BlockEvent.OnForward::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            engine.&lt;/span&gt;&lt;span&gt;bringForward&lt;/span&gt;&lt;span&gt;(block)&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;        BlockEvent.ToBack::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            engine.&lt;/span&gt;&lt;span&gt;sendToBack&lt;/span&gt;&lt;span&gt;(block)&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;        BlockEvent.ToFront::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            engine.&lt;/span&gt;&lt;span&gt;bringToFront&lt;/span&gt;&lt;span&gt;(block)&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;        BlockEvent.OnChangeFinish::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            engine.editor.&lt;/span&gt;&lt;span&gt;addUndoStep&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;        BlockEvent.OnChangeBlendMode::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            onChangeBlendMode&lt;/span&gt;&lt;span&gt;(engine, block, it.blendMode)&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;        BlockEvent.OnChangeOpacity::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            engine.block.&lt;/span&gt;&lt;span&gt;setOpacity&lt;/span&gt;&lt;span&gt;(block, it.opacity)&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;        BlockEvent.OnChangeFillColor::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            onChangeFillColor&lt;/span&gt;&lt;span&gt;(engine, block, it.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 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;syntactic-sweetness-and-performance&quot;&gt;Syntactic Sweetness and Performance&lt;/h3&gt;
&lt;p&gt;The introduction of the &lt;code&gt;to&lt;/code&gt; infix function adds a sprinkle of syntactic sweetness that enhances code expressiveness and enables a more natural usage. This makes it crystal clear what each event is all about. And fear not, the performance remains at a blazing-fast (O(1)), thanks to our trusty HashMap.&lt;/p&gt;
&lt;h3 id=&quot;flexibility-in-syntax&quot;&gt;Flexibility in Syntax&lt;/h3&gt;
&lt;p&gt;While the &lt;code&gt;to&lt;/code&gt; keyword is used here, feel free to substitute it with other terms like &lt;code&gt;handle&lt;/code&gt;, &lt;code&gt;trigger&lt;/code&gt;, or anything that best suits your context. Flexibility is the name of the game.&lt;/p&gt;
&lt;h2 id=&quot;step-4-embracing-inline-functions-for-elegance&quot;&gt;Step 4: Embracing Inline Functions for Elegance&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;sven2244_a_mesmerizing_image_of_a_kaleidoscope_with_vibrant_pat_b53a7e30-820a-4308-a7aa-11222be8a7a1.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1856px) 1856px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1856&quot; height=&quot;656&quot; src=&quot;https://img.ly/_astro/5_ZzQzhR.webp&quot; srcset=&quot;/_astro/5_Z2syT2c.webp 640w, /_astro/5_1YbAEq.webp 750w, /_astro/5_ZPB78g.webp 828w, /_astro/5_TUKqm.webp 1080w, /_astro/5_Z1qAJhw.webp 1280w, /_astro/5_Z1tdrOi.webp 1668w, /_astro/5_ZzQzhR.webp 1856w&quot;&gt;&lt;/p&gt;
&lt;p&gt;However, this is still not perfect because the &lt;code&gt;::class&lt;/code&gt; breaks smooth reading.&lt;/p&gt;
&lt;p&gt;So let’s do it differently. Let us try to introduce a more elegant way to register an event. Let us eliminate the need to specify &lt;code&gt;::class&lt;/code&gt; every time we register an event handler will make our code more concise and readable.&lt;/p&gt;
&lt;p&gt;This is made possible by an inline function with a verified type parameter that maintains the class reference at runtime.&lt;/p&gt;
&lt;p&gt;To do this, we extend the &lt;code&gt;EventsHandler&lt;/code&gt; class with this new &lt;code&gt;register&lt;/code&gt; function:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; EventsHandler&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    register: &lt;/span&gt;&lt;span&gt;EventsHandler&lt;/span&gt;&lt;span&gt;.() &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Unit,&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;    inline&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; &amp;#x3C;&lt;/span&gt;&lt;span&gt;reified&lt;/span&gt;&lt;span&gt; EventType&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;BaseEvent&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;register&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;noinline&lt;/span&gt;&lt;span&gt; lambda: (&lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;) -&gt; &lt;/span&gt;&lt;span&gt;Unit&lt;/span&gt;&lt;span&gt;) : &lt;/span&gt;&lt;span&gt;Any&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        this&lt;/span&gt;&lt;span&gt;[EventType::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; lambda&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        return&lt;/span&gt;&lt;span&gt; lambda&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;   // ... (rest of the code remains the same)&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;the-new-syntax&quot;&gt;The New Syntax&lt;/h3&gt;
&lt;p&gt;This is what registering an event handler looks like with the new syntax:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;register&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;OnChangeLineWidth&lt;/span&gt;&lt;span&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    engine.block.&lt;/span&gt;&lt;span&gt;setWidth&lt;/span&gt;&lt;span&gt;(block, engine.block.&lt;/span&gt;&lt;span&gt;getFrameWidth&lt;/span&gt;&lt;span&gt;(block))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    engine.block.&lt;/span&gt;&lt;span&gt;setHeight&lt;/span&gt;&lt;span&gt;(block, it.width)&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;Much better, right? The new syntax is more concise, eliminates redundancy, and is type-safe because the reified type parameters ensure that the event type is known at compile-time and runtime, eliminating the need for unsafe casting.&lt;/p&gt;
&lt;h2 id=&quot;step-5-elevating-register-to-an-extension-function-for-highlighting&quot;&gt;Step 5: Elevating &lt;code&gt;register&lt;/code&gt; to an Extension Function for Highlighting&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;highlighting.jpg&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;700&quot; src=&quot;https://img.ly/_astro/6-1_ZpUYI8.webp&quot; srcset=&quot;/_astro/6-1_1WCnM8.webp 640w, /_astro/6-1_Z2lJRV7.webp 750w, /_astro/6-1_1HMAQd.webp 828w, /_astro/6-1_ZlU4Yo.webp 1080w, /_astro/6-1_Z2ruRRK.webp 1280w, /_astro/6-1_Z29YNlp.webp 1668w, /_astro/6-1_ZpUYI8.webp 2000w&quot;&gt;&lt;/p&gt;
&lt;p&gt;To improve code readability, we’ll make a subtle but effective step by converting the &lt;code&gt;register&lt;/code&gt; function from a &lt;code&gt;EventsHandler&lt;/code&gt; class function, into an &lt;code&gt;EventsHandler&lt;/code&gt; extension function.&lt;/p&gt;
&lt;p&gt;Sounds stupid! So why?&lt;/p&gt;
&lt;p&gt;This small change improves code readability by highlighting the &lt;code&gt;register&lt;/code&gt; keyword through syntax highlighting from a Kotlin extension function. This will make it much more colorful, which improves readability.&lt;/p&gt;
&lt;h3 id=&quot;updated-eventshandler-class&quot;&gt;Updated &lt;code&gt;EventsHandler&lt;/code&gt; Class&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;EventsHandler&lt;/code&gt; class remains largely unchanged, but the &lt;code&gt;register&lt;/code&gt; function is now outside the class and transformed into an extension function for the &lt;code&gt;EventsHandler&lt;/code&gt; class:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; EventsHandler&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    register: &lt;/span&gt;&lt;span&gt;EventsHandler&lt;/span&gt;&lt;span&gt;.() &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Unit,&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;    // ... (rest of the code remains the same)&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;inline&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; &amp;#x3C;&lt;/span&gt;&lt;span&gt;reified&lt;/span&gt;&lt;span&gt; EventType&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;BaseEvent&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;EventsHandler&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;register&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;noinline&lt;/span&gt;&lt;span&gt; lambda: (&lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;) -&gt; &lt;/span&gt;&lt;span&gt;Unit&lt;/span&gt;&lt;span&gt;) : &lt;/span&gt;&lt;span&gt;Any&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    this&lt;/span&gt;&lt;span&gt;[EventType::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; lambda&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; lambda&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;By simply shifting &lt;code&gt;register&lt;/code&gt; out of the class, the &lt;code&gt;EventsHandler&lt;/code&gt; class definition now stands out with distinctive syntax highlighting. It’s a clever trick that doesn’t impact runtime or compile performance, since it’s an inline operation anyway.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;**&lt;/span&gt;&lt;span&gt;register&lt;/span&gt;&lt;span&gt;**&amp;#x3C;&lt;/span&gt;&lt;span&gt;BlockEvent.OnChangeLineWidth&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    engine.block.&lt;/span&gt;&lt;span&gt;setWidth&lt;/span&gt;&lt;span&gt;(block, engine.block.&lt;/span&gt;&lt;span&gt;getFrameWidth&lt;/span&gt;&lt;span&gt;(block))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    engine.block.&lt;/span&gt;&lt;span&gt;setHeight&lt;/span&gt;&lt;span&gt;(block, it.width)&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;step-6-eliminating-lateinit-variables-with-delegated-properties&quot;&gt;Step 6: Eliminating &lt;code&gt;lateinit&lt;/code&gt; Variables with Delegated Properties&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;sven2244_an_abstract_image_of_interconnected_gears_and_cogs_for_3b651ffc-9367-470d-8be3-82c3c19b9ffe.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1856px) 1856px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1856&quot; height=&quot;656&quot; src=&quot;https://img.ly/_astro/7_ZpHmyi.webp&quot; srcset=&quot;/_astro/7_2rVOk1.webp 640w, /_astro/7_1OvbcH.webp 750w, /_astro/7_Z10hwzY.webp 828w, /_astro/7_154X9V.webp 1080w, /_astro/7_Z1grwxW.webp 1280w, /_astro/7_Z1j4f5I.webp 1668w, /_astro/7_ZpHmyi.webp 1856w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Now, it’s time to address the enigmatic &lt;code&gt;lateinit&lt;/code&gt; variables and the somewhat convoluted &lt;code&gt;fillPayload&lt;/code&gt; mechanism. Let us introduce a cleaner approach, using delegated properties and lambda functions to inject dependencies.&lt;/p&gt;
&lt;p&gt;Let’s add an &lt;code&gt;Inject&lt;/code&gt; class to wrap a normal lambda as delegable:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; Inject&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Type&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; val&lt;/span&gt;&lt;span&gt; inject: () &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Type) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    operator&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; getValue&lt;/span&gt;&lt;span&gt;(thisRef: &lt;/span&gt;&lt;span&gt;Any&lt;/span&gt;&lt;span&gt;?, property: &lt;/span&gt;&lt;span&gt;KProperty&lt;/span&gt;&lt;span&gt;&amp;#x3C;*&gt;): &lt;/span&gt;&lt;span&gt;Type&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; inject&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this newfound power, our event handler code becomes cleaner and more intuitive. It takes on the style of Jetpack Compose’s declarative syntax:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;fun&lt;/span&gt;&lt;span&gt; EventsHandler&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;textBlockEvents&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    engine: () &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Engine,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    block: () &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; DesignBlock,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    fontFamilyMap: () &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Map&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;String, FontFamilyData&lt;/span&gt;&lt;span&gt;&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;    // Inject the dependencies&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    val&lt;/span&gt;&lt;span&gt; engine &lt;/span&gt;&lt;span&gt;by&lt;/span&gt;&lt;span&gt; Inject&lt;/span&gt;&lt;span&gt;(engine)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    val&lt;/span&gt;&lt;span&gt; block &lt;/span&gt;&lt;span&gt;by&lt;/span&gt;&lt;span&gt; Inject&lt;/span&gt;&lt;span&gt;(block)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    val&lt;/span&gt;&lt;span&gt; fontFamilyMap &lt;/span&gt;&lt;span&gt;by&lt;/span&gt;&lt;span&gt; Inject&lt;/span&gt;&lt;span&gt;(fontFamilyMap)&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;    // Event handling logic here&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;Whenever one of the variables is accessed, the lambda is called, and you always get the current variable.&lt;/p&gt;
&lt;p&gt;Also, the creation of the “payload” becomes more straightforward, clean, and type-safe. It kinda looks like passing a variable:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; val&lt;/span&gt;&lt;span&gt; eventHandler &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; EventsHandler&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    textBlockEvents&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        engine &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ::&lt;/span&gt;&lt;span&gt;engine&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        block &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ::&lt;/span&gt;&lt;span&gt;getBlockForEvents&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        fontFamilyMap &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;checkNotNull&lt;/span&gt;&lt;span&gt;(assetsRepo.fontFamilies.&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;getOrThrow&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;Looks and feels like magic! Pretty cool, right?&lt;/p&gt;
&lt;h2 id=&quot;step-7-multiple-event-handlers-for-single-responsibility-principle&quot;&gt;Step 7: Multiple Event Handlers for Single Responsibility Principle&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;sven2244_code_as_a_magical_candy-filled_wonderland._Syntax_Suga_a50bcd92-bea2-4fea-aa92-e1cd557277b6.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1856px) 1856px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1856&quot; height=&quot;656&quot; src=&quot;https://img.ly/_astro/8_2csiHs.webp&quot; srcset=&quot;/_astro/8_2n6BAE.webp 640w, /_astro/8_1JEXtl.webp 750w, /_astro/8_Z157Jjl.webp 828w, /_astro/8_Z1mVunf.webp 1080w, /_astro/8_1lI8HN.webp 1280w, /_astro/8_1j6qb2.webp 1668w, /_astro/8_2csiHs.webp 1856w&quot;&gt;&lt;/p&gt;
&lt;p&gt;In our grand finale, we harness the newfound flexibility from our previous changes to register multiple event handler functions. Each event handler registration function now has a specific topic, aligning perfectly with the Single Responsibility Principle (SRP).&lt;/p&gt;
&lt;h3 id=&quot;enhanced-event-handler-registration&quot;&gt;Enhanced Event Handler Registration&lt;/h3&gt;
&lt;p&gt;We can now register multiple event handler functions within the same &lt;code&gt;EventsHandler&lt;/code&gt; instance. Each function can specialize in handling a particular type of event, making the code more modular and manageable. Behold the grand design:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; val&lt;/span&gt;&lt;span&gt; eventHandler &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; EventsHandler&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    cropEvents&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        engine &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ::&lt;/span&gt;&lt;span&gt;engine&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        block &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ::&lt;/span&gt;&lt;span&gt;getBlockForEvents&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;    blockEvents&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        engine &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ::&lt;/span&gt;&lt;span&gt;engine&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        block &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ::&lt;/span&gt;&lt;span&gt;getBlockForEvents&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;    textBlockEvents&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        engine &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ::&lt;/span&gt;&lt;span&gt;engine&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        block &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ::&lt;/span&gt;&lt;span&gt;getBlockForEvents&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        fontFamilyMap &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;checkNotNull&lt;/span&gt;&lt;span&gt;(assetsRepo.fontFamilies.&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;getOrThrow&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;fun&lt;/span&gt;&lt;span&gt; EventsHandler&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;blockEvents&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    engine: () &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Engine,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    block: () &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; DesignBlock&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;    val&lt;/span&gt;&lt;span&gt; engine: &lt;/span&gt;&lt;span&gt;Engine&lt;/span&gt;&lt;span&gt; by&lt;/span&gt;&lt;span&gt; Inject&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;engine&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    val&lt;/span&gt;&lt;span&gt; block: &lt;/span&gt;&lt;span&gt;DesignBlock&lt;/span&gt;&lt;span&gt; by&lt;/span&gt;&lt;span&gt; Inject&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;block&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;    register&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;OnDelete&lt;/span&gt;&lt;span&gt;&gt; { engine.&lt;/span&gt;&lt;span&gt;delete&lt;/span&gt;&lt;span&gt;(block) }&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;    register&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;OnBackward&lt;/span&gt;&lt;span&gt;&gt; { engine.&lt;/span&gt;&lt;span&gt;sendBackward&lt;/span&gt;&lt;span&gt;(block) }&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;    register&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;OnDuplicate&lt;/span&gt;&lt;span&gt;&gt; { engine.&lt;/span&gt;&lt;span&gt;duplicate&lt;/span&gt;&lt;span&gt;(block) }&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;    register&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;OnForward&lt;/span&gt;&lt;span&gt;&gt; { engine.&lt;/span&gt;&lt;span&gt;bringForward&lt;/span&gt;&lt;span&gt;(block) }&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;    register&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ToBack&lt;/span&gt;&lt;span&gt;&gt; { engine.&lt;/span&gt;&lt;span&gt;sendToBack&lt;/span&gt;&lt;span&gt;(block) }&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;    register&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ToFront&lt;/span&gt;&lt;span&gt;&gt; { engine.&lt;/span&gt;&lt;span&gt;bringToFront&lt;/span&gt;&lt;span&gt;(block) }&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;    register&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;OnChangeFinish&lt;/span&gt;&lt;span&gt;&gt; { engine.editor.&lt;/span&gt;&lt;span&gt;addUndoStep&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;    register&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;OnChangeBlendMode&lt;/span&gt;&lt;span&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        if&lt;/span&gt;&lt;span&gt; (engine.block.&lt;/span&gt;&lt;span&gt;getBlendMode&lt;/span&gt;&lt;span&gt;(block) &lt;/span&gt;&lt;span&gt;!=&lt;/span&gt;&lt;span&gt; it.blendMode) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            engine.block.&lt;/span&gt;&lt;span&gt;setBlendMode&lt;/span&gt;&lt;span&gt;(block, it.blendMode)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            engine.editor.&lt;/span&gt;&lt;span&gt;addUndoStep&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;    register&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BlockEvent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;OnChangeOpacity&lt;/span&gt;&lt;span&gt;&gt; { engine.block.&lt;/span&gt;&lt;span&gt;setOpacity&lt;/span&gt;&lt;span&gt;(block, it.opacity) }&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;fun&lt;/span&gt;&lt;span&gt; EventsHandler&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cropEvents&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    engine: () &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Engine,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    block: () &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; DesignBlock&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;    val&lt;/span&gt;&lt;span&gt; engine: &lt;/span&gt;&lt;span&gt;Engine&lt;/span&gt;&lt;span&gt; by&lt;/span&gt;&lt;span&gt; Inject&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;engine&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    val&lt;/span&gt;&lt;span&gt; block: &lt;/span&gt;&lt;span&gt;DesignBlock&lt;/span&gt;&lt;span&gt; by&lt;/span&gt;&lt;span&gt; Inject&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;block&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // ... (event handling logic for cropping events)&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;fun&lt;/span&gt;&lt;span&gt; EventsHandler&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;textBlockEvents&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    engine: () &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Engine,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    block: () &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; DesignBlock,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    fontFamilyMap: () &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Map&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;String, FontFamilyData&lt;/span&gt;&lt;span&gt;&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;    val&lt;/span&gt;&lt;span&gt; engine &lt;/span&gt;&lt;span&gt;by&lt;/span&gt;&lt;span&gt; Inject&lt;/span&gt;&lt;span&gt;(engine)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    val&lt;/span&gt;&lt;span&gt; block &lt;/span&gt;&lt;span&gt;by&lt;/span&gt;&lt;span&gt; Inject&lt;/span&gt;&lt;span&gt;(block)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    val&lt;/span&gt;&lt;span&gt; fontFamilyMap &lt;/span&gt;&lt;span&gt;by&lt;/span&gt;&lt;span&gt; Inject&lt;/span&gt;&lt;span&gt;(fontFamilyMap)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // ... (event handling logic for text block events)&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;While the triggering and its API remain unchanged, and no extra parameters need to be passed:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;open&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; onEvent&lt;/span&gt;&lt;span&gt;(event: &lt;/span&gt;&lt;span&gt;Event&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    eventHandler.&lt;/span&gt;&lt;span&gt;handleEvent&lt;/span&gt;&lt;span&gt;(event)&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;final-words&quot;&gt;Final Words&lt;/h2&gt;
&lt;p&gt;As we conclude our journey through Kotlin code refactoring, we’ve unlocked the secrets to enhanced performance and style. By embracing techniques such as HashMaps, infix functions, and inline functions with reified type parameters, we’ve elevated our code to new heights. The benefits are clear: improved efficiency, readability, and adherence to the Single Responsibility Principle. Armed with these tools, you’re now ready to embark on your own coding adventures, transforming messy code into elegant masterpieces.&lt;/p&gt;
&lt;p&gt;If you’d like to try it out, I’ve created a working &lt;a href=&quot;https://pl.kotl.in/tEDorvc04&quot;&gt;example code on the Kotlin Playground&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thank you for accompanying, and happy coding!&lt;/strong&gt; &lt;strong&gt;Never miss out on updates and &lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i&quot;&gt;subscribe&lt;/a&gt; to our newsletter.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Sven</dc:creator><media:content url="https://blog.img.ly/2023/09/hero_01.jpg" medium="image"/><category>How-To</category><category>Android</category><category>Android App Development</category><category>Kotlin</category><category>Insights</category></item><item><title>CE.SDK v1.15 Release Notes</title><link>https://img.ly/blog/creative-editor-sdk-v_1_15_0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v_1_15_0-release-notes/</guid><description>Generate cutout lines from selections, edit across all screen sizes, and more! </description><pubDate>Tue, 26 Sep 2023 08:14:20 GMT</pubDate><content:encoded>&lt;p&gt;Since &lt;a href=&quot;https://img.ly/blog/creative-editor-sdk-v_1_14_0-release-notes/&quot;&gt;our last release&lt;/a&gt;, we’ve been busy crafting new features and enhancements to empower your creative editing journey. We are thrilled to release CE.SDK v1.15!&lt;/p&gt;
&lt;p&gt;With this release, you can:&lt;/p&gt;
&lt;h2 id=&quot;create-accurate-cutouts-and-vectors&quot;&gt;Create Accurate Cutouts and Vectors&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; All&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/1-15/cutoutlines-generate-from-selection.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Picture this: Your users are deep into a design project, and need to isolate an object from an image. Our latest feature simplifies this process. Whether it’s a logo, text, or a complex shape in an SVG - by clicking “Generate from Selection”, our system precisely detects object contours and effortlessly converts them into cutout lines. This means you can breeze through your design tasks without the hassle of manual tracing.&lt;br&gt;
Learn more about Cutouts in our &lt;a href=&quot;https://img.ly/docs/cesdk/js/stickers-and-shapes/create-cutout-384be3/&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;effortlessly-edit-across-all-screen-sizes&quot;&gt;E&lt;strong&gt;ffortlessly Edit Across All Screen Sizes&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Interfaces:&lt;/strong&gt; 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-15/responsive.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;We’re excited to introduce a suite of responsive UI enhancements that ensure effortless editing on all devices, including smaller screens and mobile devices. Our editor adapts to limited screen space, automatically fits content to avoid cutoffs, hides button labels when space is tight, and ensures panels remain easy to use, even on small screens. Plus, you have complete control over when and where labels appear, allowing you to customize the interface to your liking.&lt;/p&gt;
&lt;h2 id=&quot;improved-android-video--audio-experience&quot;&gt;&lt;strong&gt;Improved Android Video &amp;#x26; Audio Experience&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Interfaces:&lt;/strong&gt; Editor, Engine&lt;br&gt;
&lt;strong&gt;Platforms:&lt;/strong&gt; Android&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Ensure smooth audio and video playback in your Android App.&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/androidplayback_Z103jkD.webp&quot; srcset=&quot;/_astro/androidplayback_wFBav.webp 640w, /_astro/androidplayback_Z1h88WN.webp 750w, /_astro/androidplayback_RQAL1.webp 828w, /_astro/androidplayback_20VRmS.webp 1080w, /_astro/androidplayback_Z229hSl.webp 1280w, /_astro/androidplayback_Z103jkD.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Experience an enhanced video and audio experience on Android with our latest update. With our optimized codec performance, we’ve fine-tuned our tools to ensure your videos and audio play flawlessly. Enjoy &lt;strong&gt;smoother playback&lt;/strong&gt;, especially when navigating through your content. Also, no more delays or interruptions when seeking in your videos or audio files. Now, you can &lt;strong&gt;effortlessly skip to your desired moments&lt;/strong&gt; for uninterrupted enjoyment.&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-15.jpg" medium="image"/><category>Release Notes</category><category>Print</category><category>Web-to-print</category><category>Cutouts</category><category>Android App Development</category><category>Web Application</category><category>Creative Editor</category></item><item><title>CE.SDK v1.10 Release</title><link>https://img.ly/blog/creative-editor-sdk-v_1_10_0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v_1_10_0-release-notes/</guid><description>Elevate your app development game with Android Platform Support, and discover more updates with CE.SDK v.1.10.</description><pubDate>Tue, 14 Mar 2023 15:30:46 GMT</pubDate><content:encoded>&lt;p&gt;We are pleased to announce the latest release of CE.SDK v1.10 and excited to share the newest features and updates with you. For those not yet familiar with our engine, CreativeEditor SDK is a powerful design editor that enables customizable workflows and automations for brands, agencies, and printers, all with just a few lines of code. In this release, we have introduced several new features and updates that are set to elevate the functionality and usability of the SDK, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Android Platform Support, making native Android application development seamless&lt;/li&gt;
&lt;li&gt;Library Improvements, including Create, Update &amp;#x26; Delete for Asset Libraries and Asset Libraries Generalization&lt;/li&gt;
&lt;li&gt;Zoom Improvements, providing greater precision and accuracy when zooming to 100% and fitting specific pages&lt;/li&gt;
&lt;li&gt;Arrange API, simplifying the visual order of items and providing common arrange methods for easier use&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;android-platform-support&quot;&gt;Android Platform Support&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/Android_Platform_Support_rtfB1.webp&quot; srcset=&quot;/_astro/Android_Platform_Support_ZuFl9r.webp 640w, /_astro/Android_Platform_Support_vFF2J.webp 750w, /_astro/Android_Platform_Support_1r0E1d.webp 828w, /_astro/Android_Platform_Support_1YPco7.webp 1080w, /_astro/Android_Platform_Support_Z1jqPoT.webp 1280w, /_astro/Android_Platform_Support_rtfB1.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://img.ly/blog/creative-editor-sdk-v_1_9_0-release-notes/&quot;&gt;Our last release&lt;/a&gt; included iOS Native Support. So now we are thrilled to share that CE.SDK has expanded its capabilities to include full support for developing native Android applications. With this latest feature, you can seamlessly integrate the power and versatility of CE.SDK into your Android app development projects, enhancing the user experience and boosting customer engagement. Our team has worked tirelessly to make it incredibly easy for you to get started, with full Kotlin API support and plenty of integration examples to help you hit the ground running.&lt;/p&gt;
&lt;p&gt;In today’s ever-evolving digital landscape, cross-platform app development has become essential for businesses to stay competitive. By leveraging CE.SDK’s cross-platform capabilities, you can develop and deploy apps across multiple platforms with ease, saving time and resources. This not only increases your reach, but it also allows you to provide a consistent experience to your customers, regardless of their device of choice.&lt;/p&gt;
&lt;p&gt;Whether you’re a seasoned developer or new to the game, our &lt;a href=&quot;https://img.ly/docs/cesdk/android/get-started/overview-e18f40/&quot;&gt;Get Started Guide&lt;/a&gt; will equip you with the knowledge and tools necessary to begin your Android app development journey with CE.SDK.&lt;/p&gt;
&lt;h2 id=&quot;library-improvements&quot;&gt;Library Improvements&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Stay organized: You can create, upload, and delete your uploaded media.&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/Delete-Images-fromuploads_17oW4x.webp&quot; srcset=&quot;/_astro/Delete-Images-fromuploads_Z1AW0En.webp 640w, /_astro/Delete-Images-fromuploads_Z2rKlVh.webp 750w, /_astro/Delete-Images-fromuploads_2vHqrX.webp 828w, /_astro/Delete-Images-fromuploads_2gEBJt.webp 1080w, /_astro/Delete-Images-fromuploads_ZPyhus.webp 1280w, /_astro/Delete-Images-fromuploads_17oW4x.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;create-update-and-delete-for-asset-libraries&quot;&gt;Create, Update and Delete for Asset Libraries&lt;/h3&gt;
&lt;p&gt;To streamline your workflow and save valuable time, we’ve added a much-requested feature that allows you to delete uploaded images directly from inside the asset libraries, giving you greater control and flexibility over your content.&lt;/p&gt;
&lt;p&gt;We have updated our engine so that uploaded assets are no longer automatically tied to scenes.&lt;/p&gt;
&lt;h3 id=&quot;asset-libraries-generalization&quot;&gt;Asset Libraries Generalization&lt;/h3&gt;
&lt;p&gt;We have migrated all our internal and external asset handling to be based on asset sources, eliminating the need to maintain different paths for adding and displaying assets. All visible assets are now queried from asset sources, which can be modified by adding or removing assets from a source. Additionally, we have introduced convenient helpers to create IMG.LY’s default asset sources, which contain assets that you can use to jumpstart your integration.&lt;/p&gt;
&lt;h2 id=&quot;zoom-improvements&quot;&gt;Zoom Improvements&lt;/h2&gt;
&lt;p&gt;Zooming has always been an integral part of editing, and our latest release makes it even more versatile and precise. With our new zoom feature, users can now zoom to fit specific pages, providing greater control and accuracy when editing complex designs. Additionally, zooming to 100% will now automatically adjust the zoom level to match the accurate export pixel size. This means that the size of pages on the screen will match exactly the size of the printed product, ensuring a seamless transition from editing to the final product. With this latest enhancement, CE.SDK is committed to providing businesses, agencies, and printers with a comprehensive and intuitive design editor.&lt;/p&gt;
&lt;h2 id=&quot;arrange-api&quot;&gt;Arrange API&lt;/h2&gt;
&lt;p&gt;We are introducing enhanced functionality for controlling the visual order of items within blocks. Previously, this could only be achieved by manually rearranging the order of the children of a block. With our latest release, we’ve extended the API with new convenience methods that provide common arrange methods for easier use.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thanks for reading! Sign up for our&lt;/strong&gt; &lt;a href=&quot;https://img.us13.list-manage.com/subscribe?u=dc9f652839dbb620d14d6d28d&amp;#x26;id=04a306e4b2&quot;&gt;&lt;strong&gt;Newsletter&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;to receive our latest news straight to your inbox.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Neslihan</dc:creator><media:content url="https://blog.img.ly/2023/03/cesdk1_1-10.jpg" medium="image"/><category>Release Notes</category><category>Android</category><category>Android App Development</category><category>Creative Editor</category></item><item><title>Time-Based Sprites for VE.SDK on iOS and Android</title><link>https://img.ly/blog/time-based-sprites-for-ve-sdk-on-ios-and-android/</link><guid isPermaLink="true">https://img.ly/blog/time-based-sprites-for-ve-sdk-on-ios-and-android/</guid><description>Time-Based Sprites allow basic keyframing by setting the duration of your Text and Stickers in Videos. </description><pubDate>Mon, 05 Sep 2022 07:06:05 GMT</pubDate><content:encoded>&lt;p&gt;We are happy to extend VideoEditor SDK with a highly-requested feature: &lt;strong&gt;Time-Based Sprites&lt;/strong&gt;. This new feature sets the &lt;strong&gt;duration of text&lt;/strong&gt; and &lt;strong&gt;stickers&lt;/strong&gt; in your video timeline. Users may now place fun stickers and text at the right moment, and give their videos a special touch.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/basic-keyframe-video-editing.MP4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;h2 id=&quot;time-based-sprites&quot;&gt;Time-Based Sprites&lt;/h2&gt;
&lt;p&gt;The popular feature known from TikTok and Instagram Reels is now available in VE.SDK: set the starting and end point of your text or sticker. Tap your text or sticker and select &lt;em&gt;Duration&lt;/em&gt; to determine the duration of your asset.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/video-editor-sdk-white-label-edit.MOV&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Unless you have specified a custom set of sticker or text actions, this feature is &lt;strong&gt;enabled by default&lt;/strong&gt; since VE.SDK v10.3.0 for Android and v11.3.0 for iOS. See the official &lt;a href=&quot;https://img.ly/docs/vesdk/ios/guides/trim/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;documentation for iOS&lt;/a&gt; or &lt;a href=&quot;https://img.ly/docs/vesdk/android/guides/trim/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#trim-sprite-duration&quot;&gt;Android&lt;/a&gt; on Time-Based Sprites.&lt;/p&gt;
&lt;h3 id=&quot;why-is-video-important&quot;&gt;Why is Video Important?&lt;/h3&gt;
&lt;p&gt;Video content has become an essential medium for social media, marketing, sales, and support teams. According to marketing &lt;a href=&quot;https://www.wyzowl.com/video-marketing-statistics/&quot;&gt;statistics&lt;/a&gt;, people are watching an average of &lt;strong&gt;19 hours&lt;/strong&gt; of online video per week in 2022. &lt;strong&gt;88%&lt;/strong&gt; of people say that they felt convinced to buy a product or service by watching a brand’s video. The growing trend and preference of consumers are why businesses are shifting their attention toward including videos in their strategies and applications.&lt;/p&gt;
&lt;p&gt;We commit to extending our video editing features to help developers meet the demand, save resources and streamline the process of building great applications. Let us have a look at our &lt;strong&gt;previous VE.SDK releases&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Video Composition&lt;/strong&gt;&lt;br&gt;
Users may seamlessly edit their footage by trimming and adjusting video files with advanced filters. Finally, they can set the correct order of their video sequences to create a single composition.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Audio Support&lt;/strong&gt;&lt;br&gt;
Replace or add sound in videos by loading audio files. Users can trim their audio according to their footage. Developers can provide media libraries for audio and video files. That way, users may access media by choosing from labeled folders, such as genre, theme, or artist names.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Force Trim&lt;/strong&gt;&lt;br&gt;
The VE.SDK trim tool allows users to determine the start and end frame of a video clip and change the duration of their footage. Now you can enforce a &lt;strong&gt;minimum and maximum length&lt;/strong&gt; of videos. Force Trim will come in handy for use cases, such as social media stories and posts popularly limited to bite size 15 or 60 seconds by widely loved apps – see TikTok or Instagram. Adopting a ready-to-use solution like &lt;a href=&quot;https://img.ly/video-sdk/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;VE.SDK&lt;/a&gt; will set you on your path to creating equally beautiful apps.&lt;/p&gt;
&lt;p&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 check out our &lt;a href=&quot;https://photoeditorsdk.us13.list-manage.com/subscribe?u=dc9f652839dbb620d14d6d28d&amp;#x26;id=04a306e4b2&quot;&gt;Newsletter&lt;/a&gt; for more accelerating updates.&lt;/p&gt;</content:encoded><dc:creator>Neslihan</dc:creator><media:content url="https://blog.img.ly/2022/08/video-editor-sdk-duration-trim-stickers-keyframes.png" medium="image"/><category>Release Notes</category><category>VE.SDK</category><category>Android</category><category>Android App Development</category><category>iOS</category><category>iOS App Development</category><category>Video Editing</category><category>Video App</category><category>Keyframe</category><category>Company</category></item><item><title>How To Crop and Trim Videos In Kotlin for Android</title><link>https://img.ly/blog/how-to-crop-and-trim-videos-in-kotlin-for-android/</link><guid isPermaLink="true">https://img.ly/blog/how-to-crop-and-trim-videos-in-kotlin-for-android/</guid><description>In this beginner-friendly tutorial you will learn how to crop and trim videos in Android with FFmpeg.</description><pubDate>Fri, 02 Sep 2022 10:18:21 GMT</pubDate><content:encoded>&lt;p&gt;Cropping and trimming videos is a notoriously difficult task to achieve on Android. One way to implement this functionality is by using FFmpeg a free open-source suite of tools that can perform a wide range of tasks, from video converting to editing. Normally FFmpeg is used from the command line, to use it correctly in Android you have to understand its underlying APIs and how to use them.&lt;/p&gt;
&lt;p&gt;In this tutorial, you will learn how to crop and trim videos in Android by using FFmpeg. Even if you are a beginner you should be able to follow the steps to achieve the desired results.&lt;/p&gt;
&lt;p&gt;I try to summarise the most important basics that you need to know to manipulate videos with FFmpeg. After reading this article you should be able to use it in your own applications. Furthermore, I have developed a sample application and library that can be used to trim and crop videos with an Android device.&lt;/p&gt;
&lt;h2 id=&quot;what-is-ffmpeg&quot;&gt;What is FFmpeg&lt;/h2&gt;
&lt;p&gt;FFmpeg is a great multimedia framework that is able to &lt;strong&gt;mux&lt;/strong&gt;, &lt;strong&gt;demux&lt;/strong&gt;, &lt;strong&gt;decode&lt;/strong&gt;, &lt;strong&gt;encode&lt;/strong&gt;, &lt;strong&gt;transcode&lt;/strong&gt;, &lt;strong&gt;filter&lt;/strong&gt;, &lt;strong&gt;stream&lt;/strong&gt;, &lt;strong&gt;and&lt;/strong&gt; &lt;strong&gt;play&lt;/strong&gt; most media content that exists. FFmpeg supports different tools that can be used to develop an application to manipulate any kind of media to the desired output. You do not have any limitations on what to do with multimedia when using FFmpeg.&lt;/p&gt;
&lt;p&gt;Unfortunately, to use FFmpeg in an Android App using Kotlin you have to compile and build the libraries to use them as a dependency in your project. This process is not straightforward because you have to manually compile a C/C++ library with help of the Android NDK.&lt;/p&gt;
&lt;p&gt;Luckily, many people already have done this and we are able to use their compiled library in our project. However, if you want to compile FFmpeg from scratch you can do this. All necessary information should be available within the &lt;a href=&quot;https://developer.android.com/studio/projects/add-native-code&quot;&gt;android developer documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To show you how we can use FFmpeg in our app I will use a compiled FFmpeg library that can be found &lt;a href=&quot;https://github.com/WritingMinds/ffmpeg-android-java&quot;&gt;here&lt;/a&gt;. To find other FFmpeg libraries you can have a look at the &lt;a href=&quot;https://trac.ffmpeg.org/wiki/CompilationGuide/Android&quot;&gt;official FFmpeg wiki&lt;/a&gt; where several pre-packaged sources are listed.&lt;/p&gt;
&lt;h2 id=&quot;setting-up-the-project&quot;&gt;Setting up the project&lt;/h2&gt;
&lt;p&gt;In order to use the FFmpeg library of WritingMinds (or any other library), we have to follow some simple steps.&lt;/p&gt;
&lt;h3 id=&quot;1-add-dependency-for-the-ffmpeg-library-to-your-app-level-buildgradle&quot;&gt;1. Add dependency for the FFmpeg library to your app-level build.gradle&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;xml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;dependencies {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    implementation fileTree(dir: &apos;libs&apos;, include: [&apos;*.jar&apos;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    implementation &apos;com.writingminds:FFmpegAndroid:0.3.2&apos;&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;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;2-check-if-your-device-supports-the-current-implementation-of-ffmpeg-or-not&quot;&gt;2. Check if your device supports the current implementation of FFmpeg or not&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;fun&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;        val&lt;/span&gt;&lt;span&gt; ffmpeg &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; FFmpeg.&lt;/span&gt;&lt;span&gt;getInstance&lt;/span&gt;&lt;span&gt;(ctx.applicationContext)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        try&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            ffmpeg.&lt;/span&gt;&lt;span&gt;loadBinary&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;object&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;LoadBinaryResponseHandler&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                override&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; onFinish&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;onFinish&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;                override&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; onSuccess&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;onSuccess&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;                override&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; onFailure&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;onFailure&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;                override&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; onStart&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;onStart&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;catch&lt;/span&gt;&lt;span&gt; (e: &lt;/span&gt;&lt;span&gt;FFmpegNotSupportedException&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            Log.&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;FFmpeg&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;Your device does not support FFmpeg&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;3-initialize-the-ffmpeg-module-leave-command-blank&quot;&gt;3. Initialize the FFmpeg module (leave command blank)&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; ffmpeg &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; FFmpeg.&lt;/span&gt;&lt;span&gt;getInstance&lt;/span&gt;&lt;span&gt;(ctx)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       ffmpeg.&lt;/span&gt;&lt;span&gt;loadBinary&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;object&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;FFmpegLoadBinaryResponseHandler&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            override&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; onFinish&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                Log.&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;FFmpeg&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;onFinish&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            override&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; onSuccess&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                Log.&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;FFmpeg&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;onSuccess&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                val&lt;/span&gt;&lt;span&gt; command &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; //TODO: the command will added here later&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                try&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    ffmpeg.&lt;/span&gt;&lt;span&gt;execute&lt;/span&gt;&lt;span&gt;(command, &lt;/span&gt;&lt;span&gt;object&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;ExecuteBinaryResponseHandler&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                        override&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; onSuccess&lt;/span&gt;&lt;span&gt;(message: &lt;/span&gt;&lt;span&gt;String&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;onSuccess&lt;/span&gt;&lt;span&gt;(message)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                            Log.&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;(TAG, &lt;/span&gt;&lt;span&gt;&quot;onSuccess: &quot;&lt;/span&gt;&lt;span&gt; +&lt;/span&gt;&lt;span&gt; message&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                        override&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; onProgress&lt;/span&gt;&lt;span&gt;(message: &lt;/span&gt;&lt;span&gt;String&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;onProgress&lt;/span&gt;&lt;span&gt;(message)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                            Log.&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;(TAG, &lt;/span&gt;&lt;span&gt;&quot;onProgress: &quot;&lt;/span&gt;&lt;span&gt; +&lt;/span&gt;&lt;span&gt; message&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                        override&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; onFailure&lt;/span&gt;&lt;span&gt;(message: &lt;/span&gt;&lt;span&gt;String&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;onFailure&lt;/span&gt;&lt;span&gt;(message)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                            Log.&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;(TAG, &lt;/span&gt;&lt;span&gt;&quot;onFailure: &quot;&lt;/span&gt;&lt;span&gt; +&lt;/span&gt;&lt;span&gt; message&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                        override&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; onStart&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;onStart&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                            Log.&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;(TAG, &lt;/span&gt;&lt;span&gt;&quot;onStart&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                        override&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; onFinish&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;onFinish&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                            Log.&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;(TAG, &lt;/span&gt;&lt;span&gt;&quot;onFinish&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                } &lt;/span&gt;&lt;span&gt;catch&lt;/span&gt;&lt;span&gt; (e: &lt;/span&gt;&lt;span&gt;FFmpegCommandAlreadyRunningException&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                            Log.&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;FFmpeg&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;FFmpeg runs already&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            }&lt;/span&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; fun&lt;/span&gt;&lt;span&gt; onFailure&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                Log.&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;FFmpeg&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;onFailure&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            override&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; onStart&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;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;4-implement-the-commands-you-want-to-use-in-your-app&quot;&gt;4. Implement the commands you want to use in your app&lt;/h3&gt;
&lt;p&gt;All commands that are supported by FFmpeg can be included in your app with help of an array. This is done by passing every command line argument as a single element within the array. The array will then be translated into an FFmpeg command using the execute method from FFmpeg:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ffmpeg.execute(command, object : ExecuteBinaryResponseHandler() { ... }&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;As we want to implement Trim and Crop I will show how this can be done using the &lt;code&gt;arrayOf&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Trim:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; command &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; arrayOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;-y&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;-i&quot;&lt;/span&gt;&lt;span&gt;, input, &lt;/span&gt;&lt;span&gt;&quot;-ss&quot;&lt;/span&gt;&lt;span&gt;, startPos, &lt;/span&gt;&lt;span&gt;&quot;-to&quot;&lt;/span&gt;&lt;span&gt;, endPos, &lt;/span&gt;&lt;span&gt;&quot;-c&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;copy&quot;&lt;/span&gt;&lt;span&gt;, output)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;“-y”:&lt;/strong&gt; overwrites output files without asking&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“-i”:&lt;/strong&gt; specifies an input file&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;input:&lt;/strong&gt; the path of the source video to trim&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“-ss”:&lt;/strong&gt; specifies that the next value will be the starting point of the resulting video&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;startPos:&lt;/strong&gt; the starting position in “%d:%02d:%02d” format&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“-to”:&lt;/strong&gt; specifies that the next value will be the end position of the resulting video&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;endPos:&lt;/strong&gt; the end position in “%d:%02d:%02d” format&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“-c” AND “copy”&lt;/strong&gt;: defines that the stream will not be encoded. The resulting video will only be saved.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;output:&lt;/strong&gt; the path of the resulting video&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To better understand every argument you can have a look at &lt;a href=&quot;https://www.ffmpeg.org/ffmpeg.html#Main-options&quot;&gt;the official FFmpeg documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Additionally, to provide arguments for &lt;code&gt;startPos&lt;/code&gt; and &lt;code&gt;endPos&lt;/code&gt; you normally would have to use a utility function that converts the timestamp of the start and end position into the desired “%d:%02d:%02d” format (a string):&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;fun&lt;/span&gt;&lt;span&gt; convertTimestampToString&lt;/span&gt;&lt;span&gt;(timeInMs: &lt;/span&gt;&lt;span&gt;Float&lt;/span&gt;&lt;span&gt;): &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        val&lt;/span&gt;&lt;span&gt; totalSeconds &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (timeInMs &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; 1000&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;toInt&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        val&lt;/span&gt;&lt;span&gt; seconds &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; totalSeconds &lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; 60&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        val&lt;/span&gt;&lt;span&gt; minutes &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; totalSeconds &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; 60&lt;/span&gt;&lt;span&gt; %&lt;/span&gt;&lt;span&gt; 60&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        val&lt;/span&gt;&lt;span&gt; hours &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; totalSeconds &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; 3600&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        val&lt;/span&gt;&lt;span&gt; formatter &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; Formatter&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; if&lt;/span&gt;&lt;span&gt; (hours &lt;/span&gt;&lt;span&gt;&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;            formatter.&lt;/span&gt;&lt;span&gt;format&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;%d:%02d:%02d&quot;&lt;/span&gt;&lt;span&gt;, hours, minutes, seconds).&lt;/span&gt;&lt;span&gt;toString&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;else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            formatter.&lt;/span&gt;&lt;span&gt;format&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;%02d:%02d&quot;&lt;/span&gt;&lt;span&gt;, minutes, seconds).&lt;/span&gt;&lt;span&gt;toString&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Crop:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; command &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; arrayOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;-i&quot;&lt;/span&gt;&lt;span&gt;, input, &lt;/span&gt;&lt;span&gt;&quot;-filter:v&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;crop=&lt;/span&gt;&lt;span&gt;$w&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;$h&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;$x&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;$y&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;-threads&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;5&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;-preset&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;ultrafast&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;-strict&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;-2&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;-c:a&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;copy&quot;&lt;/span&gt;&lt;span&gt;, output)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;“-i”:&lt;/strong&gt; specifies an input file&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;input:&lt;/strong&gt; the path of the source video to trim&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“-filter:v”:&lt;/strong&gt; defines that a filtergraph is used&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“crop=$w:$h:$x:$y”:&lt;/strong&gt; use crop functionality to crop a part from the video start at point x:y and having a width(w) and height(h).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“-threads”:&lt;/strong&gt; specifies that the next value will set the thread count&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“5”:&lt;/strong&gt; the number of threads to use&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“-preset”:&lt;/strong&gt; specifies that the next value will set the encoding preset&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“ultrafast”:&lt;/strong&gt; the encoding preset to use&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“-strict”:&lt;/strong&gt; specifies how strictly the standards should be followed&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“-2”:&lt;/strong&gt; the strict value&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“-c:a” AND “copy”&lt;/strong&gt; defines that the stream will not be encoded and ALL audio streams will also be used.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;output:&lt;/strong&gt; the path of the resulting video&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also, check &lt;a href=&quot;https://www.ffmpeg.org/ffmpeg.html#Main-options&quot;&gt;the official FFmpeg documentation&lt;/a&gt; to better understand every argument.&lt;/p&gt;
&lt;h3 id=&quot;5-implement-the-ui&quot;&gt;5. Implement the UI&lt;/h3&gt;
&lt;p&gt;To create a fancy UI you should create a custom view that shows some of the frames available in the video (&lt;code&gt;VideoPreviewView&lt;/code&gt;). Also, it should contain a &lt;code&gt;SeekBar&lt;/code&gt; for &lt;strong&gt;cropping&lt;/strong&gt; and a &lt;code&gt;RangeSeekBar&lt;/code&gt; for &lt;strong&gt;trimming&lt;/strong&gt;. The &lt;code&gt;SeekBar&lt;/code&gt; will be used to switch to a certain timestamp within the video to see what is actually trimmed or cropped. The RangeSeekBar will only be used within the trimming UI to define the start and end position of the resulting video.&lt;/p&gt;
&lt;p&gt;While &lt;code&gt;SeekBar&lt;/code&gt; is &lt;a href=&quot;https://developer.android.com/reference/android/widget/SeekBar&quot;&gt;an Android Widget&lt;/a&gt; the &lt;code&gt;RangeSeekBar&lt;/code&gt; is more complicated but there exist several implementations that can be used: By &lt;a href=&quot;https://github.com/tizisdeepan/VideoEditor/blob/master/video-editor/src/main/java/com/video/trimmer/view/RangeSeekBarView.kt&quot;&gt;Tiszideepan&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can implement the &lt;code&gt;VideoPreviewView&lt;/code&gt; with an easy approach. Divide the video into a specific number of frames that are based on the view’s width and display every frame sequentially within a single view to have a preview. To do this you need the width of the view and the duration of the video that can be found using the &lt;a href=&quot;https://developer.android.com/reference/android/media/MediaMetadataRetriever&quot;&gt;MediaMetadataRetriever&lt;/a&gt;. With the &lt;code&gt;MediaMetadataRetriever&lt;/code&gt;, you can use &lt;code&gt;getFrameAtTime()&lt;/code&gt; to fetch a single frame at a specific timestamp. If you now want to display a complete video preview you need to display &lt;code&gt;viewWidth / frameWidth&lt;/code&gt; frames. Unfortunately, depending on the video length and video width, it could happen that only a few frames will be present within the &lt;code&gt;VideoPreviewView&lt;/code&gt;. To fix this problem you have to maintain a threshold to ensure that a specific number of frames are displayed. This means that you have to crop the frames to a certain width until calculated frames equal the threshold.&lt;/p&gt;
&lt;p&gt;The following code snippet will show how you can achieve this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; createPreview&lt;/span&gt;&lt;span&gt;(viewWidth: &lt;/span&gt;&lt;span&gt;Int&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        BackgroundExecutor.&lt;/span&gt;&lt;span&gt;execute&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;object&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;BackgroundExecutor&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Task&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;0L&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;            override&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; execute&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; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    val&lt;/span&gt;&lt;span&gt; threshold &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 11&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    val&lt;/span&gt;&lt;span&gt; thumbnails &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; LongSparseArray&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Bitmap&lt;/span&gt;&lt;span&gt;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    val&lt;/span&gt;&lt;span&gt; mediaMetadataRetriever &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; MediaMetadataRetriever&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    mediaMetadataRetriever.&lt;/span&gt;&lt;span&gt;setDataSource&lt;/span&gt;&lt;span&gt;(context, videoUri)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    val&lt;/span&gt;&lt;span&gt; videoLengthInMs &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (Integer.&lt;/span&gt;&lt;span&gt;parseInt&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                        mediaMetadataRetriever.&lt;/span&gt;&lt;span&gt;extractMetadata&lt;/span&gt;&lt;span&gt;(MediaMetadataRetriever.METADATA_KEY_DURATION)&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; 1000&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;toLong&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    val&lt;/span&gt;&lt;span&gt; frameHeight &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; viewHeight&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    val&lt;/span&gt;&lt;span&gt; initialBitmap &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; mediaMetadataRetriever.&lt;/span&gt;&lt;span&gt;getFrameAtTime&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;                        MediaMetadataRetriever.OPTION_CLOSEST_SYNC&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;                    val&lt;/span&gt;&lt;span&gt; frameWidth &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                        ((initialBitmap.width.&lt;/span&gt;&lt;span&gt;toFloat&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; initialBitmap.height.&lt;/span&gt;&lt;span&gt;toFloat&lt;/span&gt;&lt;span&gt;()) &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; frameHeight.&lt;/span&gt;&lt;span&gt;toFloat&lt;/span&gt;&lt;span&gt;()).&lt;/span&gt;&lt;span&gt;toInt&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; numThumbs &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ceil&lt;/span&gt;&lt;span&gt;((viewWidth.&lt;/span&gt;&lt;span&gt;toFloat&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; frameWidth)).&lt;/span&gt;&lt;span&gt;toInt&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; (numThumbs &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; threshold) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                        numThumbs &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; threshold&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;                    val&lt;/span&gt;&lt;span&gt; cropWidth &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; viewWidth &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; threshold&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    val&lt;/span&gt;&lt;span&gt; interval &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; videoLengthInMs &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; numThumbs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    for&lt;/span&gt;&lt;span&gt; (i &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; until numThumbs) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                        var&lt;/span&gt;&lt;span&gt; bitmap &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; mediaMetadataRetriever.&lt;/span&gt;&lt;span&gt;getFrameAtTime&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                            i &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; interval,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                            MediaMetadataRetriever.OPTION_CLOSEST_SYNC&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;                        bitmap?.&lt;/span&gt;&lt;span&gt;let&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; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                                bitmap &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; Bitmap.&lt;/span&gt;&lt;span&gt;createScaledBitmap&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                                    bitmap,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                                    frameWidth,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                                    frameHeight,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                                    false&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;                                bitmap &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; Bitmap.&lt;/span&gt;&lt;span&gt;createBitmap&lt;/span&gt;&lt;span&gt;(bitmap, &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;, cropWidth, bitmap.height)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                            } &lt;/span&gt;&lt;span&gt;catch&lt;/span&gt;&lt;span&gt; (e: &lt;/span&gt;&lt;span&gt;Exception&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                                Log.&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;(TAG, &lt;/span&gt;&lt;span&gt;&quot;error while create bitmap: &lt;/span&gt;&lt;span&gt;$e&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                            thumbnails.&lt;/span&gt;&lt;span&gt;put&lt;/span&gt;&lt;span&gt;(i.&lt;/span&gt;&lt;span&gt;toLong&lt;/span&gt;&lt;span&gt;(), bitmap)&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;                    mediaMetadataRetriever.&lt;/span&gt;&lt;span&gt;release&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    returnBitmaps&lt;/span&gt;&lt;span&gt;(thumbnails)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                } &lt;/span&gt;&lt;span&gt;catch&lt;/span&gt;&lt;span&gt; (e: &lt;/span&gt;&lt;span&gt;Throwable&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    Thread.&lt;/span&gt;&lt;span&gt;getDefaultUncaughtExceptionHandler&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;uncaughtException&lt;/span&gt;&lt;span&gt;(Thread.&lt;/span&gt;&lt;span&gt;currentThread&lt;/span&gt;&lt;span&gt;(), e)&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;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Additionally, for cropping a video you need to display a &lt;em&gt;crop rectangle&lt;/em&gt; within the UI to let users decide which part of the video they want to crop. Also, you have to give users the ability to reposition the crop area. To do this, you can use &lt;a href=&quot;https://github.com/ArthurHub/Android-Image-Cropper&quot;&gt;the ImageCropper library from ArthurHub&lt;/a&gt; which is initially designed to crop an image but can also be used for videos as you only need the values from the rectangle. Add the &lt;code&gt;ImageCropper&lt;/code&gt; to your project:&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;dependencies {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    implementation &apos;com.theartofdev.edmodo:android-image-cropper:2.8.0&apos;&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;Now, you can extend a &lt;code&gt;CropperActivity&lt;/code&gt; which loads the current frame of the video (that you can extract with the &lt;code&gt;VideoPreviewView&lt;/code&gt;) by inserting the &lt;code&gt;CropImageView&lt;/code&gt; layout to get the cropping bounds. Once, you select an area in the UI, the rectangle values can be extracted and used to calculate the needed values for video cropping with this function:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; rect &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; cropFrame.cropRect&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; w &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; abs&lt;/span&gt;&lt;span&gt;(rect.left &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; rect.right)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; h &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; abs&lt;/span&gt;&lt;span&gt;(rect.top &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; rect.bottom)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; x &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; rect.left&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; y &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; rect.top&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These values will then be used as input variables for the FFmpeg crop command.&lt;/p&gt;
&lt;p&gt;To help you use all this information I created a project that uses all explained snippets to create a sample app that can crop and trim videos. The source code can be found &lt;a href=&quot;https://github.com/paulknulst/VideoTrimmer&quot;&gt;on my personal GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;fixing-error13-permission-denied&quot;&gt;Fixing error=13, Permission denied&lt;/h2&gt;
&lt;p&gt;Unfortunately, if you implement the described functionality and use the compiled FFmpeg library you will run into this problem if you compile your app for SDK 29 and onwards.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.knulst.de/content/images/2022/08/image-4.png&quot; alt=&quot;Permission denied error due to wrong target SDK&quot;&gt;&lt;/p&gt;
&lt;p&gt;Permission denied error due to wrong target SDK The problem is caused because from Android Q onwards it is not allowed to execute binaries in your app’s private data directory. The error is described in &lt;a href=&quot;https://issuetracker.google.com/issues/128554619?pli=1&quot;&gt;the official issue tracker from google&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One solution will be that you compile your app for SDK 28 but this could lead to problems if you try to put your app into the Android Play Store.&lt;/p&gt;
&lt;p&gt;Another solution will be that you compile your app for SDK 29 and stop putting binaries in any not supported directory. Unfortunately, the code that moves the binaries is within the 3rd party lib from WritingMinds and has to be removed by you (with a Pull Request) or by the maintainer of the library. A future-proof solution will be that you stop using external binaries and start compiling dependencies as an NDK project. This will be a lot of work but you can find help within a famous repository that compiles CPP to Java and also has &lt;a href=&quot;https://github.com/bytedeco/javacpp-presets/tree/master/ffmpeg&quot;&gt;FFmpeg&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;add-more-commands&quot;&gt;Add more commands&lt;/h2&gt;
&lt;p&gt;After you implemented crop and trim you maybe want to add more cool features to your Android app. To do this with FFmpeg and the previously described code you can do this by simply creating a new function within the &lt;code&gt;VideoCommands()&lt;/code&gt; and translate the FFmpeg command into a &lt;code&gt;VideoCommands()&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;The next sections will describe some fancy functions that would improve the usability of your app. Just add a new function with this command and fill the callbacks with a toast or anything else. Then call the function from anywhere within your app (because you do not need UI for this).&lt;/p&gt;
&lt;h3 id=&quot;removing-audio-from-videos&quot;&gt;Removing audio from videos&lt;/h3&gt;
&lt;p&gt;You might run into a scenario where you’d only like to keep the visuals of a video and remove the audio track, for instance for voicing over certain footage or removing background noise:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; command &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; arrayOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;-i&quot;&lt;/span&gt;&lt;span&gt;, input, &lt;/span&gt;&lt;span&gt;&quot;-an&quot;&lt;/span&gt;&lt;span&gt;, output)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;compress-a-video&quot;&gt;Compress a video&lt;/h3&gt;
&lt;p&gt;Make big videos smaller to save your valuable disk resources.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; command &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; arrayOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;-i&quot;&lt;/span&gt;&lt;span&gt;, input, &lt;/span&gt;&lt;span&gt;&quot;-vf&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;scale=&lt;/span&gt;&lt;span&gt;$w&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;$h&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;-c:v&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;libx264&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;-preset&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;veryslow&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;-crf&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;24&quot;&lt;/span&gt;&lt;span&gt;, output)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;$w and $h&lt;/strong&gt; are the new sizes (should be smaller). If one is -1 it will keep the ratio and is automatically adjusted in relation to the other one.&lt;/p&gt;
&lt;h3 id=&quot;change-playback-speed&quot;&gt;Change playback speed&lt;/h3&gt;
&lt;p&gt;Increase the playback speed to make long videos faster or decrease it for showing something really awesome very slowly.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt; val&lt;/span&gt;&lt;span&gt; command &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; arrayOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;-i&quot;&lt;/span&gt;&lt;span&gt;, input, &lt;/span&gt;&lt;span&gt;&quot;-vf&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;\&quot;&lt;/span&gt;&lt;span&gt;setpts=&lt;/span&gt;&lt;span&gt;$scale&lt;/span&gt;&lt;span&gt;*PTS&lt;/span&gt;&lt;span&gt;\&quot;&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;, output)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;$scale&lt;/strong&gt; should be &gt; 1 for slowing down a video or &amp;#x3C; 1 for fastening a video.&lt;/p&gt;
&lt;h3 id=&quot;more&quot;&gt;More&lt;/h3&gt;
&lt;p&gt;To find more cool commands search &lt;a href=&quot;https://www.ffmpeg.org/ffmpeg.html&quot;&gt;the official argument documentation&lt;/a&gt; and implement them by putting every argument into a value of the array function as described earlier.&lt;/p&gt;
&lt;p&gt;For production-grade application you may be better served by using our &lt;a href=&quot;https://img.ly/products/video-sdk&quot;&gt;VideoEditorSDK&lt;/a&gt; which in addition to professional trim and crop features allows your users to add filters, text and audio overlays. Recently, we released time-based sprites as well allowing users to time the appearance of text and stickers in videos.&lt;/p&gt;
&lt;h3 id=&quot;closing-notes&quot;&gt;Closing Notes&lt;/h3&gt;
&lt;p&gt;In this article, you learned that you can use FFmpeg to crop and trim videos on Android. Unfortunately, it does not work out of the box and you have to compile the library using complex techniques. Luckily, there exist some useful libraries that do the heavy lifting for you.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/paulknulst/VideoTrimmer&quot;&gt;Using my app as a baseline&lt;/a&gt; you are able to crop and trim videos. Additionally, you can implement more commands easily if they do not need a GUI because creating a fancy-looking GUI was a complicated part of developing a cropping and trimming app.&lt;/p&gt;
&lt;p&gt;Unfortunately, there are problems with the library that was used because Android Q introduces a security fix that forbids apps to execute binaries within their data folder. But, this is only a problem if you want to create a “Google Play Store” ready app because you can avoid this problem if compile your app for SDK 28 (and lower). Keep in mind that if you want to create a private app that you distribute on your website instead of using the Play Store you can do this. But, if you want to upload your app to the Google Play Store you have to search for &lt;a href=&quot;https://trac.ffmpeg.org/wiki/CompilationGuide/Android&quot;&gt;another FFmpeg library within the documentation&lt;/a&gt; or build one from scratch so you can compile your app for the current needed SDK.&lt;/p&gt;
&lt;p&gt;Looking to integrate video capabilities into your app? Check out our &lt;a href=&quot;https://img.ly/products/video-sdk&quot;&gt;Video Editor SDK&lt;/a&gt;, &lt;a href=&quot;https://img.ly/use-cases/story-reels-short-video-creation&quot;&gt;Short Video Creation&lt;/a&gt;, and &lt;a href=&quot;https://img.ly/products/camera-sdk&quot;&gt;Camera SDK&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;I hope you enjoyed reading this article and are able to create an Android app that can crop and trim videos. If you have any questions, need help, or want to give feedback @ us on &lt;a href=&quot;https://twitter.com/imgly&quot;&gt;Twitter&lt;/a&gt;. We are happy to help.&lt;/p&gt;</content:encoded><dc:creator>Paul</dc:creator><media:content url="https://blog.img.ly/2022/09/Android-trimmimg-with-Kotlin.png" medium="image"/><category>How-To</category><category>Tech</category><category>Android</category><category>Android App Development</category><category>Tutorial</category></item><item><title>How to Apply Filter Effects to Video using VidEffects library on Android</title><link>https://img.ly/blog/how-to-apply-filter-effects-to-video-using-videffects-on-android/</link><guid isPermaLink="true">https://img.ly/blog/how-to-apply-filter-effects-to-video-using-videffects-on-android/</guid><description>Learn about the benefits and limitations of VidEffects for video editing on Android.</description><pubDate>Tue, 24 May 2022 11:41:23 GMT</pubDate><content:encoded>&lt;p&gt;Video manipulation is a complex topic on Android because there is no out-of-the-box support from the Android SDK, and using FFmpeg requires not just a very elaborate setup but having to climb a steep learning curve to learn its CLI commands.&lt;/p&gt;
&lt;p&gt;As an aside, we have also put together how-to blogs to elaborate on other video manipulation operations like merging still images to form videos, &lt;a href=&quot;https://img.ly/blog/working-with-large-video-and-image-files-on-ios-with-swift/&quot;&gt;compressing and resizing videos&lt;/a&gt;, or background removal.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/krazykira/VidEffects&quot;&gt;VidEffects&lt;/a&gt; library is much faster to set up than FFmpeg, and it works by applying effects to &lt;code&gt;GLSurfaceView&lt;/code&gt;. This blog post will demonstrate how to apply Filter effects to a video in an Android app using the VidEffects library.&lt;/p&gt;
&lt;p&gt;VidEffects does support storing videos on the disk, but it has limitations in this regard which we will discuss in a moment.&lt;/p&gt;
&lt;p&gt;Before we begin, keep in mind that the VidEffects library differentiates between &lt;strong&gt;Effects&lt;/strong&gt; and &lt;strong&gt;Filters&lt;/strong&gt;. As an example, we will apply both and discuss the crucial difference between the two.&lt;/p&gt;
&lt;p&gt;Without much further ado, let’s start coding.&lt;/p&gt;
&lt;h2 id=&quot;create-a-videffects-example-app&quot;&gt;Create a VidEffects Example App&lt;/h2&gt;
&lt;p&gt;Create a &lt;strong&gt;New Project&lt;/strong&gt; with an Empty Activity in Android Studio. Select &lt;em&gt;Kotlin&lt;/em&gt; as the language (or Java if you wish), and set **Minimum SDK to API 21.&lt;/p&gt;
&lt;p&gt;You can also download the final code from &lt;a href=&quot;https://github.com/numerative/videffects_sample&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;add-dependency&quot;&gt;Add Dependency&lt;/h3&gt;
&lt;p&gt;In your module-level &lt;strong&gt;build.gradle&lt;/strong&gt; (app/build.gradle) file add the latest VidEffects dependency.&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;dependencies {&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;    implementation &lt;/span&gt;&lt;span&gt;&quot;com.github.krazykira:videffects:1.1.1&quot;&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&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, enable &lt;code&gt;viewBinding&lt;/code&gt; by adding the following lines within the &lt;code&gt;android{}&lt;/code&gt; closure.&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;    ..&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    buildFeatures {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        viewBinding &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By using View Binding, we can avoid the &lt;code&gt;findViewById()&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;Click &lt;strong&gt;Sync Now&lt;/strong&gt; to sync the project with gradle files.&lt;/p&gt;
&lt;h3 id=&quot;add-video-asset-file&quot;&gt;Add Video Asset File&lt;/h3&gt;
&lt;p&gt;Place the sample video file in &lt;strong&gt;app/src/main/assets/&lt;/strong&gt; directory. Ideally, your app will load the video file from disk – but to avoid complexity, we are placing the video in the assets directory.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;directory_tree_android_video-effect&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 304px) 304px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;304&quot; height=&quot;299&quot; src=&quot;https://img.ly/_astro/directory_tree_android_video-effect_4vaxk.webp&quot; srcset=&quot;/_astro/directory_tree_android_video-effect_4vaxk.webp 304w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;create-a-layout&quot;&gt;Create a Layout&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;screen_no_filter-1&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;889&quot; src=&quot;https://img.ly/_astro/screen_no_filter-1_g8KRl.webp&quot; srcset=&quot;/_astro/screen_no_filter-1_g8KRl.webp 500w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Create the above layout with a &lt;code&gt;VideoSurfaceView&lt;/code&gt;, three Filter buttons, and one Reset Button.&lt;/p&gt;
&lt;p&gt;Replace your &lt;strong&gt;activity_main.xml&lt;/strong&gt;`s code with the following.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;xml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;androidx.constraintlayout.widget.ConstraintLayout&lt;/span&gt;&lt;span&gt; xmlns:android&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;http://schemas.android.com/apk/res/android&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    xmlns:app&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;http://schemas.android.com/apk/res-auto&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    xmlns:tools&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;http://schemas.android.com/tools&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    android:layout_width&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;match_parent&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    android:layout_height&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;match_parent&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    tools:context&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;.MainActivity&quot;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;com.sherazkhilji.videffects.view.VideoSurfaceView&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        android:id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;@+id/mVideoSurfaceView&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        android:layout_width&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;match_parent&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        android:layout_height&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;300dp&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        app:layout_constraintTop_toTopOf&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;parent&quot;&lt;/span&gt;&lt;span&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;androidx.constraintlayout.widget.ConstraintLayout&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        android:id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;@+id/wrapper&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        android:layout_width&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;wrap_content&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        android:layout_height&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;wrap_content&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        app:layout_constraintEnd_toEndOf&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;parent&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        app:layout_constraintStart_toStartOf&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;parent&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        app:layout_constraintTop_toBottomOf&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;@id/mVideoSurfaceView&quot;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;&lt;/span&gt;&lt;span&gt;androidx.appcompat.widget.AppCompatButton&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            android:id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;@+id/bwButton&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            android:layout_width&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;wrap_content&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            android:layout_height&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;wrap_content&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            android:text&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;Black and White&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            app:layout_constraintStart_toStartOf&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;parent&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            app:layout_constraintTop_toTopOf&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;parent&quot;&lt;/span&gt;&lt;span&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;&lt;/span&gt;&lt;span&gt;androidx.appcompat.widget.AppCompatButton&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            android:id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;@+id/grainButton&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            android:layout_width&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;wrap_content&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            android:layout_height&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;wrap_content&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            android:text&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;Grain&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            app:layout_constraintStart_toEndOf&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;@id/bwButton&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            app:layout_constraintTop_toTopOf&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;parent&quot;&lt;/span&gt;&lt;span&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;&lt;/span&gt;&lt;span&gt;androidx.appcompat.widget.AppCompatButton&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            android:id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;@+id/duotoneButton&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            android:layout_width&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;wrap_content&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            android:layout_height&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;wrap_content&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            android:text&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;DuoTone&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            app:layout_constraintStart_toEndOf&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;@id/grainButton&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            app:layout_constraintTop_toTopOf&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;parent&quot;&lt;/span&gt;&lt;span&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span&gt;androidx.constraintlayout.widget.ConstraintLayout&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;androidx.appcompat.widget.AppCompatButton&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        android:id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;@+id/resetButton&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        android:layout_width&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;wrap_content&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        android:layout_height&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;wrap_content&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        android:text&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;Reset&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        app:layout_constraintEnd_toEndOf&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;parent&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        app:layout_constraintStart_toStartOf&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;parent&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        app:layout_constraintTop_toBottomOf&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;@+id/wrapper&quot;&lt;/span&gt;&lt;span&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;androidx.constraintlayout.widget.ConstraintLayout&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;initialize-the-video&quot;&gt;Initialize the video&lt;/h2&gt;
&lt;p&gt;Before initializing the video, set up an instance of the Binding class to use it within the Activity.&lt;/p&gt;
&lt;h3 id=&quot;setup-view-binding&quot;&gt;Setup View Binding&lt;/h3&gt;
&lt;p&gt;Add the following code in &lt;strong&gt;MainActivity.kt&lt;/strong&gt; before calling &lt;code&gt;setContentView()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you do not wish to use View Binding and instead prefer using &lt;code&gt;findViewById()&lt;/code&gt;, skip to the next step &lt;em&gt;Initializing the Sample Video&lt;/em&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; lateinit&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt; binding: &lt;/span&gt;&lt;span&gt;ActivityMainBinding&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; MainActivity&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;AppCompatActivity&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;		private&lt;/span&gt;&lt;span&gt; lateinit&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt; binding: &lt;/span&gt;&lt;span&gt;ActivityMainBinding&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    override&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; onCreate&lt;/span&gt;&lt;span&gt;(savedInstanceState: &lt;/span&gt;&lt;span&gt;Bundle&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;onCreate&lt;/span&gt;&lt;span&gt;(savedInstanceState)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        binding &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ActivityMainBinding.&lt;/span&gt;&lt;span&gt;inflate&lt;/span&gt;&lt;span&gt;(layoutInflater)&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;    companion&lt;/span&gt;&lt;span&gt; object&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        private&lt;/span&gt;&lt;span&gt; const&lt;/span&gt;&lt;span&gt; val&lt;/span&gt;&lt;span&gt; TAG &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &quot;MainActivity&quot;&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;ActivityMainBinding&lt;/code&gt; class is auto-generated. If it did not get auto-generated, then sync the project with the gradle file from &lt;strong&gt;File &gt; Sync Project with Gradle Files.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Next, pass the &lt;em&gt;root view&lt;/em&gt; to the &lt;code&gt;setContentView()&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; MainActivity&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;AppCompatActivity&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&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    override&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; onCreate&lt;/span&gt;&lt;span&gt;(savedInstanceState: &lt;/span&gt;&lt;span&gt;Bundle&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&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        setContentView&lt;/span&gt;&lt;span&gt;(binding.root)&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;initializing-the-sample-video&quot;&gt;Initializing the Sample Video&lt;/h3&gt;
&lt;p&gt;Next, declare and initialize the &lt;code&gt;MediaPlayer&lt;/code&gt; variable.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; MainActivity&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;AppCompatActivity&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&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    private&lt;/span&gt;&lt;span&gt; lateinit&lt;/span&gt;&lt;span&gt; var&lt;/span&gt;&lt;span&gt; mMediaPlayer: &lt;/span&gt;&lt;span&gt;MediaPlayer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        override&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; onCreate&lt;/span&gt;&lt;span&gt;(savedInstanceState: &lt;/span&gt;&lt;span&gt;Bundle&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&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            mMediaPlayer &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; MediaPlayer&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 open the video file from our assets directory and pass it as the data source to the Media Player.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;override&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; onCreate&lt;/span&gt;&lt;span&gt;(savedInstanceState: &lt;/span&gt;&lt;span&gt;Bundle&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&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    try&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        val&lt;/span&gt;&lt;span&gt; afd &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; assets.&lt;/span&gt;&lt;span&gt;openFd&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;sample.mp4&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        mMediaPlayer.&lt;/span&gt;&lt;span&gt;setDataSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            afd.fileDescriptor,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            afd.startOffset, afd.length&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;catch&lt;/span&gt;&lt;span&gt; (e: &lt;/span&gt;&lt;span&gt;Exception&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        Log.&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;(TAG, e.message, e)&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;Now, all that is remaining is to initialize the &lt;code&gt;VideoSurfaceView&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;override&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; onCreate&lt;/span&gt;&lt;span&gt;(savedInstanceState: &lt;/span&gt;&lt;span&gt;Bundle&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&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        binding.mVideoSurfaceView.&lt;/span&gt;&lt;span&gt;init&lt;/span&gt;&lt;span&gt;(mMediaPlayer, &lt;/span&gt;&lt;span&gt;NoEffectFilter&lt;/span&gt;&lt;span&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your app should run. While the buttons still do not work, we will &lt;code&gt;setOnClickListeners()&lt;/code&gt; next.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;screen_no_filter-2&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;889&quot; src=&quot;https://img.ly/_astro/screen_no_filter-2_biy8Y.webp&quot; srcset=&quot;/_astro/screen_no_filter-2_biy8Y.webp 500w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;apply-videffects-effects&quot;&gt;Apply VidEffects Effects&lt;/h2&gt;
&lt;p&gt;The VidEffects library offers &lt;a href=&quot;https://github.com/krazykira/VidEffects#supported-effects&quot;&gt;multiple effects&lt;/a&gt;, but we will be applying three: Black and White, Grain, and Duotone.&lt;/p&gt;
&lt;p&gt;In &lt;strong&gt;MainActivity&lt;/strong&gt;’s &lt;code&gt;onCreate()&lt;/code&gt;, copy the following code to setup all the &lt;code&gt;setOnClickListeners&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;kotlin&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;override&lt;/span&gt;&lt;span&gt; fun&lt;/span&gt;&lt;span&gt; onCreate&lt;/span&gt;&lt;span&gt;(savedInstanceState: &lt;/span&gt;&lt;span&gt;Bundle&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&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    //Black and White Effect&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    binding.bwButton.&lt;/span&gt;&lt;span&gt;setOnClickListener&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        binding.mVideoSurfaceView.shader &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; BlackAndWhiteEffect&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;    //Grain Filter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    binding.grainButton.&lt;/span&gt;&lt;span&gt;setOnClickListener&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        val&lt;/span&gt;&lt;span&gt; grainFilter &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GrainFilter&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        grainFilter.&lt;/span&gt;&lt;span&gt;setIntensity&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0.5f&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        binding.mVideoSurfaceView.filter &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; grainFilter&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;    //Duotone Effect&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    binding.duotoneButton.&lt;/span&gt;&lt;span&gt;setOnClickListener&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        binding.mVideoSurfaceView.shader &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            DuotoneEffect&lt;/span&gt;&lt;span&gt;(Color.BLUE, Color.YELLOW)&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;    //Reset with AutoFixFilter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    binding.resetButton.&lt;/span&gt;&lt;span&gt;setOnClickListener&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        binding.mVideoSurfaceView.filter &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; NoEffectFilter&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.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;screen-bw-duo-grain&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1500px) 1500px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1500&quot; height=&quot;889&quot; src=&quot;https://img.ly/_astro/screen-bw-duo-grain_U18c2.webp&quot; srcset=&quot;/_astro/screen-bw-duo-grain_6sBsy.webp 640w, /_astro/screen-bw-duo-grain_1q99jx.webp 750w, /_astro/screen-bw-duo-grain_Z1jzBKe.webp 828w, /_astro/screen-bw-duo-grain_ZowVa8.webp 1080w, /_astro/screen-bw-duo-grain_Z2lItwG.webp 1280w, /_astro/screen-bw-duo-grain_U18c2.webp 1500w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;difference-between-effects-and-filters&quot;&gt;Difference Between Effects and Filters&lt;/h2&gt;
&lt;p&gt;As mentioned before, Effects and Filters are two separate functions in the VidEffects library.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Effects&lt;/em&gt; are temporary, view-only overlays that cannot be stored on the disk. &lt;em&gt;Filters&lt;/em&gt; can be viewed and stored on the disk. Unfortunately, a majority of the overlays offered by VidEffects are &lt;a href=&quot;https://github.com/krazykira/VidEffects/tree/master/videffects/src/main/java/com/sherazkhilji/videffects&quot;&gt;Effects&lt;/a&gt; and therefore only useful for playback only. At the time of writing this article, only three &lt;a href=&quot;https://github.com/krazykira/VidEffects/tree/master/videffects/src/main/java/com/sherazkhilji/videffects/filter&quot;&gt;Filters&lt;/a&gt; are available.&lt;/p&gt;
&lt;h2 id=&quot;limitations&quot;&gt;Limitations&lt;/h2&gt;
&lt;p&gt;One of the biggest limitations of this library, as mentioned above, is that the majority of the effects provided by the library are just view-only.&lt;/p&gt;
&lt;p&gt;Moreover, to save videos with filters, the app must target &lt;code&gt;minSdk 23&lt;/code&gt; at least or use FFmpeg.&lt;/p&gt;
&lt;p&gt;Many of these Effects do not have an intensity parameter and therefore we cannot fine-tune these effects.&lt;/p&gt;
&lt;h2 id=&quot;alternative&quot;&gt;Alternative&lt;/h2&gt;
&lt;p&gt;If you are looking for an easy-to-integrate solution that overcomes these limitations, take a look at IMG.LY’s &lt;a href=&quot;https://img.ly/docs/vesdk/android/introduction/getting_started?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;VideoEditor SDK&lt;/a&gt;. It provides more than 60 high-quality adjustable filters out-of-the-box. Moreover, you can easily add &lt;a href=&quot;https://img.ly/docs/vesdk/android/features/filters/#add-custom-lut-filters?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;custom filters&lt;/a&gt; using LUT files. VideoEditor SDK works for Android SDK version 21 and above and thus targets more devices.&lt;/p&gt;
&lt;p&gt;If the purpose is to apply effects during the playback, the VidEffects library is a solid and free open-source solution. While it handles all the complex video editing, developers will have to spend some time developing the layout.&lt;/p&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>Neslihan</dc:creator><media:content url="https://blog.img.ly/2022/05/videffects-add-filter-to-video-android.png" medium="image"/><category>How-To</category><category>Video Editing</category><category>Android</category><category>Android App Development</category><category>Mobile App Development</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>Case Study: Vapiano &amp; PhotoEditor SDK</title><link>https://img.ly/blog/case-study-vapiano-photoeditor-sdk-7f335ecc6ac7/</link><guid isPermaLink="true">https://img.ly/blog/case-study-vapiano-photoeditor-sdk-7f335ecc6ac7/</guid><description>Restaurant experience gone App </description><pubDate>Thu, 24 Aug 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The German casual dining restaurant chain &lt;a href=&quot;https://vapiano.com/&quot;&gt;Vapiano&lt;/a&gt; facilitates and streamlines their customer’s visits with a feature-rich app that lets its users: check in at the restaurant, order beverages and desserts from their seat, pay after their visit, collect loyalty points, browse the menu, save favorite dishes, locate the nearest subsidiary and even create images for social media postings.&lt;/p&gt;
&lt;p&gt;With 180 restaurants in 31 countries, Vapiano is one of the biggest fast-casual dining chains around. Especially at lunchtime and early evening hours each restaurant wines and dines plenty of hungry customers, with Vapiano’s current approach (ordering at the counter, receiving the meal, finding a table and after that checking out on a regular register) that sometimes resulted in long lines and consequently frustration among their guests. With the Vapiano app, that is a thing of the past as the visit can almost solely be handled by the app from check-in to check-out. As Vapiano’s target audience is very photography and social media affine, their app holds another gem for their users to play around with. When taking a picture of themselves and their food in a Vapiano restaurant, the users can directly add Vapiano stickers to their pictures and then post them online. Said feature was realized by &lt;a href=&quot;https://mobilabsolutions.com/&quot;&gt;MobiLab Solutions&lt;/a&gt; utilizing the &lt;a href=&quot;https://img.ly/photo-sdk&quot;&gt;PhotoEditor SDK&lt;/a&gt;. We sat down with Max Afflerbach and Robert Rabe of MobiLab Solutions GmbH to talk about their experiences with PhotoEditor SDK.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 800px) 800px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;800&quot; height=&quot;686&quot; src=&quot;https://img.ly/_astro/1-lH2pCjVBFT4HH2MKY6yF3Q_1LBv8g.webp&quot; srcset=&quot;/_astro/1-lH2pCjVBFT4HH2MKY6yF3Q_Z1p42nx.webp 640w, /_astro/1-lH2pCjVBFT4HH2MKY6yF3Q_LL6J.webp 750w, /_astro/1-lH2pCjVBFT4HH2MKY6yF3Q_1LBv8g.webp 800w&quot;&gt;&lt;/p&gt;
&lt;p&gt;“Vapiano’s vision regarding the photo feature is to spread their brand, enhance brand recognition and broaden the brand’s visibility,” Max Afflerbach, Chief Customer Officer at MobiLab Solutions explains. “Basically, they wanted to provide their guests with a tool that facilitates what they’re already doing when dining at Vapiano, that is taking pictures of their food and then uploading them to Snapchat, Instagram, Facebook, you name it. And so, we came up with a built-in branding feature that uses custom stickers.”&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“…on StackOverflow or Quora, &lt;a href=&quot;https://img.ly/photo-sdk&quot;&gt;PhotoEditor SDK&lt;/a&gt; is listed and praised as the only real alternative to Aviary”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As they were on a schedule and didn’t have the time to develop the feature themselves the folks at MobiLab started searching for a third-party solution. “We’ve been looking for an SDK that does exactly what we imagined the feature to be capable of, namely taking a picture, adding assets and then exporting it,” says Robert Rabe, iOS developer at MobiLab Solutions. “We first considered Adobe Creative SDK because it is the best-known SDK in that field. However, it lacked a crucial feature for us that PhotoEditor SDK luckily has and that is the possibility to upload custom stickers,” says Max Afflerbach. “Also,” Rabe adds, “we weren’t 100% sure whether this whole thing would work without the user having to log into the Adobe Cloud.” “When you’re searching for other image processing SDKs on StackOverflow or Quora, PhotoEditor SDK is listed and praised as the only real alternative to Aviary. And besides, there aren’t exactly a lot of SDKs out there that cover both iOS and Android. So, that wasn’t a tough decision at all,” Afflerbach explains.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 800px) 800px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;800&quot; height=&quot;686&quot; src=&quot;https://img.ly/_astro/1-ReYFlxaZFXGtSClTwKYlRw_Z2bRyNU.webp&quot; srcset=&quot;/_astro/1-ReYFlxaZFXGtSClTwKYlRw_ZilXvM.webp 640w, /_astro/1-ReYFlxaZFXGtSClTwKYlRw_17tOXu.webp 750w, /_astro/1-ReYFlxaZFXGtSClTwKYlRw_Z2bRyNU.webp 800w&quot;&gt;&lt;/p&gt;
&lt;p&gt;From the initial decision to work with PhotoEditor SDK until the feature was finished and ready for rollout, only a short period passed as Rabe explains: “Working with the SDK is really straightforward. The implementation is fast, and it’s all well documented. The SDK is a powerful tool and holds a lot of features with a great many possibilities. Setting up the feature exactly as we wanted it to be didn’t take longer than three working days tops. And if we had any issues or questions, we had no problems whatsoever getting in touch with the folks at PhotoEditor SDK which is really nice.”&lt;/p&gt;
&lt;p&gt;“I really like the product, it’s working very well, and especially the communication with the PhotoEditor SDK team was highly pleasant,” Robert Rabe concludes. “Working together with the team of &lt;a href=&quot;https://img.ly/photo-sdk&quot;&gt;PhotoEditor SDK&lt;/a&gt; was super easygoing, the few requests and inquiries we had were answered quickly, and the technical licensing was a cinch as well. We are delighted with the product, the integration was very simple, and our developers are happy, I guess you couldn’t ask for more from an agency’s perspective,” Max Afflerbach adds.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thanks for reading! To stay in the loop, subscribe to our &lt;a href=&quot;https://photoeditorsdk.us13.list-manage.com/subscribe?u=dc9f652839dbb620d14d6d28d&amp;#x26;id=04a306e4b2&quot;&gt;Newsletter&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Felix</dc:creator><media:content url="https://blog.img.ly/2020/04/image-41.png" medium="image"/><category>Android App Development</category><category>iOS App Development</category><category>Social Media</category><category>Mobile Photography</category><category>Case Study</category><category>Case Studies</category></item></channel></rss>