<?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>Malte – IMG.LY Blog</title><description>Posts by Malte on the IMG.LY blog.</description><link>https://img.ly/blog/author/malte/</link><language>en-us</language><image><url>https://img.ly/apple-touch-icon.png</url><title>Malte – IMG.LY Blog</title><link>https://img.ly/blog/author/malte/</link></image><atom:link href="https://img.ly/blog/author/malte/rss.xml" rel="self" type="application/rss+xml"/><generator>Astro</generator><lastBuildDate>Fri, 19 Jun 2026 11:25:52 GMT</lastBuildDate><ttl>60</ttl><item><title>CE.SDK v1.7.0 Release and Roadmap</title><link>https://img.ly/blog/creative-editor-sdk-v_1_7_0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v_1_7_0-release-notes/</guid><description>Enjoy powerful Blur and Effects APIs, Shadows, Rotation of Groups and Hierarchies, and more. Our Product Roadmap will keep you up-to-date.</description><pubDate>Mon, 08 Aug 2022 12:07:47 GMT</pubDate><content:encoded>&lt;p&gt;Today, we are thrilled to highlight the best new features and changes in CE.SDK since our &lt;a href=&quot;https://img.ly/blog/creative-editor-sdk-v_1_6_0-release-notes/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;v1.6.0 Release&lt;/a&gt;. We have also published our &lt;a href=&quot;https://roadmap.img.ly/&quot;&gt;&lt;strong&gt;Product Roadmap for CE.SDK&lt;/strong&gt;&lt;/a&gt; to share our vision and direction for upcoming releases. This roadmap will let you know ahead of time what features you can expect from us and accelerate your product planning and development. We are excited to hear your feedback and suggestions to build more powerful features for your application!&lt;/p&gt;
&lt;h2 id=&quot;cesdk-v170&quot;&gt;CE.SDK v1.7.0&lt;/h2&gt;
&lt;p&gt;This release includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Auto Close Option in Web UI Configuration for Asset Libraries&lt;/li&gt;
&lt;li&gt;Custom URI Resolver&lt;/li&gt;
&lt;li&gt;Improving Mobile Touch Support&lt;/li&gt;
&lt;li&gt;Rotation of Groups and Hierarchies&lt;/li&gt;
&lt;li&gt;Custom Asset Source UI&lt;/li&gt;
&lt;li&gt;Disconnecting UI Variants from Roles&lt;/li&gt;
&lt;li&gt;Asset Source ApplyAsset API&lt;/li&gt;
&lt;li&gt;Blur API&lt;/li&gt;
&lt;li&gt;Effects API&lt;/li&gt;
&lt;li&gt;Image Fills API&lt;/li&gt;
&lt;li&gt;Image Straighten API&lt;/li&gt;
&lt;li&gt;Improved Group Selection and API&lt;/li&gt;
&lt;li&gt;Scopes API&lt;/li&gt;
&lt;li&gt;Shadows API&lt;/li&gt;
&lt;li&gt;Zoom API&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;auto-close-option-in-web-ui-configuration-for-asset-libraries&quot;&gt;Auto Close Option in Web UI Configuration for Asset Libraries&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;Should it stay or should it go? Have control over your library behavior with this update.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 740px) 740px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;740&quot; height=&quot;321&quot; src=&quot;https://img.ly/_astro/auto_close_lib_1W98pV.webp&quot; srcset=&quot;/_astro/auto_close_lib_1Jj7hj.webp 640w, /_astro/auto_close_lib_1W98pV.webp 740w&quot;&gt;&lt;/p&gt;
&lt;p&gt;There are no one-size-fits-all solutions for the behavior of asset library panels after an action was triggered. It depends on the use case and might vary between the panels and the available screen space. Thus, this is now configurable.&lt;/p&gt;
&lt;h3 id=&quot;custom-uri-resolver&quot;&gt;Custom URI Resolver&lt;/h3&gt;
&lt;p&gt;Custom URI Resolvers give you full control over how URIs should be resolved. You can create custom storage backends and even resolve different resolution images in different instances. Find more information in our &lt;a href=&quot;https://img.ly/docs/cesdk/js/open-the-editor/uri-resolver-36b624/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;improving-mobile-touch-support&quot;&gt;Improving Mobile Touch Support&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;Great design-to-go: improved mobile touch support.&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/mobile_touch_Z2g42pt.webp&quot; srcset=&quot;/_astro/mobile_touch_ZJKt2L.webp 640w, /_astro/mobile_touch_Z1AgDJY.webp 750w, /_astro/mobile_touch_ZGdINX.webp 828w, /_astro/mobile_touch_Z2doG6d.webp 1080w, /_astro/mobile_touch_imcDC.webp 1280w, /_astro/mobile_touch_Z2g42pt.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Input handling was streamlined to handle both touch and mouse input efficiently. On touch devices, all handles maintain the recommended minimum size for touch input and are intelligently hidden to minimize overlap. Thanks to this mechanism, resizing and rotating are always a breeze.&lt;/p&gt;
&lt;h3 id=&quot;rotation-of-groups-and-hierarchies&quot;&gt;Rotation of Groups and Hierarchies&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;Simplify your design process by grouping elements and edit them altogether.&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/rotation_of_groups_oxAW4.webp&quot; srcset=&quot;/_astro/rotation_of_groups_1NFy6r.webp 640w, /_astro/rotation_of_groups_2ss6Qm.webp 750w, /_astro/rotation_of_groups_ZCO3fG.webp 828w, /_astro/rotation_of_groups_29du7E.webp 1080w, /_astro/rotation_of_groups_Z1gd1mB.webp 1280w, /_astro/rotation_of_groups_oxAW4.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;The engine and user interface add options for rotating groups and design blocks with children. This allows changing the rotation of multiple elements at once quickly.&lt;/p&gt;
&lt;h3 id=&quot;custom-asset-source-ui&quot;&gt;Custom Asset Source UI&lt;/h3&gt;
&lt;p&gt;Instead of fixed entry points such as “Images,” “Stickers,” or “Shapes,” we want to enable custom and flexible entry points. Until today, we tied them to a block type, which is currently only relevant when users add an asset to the scene.&lt;/p&gt;
&lt;h3 id=&quot;moving-from-roles-to-abilities-disconnecting-ui-variants-from-roles&quot;&gt;Moving from Roles to Abilities: Disconnecting UI Variants from Roles&lt;/h3&gt;
&lt;p&gt;Before the change, the Advanced UI was tied to the creator role and the Default UI was tied to the Adopter Role. This is now no longer the case. The scopes and editing options are still controlled by the abilities of the current role.&lt;/p&gt;
&lt;h3 id=&quot;shadows-in-advanced-ui&quot;&gt;Shadows in Advanced UI&lt;/h3&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/shadows_in_advanced_API_Z1FOoi7.webp&quot; srcset=&quot;/_astro/shadows_in_advanced_API_Z45be.webp 640w, /_astro/shadows_in_advanced_API_Zy5jRz.webp 750w, /_astro/shadows_in_advanced_API_egkMm.webp 828w, /_astro/shadows_in_advanced_API_Qlk0w.webp 1080w, /_astro/shadows_in_advanced_API_27QwKF.webp 1280w, /_astro/shadows_in_advanced_API_Z1FOoi7.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;With this update, we roll out the long-awaited ability to apply shadows to elements in our Advanced UI. Realistic drop shadow effects add more depth to your designs with a few clicks – no other editor is needed.&lt;/p&gt;
&lt;h3 id=&quot;blur-api&quot;&gt;Blur API&lt;/h3&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/blur_API_Zfrq6A.webp&quot; srcset=&quot;/_astro/blur_API_1o848m.webp 640w, /_astro/blur_API_ZGbmUm.webp 750w, /_astro/blur_API_ZziuOW.webp 828w, /_astro/blur_API_Z2rt0Ii.webp 1080w, /_astro/blur_API_Z1lsdpr.webp 1280w, /_astro/blur_API_Zfrq6A.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;We introduce new APIs to modify the blur for images and other blocks. This change allows programmatic access to add blur effects in automation cases and when building your own UI.&lt;/p&gt;
&lt;h3 id=&quot;effects-api&quot;&gt;Effects API&lt;/h3&gt;
&lt;p&gt;We introduce new APIs to modify the effect stack for shapes and other blocks. This allows programmatic access to effects like adjustments, LUT filters, and many more.&lt;/p&gt;
&lt;h3 id=&quot;image-fills-api&quot;&gt;Image Fills API&lt;/h3&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/image_fill_HmPh2.webp&quot; srcset=&quot;/_astro/image_fill_Z1IbTb.webp 640w, /_astro/image_fill_Z14KA8n.webp 750w, /_astro/image_fill_1rwknl.webp 828w, /_astro/image_fill_274TKn.webp 1080w, /_astro/image_fill_1pdRvH.webp 1280w, /_astro/image_fill_HmPh2.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Currently, you can only access and use images with the image block. However, pages or vector shapes could use more than just a color or gradient fill. Therefore, we broaden the concept of fills by allowing every block to have an image fill, e.g., pages. This change will enable building a more natural photo- or video-editor experience. &lt;a href=&quot;https://img.ly/docs/cesdk/js/fills/overview-3895ee/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;Documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;image-straighten-api&quot;&gt;Image Straighten API&lt;/h3&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/image_straighten_Z1uLpF1.webp&quot; srcset=&quot;/_astro/image_straighten_Z29KtL5.webp 640w, /_astro/image_straighten_vwHgA.webp 750w, /_astro/image_straighten_Z1O428T.webp 828w, /_astro/image_straighten_ZymsGh.webp 1080w, /_astro/image_straighten_Z124rb9.webp 1280w, /_astro/image_straighten_Z1uLpF1.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;We are extending the Image Crop API to allow straightening, flipping, and rotating images during cropping. This change allows more fine-grained control.&lt;/p&gt;
&lt;h3 id=&quot;improved-group-selection-and-api&quot;&gt;Improved Group Selection and API&lt;/h3&gt;
&lt;p&gt;There are multiple options to select blocks inside a group:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;selecting a group first and with each click select one block deeper in the hierarchy&lt;/li&gt;
&lt;li&gt;selecting an element under the cursor directly, neglecting the hierarchy&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Previously, we defaulted to different behaviors depending on the user’s role. Now, this is configurable and also customizable during runtime via APIs. Therefore, it’s up to the implementor how the selection should work.&lt;/p&gt;
&lt;h3 id=&quot;scopes-api&quot;&gt;Scopes API&lt;/h3&gt;
&lt;p&gt;We introduce new APIs to modify the scopes for blocks. This update allows programmatic access to change the scopes for users and allows control over the possible edits a user can make to a scene.&lt;/p&gt;
&lt;h3 id=&quot;shadows-api&quot;&gt;Shadows API&lt;/h3&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/shadows_API_jTf6L.webp&quot; srcset=&quot;/_astro/shadows_API_PF3VL.webp 640w, /_astro/shadows_API_1R2ETk.webp 750w, /_astro/shadows_API_Gh7bU.webp 828w, /_astro/shadows_API_2a5X4g.webp 1080w, /_astro/shadows_API_Z1i5WNW.webp 1280w, /_astro/shadows_API_jTf6L.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;We introduce new APIs to modify shadows for images and other blocks. This change allows programmatic access to add shadow effects to be used in automation cases and when you build your UI.&lt;/p&gt;
&lt;h3 id=&quot;zoom-api&quot;&gt;Zoom API&lt;/h3&gt;
&lt;p&gt;We introduce new APIs to modify the current zoom level. This allows programmatic access to change the current zoom easily for automation use-cases or for building your own user interface.&lt;/p&gt;
&lt;h2 id=&quot;product-roadmap&quot;&gt;Product Roadmap&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/API_general_snkLp.webp&quot; srcset=&quot;/_astro/API_general_Z2gaGAs.webp 640w, /_astro/API_general_Z1eN5CT.webp 750w, /_astro/API_general_Z2pyDlj.webp 828w, /_astro/API_general_2iz3IT.webp 1080w, /_astro/API_general_Z19BR9j.webp 1280w, /_astro/API_general_snkLp.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;p&gt;As mentioned before, we are happy to publish our &lt;a href=&quot;https://roadmap.img.ly&quot;&gt;Product Roadmap&lt;/a&gt; to let you in on our new features and enhancements for CE.SDK. This way, we can elaborate our decisions and plans for the product and how you can benefit while allowing you to give us feedback and indicate the importance of particular features.&lt;br&gt;
Now that you know what’s coming down the pike, you can prepare for the release of significant improvements and new features such as &lt;strong&gt;Video Support for Web&lt;/strong&gt; or &lt;strong&gt;Native iOS Support&lt;/strong&gt; well in advance.&lt;/p&gt;
&lt;h3 id=&quot;thanks-for-reading-let-us-know-what-you-think-on-twitter-to-stay-in-the-loop-subscribe-to-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;! 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;/h3&gt;</content:encoded><dc:creator>Malte</dc:creator><dc:creator>Daniel</dc:creator><media:content url="https://blog.img.ly/2022/08/creative-editor-sdk-design-photo-editor-javascript.png" medium="image"/><category>Release Notes</category><category>CE.SDK</category><category>Roadmap</category><category>Web Application</category><category>Web Development</category><category>Creative Editor</category><category>Design Editor</category><category>Photo Editor</category><category>SDK</category></item><item><title>CE.SDK v1.6.0 Release</title><link>https://img.ly/blog/creative-editor-sdk-v_1_6_0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v_1_6_0-release-notes/</guid><description>CE.SDK brings stunning Linear Gradient Fills, Blend Modes, powerful APIs, and more.</description><pubDate>Fri, 20 May 2022 09:21:48 GMT</pubDate><content:encoded>&lt;p&gt;Today, we are highlighting the best new features and changes in CE.SDK since our &lt;a href=&quot;https://img.ly/blog/creative-editor-sdk-v_1_5_0-release-notes/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;v1.5.0 Release&lt;/a&gt; six weeks ago. CE.SDK v1.6.0 is adding:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Linear Gradient Fills&lt;/li&gt;
&lt;li&gt;Strokes, Outline, Insets, and Stroke Patterns&lt;/li&gt;
&lt;li&gt;Blend Modes&lt;/li&gt;
&lt;li&gt;Scale Groups, Multi-Selection, and Hierarchies&lt;/li&gt;
&lt;li&gt;UI Template Library&lt;/li&gt;
&lt;li&gt;Floating and Static Asset Library Panels&lt;/li&gt;
&lt;li&gt;Placeholders API&lt;/li&gt;
&lt;li&gt;Editing State APIs&lt;/li&gt;
&lt;li&gt;API for Image Fit Modes&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;linear-gradient-fills&quot;&gt;Linear Gradient Fills&lt;/h3&gt;
&lt;p&gt;With this update, we are introducing linear gradient fills. This feature creates a gradual blend between two colors, including transparency. Use the Color Picker to switch between solid color and linear gradient fill modes and determine the order of colors.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Let users create stunning backgrounds or shapes with Linear Gradient Fills.&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/Gradient_ZjWgRX.webp&quot; srcset=&quot;/_astro/Gradient_Z2n9Nkn.webp 640w, /_astro/Gradient_BHSpP.webp 750w, /_astro/Gradient_IAKvf.webp 828w, /_astro/Gradient_Z2vXQuF.webp 1080w, /_astro/Gradient_Z1pX4bO.webp 1280w, /_astro/Gradient_ZjWgRX.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;strokes-outline-insets-and-stroke-patterns&quot;&gt;Strokes, Outline, Insets, and Stroke Patterns&lt;/h3&gt;
&lt;p&gt;This feature introduces strokes and stroke patterns. Strokes apply to any block, including images, text, and shapes. Use our APIs or UIs to set the stroke width, color, style, and more options affecting the stroke appearance.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Walk the line: apply strokes to any block and determine the appearance.&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/Strokes_photo_design_editor_SDK-1_1XfV7m.webp&quot; srcset=&quot;/_astro/Strokes_photo_design_editor_SDK-1_XdcAU.webp 640w, /_astro/Strokes_photo_design_editor_SDK-1_Zq9kWH.webp 750w, /_astro/Strokes_photo_design_editor_SDK-1_Z2uLzL5.webp 828w, /_astro/Strokes_photo_design_editor_SDK-1_1gU45l.webp 1080w, /_astro/Strokes_photo_design_editor_SDK-1_ZU0yN7.webp 1280w, /_astro/Strokes_photo_design_editor_SDK-1_1XfV7m.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;blend-modes&quot;&gt;Blend Modes&lt;/h3&gt;
&lt;p&gt;Blend modes are a popular feature in creative and image editing tools. They blend two blocks or layers to get different types of effects. This feature is available in both the API and the UI.&lt;/p&gt;
&lt;h3 id=&quot;scale-groups-multi-selection-and-hierarchies&quot;&gt;Scale Groups, Multi-Selection, and Hierarchies&lt;/h3&gt;
&lt;p&gt;Our engine and user interface now provide options to scale groups, multi-select and create design blocks with children. You can easily change the scaling of multiple elements at once. This also simplifies resizing and rescaling your template designs for other page and art board sizes.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Easily group, multi-select and scale your elements.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 887px) 887px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;887&quot; height=&quot;492&quot; src=&quot;https://img.ly/_astro/creative-editor-group-elements_CE-SDK_2lijEh.webp&quot; srcset=&quot;/_astro/creative-editor-group-elements_CE-SDK_Zrb4wY.webp 640w, /_astro/creative-editor-group-elements_CE-SDK_ZfRGvT.webp 750w, /_astro/creative-editor-group-elements_CE-SDK_1dzvKF.webp 828w, /_astro/creative-editor-group-elements_CE-SDK_2lijEh.webp 887w&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;ui-template-library&quot;&gt;UI Template Library&lt;/h3&gt;
&lt;p&gt;We are introducing the template library in all UIs. Allow users to switch between multiple templates while editing.&lt;/p&gt;
&lt;h3 id=&quot;floating-and-static-asset-library-panels&quot;&gt;Floating and Static Asset Library Panels&lt;/h3&gt;
&lt;p&gt;For some screen sizes and use-cases, it might be tedious that the asset library floats over your canvas and covers your design. Therefore, you can now configure the asset library panel to be either floating or static. A static asset library won’t overlap with your design and adjusts to your screen size perfectly.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;An editor with a view: set your Asset Library to float or static.&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/Float-Static_1XM7K1.webp&quot; srcset=&quot;/_astro/Float-Static_Z7nVnb.webp 640w, /_astro/Float-Static_ZWT75o.webp 750w, /_astro/Float-Static_Z3Qc9n.webp 828w, /_astro/Float-Static_21rt4h.webp 1080w, /_astro/Float-Static_ZwXKYO.webp 1280w, /_astro/Float-Static_1XM7K1.webp 1480w&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;placeholders-api&quot;&gt;Placeholders API&lt;/h3&gt;
&lt;p&gt;CE.SDK 1.6 introduces an additional API that allows you to interact with all placeholders on the canvas. The API queries the number of placeholders in a template or document and lists all available placeholders in the current scene.&lt;/p&gt;
&lt;h3 id=&quot;editing-state-apis&quot;&gt;Editing State APIs&lt;/h3&gt;
&lt;p&gt;We extend the API to allow querying and modifying the current editing mode. That includes changing the on-canvas editing mode to &lt;em&gt;Crop&lt;/em&gt;, &lt;em&gt;Text&lt;/em&gt;, or others. You can also query the editor state for helpful information like the desired cursor type and rotation and the text cursor position. To observe these values more comfortably, an additional endpoint allows registering for callbacks whenever the editing state changes.&lt;/p&gt;
&lt;h3 id=&quot;api-for-image-fit-modes&quot;&gt;API for Image Fit Modes&lt;/h3&gt;
&lt;p&gt;The API now allows switching between fit modes for images:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Crop&lt;/code&gt; applies crop properties, and ignores the aspect ratio.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Cover&lt;/code&gt; resizes the image aspect-aware to fill the frame.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Contain&lt;/code&gt; allows resizing the image aspect-aware to fit into its frame.&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>Malte</dc:creator><dc:creator>Daniel</dc:creator><media:content url="https://blog.img.ly/2022/05/creative-editor-sdk-v-1_6_0.png" medium="image"/><category>Release Notes</category><category>Web Development</category><category>JavaScript</category><category>Design Editor</category><category>Photo Editor</category></item><item><title>CE.SDK v1.5.0 Release</title><link>https://img.ly/blog/creative-editor-sdk-v_1_5_0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/creative-editor-sdk-v_1_5_0-release-notes/</guid><description>This quarter CE.SDK brings PDF Export, High-Performance Rendering, and more updates.</description><pubDate>Thu, 14 Apr 2022 12:53:45 GMT</pubDate><content:encoded>&lt;p&gt;Another six weeks have passed since our &lt;a href=&quot;https://img.ly/blog/ce-sdk-v140-release/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;v1.4.0 release&lt;/a&gt; that brought an updated asset library and headless APIs. Since the initial CE.SDK release, we’ve been listening to your feedback and continuously releasing updates to improve and expand CE.SDK to better serve your needs. Here’s a short overview of what’s happened in the last quarter.&lt;/p&gt;
&lt;p&gt;CE.SDK v1.5.0 is adding:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hierarchies (Groups)&lt;/li&gt;
&lt;li&gt;Template Imports &amp;#x26; Exports&lt;/li&gt;
&lt;li&gt;More Performance, More Power&lt;/li&gt;
&lt;li&gt;High-Performance Rendering&lt;/li&gt;
&lt;li&gt;Improved Touch Support&lt;/li&gt;
&lt;li&gt;PDF Export&lt;/li&gt;
&lt;li&gt;Subscription/Events API&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;hierarchies-groups&quot;&gt;Hierarchies (Groups)&lt;/h2&gt;
&lt;p&gt;With this release, we finally extended our flat hierarchy model to the typical parent-child relationship model between items on the canvas. That allows you to build an even more complex design: Group items to form a single unit and handle those items as one or control their opacity.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;group-elements-editor.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 841px) 841px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;841&quot; height=&quot;564&quot; src=&quot;https://img.ly/_astro/group-elements-editor_OYf4m.webp&quot; srcset=&quot;/_astro/group-elements-editor_1uc9Su.webp 640w, /_astro/group-elements-editor_Z2l4gRb.webp 750w, /_astro/group-elements-editor_q95Qy.webp 828w, /_astro/group-elements-editor_OYf4m.webp 841w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;template-imports--exports&quot;&gt;Template Imports &amp;#x26; Exports&lt;/h2&gt;
&lt;p&gt;Export your template scenes as .scene-files that pack all assets that were used. You can also share your template by URL - all dependencies will resolve accordingly.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;export-scene-file.png&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1484px) 1484px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1484&quot; height=&quot;994&quot; src=&quot;https://img.ly/_astro/export-scene-file-1_Z1uOhDg.webp&quot; srcset=&quot;/_astro/export-scene-file-1_Z1YOoN9.webp 640w, /_astro/export-scene-file-1_Z26gUFE.webp 750w, /_astro/export-scene-file-1_2puJLQ.webp 828w, /_astro/export-scene-file-1_ZUXUBt.webp 1080w, /_astro/export-scene-file-1_ZoLrs3.webp 1280w, /_astro/export-scene-file-1_Z1uOhDg.webp 1484w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;more-performance&quot;&gt;More Performance&lt;/h2&gt;
&lt;p&gt;We have replaced our underlying rendering engine with a new high-performance implementation, resulting in the performance of distinct scenarios improving by 100%. Likewise, as a result of polishing up various logic, CE.SDK runs faster than ever.&lt;/p&gt;
&lt;h2 id=&quot;improved-touch--mobile-support&quot;&gt;Improved Touch &amp;#x26; Mobile Support&lt;/h2&gt;
&lt;p&gt;After evaluation, CE.SDK v1.5.0 expands upon our mobile advancement efforts by improving our web UI for touch inputs on mobile devices.&lt;/p&gt;
&lt;h2 id=&quot;pdf-export&quot;&gt;PDF Export&lt;/h2&gt;
&lt;p&gt;CE.SDK now supports PDF export. Vector paths and images are embedded, and rasterization will only be applied when necessary. Scenes of multiple pages can be exported as a multipage document.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Create a design or a multipage document, such as a presentation, and export it as a PDF. Your text remains selectable.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1132px) 1132px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1132&quot; height=&quot;690&quot; src=&quot;https://img.ly/_astro/pdf-online-creator_Z2nOnpt.webp&quot; srcset=&quot;/_astro/pdf-online-creator_1YzfbM.webp 640w, /_astro/pdf-online-creator_JPlYt.webp 750w, /_astro/pdf-online-creator_1gRVvw.webp 828w, /_astro/pdf-online-creator_1bCiFX.webp 1080w, /_astro/pdf-online-creator_Z2nOnpt.webp 1132w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;build-your-custom-ui&quot;&gt;Build Your Custom UI&lt;/h2&gt;
&lt;p&gt;We vastly improved support for building custom UIs on top of CE.SDK engine:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;CreativeEngine&lt;/code&gt; offers a powerful set of APIs to inspect, modify and interact with a scene.&lt;/li&gt;
&lt;li&gt;A new set of UI-specific APIs, including history and zoom management, was added as a preview.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;events-api&quot;&gt;Events API&lt;/h2&gt;
&lt;p&gt;An Event API allows subscribing to scene changes and updates custom UI components accordingly.&lt;/p&gt;
&lt;h2 id=&quot;other&quot;&gt;&lt;strong&gt;Other&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;For an even smoother UI experience, we have improved the visual quality of element state indicators, and they now respect the element order.&lt;/p&gt;
&lt;h3 id=&quot;thanks-for-reading-to-stay-in-the-loop-with-our-latest-articles-and-releases-subscribe-to-our-newsletter&quot;&gt;Thanks for reading! To stay in the loop with our latest articles and releases, subscribe to our &lt;a href=&quot;https://photoeditorsdk.us13.list-manage.com/subscribe?u=dc9f652839dbb620d14d6d28d&amp;#x26;id=04a306e4b2&quot;&gt;Newsletter&lt;/a&gt;.&lt;/h3&gt;</content:encoded><dc:creator>Daniel</dc:creator><dc:creator>Malte</dc:creator><media:content url="https://blog.img.ly/2022/04/ce-sdk-v_1_5_0-editor-2.png" medium="image"/><category>Release Notes</category><category>Web Development</category><category>Design Editor</category><category>Photo Editor</category></item><item><title>From 2D to 3D Photo Editing</title><link>https://img.ly/blog/from-2d-to-3d-photo-editing-948690b7b45e/</link><guid isPermaLink="true">https://img.ly/blog/from-2d-to-3d-photo-editing-948690b7b45e/</guid><pubDate>Tue, 26 Jun 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Last November, we released Portrait, an iOS app that helps create amazing, stylized selfies and portraits instantly.&lt;/p&gt;
&lt;p&gt;With over a million downloads and many more portrait images created, we feel that the idea and vision of Portrait was more than confirmed. The central component of Portrait is an AI that is trained to clip portraits from the background, a technique we are eager to further improve and refine. In fact, Portrait helped us to explore a novel technique for image editing, as we were able to leverage a new powerful data set in photography: depth data.&lt;/p&gt;
&lt;p&gt;We began feeding our AI models with the depth data from the iPhone Xs TrueDepth camera and had one goal in mind: to infer depth information for portrait imagery, or bringing three-dimensionality into a two-dimensional photo. Along the way, we created a new architecture concept, that allows performance and memory improvements through modularizing and reusing neural networks.&lt;/p&gt;
&lt;p&gt;In the following article, we’d like to present some of our results along with the insights we made.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;An image and it’s corresponding depth map. (Source)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 600px) 600px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;600&quot; height=&quot;801&quot; src=&quot;https://img.ly/_astro/1-r23YFAfXu_OHchBqd4plKw_Z1KsEdA.webp&quot; srcset=&quot;/_astro/1-r23YFAfXu_OHchBqd4plKw_Z1KsEdA.webp 600w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-new-cool-depthdata&quot;&gt;The New Cool: Depth Data&lt;/h2&gt;
&lt;p&gt;The usage of depth data in image editing initially became available with the iPhone 7 Plus when Apple introduced ‘Portrait Mode’. By combining a depth map and face detection, the devices are able to blur our distant objects and backgrounds, mimicking a ‘bokeh’ or depth of field effect, which is well known from DSLRs cameras.&lt;/p&gt;
&lt;p&gt;While the actual implementation varies, all major manufacturers nowadays offer a similar mode by incorporating depth data into their image editing pipeline. This is either achieved through the conventional dual or even triple camera on the back of a phone, dual-pixel offset calculations combined with machine learning or dedicated sensors like Apples TrueDepth module. In fact, for a modern flagship phone, some sort of depth based portrait mode is almost a commodity.&lt;/p&gt;
&lt;p&gt;From a developers perspective, things look a little different: Depth data became a first-class citizen throughout the iOS APIs in iOS 11 and such data is now easily accessible on supported devices. Android users obviously have access to depth data as well, either by utilizing multiple cameras or by Googles dual-pixel based machine learning approach, seen in the newer Pixel 2 phones. But contrary to iOS, Android doesn’t yet offer a common developer interface to access such data. In fact, developers aren’t able to access any of the depth information Google or other manufacturers collected within their camera apps. This means developers would either need to implement the algorithm to infer depth from two images themselves or try to rebuild Googles sophisticated machine learning powered system. Neither of these options is practical and probably not even possible given the usual limitations to camera APIs.&lt;/p&gt;
&lt;p&gt;So although being quite common, depth data isn’t as easily accessible for developers as one might think. Right now you’re out of luck on Android, dependent on hardware on iOS and even then limited to the 1.000$ flagship if you’re interested in depth for images taken with the front camera. And last but not least, across all devices and platforms, there is no way for you to generate a depth map for an existing image.&lt;/p&gt;
&lt;h2 id=&quot;deep-possibilities&quot;&gt;Deep Possibilities&lt;/h2&gt;
&lt;p&gt;Despite the restrictions, we decided to first explore the power of depth for image editing, as depth data provides many new exciting creative possibilities:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A depth map visualized in 3D space. (Source)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1000px) 1000px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1000&quot; height=&quot;433&quot; src=&quot;https://img.ly/_astro/1-UyLhWSDUQdKU-0wfKcYPgg_2cc62N.webp&quot; srcset=&quot;/_astro/1-UyLhWSDUQdKU-0wfKcYPgg_1RzFAE.webp 640w, /_astro/1-UyLhWSDUQdKU-0wfKcYPgg_1jHR91.webp 750w, /_astro/1-UyLhWSDUQdKU-0wfKcYPgg_1y3t3X.webp 828w, /_astro/1-UyLhWSDUQdKU-0wfKcYPgg_2cc62N.webp 1000w&quot;&gt;&lt;/p&gt;
&lt;p&gt;If we have a depth map for a given image, our editing possibilities are increased dramatically. Instead of a 2D image, a flat plane of color values, we suddenly have a depth value for each individual pixel, which translates into a 3D landscape highlighting distinct objects in the foreground and a clear indication of background.&lt;/p&gt;
&lt;h3 id=&quot;depth-aware-editing&quot;&gt;Depth-aware Editing&lt;/h3&gt;
&lt;p&gt;Instead of relying on color and texture differences to determine fore- and background, one could literally edit these regions individually. This allows adjustments like darkening the background while lightening the foreground, which makes portraits ‘pop’. If we’d be able to generate a high-resolution depth map, we could easily replace the AI currently used in Portrait and would allow even more sophisticated creatives. Thanks to the new APIs, there are already some awesome iOS apps available that specialize in depth based editing. One famous example is Darkroom with their “depth-aware filters”:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Darkrooms ‘depth-aware’ filters. (Source)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1000px) 1000px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1000&quot; height=&quot;450&quot; src=&quot;https://img.ly/_astro/1-RP-bR21xfOyDciBNgiQovQ_e4d4z.webp&quot; srcset=&quot;/_astro/1-RP-bR21xfOyDciBNgiQovQ_1k66MV.webp 640w, /_astro/1-RP-bR21xfOyDciBNgiQovQ_H7L4v.webp 750w, /_astro/1-RP-bR21xfOyDciBNgiQovQ_chxWN.webp 828w, /_astro/1-RP-bR21xfOyDciBNgiQovQ_e4d4z.webp 1000w&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;depth-of-fieldeffects&quot;&gt;Depth of Field Effects&lt;/h3&gt;
&lt;p&gt;As a depth of field or bokeh effect was the initial motivation for Apple to incorporate depth sensing technology, it is one of the most obvious applications. Depth is crucial for such an effect, as the amount of bluriness of any given region directly depends on its distance to the camera lens.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 450px) 450px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;450&quot; height=&quot;600&quot; src=&quot;https://img.ly/_astro/1-t-iuevsvhcRZK1krCv4GVw_wkaR3.webp&quot; srcset=&quot;/_astro/1-t-iuevsvhcRZK1krCv4GVw_wkaR3.webp 450w&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Artificial Depth of Field (Source) and 3D asset placement examples.&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;599&quot; src=&quot;https://img.ly/_astro/1-Uj0A37iDdBj7qljbO8tKEA_1bOpp5.webp&quot; srcset=&quot;/_astro/1-Uj0A37iDdBj7qljbO8tKEA_Blyk2.webp 640w, /_astro/1-Uj0A37iDdBj7qljbO8tKEA_Z1oLE5s.webp 750w, /_astro/1-Uj0A37iDdBj7qljbO8tKEA_1bOpp5.webp 800w&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;3d-asset-placement&quot;&gt;3D Asset Placement&lt;/h3&gt;
&lt;p&gt;As mentioned above, a depth map gives us a 3D understanding of the image. We’re able to tell if subject A is positioned in front of or behind subject B. This allows placement of digital assets like stickers or text in a ‘depth-aware’ fashion, but could also be used to apply ‘intelligent’ depth of field, e.g. a bokeh effect that ensures all faces are in focus.&lt;/p&gt;
&lt;h2 id=&quot;enter-deeplearning&quot;&gt;Enter Deep Learning&lt;/h2&gt;
&lt;p&gt;Motivated by the possibilities enabled by depth maps, we were wondering if we could bring this magic to any type of portrait image. We consulted existing literature on depth inference and found various papers¹ and articles on the topic, some of which even presented results that seemed sufficient for our use cases. In our case, we didn’t need accurate, as in ‘this pixel is 30cm in front of the camera’, results, but we were only interested in getting the general distance relations correct. For us, knowing that region A was slightly behind but definitely way in front of region B was enough to generate a visually pleasing effect and by constraining our domain to portrait imagery, we were able to further reduce the tasks complexity.&lt;/p&gt;
&lt;p&gt;Given our experience with deep learning and our current focus on introducing machine learning powered features to the &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt;, we immediately decided to tackle the new challenge with deep learning or more specifically convolutional neural networks. Having a huge dataset of image and depth map pairs available, made this choice even easier. We stuck to a system similar to our previous segmentation model but decided to put more emphasis on allowing the reuse of individual parts, as this would come in handy when adding additional features in the future. To achieve this, we created a new modularized neural network approach named Hydra, which will be presented in an upcoming blog post.&lt;/p&gt;
&lt;p&gt;During development, we followed our tried and tested workflow of starting with a complex custom model, which is then tweaked and refined to match our performance requirements while maintaining the prediction quality we need. Once that was done, we had a fast and small model, trained on thousands of iPhone front camera selfies and capable of inferring high fidelity depth maps from a plain RGB image in under a second.&lt;/p&gt;
&lt;h2 id=&quot;the-prototype&quot;&gt;The Prototype&lt;/h2&gt;
&lt;p&gt;After creating a small model capable of inferring depth maps for any given portrait image, we immediately wanted to evaluate its performance in a ‘real-world’ environment. We decided to build a prototype that applies a depth of field effect to a portrait image, by using the model and its outputs. With our long-term goal of deploying the model to iOS, Android and the web in mind, we built the prototype using TensorFlowJS to explore this newly released library. Our browser demo consists of a minimal ‘Hydra’ implementation with individual modules, one for extracting features and one for the actual depth inference, which can both be executed individually.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Our demo web app in action.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1200px) 1200px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1200&quot; height=&quot;442&quot; src=&quot;https://img.ly/_astro/1-rVZLH5Tsq0bBKjFNSlKYlA_Z23OWO9.webp&quot; srcset=&quot;/_astro/1-rVZLH5Tsq0bBKjFNSlKYlA_Z1dWDjs.webp 640w, /_astro/1-rVZLH5Tsq0bBKjFNSlKYlA_KKQvH.webp 750w, /_astro/1-rVZLH5Tsq0bBKjFNSlKYlA_ZoEQaL.webp 828w, /_astro/1-rVZLH5Tsq0bBKjFNSlKYlA_25hiok.webp 1080w, /_astro/1-rVZLH5Tsq0bBKjFNSlKYlA_Z23OWO9.webp 1200w&quot;&gt;&lt;/p&gt;
&lt;p&gt;While being optimized for performance and memory footprint, the trained weights of the model still add up to ~18MB, which we will improve by further fine-tuning or even applying pruning or quantization. Once the models are loaded, all further processing happens on the device though, so you may try out all the samples without worrying about your data plan.&lt;/p&gt;
&lt;h2 id=&quot;results&quot;&gt;Results&lt;/h2&gt;
&lt;p&gt;Seeing our vision come to life was quite a stunning experience. Suddenly our browser was able to perform a complex depth of field effect without the need for special hardware, manual annotations or anything else apart from our image. And the best part was manually moving the focal plane through the image, either by sliding or tapping on different regions. Although being trained on ‘just’ selfies the model handles turned heads, silhouettes and multiple people pretty well and isn’t as restricted to its domain as we initially expected.&lt;/p&gt;
&lt;p&gt;And while our initial prototype is still weighing in at ~18MB, we’re certain to slim that down further in order to use the model in production. Performance wise we were very impressed with the TensorFlowJS inference speed. Even though everything is happening on the client side and is therefore dependent on the clients hardware, we saw inference speed below one second right of the bat and those greatly improved after the initial run, as the resources were already allocated. While not being immediately helpful for the depth inference part, this allowed us to further confirm our theory behind Hydra: Re-running inference once the necessary resources on the machine have been allocated greatly increases performance and might even allow real-time performance after an initial setup-time.&lt;/p&gt;
&lt;p&gt;To summarise, we’re definitely eager to further explore the use of depth data in image editing and think we have found a way to overcome the access restrictions on different platforms and hardware with our custom model. Combined with our new Hydra approach we can see lots of potential features that will delight both our users and customers and we will keep you updated right here.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;(1)&lt;/strong&gt; &lt;br&gt;
The papers we extracted most knowledge for our use case from were:&lt;br&gt;
“Depth Map Prediction from a Single Image using a Multi-Scale Deep Network” (&lt;a href=&quot;https://arxiv.org/abs/1406.2283&quot;&gt;arXiv&lt;/a&gt;)&lt;br&gt;
“Deeper Depth Prediction with Fully Convolutional Residual Networks” (&lt;a href=&quot;https://arxiv.org/abs/1606.00373&quot;&gt;arXiv&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;*&lt;strong&gt;*Thanks for reading! To stay in the loop, subscribe to our&lt;/strong&gt; &lt;a href=&quot;https://photoeditorsdk.us13.list-manage.com/subscribe?u=dc9f652839dbb620d14d6d28d&amp;#x26;id=04a306e4b2&quot;&gt;&lt;strong&gt;Newsletter&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;.**&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Malte</dc:creator><dc:creator>Eray</dc:creator><media:content url="https://blog.img.ly/2020/03/1-Rd4wX6T9PmoXZA56yVLgCQ-1.png" medium="image"/><category>Machine Learning</category><category>Photography</category><category>Deep Learning</category><category>Photos</category><category>Technology</category><category>AI</category></item><item><title>Almost Getting Sherlocked by Apple’s Core Image Team</title><link>https://img.ly/blog/almost-getting-sherlocked-by-apples-core-image-team-76249c370320/</link><guid isPermaLink="true">https://img.ly/blog/almost-getting-sherlocked-by-apples-core-image-team-76249c370320/</guid><pubDate>Tue, 12 Jun 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;During each World Wide Developer Conference keynote, app developers all over the world are fearing their app may &lt;a href=&quot;https://www.urbandictionary.com/define.php?term=sherlocked&quot;&gt;get sherlocked&lt;/a&gt; by Apple. This has happened to flashlight apps when Apple introduced a simple toggle in the control center, to f.lux when Apple added exactly the same functionality to macOS and iOS, in parts to Dropbox with the launch of iCloud Drive and to many other developers. This year there was only one obvious of such things, the Workflow app which was acquired a few month ago and instantly turned into Siri Shortcuts by Apple. So no real ‘sherlocking’. But when we skimmed the newest APIs, release notes and session descriptions after the keynote, we found out that the technology behind our Portrait by img.ly app might have gotten sherlocked by the Core Image team. The reason is perfectly summarized in this tweet:&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;“Portrait Segmentation API&lt;br&gt;&lt;br&gt;A new API for third-party developers allows for the separation of layers in a photo, such as separating the background from the foreground.”&lt;br&gt;&lt;br&gt;Hi &lt;a href=&quot;https://twitter.com/halidecamera?ref_src=twsrc%5Etfw&quot;&gt;@halidecamera&lt;/a&gt;&lt;/p&gt;— Preshit Deorukhkar (@preshit) &lt;a href=&quot;https://twitter.com/preshit/status/1003722022466121730?ref_src=twsrc%5Etfw&quot;&gt;June 4, 2018&lt;/a&gt;&lt;/blockquote&gt;&lt;figcaption&gt;How we found out about the new Portrait Segmentation API.&lt;/figcaption&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Quick spoiler&lt;/em&gt;: While Core Images new API is impressive, our technology is still ahead in terms of general availability, required hardware and cross-platform compatibility. But let’s start from the beginning:&lt;/p&gt;
&lt;p&gt;We started working on automated image segmentation in 2016 and decided to focus on portraits in 2017. After spending most of the year on &lt;a href=&quot;https://img.ly/blog/when-creativity-meets-a-i-f48ee9a3612d/&quot;&gt;building a custom deep learning model&lt;/a&gt;, running hundreds of experiments and tweaking our post processing pipeline, we finally released the Portrait app in fall 2017. The app is able to generate portrait segmentations in real-time and allows the user to take a nice selfie, which is then automatically stylized using the segmentation mask and some post processing. This allows for sophisticated effects and got great reception all over the world. The app even got featured multiple times in many different countries. Recently we started looking into inferring depth, as we wanted to bring depth based features to our &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt;, but needed support on more iPhone devices, Android and especially required depth data for existing images.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 600px) 600px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;600&quot; height=&quot;720&quot; src=&quot;https://img.ly/_astro/1-gGBarteLQ3HLyjk_BOWRqg_1P3HFh.webp&quot; srcset=&quot;/_astro/1-gGBarteLQ3HLyjk_BOWRqg_1P3HFh.webp 600w&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 400px) 400px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;400&quot; height=&quot;510&quot; src=&quot;https://img.ly/_astro/1-wIEvPF-CwcYYkguN3hKyrQ_3DVOn.webp&quot; srcset=&quot;/_astro/1-wIEvPF-CwcYYkguN3hKyrQ_3DVOn.webp 400w&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Stylized selfies created using the Portrait app.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 400px) 400px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;400&quot; height=&quot;533&quot; src=&quot;https://img.ly/_astro/1-SbpOElYlADGGsomoQWo1UQ_Xq8J4.webp&quot; srcset=&quot;/_astro/1-SbpOElYlADGGsomoQWo1UQ_Xq8J4.webp 400w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Reading the tweet above, it looked like Apple just added the Portrait apps core functionality to the Core Image framework, making it available to all developers and users running or targeting iOS 12. A little worried about the new competition, we immediately looked into the docs and eagerly waited for the session on last Thursday to see if we’d soon need to find a new unique way of using technology to empower creativity.&lt;/p&gt;
&lt;p&gt;We found out that all you need to do in order to get a segmentation mask along with your image is toggle the following flags when requesting a photo capture from your &lt;code&gt;AVCapturePhotoOutput&lt;/code&gt;:&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;let settings: AVCapturePhotoSettings = AVCapturePhotoSettings()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;settings.isDepthDataDeliveryEnabled = true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;settings.isPortraitEffectsMatteDeliveryEnabled = true&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;After the photo is captured, you’re then able to extract the matte in the &lt;code&gt;didFinishProcessingPhoto&lt;/code&gt; callback. And voila, you now have the captured image, a depth map and the mask separating fore- and background available:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 400px) 400px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;400&quot; height=&quot;533&quot; src=&quot;https://img.ly/_astro/1-wNVP-7aqqOfyDpnWcKEc0w_ZrbWCi.webp&quot; srcset=&quot;/_astro/1-wNVP-7aqqOfyDpnWcKEc0w_ZrbWCi.webp 400w&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 400px) 400px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;400&quot; height=&quot;533&quot; src=&quot;https://img.ly/_astro/1-k3bRAeLEIxoZ0otelumcdQ_Z1Vd9sB.webp&quot; srcset=&quot;/_astro/1-k3bRAeLEIxoZ0otelumcdQ_Z1Vd9sB.webp 400w&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Input image, depth map and portrait matte generated by Core Image. (Source)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 400px) 400px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;400&quot; height=&quot;533&quot; src=&quot;https://img.ly/_astro/1-_ti3BobfUiGJmsb8MOkJvQ_Z1FhYlR.webp&quot; srcset=&quot;/_astro/1-_ti3BobfUiGJmsb8MOkJvQ_Z1FhYlR.webp 400w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Of course, we quickly spun up our own models and algorithms and compared the portrait matte, as well as the depth map to Apples results. As there is no way to rerun Apples matting algorithm for an existing image, we took one of Apples samples and compared their mask with results from our model:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 400px) 400px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;400&quot; height=&quot;533&quot; src=&quot;https://img.ly/_astro/1-wNVP-7aqqOfyDpnWcKEc0w_ZrbWCi.webp&quot; srcset=&quot;/_astro/1-wNVP-7aqqOfyDpnWcKEc0w_ZrbWCi.webp 400w&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 225px) 225px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;225&quot; height=&quot;299&quot; src=&quot;https://img.ly/_astro/1-Tr1guJROO6OdL0BDhMlJ4g_ZGYUc4.webp&quot; srcset=&quot;/_astro/1-Tr1guJROO6OdL0BDhMlJ4g_ZGYUc4.webp 225w&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Input image, depth map and portrait matte generated by our algorithms and models.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 400px) 400px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;400&quot; height=&quot;533&quot; src=&quot;https://img.ly/_astro/1-2Vj62Jh6cBafzw0kN1xVuA_2h3Jco.webp&quot; srcset=&quot;/_astro/1-2Vj62Jh6cBafzw0kN1xVuA_2h3Jco.webp 400w&quot;&gt;&lt;/p&gt;
&lt;p&gt;While it may not have been the greatest idea to pick Apples shiny developer example, Apples mask is a little more detailed and for this particular image our model missed parts of the neck on the left. But overall we were still very happy with our results, especially when considering, that everything was generated from the plain image and didn’t require any dedicated hardware like dual cameras or a TrueDepth sensor. We did of course expect a superior depth map from Apple, as we’re clearly lacking data and are still actively working on the depth model used to generate the image above. But Apples depthmap interestingly has some issues around the neck as well, despite their use of a dual camera system. And keep in mind, that our results were all processed on the mobile device, entirely based on the RGB data contained in the image, and could be repeated on an Android phone, older iOS devices and even your browser.&lt;/p&gt;
&lt;p&gt;When we wanted to try more samples, we quickly noticed the major limitations of Apples API: As the portrait matte capture is only available in combination with depth data, it’s limited to the iPhone 7 Plus, 8 Plus and iPhone X. And, most important to us, portrait mattes taken using the front camera are exclusively limited to the iPhone X and it’s TrueDepth sensor array. So for our Portrait app, switching to the new API would require us to ditch our live preview and go iPhone X and iOS 12 only. This was enough to calm our minds and we started thinking deeper about Apples technology:&lt;/p&gt;
&lt;p&gt;While the depth requirement is annoying, it also explains the higher quality of Apples predictions. Our model is trained to solve the individual problems of portrait matting and depth map inference as a whole, but Apple is able to focus on improving the edges, while the ‘rough’ foreground/background segmentation is handled by masking based on the depth of the face detected within the image. We might be able to combine both models as well, but that would make the segmentation model currently used in the Portrait app obsolete and would most certainly kill the real-time functionality.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A stylized portrait of the sample image, created using our app.&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;1066&quot; src=&quot;https://img.ly/_astro/1-suYaswJDYtDiIFTs3w-aHQ_Z29DuwE.webp&quot; srcset=&quot;/_astro/1-suYaswJDYtDiIFTs3w-aHQ_ZJM4aC.webp 640w, /_astro/1-suYaswJDYtDiIFTs3w-aHQ_Z23jUhb.webp 750w, /_astro/1-suYaswJDYtDiIFTs3w-aHQ_Z29DuwE.webp 800w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Overall, Apples technology is, as almost always, pretty impressive and the portrait matte generation works flawless, but we can now say, that for the use within our app, we reach a good quality with our current algorithms and think that a real-time preview is more important to our users. For our &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt; we’d happily use the high fidelity maps generated by iOS 12, but the hardware requirements are not yet suitable for SDK deployment. Our algorithms on the other hand, neither require a depth map, nor are we limited to processing after the image was captured, but can perform real-time inference on devices as old as the iPhone 6S. And the best of all: Once a TrueDepth camera is more common and everyone is running iOS 12, we can still use the Portrait Segmentation API and enjoy it’s simplicity.&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>Malte</dc:creator><media:content url="https://blog.img.ly/2020/03/1-EXAAKrECABcaDEs3BtfzgQ.jpeg" medium="image"/><category>Apple</category><category>WWDC</category><category>Core Image</category><category>iOS</category><category>Software Development</category><category>Tech</category><category>How-To</category><category>Insights</category></item><item><title>How to build Instagram’s Story Editor in a Day</title><link>https://img.ly/blog/how-to-build-instagrams-story-editor-in-a-day-23be9adff9b/</link><guid isPermaLink="true">https://img.ly/blog/how-to-build-instagrams-story-editor-in-a-day-23be9adff9b/</guid><pubDate>Wed, 13 Dec 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A common question we get asked from our customers, is whether they’ll be able to create an entirely different user interface using our &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt;. The SDK comes with it’s own customizable UI, but customization are of course limited to a certain extent. As our SDK is used in many different use cases and contexts, we like to explore what’s possible with the PhotoEditor SDK and its included components. Here, &lt;strong&gt;we decided to build a UI similar to Instagram’s Stories or Snapchat using our SDK&lt;/strong&gt;. By now, this ‘Story UI’ has become a popular way of quickly designing with different elements (stickers, brush and text) rather than enhancing and styling the image only.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Our default UI vs Story UI&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;590&quot; src=&quot;https://img.ly/_astro/1-Rv39RvsHUCI4TXKC1rHXZQ_Z1l5n2b.webp&quot; srcset=&quot;/_astro/1-Rv39RvsHUCI4TXKC1rHXZQ_Z2eFP2.webp 640w, /_astro/1-Rv39RvsHUCI4TXKC1rHXZQ_1qqAh8.webp 750w, /_astro/1-Rv39RvsHUCI4TXKC1rHXZQ_Z1l5n2b.webp 800w&quot;&gt;&lt;/p&gt;
&lt;p&gt;So we grabbed our own &lt;a href=&quot;https://img.ly/docs/pesdk/&quot;&gt;docs&lt;/a&gt; and headed out to create a demo in which we recreate the Instagram Stories using components from the PhotoEditor SDK. This article presents our approach by starting with a general overview and then diving into the different view controllers to look at specific implementation details. You can follow along by downloading the accompanying &lt;a href=&quot;https://github.com/imgly/pesdk-blog-instagram-ui&quot;&gt;code&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Our customized Story UI in action.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 290px) 290px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;290&quot; height=&quot;580&quot; src=&quot;https://img.ly/_astro/1-s-ZFgd4EuUcuy_s4MDz2sQ_Z9PmrR.webp&quot; srcset=&quot;/_astro/1-s-ZFgd4EuUcuy_s4MDz2sQ_Z9PmrR.webp 290w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;architecture-andoverview&quot;&gt;Architecture and Overview&lt;/h2&gt;
&lt;p&gt;Any image editing interface is naturally centered around some sort of canvas or preview. This is where the image with all operations applied is rendered and any changes are shown to the user. All tools add their own interface elements to allow modifications like adding stickers, text or brush strokes to the image. To create such a hierarchy of tools, the &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt; makes heavy use of an iOS pattern called &lt;em&gt;view controller containment&lt;/em&gt;. The root view controller, an &lt;code&gt;EditViewController&lt;/code&gt; in this case, manages a series of child view controllers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;PhotoEditPreviewController&lt;/code&gt; that handles the internal model and all rendering, as well as the rendering canvas itself&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;TextSpriteEditController&lt;/code&gt; above the &lt;code&gt;PhotoEditPreviewController&lt;/code&gt; that allows selection and manipulation of text sprites&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;StickerSpriteEditController&lt;/code&gt; above the &lt;code&gt;PhotoEditPreviewController&lt;/code&gt;manages selection and manipulation of stickers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://miro.medium.com/max/1024/1*iNnmjNai7mPywoKsgLz-xg.png&quot; alt=&quot;The view hierarchy within the EditViewController. The user facing controls are on the left, the root window is on the right.&quot;&gt;&lt;/p&gt;
&lt;p&gt;The child view controllers may manage additional view controllers themselves, but we only need to manage the topmost objects and wire their interfaces together. This is done within the &lt;code&gt;EditViewController&lt;/code&gt; who is also responsible for presenting the view controllers that implement the different tools, &lt;code&gt;StickerViewController&lt;/code&gt;, &lt;code&gt;BrushViewController&lt;/code&gt; and &lt;code&gt;TextViewController&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;These are mainly responsible for managing the interface and adjusting the model accordingly, while the ‘real’ work is being done in the background by the &lt;code&gt;PhotoEditPreviewController&lt;/code&gt; whenever the model gets updated. Thanks to the SDK, creating our &lt;code&gt;BrushViewController&lt;/code&gt; boils down to creating and wiring a &lt;code&gt;BrushEditController&lt;/code&gt; and adding its view, color and size controls to the &lt;code&gt;BrushViewControllers&lt;/code&gt; view. This creates a fully fledged brush tool with OpenGL rendering, color and brush size adjustments, and great performance in just &lt;strong&gt;89 lines&lt;/strong&gt; of code.&lt;/p&gt;
&lt;h2 id=&quot;editviewcontroller&quot;&gt;EditViewController&lt;/h2&gt;
&lt;p&gt;As described in the previous section, the &lt;code&gt;EditViewController&lt;/code&gt; is the root view controller of our demo application and is responsible for showing a preview, presenting tools and rendering the final output. To do so, we add a &lt;code&gt;PreviewEditViewController&lt;/code&gt; and &lt;code&gt;SpriteEditControllers&lt;/code&gt; to the root view and register the &lt;code&gt;EditViewController&lt;/code&gt; as their delegate. Registering as a delegate, allows the &lt;code&gt;EditViewController&lt;/code&gt; to wire all child view controllers and pass data between them. In order to do so, we just need to return objects of other view controllers or react to model changes. All controllers then use the &lt;code&gt;EditViewController&lt;/code&gt; to ask for objects or data they need, for example the current size of the preview view, in order to rearrange interface elements or calculate model updates. As an example, the &lt;code&gt;spriteEditControllerPreviewView(_ spriteEditController:)&lt;/code&gt; method of the &lt;code&gt;SpriteEditControllerDelegate&lt;/code&gt; protocol, asks for the current preview view. All we need to do in our &lt;code&gt;EditViewController&lt;/code&gt; is to get this view from our &lt;code&gt;PreviewEditViewController&lt;/code&gt; and return it:&lt;/p&gt;

&lt;h3 id=&quot;sprite-handling&quot;&gt;Sprite Handling&lt;/h3&gt;
&lt;p&gt;Stickers and text sprites are both sprites, but there are different &lt;code&gt;SpriteEditController&lt;/code&gt; subclasses for each sprite type, because of differing gestures and UI elements. The Instagram UI allows the editing of both sticker and text sprites within a single view, so we need to add both specific controllers, &lt;code&gt;StickerSprite&lt;/code&gt;- and &lt;code&gt;TextSpriteEditController&lt;/code&gt; to our &lt;code&gt;EditViewController&lt;/code&gt; and dynamically enable the appropriate one depending on the currently selected sprite.&lt;/p&gt;
&lt;h2 id=&quot;stickerviewcontroller&quot;&gt;StickerViewController&lt;/h2&gt;
&lt;p&gt;For adding stickers, the Instagram Stories UI offers a single button that presents a grid of all available stickers. Replicating this using the PhotoEditor SDK is easy to do, as the SDK uses a collection view for presentation as well. This collection view is embedded in a &lt;code&gt;StickerSelectionController&lt;/code&gt; which we add to our &lt;code&gt;StickerViewController&lt;/code&gt;. Once again, after registering as the &lt;code&gt;StickerSelectionController&lt;/code&gt;s delegate, we get notified upon selection of any sticker and just need to change the &lt;code&gt;PhotoEditModel&lt;/code&gt; accordingly. To do so, we create a link between the root and the currently presented view controller using the &lt;code&gt;StickerViewControllerDelegate&lt;/code&gt; protocol. Once a sticker has been selected, we create or update a &lt;code&gt;StickerSpriteModel&lt;/code&gt;, pass it to the &lt;code&gt;EditViewController&lt;/code&gt;, which updates the &lt;code&gt;PreviewEditViewController&lt;/code&gt; model:&lt;/p&gt;

&lt;p&gt;This triggers a new rendering pass and the sticker appears on screen. All that’s left to do now is closing the &lt;code&gt;StickerViewController&lt;/code&gt;. Again, we use the delegate pattern to ask the &lt;code&gt;EditViewController&lt;/code&gt; about the &lt;code&gt;referenceSize&lt;/code&gt; that’s needed to calculate the sticker’s normalized size.&lt;/p&gt;
&lt;h2 id=&quot;brushviewcontroller&quot;&gt;BrushViewController&lt;/h2&gt;
&lt;p&gt;This view controller, just as described above, is just a wrapper around the &lt;code&gt;BrushEditController&lt;/code&gt; that adds a color and size selection. Once again, all interaction is handled through delegates and upon closing of the brush tool, the internal model is updated. To support &lt;em&gt;undo&lt;/em&gt;, we need to pass the &lt;code&gt;PreviewEditViewController&lt;/code&gt;’s &lt;code&gt;undoController&lt;/code&gt; and begin a new group, whenever we fire up the tool.&lt;/p&gt;
&lt;h2 id=&quot;textviewcontroller&quot;&gt;TextViewController&lt;/h2&gt;
&lt;p&gt;The text editor Instagram created within their Stories UI is essentially a fullscreen textfield with additional controls for color and size selection. Ignoring the customized design, this can easily be recreated using stock iOS components and essentially only requires listening for keyboard notifications to handle the layout and adjusting the textfield’s properties according to user interactions. Once finished, we create a corresponding &lt;code&gt;TextSpriteModel&lt;/code&gt; that is positioned below the &lt;code&gt;UITextField&lt;/code&gt; and notify the &lt;code&gt;EditViewController&lt;/code&gt; using the delegate. After dismissing the &lt;code&gt;TextViewController&lt;/code&gt; the text rendering is handled by the &lt;code&gt;PhotoEditPreviewController&lt;/code&gt;. When reselecting an existing label, we just prefill the &lt;code&gt;UITextField&lt;/code&gt; with it’s contents and update the model when the label textfield changes. To ensure the &lt;code&gt;UITextField&lt;/code&gt; is the only place the text is currently visible, we hide the &lt;code&gt;spriteView&lt;/code&gt; we previously selected and show it again, once editing has finished.&lt;/p&gt;
&lt;h2 id=&quot;the-result&quot;&gt;The Result&lt;/h2&gt;
&lt;p&gt;Recreating the Instagram Stories UI seemed rather challenging at first, but using our &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt;, it quickly turned into a very rewarding project. Being able to create something like a brush tool without the need to actually implement any drawing or gesture handling is amazing and helped to create a working prototype in no time. Tricky details like sprite transformations, remote loading of stickers or undo management were entirely handled by the SDK and we could completely focus on the interface itself.&lt;/p&gt;
&lt;p&gt;For more details and some actual code, take a look at the &lt;a href=&quot;https://github.com/imgly/pesdk-blog-instagram-ui&quot;&gt;repository&lt;/a&gt;. We documented all tricky parts and you should be able to start your own implementation using the code. Please keep in mind, that the code may target a slightly older PhotoEditor SDK version, so check for a new version before you start your journey.&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>Malte</dc:creator><media:content url="https://blog.img.ly/downloaded_images/How-to-build-Instagram-s-Story-Editor-in-a-Day/1-iNnmjNai7mPywoKsgLz-xg.png" medium="image"/><category>iOS</category><category>Swift</category><category>Instagram</category><category>Snapchat</category><category>Mobile App Development</category><category>Tech</category><category>How-To</category><category>Tutorial</category><category>Learning</category></item><item><title>PhotoEditor SDK + Cordova &amp; Ionic</title><link>https://img.ly/blog/photoeditor-sdk-cordova-dabe146e6c13/</link><guid isPermaLink="true">https://img.ly/blog/photoeditor-sdk-cordova-dabe146e6c13/</guid><pubDate>Wed, 14 Jun 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Despite the growing trend towards React Native, Cordova (formerly PhoneGap) is still going strong and creates frequent plugin requests from our customers. Although we can’t offer full support, we set out to create a demo app and put together a guide on how to easily set up the &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt; with Cordova. And as Ionic is built on top of Cordova, the finished plugin is usable in Ionic as well.&lt;/p&gt;
&lt;p&gt;The idea is to create a Cordova app that allows the user to open an image from their photo library and edit this image using the &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt; on iOS and Android. This is done by using an existing library to access native photo pickers on both platforms and passing the path to the found image to a plugin. The plugin manages the configuration and opening of the PhotoEditor SDK’s editor and passes the edited image back to Cordova.&lt;/p&gt;
&lt;p&gt;In this article we’ll start with the basic setup of the plugin and example app code, explain the plugin code in depth and cover how to integrate the plugin into your app. All code is available in the corresponding &lt;a href=&quot;https://github.com/imgly/pesdk-cordova-demo&quot;&gt;GitHub repository&lt;/a&gt; and after reading this article, you’ll be able to add a the PhotoEditor SDK to your Cordova app, customize it to your needs and delight your customers.&lt;/p&gt;
&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;/h2&gt;
&lt;p&gt;As we’ll have to build a Cordova plugin that wraps the PhotoEditor SDK into a JavaScript interface, we start with creating the following folder structure within our 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;demo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- src&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- example&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;src&lt;/code&gt; folder contains the actual Cordova plugin consisting of JavaScript, Objective-C and Java code, while the &lt;code&gt;example&lt;/code&gt; folder contains a conventional Cordova project that uses our plugin to open the PhotoEditor SDK and manages the image selection from the users library.&lt;/p&gt;
&lt;h2 id=&quot;the-demoapp&quot;&gt;The demo app&lt;/h2&gt;
&lt;p&gt;To start with our demo, we just use the &lt;code&gt;cordova create example&lt;/code&gt; command, to create a new Cordova application. We add our target platforms, iOS and Android, using the &lt;code&gt;cordova platform add &amp;#x3C;platform&gt;&lt;/code&gt; command and are ready to head into actual coding.&lt;/p&gt;
&lt;p&gt;Due to the focus on integrating the &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt; in this blog post, we’ll skip the details on how to open the native image pickers and dive directly into plugin development. For now we’re just left with the following snippet in our example app, that’s supposed to open the PhotoEditor SDK at some point in the future:&lt;/p&gt;

&lt;h2 id=&quot;creating-a-cordovaplugin&quot;&gt;Creating a Cordova Plugin&lt;/h2&gt;
&lt;p&gt;Any Cordova plugin starts with a &lt;code&gt;plugin.xml&lt;/code&gt; manifest file and then covers the supported platforms in separate files. All these files get wrapped in a JavaScript interface, that exposes the functionality to Cordova. The bridging between JavaScript and the native source files is managed by Cordova and made possible by subclassing &lt;code&gt;CDVPlugin&lt;/code&gt; on iOS and &lt;code&gt;CordovaPlugin&lt;/code&gt; on Android.&lt;/p&gt;
&lt;h3 id=&quot;plugin-configuration&quot;&gt;Plugin Configuration&lt;/h3&gt;
&lt;p&gt;Our &lt;code&gt;plugin.xml&lt;/code&gt; becomes quite long due to the involved platforms, so we’ll just &lt;a href=&quot;https://gist.github.com/imgly-gists/3cb6ffd562471008e3bb82c57480716b&quot;&gt;link it&lt;/a&gt; here and explain some specific details.&lt;/p&gt;
&lt;p&gt;The first lines configure the plugins name, version etc. and define the main pesdk.js file containing the interface we’ll later call from our Cordova application. The &lt;code&gt;&amp;#x3C;clobbers&gt;&lt;/code&gt; tag specifies the namespace under which the exports are later available in the &lt;code&gt;window&lt;/code&gt; object.&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;&amp;#x3C;js-module src=&quot;src/www/pesdk.js&quot; name=&quot;PESDK&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &amp;#x3C;clobbers target=&quot;PESDK&quot; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;/js-module&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The file then defines the plugin details for both platforms. Starting with Android, we list the parameters the plugin will add to the &lt;code&gt;config.xml&lt;/code&gt; and &lt;code&gt;AndroidManifest.xml&lt;/code&gt; files. These specify the Java package, when the plugin should load, register activities etc. The remaining lines for Android embed a custom &lt;code&gt;build.gradle&lt;/code&gt; file, ensuring all features are enabled for the PhotoEditor SDK and finally copy our source files &lt;code&gt;PESDKPlugin.java&lt;/code&gt; and &lt;code&gt;CameraActivity.java&lt;/code&gt; into the application folder.&lt;/p&gt;
&lt;p&gt;Moving on with iOS, which behaves a little more picky in this case, we repeat the initial Android steps like defining the package, copying files and linking all frameworks required by the plugin. The last embedded framework is the &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt;:&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;&amp;#x3C;framework src=&quot;src/ios/PhotoEditorSDK.framework&quot; custom=&quot;true&quot; embed=&quot;true&quot; /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sadly Cordova doesn’t correctly handle the embedding of our SDK, as it doesn’t add the SDK to the embedded binaries tab in the Xcode project. Therefore we adapted a &lt;code&gt;resolveDependencies.js&lt;/code&gt; script from &lt;a href=&quot;https://stackoverflow.com/questions/36650522/custom-cordova-plugin-add-framework-to-embedded-binaries&quot;&gt;StackOverflow&lt;/a&gt; that uses &lt;code&gt;node-xcode&lt;/code&gt; to configure the project correctly during plugin installation. This script is saved in the &lt;code&gt;/hooks/resolveDependencies.js&lt;/code&gt; file and called using specific hooks:&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;&amp;#x3C;hook type=&quot;after_platform_add&quot; src=&quot;hooks/resolveDependencies.js&quot; /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The last iOS specific step is setting two keys in the applications &lt;code&gt;Info.plist&lt;/code&gt; file that describe our camera and photo library usage when asking the user for access permissions. In this example we won’t actually be requesting these permissions from the PhotoEditor SDK, but when using the integrated camera implementation without these keys, the plugin would never gain access to the iOS camera and photo roll:&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;&amp;#x3C;config-file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  parent=&quot;NSCameraUsageDescription&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  target=&quot;*-Info.plist&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &amp;#x3C;string&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    Uses your camera to snap pictures.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &amp;#x3C;/string&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;/config-file&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;config-file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  parent=&quot;NSPhotoLibraryUsageDescription&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  target=&quot;*-Info.plist&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &amp;#x3C;string&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    Accesses your photo library to save and open pictures.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &amp;#x3C;/string&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;/config-file&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this &lt;code&gt;plugin.xml&lt;/code&gt; file in place, we can actually start implementing our plugin for iOS and Android.&lt;/p&gt;
&lt;h3 id=&quot;platform-specific-implementations&quot;&gt;Platform Specific Implementations&lt;/h3&gt;
&lt;p&gt;As we fiddled around with iOS last, we’ll start with the iOS specific code. The &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt; is written in Swift, but Cordova prefers Objective-C instead. We could write our plugin in Swift as well and add an Objective-C wrapper, but for the sake of simplicity we’ll just stick with Objective-C for our plugin, as the PhotoEditor SDK is &lt;a href=&quot;https://img.ly/docs/pesdk/ios/getting-started/integration/swift-package-manager/&quot;&gt;fully usable&lt;/a&gt; from Objective-C anyway.&lt;/p&gt;
&lt;p&gt;We need to add three files to our &lt;code&gt;ios&lt;/code&gt; directory: The framework itself and our plugin classes header and implementation files &lt;code&gt;PESDKPlugin.h&lt;/code&gt; &amp;#x26; &lt;code&gt;PESDKPlugin.m&lt;/code&gt;. The plugin exposes a single method, &lt;code&gt;present:&lt;/code&gt;, taking a filepath as a simple string. The method then loads the image at the given path, configures the PhotoEditor SDK and creates and presents a &lt;code&gt;PESDKPhotoEditViewController&lt;/code&gt; that takes the image:&lt;/p&gt;

&lt;p&gt;To ensure the SDK is fully loaded and unlocked, we need to add a small &lt;code&gt;initialize&lt;/code&gt; method as well. And as you can see, we need to add our iOS license as well. This has to be done by opening the Xcode project and dragging the license file into the sidebar, as it won’t be copied into the app bundle otherwise. Once this is done, we can initialize the SDK in the following way:&lt;/p&gt;

&lt;p&gt;These methods contain all the native Objective-C code you need in order to open the PhotoEditor SDK from a Cordova plugin. Except for some boilerplate code for bridging between JavaScript and Objective-C. If you want to configure the &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK’s&lt;/a&gt; style or available functionality you may modify the &lt;code&gt;configuration&lt;/code&gt; object according to our &lt;a href=&quot;https://img.ly/docs/pesdk/ios/getting-started/integration/swift-package-manager/&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Moving on with Android, we create a &lt;code&gt;build.gradle&lt;/code&gt; according to our &lt;a href=&quot;https://img.ly/docs/pesdk/&quot;&gt;docs&lt;/a&gt; and the &lt;code&gt;PESDKPlugin.java&lt;/code&gt; file that will contain our plugin code. Once again the native code boils down to opening the PhotoEditor SDK and passing a file path and some boiler plate code required by Cordova:&lt;/p&gt;

&lt;p&gt;The code extracts the file path we passed from Cordova and prepares the PhotoEditor SDKs editor activity using a &lt;code&gt;PhotoEditorBuilder&lt;/code&gt;. Important, but easily overseen parts are saving the &lt;code&gt;callbackContext&lt;/code&gt; for notifying Cordova when the editor closes in line 2 and registering the plugin for activity callbacks in line 18. As we did on iOS, we need to initialize the SDK and pass our license file, but in this case we can just copy the file to the &lt;code&gt;example/platforms/android/assets&lt;/code&gt; folder:&lt;/p&gt;

&lt;hr&gt;
&lt;p&gt;To finish up, we now need to define an interface using JavaScript. This interface defines the methods available in the plugin and will later be called from our Cordova application. Cordova then handles the delegation to the native implementations for us. In our case, the interface is rather minimal and only consists of our &lt;code&gt;present&lt;/code&gt; method:&lt;/p&gt;

&lt;p&gt;And thats it! We now have successfully created a Cordova plugin, which will allow us to open the &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt; editor from our own application, while passing an already existing image. Now we just need to wire everything in order to get our final result, the PhotoEditor SDK running on both platforms:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The PhotoEditor SDK running on iOS and Android.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 630px) 630px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;630&quot; height=&quot;600&quot; src=&quot;https://img.ly/_astro/1-pt26bZ-jVXzyHkWsZGm5cA_vBxjz.webp&quot; srcset=&quot;/_astro/1-pt26bZ-jVXzyHkWsZGm5cA_vBxjz.webp 630w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;wiring-it-allup&quot;&gt;Wiring it all up&lt;/h2&gt;
&lt;p&gt;We’re now ready to put our fresh plugin to good use. We use the &lt;a href=&quot;https://github.com/danielehrhardt/cordova-image-picker&quot;&gt;&lt;code&gt;cordova-image-picker&lt;/code&gt;&lt;/a&gt; plugin to let our users pick an image from their photo library and pass the path of the image to our plugin. To add the plugin to our example project, we just need to call &lt;code&gt;cordova plugin add .. --link&lt;/code&gt;. This will use the &lt;code&gt;plugin.xml&lt;/code&gt; file to add the plugin and its files to our example project. Now we just need to replace the &lt;code&gt;TODO&lt;/code&gt; from the beginning of this article, with the following:&lt;/p&gt;

&lt;p&gt;This looks a little crazy at first, but doesn’t do anything magical: We first use the &lt;code&gt;imagePicker&lt;/code&gt; object to open the native image pickers and take the first image path from the returned results array. We then use the &lt;code&gt;present:&lt;/code&gt; method of our &lt;code&gt;PESDK&lt;/code&gt; plugin to open the &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt; and pass the found image path. Everything else is handling errors and returns by presenting them using a conventional JavaScript alert.&lt;/p&gt;
&lt;p&gt;When called, the plugin prepares the inputs using native Objective-C or Java and presents the PhotoEditor SDK’s editor with the loaded image. A user can then add filters, stickers and frames, adjust the images colors or transform it to a different size. All with native performance and a polished UI. Once finished, the image is returned by the editor and our plugin saves the file to the native photo rolls. Finally, the plugin returns the path to the edited image to Cordova. From there you could display the image, offer sharing functionality or anything else. On iOS, the running example looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Our example app, opening the PhotoEditor SDK from Cordova.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 241px) 241px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;241&quot; height=&quot;500&quot; src=&quot;https://img.ly/_astro/1-4daA2PAMShT1c3RlIXEROA_2pfyJM.webp&quot; srcset=&quot;/_astro/1-4daA2PAMShT1c3RlIXEROA_2pfyJM.webp 241w&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;And thats it!&lt;/strong&gt; You have now successfully created a Cordova plugin that wraps the &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK’s&lt;/a&gt; native components for use with Cordova. If you need to configure the SDK, e.g. changing behaviour and colors or adding/removing stickers, you can adjust the plugin to modify the configuration object. Take a look at our configuration docs for &lt;a href=&quot;https://img.ly/docs/pesdk/ios/getting-started/integration/swift-package-manager/&quot;&gt;iOS&lt;/a&gt; and &lt;a href=&quot;https://img.ly/docs/pesdk/android/getting-started/integration/&quot;&gt;Android&lt;/a&gt; for more details.&lt;/p&gt;
&lt;h2 id=&quot;ionic&quot;&gt;Ionic&lt;/h2&gt;
&lt;p&gt;Ionic is built on Cordova, so you’re able to use the plugin from your Ionic application as well. Just take a look at our demo repository to get started. The repository contains a Ionic demo app that uses the plugin we just built to open the PhotoEditor SDK.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;Creating a Cordova plugin that wraps the &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt; requires some upfront work, mostly caused by Cordova quirks, but quickly yields very usable results. Combined with the SDK’s configuration options, one can easily embed a photo editor into his Cordova or Ionic app and move on to other parts. For all details, take a look at the corresponding &lt;a href=&quot;https://github.com/imgly/pesdk-cordova-demo&quot;&gt;GitHub repository&lt;/a&gt;, our &lt;a href=&quot;https://img.ly/docs/pesdk/ios/getting-started/integration/swift-package-manager/&quot;&gt;iOS&lt;/a&gt; and &lt;a href=&quot;https://img.ly/docs/pesdk/android/getting-started/integration/&quot;&gt;Android&lt;/a&gt; docs and the &lt;a href=&quot;https://github.com/imgly/pesdk-ionic-demo&quot;&gt;Ionic demo repository&lt;/a&gt;.&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>Malte</dc:creator><media:content url="https://blog.img.ly/2020/03/1-jnS6C6he1NrKGOdwkZEubg.png" medium="image"/><category>JavaScript</category><category>Cordova</category><category>Ionic</category><category>iOS</category><category>Android</category><category>Tech</category><category>How-To</category><category>Company</category></item><item><title>Deep Learning for Photo Editing</title><link>https://img.ly/blog/deep-learning-for-photo-editing-943bdf9765e1/</link><guid isPermaLink="true">https://img.ly/blog/deep-learning-for-photo-editing-943bdf9765e1/</guid><pubDate>Thu, 20 Apr 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Deep learning, a subfield of machine learning, has become one of the most known areas in the ongoing AI hype. Having led to many important publications and impressive results, it is applied to dozens of different scenarios and has already yielded interesting results like human-like speech generation, high accuracy object detection, &lt;a href=&quot;https://ai.googleblog.com/2016/09/a-neural-network-for-machine.html&quot;&gt;advanced machine translation&lt;/a&gt;, &lt;a href=&quot;https://ai.googleblog.com/2016/11/enhance-raisr-sharp-images-with-machine.html&quot;&gt;super resolution&lt;/a&gt; and many more.&lt;/p&gt;
&lt;p&gt;There is a steady flow of papers and publications that describe the latest advances in network design, compare existing architectures or describe unseen approaches leading to even better results than the current state-of-the-art. At the same time more and more companies and developers jump on the deep learning bandwagon and deploy the ideas and architectures to real world production systems.&lt;/p&gt;
&lt;p&gt;This article describes our approach to applying deep learning to our image editing product, the struggle we had with finding the right architecture and the experiences we made while developing a system that can be deployed to mobile devices.&lt;/p&gt;
&lt;h2 id=&quot;our-vision&quot;&gt;Our vision&lt;/h2&gt;
&lt;p&gt;At &lt;a href=&quot;https://9elements.com&quot;&gt;9elements&lt;/a&gt;, we’ve had various AI topics on our radar for quite some time now. With deep learning, we finally found a tremendous opportunity for our product, the &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;Photoeditor SDK&lt;/a&gt;: &lt;strong&gt;We believe AI-based algorithms could be the ideal approach to boost our users creative output and simplify complex design tasks&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Given the hype and results, we decided to dip our toes into deep learning, which quickly lead to some research regarding the most common challenges in interactive image editing. We quickly surfaced image segmentation as a major challenge that could be solved using deep learning and started investigating further.&lt;/p&gt;
&lt;p&gt;If you have ever tried to select a distinctive region in a picture, say your best friend on the beach or your cute pet, you know the struggle of carefully moving your cursor along the object’s outer bounds until you eventually miss a part or accidentally select something that doesn’t belong to the object. Professional image editing tools can be quite helpful in accomplishing such tasks, but on the one hand, they aren’t available on your mobile device, where you take and publish the images, and on the other hand, can be quite expensive and usually require some hands-on time, before you can produce anything usable.&lt;/p&gt;
&lt;p&gt;Our goal was to finally remove the hassle from image clipping. We wanted to &lt;strong&gt;reduce the required user interaction to a minimum&lt;/strong&gt; while offering an intuitive solution that doesn’t require any manuals or online courses. On top of that, as we provide native SDKs for &lt;a href=&quot;https://img.ly/docs/pesdk/web/introduction/getting_started/&quot;&gt;web&lt;/a&gt;, &lt;a href=&quot;https://img.ly/docs/pesdk/ios/getting-started/integration/swift-package-manager/&quot;&gt;iOS&lt;/a&gt;, and &lt;a href=&quot;https://img.ly/docs/pesdk/android/getting-started/integration/&quot;&gt;Android&lt;/a&gt;, the solution had to be deployable to all of these systems without relying on a powerful backend or being limited to certain features.&lt;/p&gt;
&lt;p&gt;Having formulated our rather ambitious goals, we started our journey by looking into the most common research papers and classic techniques for image segmentation. We then focused on the deep learning part and quickly had an idea on how to design our approach.&lt;/p&gt;
&lt;h2 id=&quot;our-journey&quot;&gt;Our journey&lt;/h2&gt;
&lt;p&gt;Image segmentation, the process of classifying each pixel in a picture to be rather fore- or background, is a popular research field and still perceived as quite challenging due to the complicated nature of the task. We, humans, are extremely well trained at perceiving scenes, identifying objects and making logical assumptions based on the visual input we receive.&lt;/p&gt;
&lt;p&gt;For a long time, all approaches were based on colors, edges, and contrast and relied heavily on fine-tuned parameters, which had to be adjusted to every new scenario. That changed in 2012 when Krizhevsky et al. presented &lt;a href=&quot;https://papers.nips.cc/paper/2012/hash/c399862d3b9d6b76c8436e924a68c45b-Abstract.html&quot;&gt;astonishing object classification results&lt;/a&gt; on the ImageNet benchmark using a neural network. Suddenly a system was able to classify objects with unprecedented accuracy and no need for any human fine-tuning. The neural network was ‘just’ trained on the dataset by seeing images combined with their corresponding labels and adjusting its internal representation until it couldn’t learn any further.&lt;/p&gt;
&lt;p&gt;As we had already decided on using deep learning for our task, using a neural net clearly was our way to go. We started by examining the existing solutions and approaches, created our first prototype based on our findings and refined our approach and implementation until everything met our expectations.&lt;/p&gt;
&lt;h3 id=&quot;scene-labeling&quot;&gt;Scene Labeling&lt;/h3&gt;
&lt;p&gt;The first approaches we examined focused on segmenting the whole image. This is a common task called scene labeling or semantic labeling, because it allows robots and other systems to understand a scene. The goal is to classify each pixel in an image to a particular object category. An example could be a self-driving car that searches for the road and tries to determine whether any pedestrians are crossing the street. Such a car would try to classify each pixel as road, pedestrian, tree, traffic sign, etc.:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Human labeled scene from the Cityscapes Dataset&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1200px) 1200px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1200&quot; height=&quot;597&quot; src=&quot;https://img.ly/_astro/1-c5yvBgnNeMYxQlwr5yN5yQ_1QBHVb.webp&quot; srcset=&quot;/_astro/1-c5yvBgnNeMYxQlwr5yN5yQ_1m3G3a.webp 640w, /_astro/1-c5yvBgnNeMYxQlwr5yN5yQ_hH8pz.webp 750w, /_astro/1-c5yvBgnNeMYxQlwr5yN5yQ_14yPz1.webp 828w, /_astro/1-c5yvBgnNeMYxQlwr5yN5yQ_10qoxR.webp 1080w, /_astro/1-c5yvBgnNeMYxQlwr5yN5yQ_1QBHVb.webp 1200w&quot;&gt;&lt;/p&gt;
&lt;p&gt;While offering lots of possibilities, the existing solutions were lacking the desired accuracy we needed to provide visually pleasing image segmentations. For a self-driving car, it doesn’t matter if the ‘person’ region for some pedestrian accurately covers the person’s outlines. However, for us it does.&lt;/p&gt;
&lt;p&gt;To overcome these issues we experimented with post processing techniques that used the segmentations we found as a base for further optimisations. This lead to our first approach where we would initially segment the entire image using a convolutional neural network, offer the found regions as selectable regions to a user and then try to refine the user’s selection using conventional image segmentations to find the best possible mask.&lt;/p&gt;
&lt;p&gt;While already yielding some useful results the system did not quite match our requirements. If the initial segmentation was too coarse or off in critical regions, the user could never select an area that would lead to his desired segmentation.&lt;/p&gt;
&lt;h3 id=&quot;image-segmentation-based-on-userinputs&quot;&gt;Image segmentation based on user inputs&lt;/h3&gt;
&lt;p&gt;We went back to the drawing board and searched for other approaches that would fit our use case. It didn’t take long, and we stumbled upon &lt;a href=&quot;https://arxiv.org/abs/1603.04042&quot;&gt;Deep Interactive Object Selection&lt;/a&gt;, a paper that presents an interactive system which creates image segmentations based on user clicks. It looked like a good fit for our requirements, and we updated our existing system to generate fake user inputs and train on combinations of these inputs and images.&lt;/p&gt;
&lt;p&gt;To train the net, we used the publicly available COCO dataset, which contains around 300.000 images with more than 2 million annotated object instances. To handle the amount of data, we limited our training data to a subset of the full dataset. This subset was made up of images that contain objects from certain categories and cover a minimum area within the image. As we generated the inputs artificially by adding clicks on the object mask, we could generate as many training data from the COCO subset as we wanted. After some experiments, we settled for three different strategies to create user inputs and trained the net with roughly 300.000 training records.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 400px) 400px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;400&quot; height=&quot;400&quot; src=&quot;https://img.ly/_astro/1-ha6lNjDWPH5FDOhASLSYOg_Zzijvu.webp&quot; srcset=&quot;/_astro/1-ha6lNjDWPH5FDOhASLSYOg_Zzijvu.webp 400w&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 400px) 400px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;400&quot; height=&quot;400&quot; src=&quot;https://img.ly/_astro/1--yMNXhbET6JfRAr7UKLz-w_2l2CfT.webp&quot; srcset=&quot;/_astro/1--yMNXhbET6JfRAr7UKLz-w_2l2CfT.webp 400w&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;An input image, a distance map generated from user clicks and the corresponding groundtruth label for an MSCoco sample.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 400px) 400px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;400&quot; height=&quot;400&quot; src=&quot;https://img.ly/_astro/1-nYVbp1evh1hvHaXdj-vDlg_Z1Mhbbk.webp&quot; srcset=&quot;/_astro/1-nYVbp1evh1hvHaXdj-vDlg_Z1Mhbbk.webp 400w&quot;&gt;&lt;/p&gt;
&lt;p&gt;The masks generated by the updated system were quite impressive already. The neural net could infer which object the user wanted to mask in the image, just by looking at raw pixel data and the user’s clicks on the object. Happy with the first results, we tried to tackle the next hurdle. Before diving deeper into optimizing the neural net, which is a rather error prone process and consumes lots of time, we wanted to deploy the net to a mobile device. We wanted to make sure that such a tool is usable on any device and the performance would match our expectations.&lt;/p&gt;
&lt;h3 id=&quot;neural-nets-on-mobiledevices&quot;&gt;Neural nets on mobile devices&lt;/h3&gt;
&lt;p&gt;Neural nets are sets of operations, executed in a specific order and based on millions of parameters. Therefore one “run” of such a net requires a lot of computation power, as millions of calculations have to be carried out. At the same time, the millions of parameters need to be deployed, as they represent the model or the representation the neural net has learned during training. So, to deploy our neural net, we had to solve these two requirements on an iPhone.&lt;/p&gt;
&lt;p&gt;The first requirement, computing power, was thankfully solved by Apple. With the latest iOS version a specialised framework, called &lt;em&gt;Metal Performance Shaders&lt;/em&gt;, was introduced. It offers the all required operations and is tailored to run these on the phones GPU, which is fast and efficient. To execute our net using the framework we had to translate our TensorFlow network code to Swift and rebuild the net’s architecture using Metal Performance Shader operations. Sadly Apple only supports a subset of todays common neural network operations, so we were forced to write some shader code to reconstruct the full network.&lt;/p&gt;
&lt;p&gt;The second requirement, extracting the trained parameters and deploying them to the device was much easier. We just had to restore our previously trained model from a TensorFlow checkpoint, write all trained variables into a file and deploy this file with our iOS app. When needed, the iOS app would load the file into memory, and our network implementation would use the given parameters to run an inference pass.&lt;/p&gt;
&lt;p&gt;Having met the two requirements, our network worked fine on an iPhone. We added the postprocessing operations and were able to segment images by a single tap without the need for a backend or any network communication. But there were some caveats.&lt;/p&gt;
&lt;p&gt;While our neural net was a very common and widely used network, it was huge regarding the trainable variables. A trained model contains ~134 million parameters, which translates to about half a gigabyte of data that needs to be deployed with the app. This was obviously a showstopper for a mobile image editing app, as we couldn’t justify a 500MB download just to be able to segment images with your finger.&lt;/p&gt;
&lt;p&gt;Furthermore, the results were still very coarse. If your colleague waved his arms in an image, the net usually could easily detect his torso, head and maybe his legs, but almost never the arms or hands. Fixing this using our postprocessing algorithms wasn’t that much of an option as it would have required lots of computing power and why bother using a neural net with millions of parameters if we fall back to conventional image processing techniques anyway?&lt;/p&gt;
&lt;p&gt;So all in all, we had already learned a lot: Our approach of processing user inputs combined with raw image data as neural net input led to usable outputs, although quite coarse. Deploying such a net to mobile devices was possible, and the performance was good enough for using it in an interactive tool. The next step was to optimize the system to fix the parameter size and get finer results.&lt;/p&gt;
&lt;h3 id=&quot;combining-squeezenet-and-sharpmask&quot;&gt;Combining SqueezeNet and SharpMask&lt;/h3&gt;
&lt;p&gt;We decided to tackle the network size first, as laying a proper foundation for optimizing the coarseness seemed like a sane thing to do. When looking for small nets with few parameters and fast inference its hard not to stumble across the &lt;a href=&quot;https://arxiv.org/abs/1602.07360&quot;&gt;SqueezeNet architecture&lt;/a&gt; by Iandola et al. which was published in November 2016. It met our use case, didn’t use any exotic operations that would be hard to implement on mobile and the results looked promising, so we removed the original network from our system and replaced it with an altered SqueezeNet implementation. And to our surprise, it worked almost right away. We had to tweak our training pipeline, and the results differed slightly, but all in all the small network with only ~5 million parameters matched the performance of our previous behemoth with ~134 million parameters. We quickly updated our conversion script and found out that our deployable model file just &lt;strong&gt;shrunk from ~500mb to 2.9mb&lt;/strong&gt;. What a happy day!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The SqueezeNet architecture.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1200px) 1200px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1200&quot; height=&quot;183&quot; src=&quot;https://img.ly/_astro/1-zPnkborOECNOZR86UCvMKQ_FzrRz.webp&quot; srcset=&quot;/_astro/1-zPnkborOECNOZR86UCvMKQ_Z1cnUlc.webp 640w, /_astro/1-zPnkborOECNOZR86UCvMKQ_Z1Qo2mJ.webp 750w, /_astro/1-zPnkborOECNOZR86UCvMKQ_Z6B1z.webp 828w, /_astro/1-zPnkborOECNOZR86UCvMKQ_1McUss.webp 1080w, /_astro/1-zPnkborOECNOZR86UCvMKQ_FzrRz.webp 1200w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Having solved the network size issue, we went ahead and thought about increasing the precision of our predictions. A loss of resolution is unavoidable in convolutional neural networks, as later layers acquire a larger “view” of the inputs by reducing their input size with so-called “pooling” layers. These layers take for example four values from the previous layer and merge them into a single one. Therefore our new SqueezeNet-based system created a 32 by 32-pixel image mask from a 512 by 512-pixel input image. Up to now we just scaled these up by using a transposed convolution. This allowed the net to learn how the upscaling worked best, but the fine details from the initial input image were already lost at this point.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A SharpMask refinement module.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 300px) 300px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;300&quot; height=&quot;390&quot; src=&quot;https://img.ly/_astro/1-Pu3jkltytfzkRs9ENoZsCQ_lDw3p.webp&quot; srcset=&quot;/_astro/1-Pu3jkltytfzkRs9ENoZsCQ_lDw3p.webp 300w&quot;&gt;&lt;/p&gt;
&lt;p&gt;We remembered &lt;a href=&quot;https://arxiv.org/abs/1603.08695&quot;&gt;Facebooks SharpMask&lt;/a&gt; system introduced in summer 2016 and revisited the accompanying paper. Their refinement modules seemed like a good fit, as they were able to gradually incorporate features from lower levels, but with higher resolution, into the coarse outputs. We adopted the idea and altered the refinement modules to take the final SqueezeNet output. The modules then combined the coarse SqueezeNet output with the pooling layers intermediate results and were able to refine the result. This increased our model size and the computation costs by a fair amount, but lead to much finer and more detailed results.&lt;/p&gt;
&lt;p&gt;Once we settled on our architecture, we started an extensive training run, in which we tested more than one hundred different variations of hyperparameters, architectural details, and resizing techniques. Evaluating the results, we selected a variation, which made the best compromise between accuracy and inference speed/model size.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A chart showing the accuracies that each variation achieved after a given number of steps during the training process.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1200px) 1200px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1200&quot; height=&quot;273&quot; src=&quot;https://img.ly/_astro/1-Vz_5BpREzqAGa_ZNFp1bHA_Z8rNCE.webp&quot; srcset=&quot;/_astro/1-Vz_5BpREzqAGa_ZNFp1bHA_XpgkK.webp 640w, /_astro/1-Vz_5BpREzqAGa_ZNFp1bHA_143Xbw.webp 750w, /_astro/1-Vz_5BpREzqAGa_ZNFp1bHA_Z2kkwwm.webp 828w, /_astro/1-Vz_5BpREzqAGa_ZNFp1bHA_2qNT7X.webp 1080w, /_astro/1-Vz_5BpREzqAGa_ZNFp1bHA_Z8rNCE.webp 1200w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;our-results-and-prototype&quot;&gt;Our results and prototype&lt;/h2&gt;
&lt;p&gt;Having managed to fix all the issues, we were eager to see how the whole system performed on a mobile device with limited computing power and inputs. We updated our mobile app to use the new network architecture and the freshly trained model to compare the refined system to our previous approach. The results were amazing. When selecting objects that matched the categories of our training data and were fully visible in the image, we were able to generate fine-grained selection masks with &lt;strong&gt;just a single tap&lt;/strong&gt;. More complex or larger objects required a few more taps, but we could always find a selection mask for our object, that was at least a solid starting point for further optimizations.&lt;/p&gt;
&lt;p&gt;We decided to build a more polished prototype based on our existing img.ly iOS app. This app uses our &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt; to offer advanced image editing including focus and filter operations. As we were now able to create masks based on objects in the image we quickly settled on enhancing our filter and focus tools with selective masking.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 331px) 331px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;331&quot; height=&quot;580&quot; src=&quot;https://img.ly/_astro/1-rf1v_R_PHbQDo8MpMPFg8w_ZIWoo9.webp&quot; srcset=&quot;/_astro/1-rf1v_R_PHbQDo8MpMPFg8w_ZIWoo9.webp 331w&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 331px) 331px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;331&quot; height=&quot;580&quot; src=&quot;https://img.ly/_astro/1-naxBkJ1MXe09LXkIHmdkFA_1QJtfk.webp&quot; srcset=&quot;/_astro/1-naxBkJ1MXe09LXkIHmdkFA_1QJtfk.webp 331w&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Our first prototype in action.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 331px) 331px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;331&quot; height=&quot;580&quot; src=&quot;https://img.ly/_astro/1-Oa6rKX7fZMDEQ-QPDsGznA_19ef6u.webp&quot; srcset=&quot;/_astro/1-Oa6rKX7fZMDEQ-QPDsGznA_19ef6u.webp 331w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;retrospective&quot;&gt;Retrospective&lt;/h2&gt;
&lt;p&gt;Looking back at our journey into deep learning, it was one of the more frustrating yet fascinating ones. The sheer amount of possible applications is exciting, and once you get the hang of training something on your data, you immediately want to start experimenting with new things. On the other hand, you’re usually building huge black boxes with millions of float values, which makes debugging a pain. Especially when trying to replicate an already implemented architecture on other platforms, this can quickly become rather frustrating. If your outputs don’t match the expected results, your only option is to repeatedly go over your code, check all parameters and hope you stumble upon the wrong number somewhere. But once you manage to set everything up and start seeing some good results, you instantly want to tweak and optimise the bits and pieces of your system.&lt;/p&gt;
&lt;p&gt;Overall, deep learning is a pain to debug, but yields great results, opens up a new field of photo editing applications and we’ll definitely keep exploring the new possibilities of applying the techniques in our product. Stay tuned for upcoming features!&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>Malte</dc:creator><media:content url="https://blog.img.ly/2020/03/1-rZLmjkiT9VNRU5eJNK77Jg.jpeg" medium="image"/><category>Machine Learning</category><category>AI</category><category>Deep Learning</category><category>Photography</category><category>Artificial Intelligence</category></item><item><title>PhotoEditor SDK + React Native</title><link>https://img.ly/blog/photoeditor-sdk-react-native-15179c589a55/</link><guid isPermaLink="true">https://img.ly/blog/photoeditor-sdk-react-native-15179c589a55/</guid><pubDate>Mon, 20 Mar 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Often our users ask whether it’s possible to use the &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt; for iOS and Android with React Native (the good news right away: Yes, it is possible and fairly easy as well). So, we set out to create a demo app and put together a guide on how to easily set up the PhotoEditor SDK with React Native and how to avoid eventual pitfalls.&lt;/p&gt;
&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;/h2&gt;
&lt;p&gt;We started our demo project by creating a new React Native project using &lt;code&gt;react-native init PESDKDemo&lt;/code&gt;. We then added &lt;a href=&quot;https://github.com/wix/react-native-navigation&quot;&gt;&lt;code&gt;react-native-navigation&lt;/code&gt;&lt;/a&gt;, a navigation library from the awesome folks at Wix, to get a base for our demo app. However, &lt;code&gt;react-native-navigation&lt;/code&gt; is not required for embedding the PESDK into your React Native application.&lt;/p&gt;
&lt;h2 id=&quot;launching-the-photoeditor-sdk-from-reactnative&quot;&gt;Launching the PhotoEditor SDK from React Native&lt;/h2&gt;
&lt;p&gt;To successfully launch our editor from React Native we needed to do three things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add the PESDK library to our iOS project.&lt;/li&gt;
&lt;li&gt;Create a native module that bridges between React Native and the PhotoEditor SDK.&lt;/li&gt;
&lt;li&gt;Add a method to create a &lt;code&gt;ToolbarController&lt;/code&gt;, push a &lt;code&gt;PhotoEditController&lt;/code&gt; and present them from the current view controller.&lt;/li&gt;
&lt;li&gt;Call the method, wherever we want to edit an image in our React Native code&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first step was rather easy. We just followed the &lt;a href=&quot;https://img.ly/docs/pesdk/ios/getting-started/integration/swift-package-manager/&quot;&gt;steps for a manual installation&lt;/a&gt; and had the PESDK library ready in minutes.&lt;/p&gt;
&lt;p&gt;Creating a native module in React Native was fairly easy as well. We simply created &lt;code&gt;PESDKModule.h&lt;/code&gt; and &lt;code&gt;PESDKModule.m&lt;/code&gt; and defined a &lt;code&gt;PESDKModule&lt;/code&gt; class that inherits from NSObject and implements the &lt;code&gt;RCTBridgeModule&lt;/code&gt; protocol. In the classes implementation we registered our module with React Native by calling &lt;code&gt;RCT_EXPORT_MODULE(PESDK)&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;In order to create a new photo editor view controller we needed to create a new &lt;code&gt;ToolbarController&lt;/code&gt; and push a &lt;code&gt;PhotoEditController&lt;/code&gt; that loads a sample image. As we’ll always use such a hierarchy, we bundled this setup into the &lt;code&gt;present()&lt;/code&gt; method of our native module and exported it to React Native using the &lt;code&gt;RCT_EXPORT_METHOD&lt;/code&gt; macro:&lt;/p&gt;

&lt;p&gt;The final step was putting our newly created module to good use and actually pushing our photo editor from React Native. To do so, we imported the &lt;code&gt;PESDK&lt;/code&gt; native module using &lt;code&gt;var PESDK = NativeModules.PESDK&lt;/code&gt;. We could then call &lt;code&gt;PESDK.present()&lt;/code&gt; and the native module created the &lt;code&gt;ToolbarController&lt;/code&gt; and &lt;code&gt;PhotoEditViewController&lt;/code&gt; objects and pushed them from the current view controller. If you were to use a simple &lt;code&gt;TouchableHighlight&lt;/code&gt;, this could look like this:&lt;/p&gt;

&lt;p&gt;Bringing it all together, we were now able to open the native iOS PESDK &lt;code&gt;PhotoEditController&lt;/code&gt; from our React Native code. Surprisingly easy, isn’t it?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Our initial result: The button pushes our SDK with a sample image.&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;314&quot; src=&quot;https://img.ly/_astro/1-wyxWgOjJbTS4nR4Jgk8ugg_1ALLeW.webp&quot; srcset=&quot;/_astro/1-wyxWgOjJbTS4nR4Jgk8ugg_Z1Io0kC.webp 640w, /_astro/1-wyxWgOjJbTS4nR4Jgk8ugg_ZvNqbf.webp 750w, /_astro/1-wyxWgOjJbTS4nR4Jgk8ugg_1ALLeW.webp 800w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;passing-an-image-to-theeditor&quot;&gt;Passing an image to the editor&lt;/h2&gt;
&lt;p&gt;Opening an image editor with a sample image is nice but wasn’t really our intention, when we started integrating the &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt;. Instead, we wanted to be able to edit &lt;strong&gt;any&lt;/strong&gt; image and save the result into our camera roll or share it with our friends. For our little demo, we decided to present a grid of images from unsplash.com to the user, so he can choose any image from the list and edit it with our editor.&lt;/p&gt;
&lt;p&gt;The JavaScript for creating the image grid is a little out of scope for this article, so we won’t cover it in detail. It basically uses a &lt;code&gt;ListView&lt;/code&gt; to create rows of three cells and fills them with images loaded from the unsplash.it service. All image fetching, scrolling, etc. is handled by React Native, so we only needed to handle the user’s taps on an image:&lt;/p&gt;

&lt;p&gt;We used &lt;code&gt;[react-native-fs](https://github.com/itinance/react-native-fs)&lt;/code&gt; to download a larger resolution image to the local filesystem, pass the path of the local file to our &lt;code&gt;present()&lt;/code&gt; call and modify our iOS native module:&lt;/p&gt;

&lt;p&gt;We then had a nice little app, that shows a grid of images, loads a high-resolution image upon selection and opens the PhotoEditor SDK:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The iOS demo app running on a device.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 326px) 326px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;326&quot; height=&quot;600&quot; src=&quot;https://img.ly/_astro/1-rb4iEgDv941RQpQvESCMlw_Wq8wK.webp&quot; srcset=&quot;/_astro/1-rb4iEgDv941RQpQvESCMlw_Wq8wK.webp 326w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;android-implementation&quot;&gt;Android implementation&lt;/h2&gt;
&lt;p&gt;As we have seen, opening the PESDK from React Native can easily be done on iOS. But why use React Native, if the app only runs on iOS? It was time to add Android support to our little demo app. To accomplish this we needed to repeat some of the previous steps for Android:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add the PESDK to our Android project.&lt;/li&gt;
&lt;li&gt;Create a native module that bridges between React Native and the PESDK.&lt;/li&gt;
&lt;li&gt;Add a method to launch an &lt;code&gt;ImglyIntent&lt;/code&gt; using the &lt;code&gt;PhotoEditorBuilder&lt;/code&gt; from the current &lt;code&gt;Activity&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Installing the SDK is again done by following the instructions for integrating the PESDK and shouldn’t take more than a few minutes. Creating a native module on Android is quite similar to iOS, although a little more setup code is required: We created our &lt;code&gt;PESDKModule&lt;/code&gt; that recreates the &lt;code&gt;present(path)&lt;/code&gt;method from iOS, a &lt;code&gt;PESDKPackage&lt;/code&gt; containing our module and finally added the package to our &lt;code&gt;Application&lt;/code&gt;:&lt;/p&gt;



&lt;p&gt;This time, we prepared the desired settings for our editor, added our image path and passed everything to a PhotoEditorBuilder. The builder creates an intent and we launch it from our current &lt;code&gt;Activity&lt;/code&gt;. That’s it! Running our sample app on an Android device now leads to this:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The example app running on an Android device.&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;345&quot; src=&quot;https://img.ly/_astro/1-vsocOovAQ85pAWggvd9KuQ_Oz3Ce.webp&quot; srcset=&quot;/_astro/1-vsocOovAQ85pAWggvd9KuQ_ZKHc7R.webp 640w, /_astro/1-vsocOovAQ85pAWggvd9KuQ_ZOSbAT.webp 750w, /_astro/1-vsocOovAQ85pAWggvd9KuQ_Oz3Ce.webp 800w&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;nifty-details&quot;&gt;Nifty details&lt;/h3&gt;
&lt;p&gt;Experimenting with our new app, we noticed an issue: While the Android app closed the editor just fine when canceling the editor, the iOS app did nothing at all. That is because the iOS module doesn’t handle the PESDKs delegate methods. However, this can be fixed easily:&lt;/p&gt;

&lt;p&gt;It could be taken even further by turning our native iOS module into a &lt;code&gt;RCTEventEmitter&lt;/code&gt; and sending events to React Native when the delegate methods are called. Just take a look into our &lt;a href=&quot;https://github.com/imgly/pesdk-react-native-demo&quot;&gt;GitHub repository&lt;/a&gt; to find the corresponding code.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;To sum it up: Using the &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt; from React Native was rather easy to do and we were very happy with the results. Handling the data flows between React Native and the Java or Objective-C classes can be tricky, but when dealing with a specific use case, it should be easy to adjust the native modules to meet your requirements. Feel free to adapt &lt;a href=&quot;https://github.com/imgly/pesdk-react-native-demo&quot;&gt;our code&lt;/a&gt; and add the PhotoEditor SDK to your React Native app. We’re looking forward to your feedback and any pull requests, that further optimize our implementation.&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>Malte</dc:creator><media:content url="https://blog.img.ly/2020/03/1-OHCSavYLUI1iSouT83EHhg.png" medium="image"/><category>React Native</category><category>iOS</category><category>Android</category><category>Photo Editing</category><category>Photo Editor</category><category>Tech</category><category>How-To</category><category>Company</category></item></channel></rss>