<?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>Photo Editor – IMG.LY Blog</title><description>Posts tagged Photo Editor on the IMG.LY blog.</description><link>https://img.ly/blog/tag/photo-editor/</link><language>en-us</language><image><url>https://img.ly/apple-touch-icon.png</url><title>Photo Editor – IMG.LY Blog</title><link>https://img.ly/blog/tag/photo-editor/</link></image><atom:link href="https://img.ly/blog/tag/photo-editor/rss.xml" rel="self" type="application/rss+xml"/><generator>Astro</generator><lastBuildDate>Tue, 09 Jun 2026 09:48:34 GMT</lastBuildDate><ttl>60</ttl><item><title>The Best Photo Editor SDKs: 2025 Ranking</title><link>https://img.ly/blog/the-best-photo-editor-sdks-2025-ranking/</link><guid isPermaLink="true">https://img.ly/blog/the-best-photo-editor-sdks-2025-ranking/</guid><description>Are you looking for the right photo editor SDK for your company? This decision goes beyond adding filters or cropping tools. You need a tool that fits your product vision, scales with your user base, and supports the workflows your customers expect.</description><pubDate>Tue, 16 Sep 2025 07:52:46 GMT</pubDate><content:encoded>&lt;p&gt;In this guide, we’ll compare seven leading image editor SDKs - &lt;strong&gt;IMG.LY (CreativeEditor SDK), Fotor, Banuba, Pintura, Polotno, Imgpen, and Cloudinary,&lt;/strong&gt; by focusing on each of their:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Features &amp;#x26; capabilities&lt;/li&gt;
&lt;li&gt;Implementation &amp;#x26; use cases&lt;/li&gt;
&lt;li&gt;Future-Proofing, support &amp;#x26; pricing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At the end, we’ll give honest feedback on who would benefit the most from using these different tools and highlight where IMG.LY CreativeEditor SDK stands out as the most complete, enterprise-ready option.&lt;/p&gt;
&lt;h2 id=&quot;1-imgly-creativeeditor-sdk-cesdk&quot;&gt;&lt;strong&gt;1. IMG.LY CreativeEditor SDK (CE.SDK)&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;IMG.LY CreativeEditor SDK is an enterprise‑grade design and editing SDK that supports photo, video, and template workflows. It goes beyond simple photo adjustments to deliver a scalable editing tool that fits easily into products used by millions of end‑users.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Features &amp;#x26; capabilities:&lt;/strong&gt; CreativeEditor SDK offers a full suite of photo editing tools including filters, adjustments, cropping, and background removal, alongside advanced design capabilities. You can layer elements, apply templates, and use generative features to streamline creative workflows. CE.SDK offers complete content creation and personalization experiences.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Platforms &amp;#x26; customization:&lt;/strong&gt; Available for Web, iOS, Android, React Native, Flutter, Node.js, and Electron. The SDK is white-label and fully customizable. You control the entire UI and can extend functionality with plugins, making it suitable for teams that want both flexibility and enterprise stability.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implementation &amp;#x26; use cases:&lt;/strong&gt; Integration is straightforward with ready-made UIs for image editing. Businesses use CE.SDK to power e-commerce personalization, marketing platforms, DAMs, SaaS tools, and social apps. A key differentiator of CE.SDK is a single engine that runs across platforms, ensuring consistent performance and reducing development overhead.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Future-Proofing, support &amp;#x26; pricing:&lt;/strong&gt; IMG.LY follows a clear AI-driven roadmap, with frequent feature releases and updates. Customers benefit from SLAs, dedicated onboarding, and solution engineers. Pricing is based on custom enterprise licensing, ensuring it aligns with your business needs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Who its for:&lt;/strong&gt; CE.SDK is perfect for companies looking for more than a basic photo editor. If you want a scalable solution that supports automation, cross-platform deployment, and advanced design features, CE.SDK is the strongest choice.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;key-differentiator&quot;&gt;&lt;strong&gt;Key differentiator&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;CE.SDK is the only SDK that combines a polished, embeddable editor with a scalable automation engine in a single stack. This means you don’t need separate tools for editing and backend workflows. This integration saves development time, reduces costs, and ensures a smoother experience for end users. For teams building long-term products, this combination is a significant competitive advantage.&lt;/p&gt;
&lt;p&gt;See the &lt;a href=&quot;https://img.ly/showcases/cesdk/photo-editor-ui/web&quot;&gt;CreativeEditor SDK showcase&lt;/a&gt; for examples of its photo editing UI in action.&lt;/p&gt;
&lt;h2 id=&quot;2-fotor-sdk&quot;&gt;&lt;strong&gt;2. Fotor SDK&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Fotor SDK is an AI-first editing API/SDK with a focus on automation. It provides ready-to-use AI endpoints that help teams handle common tasks like background removal and retouching without building their own machine learning models.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Features &amp;#x26; capabilities:&lt;/strong&gt; Fotor SDK focuses on AI-driven editing. It offers background removal, AI upscaling, skin retouching, magic eraser, and face unblur. The tools are strong for quick, one-off edits but limited in scope, mainly targeting simple editing tasks rather than broader workflows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Platforms &amp;#x26; customization:&lt;/strong&gt; Primarily web-based with some mobile support through APIs. Customization is minimal compared to other UI SDKs since Fotor is focused on prebuilt AI endpoints.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implementation &amp;#x26; use cases:&lt;/strong&gt; Setup is fast, but teams need to build their own UI for more complex workflows. Common use cases include e-commerce product photo cleanups and social integrations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Future-proofing, support &amp;#x26; pricing:&lt;/strong&gt; Fotor invests heavily in AI features but is smaller in scale compared to enterprise-ready vendors. Commercial support is available, and pricing follows a tiered SaaS model.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Who it’s for:&lt;/strong&gt; Fotor SDK is suitable for teams wanting fast AI editing without building in-house ML.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;how-it-compares-to-imgly&quot;&gt;&lt;strong&gt;How it compares to IMG.LY&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Fotor is best for narrow AI workflows, making it useful when you only need quick automation. IMG.LY, on the other hand, supports both automated editing and rich, customizable UIs in a single platform. This gives product teams the flexibility to deliver fast AI-powered edits while also providing a full-featured editor that can scale to enterprise needs. For businesses building long-term creative workflows, this combination ensures they don’t outgrow the tool as their product evolves.&lt;/p&gt;
&lt;h2 id=&quot;3-banuba-photo-editor-sdk&quot;&gt;&lt;strong&gt;3. Banuba Photo Editor SDK&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Banuba Photo Editor SDK is a mobile‑first solution specialized in AR and beauty editing. It is widely used in apps where engaging face filters and real‑time effects are critical to user experience.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Features &amp;#x26; capabilities:&lt;/strong&gt; Banuba is designed for AR and beauty editing. It offers features like virtual makeup, skin smoothing, AR masks, and background replacement. This makes it particularly popular for apps where face editing and engagement features are key.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Platforms &amp;#x26; customization&lt;/strong&gt;: Banuba supports iOS, Android, React Native, and Flutter. Its modular SDK allows developers to mix and match features, but its focus is mobile-first.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implementation &amp;#x26; use cases:&lt;/strong&gt; Banuba’s integration is fast for mobile apps, especially those in social media, UGC apps, beauty, and fashion e-commerce. However, support for web-based apps is quite limited.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Future-proofing, support &amp;#x26; pricing:&lt;/strong&gt; They are expanding their AR and AI stack, adding new features in line with industry trends. They offer enterprise agreements for larger customers, but pricing is high and not public, which can make it difficult for smaller teams to evaluate or plan budgets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Who it’s for:&lt;/strong&gt; Banuba is suitable for social media apps, beauty brands, and fashion retailers where AR features are essential to the product.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;how-it-compares-to-imgly-1&quot;&gt;&lt;strong&gt;How it compares to IMG.LY&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Banuba dominates in AR and beauty features, making it a strong choice for social or fashion apps. IMG.LY, however, is designed for enterprise use cases where scalability, cross‑platform consistency, and deeper workflow integration matter most. While Banuba is powerful for AR effects, IMG.LY combines editing, automation, and enterprise‑grade support, helping teams build creative products that can grow and adapt across both mobile and web platforms.&lt;/p&gt;
&lt;p&gt;Learn more about how &lt;a href=&quot;https://img.ly/banuba-alternative?ref=img.ly&quot;&gt;IMG.LY compares to Banuba here.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;4-pintura&quot;&gt;&lt;strong&gt;4. Pintura&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Pintura is a JavaScript image editor SDK built specifically for the browser. It’s designed to be lightweight and developer-friendly, making it a good fit for teams that need straightforward image editing without enterprise-level complexity.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Features &amp;#x26; capabilities:&lt;/strong&gt; Pintura covers essential editing tasks such as cropping, rotating, resizing, and applying filters. It provides a clean editing interface that feels polished despite its narrower scope.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Platforms &amp;#x26; customization:&lt;/strong&gt; Works in the browser and supports vanilla JS, React, Vue and Angular. Developers can integrate it easily and customize the UI to fit their application’s look and feel.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implementation &amp;#x26; use cases:&lt;/strong&gt; Setup is simple and quick, which makes it appealing for SaaS products and web apps that want to add photo editing features without heavy development. It’s commonly used for lightweight content creation and adjustments inside web platforms.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Future-proofing, support &amp;#x26; pricing:&lt;/strong&gt; Pintura is actively maintained, but its scope is intentionally limited. Support options are modest, reflecting the vendor’s smaller scale. Pricing is offered as a one-time license or annual subscription, which may suit smaller teams with predictable budgets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Who it’s for&lt;/strong&gt;: Developers who want a reliable, browser-native editor for web apps and don’t need advanced enterprise workflows.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;how-it-compares-to-imgly-2&quot;&gt;&lt;strong&gt;How it compares to IMG.LY&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Pintura is ideal for lightweight browser-native projects where simplicity matters most. IMG.LY, however, delivers an enterprise-grade SDK with broader capabilities, including automation, multi-platform support, and advanced customization. For teams that expect their product to scale or require editing as part of larger workflows, IMG.LY provides the flexibility and stability that Pintura doesn’t provide yet.&lt;/p&gt;
&lt;p&gt;Find out more about &lt;a href=&quot;https://img.ly/pintura-alternative&quot;&gt;how IMG.LY is a great alternative to Pintura here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;5-polotno&quot;&gt;&lt;strong&gt;5. Polotno&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Polotno is a JavaScript framework built for developers who want to create custom design and photo editors from the ground up. It offers a flexible canvas environment but shifts most of the responsibility for UI and workflow design onto the development team.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Features &amp;#x26; capabilities:&lt;/strong&gt; Supports canvas editing, text, shapes, and stock image integrations. Because it’s more of a toolkit than a finished editor, teams can tailor it in almost any direction, but they also need to do more work to reach a polished product.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Platforms &amp;#x26; customization:&lt;/strong&gt; Polotno runs on the web with JavaScript. It’s highly flexible, but developers must build their own UI and workflow, which increases development effort compared to ready-made SDKs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implementation &amp;#x26; use cases:&lt;/strong&gt; Polotno is best suited for prototyping, SaaS experiments, or internal tools where flexibility is more important than speed because creating a production-ready editor requires significant investment in development time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Future-proofing, support &amp;#x26; pricing:&lt;/strong&gt; The tool is community-driven, which means it benefits from active developers but lacks the proven enterprise readiness of larger vendors. Support is limited to community forums, and pricing is through a commercial licence.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Who it’s for:&lt;/strong&gt; Polento is best for developers who want full control and are willing to build editors from scratch rather than use a prebuilt solution.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;how-it-compares-to-imgly-3&quot;&gt;&lt;strong&gt;How it compares to IMG.LY&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Polotno gives you a foundation to build a custom editor, but leaves scalability, long-term support, and advanced workflows to your team. IMG.LY, on the other hand, delivers enterprise-grade stability, a rich feature set, and an AI-powered roadmap right out of the box.&lt;/p&gt;
&lt;p&gt;For businesses that want to move quickly, reduce technical overhead, and rely on a proven partner, IMG.LY is the better choice.&lt;/p&gt;
&lt;p&gt;Read our detailed guide on &lt;a href=&quot;https://img.ly/polotno-alternative&quot;&gt;IMG.LY vs. Polotno to know more.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;6-imgpen&quot;&gt;&lt;strong&gt;6. Imgpen&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Imgpen is a lightweight, web-focused photo editing SDK built for simple integrations. It is aimed at small teams that need quick editing features without enterprise complexity.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Features &amp;#x26; capabilities:&lt;/strong&gt; Imgpen provides only basic image editing features like filters, cropping, text overlays, and simple effects. These features are useful for apps that want to give users quick editing options without overwhelming them, but they lack the depth required for more advanced creative workflows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Platforms &amp;#x26; customization:&lt;/strong&gt; Imgpen runs on the web with JavaScript and offers minimal customization options. Teams can adjust the look and feel slightly, but the SDK doesn’t allow for deeper UI or workflow changes, which can limit how well it fits into complex applications.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implementation &amp;#x26; use cases:&lt;/strong&gt; The SDK is easy to set up and lightweight, making it attractive for small SaaS apps, niche tools, or websites that need basic editing capabilities. It’s best suited for scenarios like adding a quick photo filter in a social widget or allowing simple image adjustments in a lightweight web app.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Future-proofing, support &amp;#x26; pricing:&lt;/strong&gt; The vendor’s roadmap is unclear, and the small team behind Imgpen means resources for updates or long-term support are limited. But their pricing is affordable, which makes it appealing for startups or teams on a budget.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Who it’s for:&lt;/strong&gt; Teams with lightweight editing needs, small budgets, or projects where image editing is a side feature rather than a core part of the product.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;how-it-compares-to-imgly-4&quot;&gt;&lt;strong&gt;How it compares to IMG.LY&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Imgpen is budget‑friendly and covers the basics of photo editing, which may be useful for lightweight apps or early-stage projects.&lt;/p&gt;
&lt;p&gt;However, if you’re looking for full‑scale deployments with advanced editing, automation, and enterprise‑grade support, IMGLY is the better option. For teams that want their product to evolve and scale, IMG.LY ensures they don’t hit limitations as their needs grow.&lt;/p&gt;
&lt;h2 id=&quot;7-cloudinary-sdk&quot;&gt;&lt;strong&gt;7. Cloudinary SDK&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The last on the list is Cloudinary, which is best known as a media management and optimization platform that also provides an SDK for image editing. It focuses on performance and delivery, helping companies manage and serve large volumes of media efficiently.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Features &amp;#x26; capabilities:&lt;/strong&gt; For editing photos, Cloudinary offers features like cropping, resizing, optimization, filters, effects, and format conversion.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Platforms &amp;#x26; customization:&lt;/strong&gt; Cloudinary supports web, iOS, and Android. It is built around APIs, which give developers strong control over how media is processed and delivered. However, it does not include a ready-made editor interface for end users.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implementation &amp;#x26; use cases:&lt;/strong&gt; Cloudinary is simple to integrate into media-heavy platforms that need to serve thousands of images quickly. It is often used by e-commerce sites, publishing platforms, and other services where fast delivery and optimized file sizes are essential.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Future-proofing, support &amp;#x26; pricing:&lt;/strong&gt; Cloudinary is a mature, established vendor with enterprise-grade support available globally. Pricing is usage-based, so your costs scale with the volume of media processed and delivered.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Who it’s for:&lt;/strong&gt; Companies that want to focus on managing, delivering, and optimizing large media libraries rather than offering in-app image editing features.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;how-it-compares-to-imgly-5&quot;&gt;&lt;strong&gt;How it compares to IMG.LY&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Cloudinary excels in infrastructure and is a strong choice for optimizing and delivering media at scale.&lt;/p&gt;
&lt;p&gt;However, it doesn’t provide an in‑app editing experience. IMG.LY combines those infrastructure capabilities with advanced editing and automation, giving teams both performance optimization and the creative tools their users expect. This makes IMG.LY a stronger option for teams building creative products that want to offer a complete creative workflow, not just media delivery.&lt;/p&gt;
&lt;h2 id=&quot;overview-table&quot;&gt;Overview Table&lt;/h2&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Each SDK that we’ve listed here is unique and offers different features. The right choice between these tools depends on your product goals and customer expectations. Here’s a quick rundown:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Banuba&lt;/strong&gt;: Best for AR and beauty use cases, particularly in social and fashion apps.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fotor:&lt;/strong&gt; Great for AI-powered quick edits where automation is the main priority.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pintura, Polotno, Imgpen:&lt;/strong&gt; Lightweight, developer-focused solutions that work for smaller projects or teams with specific, limited needs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cloudinary:&lt;/strong&gt; Strong for media optimization and delivery when speed and performance are top concerns.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;IMG.LY CreativeEditor SDK:&lt;/strong&gt; The only SDK that unites polished editing UX with automation, cross-platform support, and enterprise stability. Read on to know more.&lt;/p&gt;
&lt;h2 id=&quot;why-imgly-stands-out&quot;&gt;&lt;strong&gt;Why IMG.LY stands out?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Taken together, these comparisons show a clear pattern: most SDKs solve a narrow problem well, but few address the full range of editing, automation, and scalability requirements.&lt;/p&gt;
&lt;p&gt;IMG.LY CreativeEditor SDK is built to do exactly that. It allows businesses to offer advanced photo editing directly in their apps, while also supporting automation and backend workflows on a single engine. This dual focus means your team doesn’t need to stitch together multiple solutions to achieve both creative flexibility and operational efficiency.&lt;/p&gt;
&lt;p&gt;For product teams, this translates into faster time to market, less technical overhead, and the confidence that the editor will scale as user expectations grow.&lt;/p&gt;
&lt;p&gt;If your goal is to build long-term, scalable creative tools, IMG.LY CreativeEditor SDK offers the most complete package and ensures your product can evolve without hitting limits. To learn more about how CreativeEditor SDK can support your business, &lt;a href=&quot;https://img.ly/forms/contact-sales&quot;&gt;get in touch with our team at IMG.LY&lt;/a&gt;, and we’ll be happy to guide you!&lt;/p&gt;</content:encoded><dc:creator>Vatsala</dc:creator><media:content url="https://blog.img.ly/2025/09/best-photo-editor-sdk.jpg" medium="image"/><category>Photo Editor</category><category>Insights</category></item><item><title>IMG.LY Announces Open Source JavaScript Library for In-Browser Background Removal</title><link>https://img.ly/blog/announcing-imgly-background-removal/</link><guid isPermaLink="true">https://img.ly/blog/announcing-imgly-background-removal/</guid><description>Seamlessly remove backgrounds in-browser with ease. Empower your creativity and protect data privacy. Learn how!</description><pubDate>Wed, 28 Jun 2023 11:38:49 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;UPDATE October 2023&lt;/strong&gt;: We’ve recently introduced Node.js support for the &lt;a href=&quot;https://www.npmjs.com/package/@imgly/background-removal&quot;&gt;@imgly/background-removal&lt;/a&gt; npm package. This enhancement enables you to remove backgrounds from images not only in the user’s browser but also on your server. This opens up the potential for batch processing and allows you to bypass memory constraints, especially for larger images.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Just before the summer lull engulfs us all, we have something exciting to share! We are thrilled to announce the release of &lt;a href=&quot;https://www.npmjs.com/package/@imgly/background-removal&quot;&gt;@imgly/background-removal&lt;/a&gt;, an innovative npm package that empowers developers to seamlessly remove backgrounds from images directly in the browser.&lt;/p&gt;
&lt;p&gt;Gone are the days of relying on server-side processing or sacrificing data privacy. With IMG.LY’s Background Removal, you can now harness the power of in-browser background removal with ease. Let’s dive into the key features that make this library truly exceptional:&lt;/p&gt;
&lt;h3 id=&quot;in-browser-background-removal&quot;&gt;In-Browser Background Removal&lt;/h3&gt;
&lt;p&gt;Our one-of-a-kind solution performs the entire background removal process directly in the user’s browser, eliminating the need for additional server costs. By leveraging the computing power of the local device, users can enjoy a fast and efficient background removal process that streamlines their workflow.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/bg-removal-javascript-open-source.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;h3 id=&quot;data-protection&quot;&gt;Data Protection&lt;/h3&gt;
&lt;p&gt;Rest assured that your images and sensitive information remain secure within your own devices. As IMG.LY’s Background Removal runs entirely in the browser, there are no data transfers to external servers, ensuring robust data privacy and alleviating any concerns you may have.&lt;/p&gt;
&lt;p&gt;You can experience it in action on our &lt;a href=&quot;https://img.ly/showcases/cesdk/web/background-removal/web&quot;&gt;background removal showcase&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;seamless-integration-with-imglys-cesdk&quot;&gt;Seamless Integration with IMG.LY’s CE.SDK&lt;/h3&gt;
&lt;p&gt;IMG.LY’s Background Removal seamlessly integrates with IMG.LY’s CE.SDK, making it easier than ever to incorporate powerful in-browser image matting and background removal capabilities into your projects. Boost your creative endeavors with this intuitive integration.&lt;/p&gt;
&lt;p&gt;The Neural Network (ONNX model) and WebAssembly (WASM) files used by IMG.LY’s Background Removal are hosted on UNPKG, making them readily available for download to all users of the library. However, if you prefer to host the data on your own servers, our library also supports custom asset serving. The choice is yours!&lt;/p&gt;
&lt;p&gt;Background removal is often the first step in any creative workflow involving image composition. Whether you are developing e-commerce applications that need real-time background removal, enhancing user experience in image editing applications, or simplifying the creative process with web-based graphic design tools, IMG.LY’s Background Removal is your go-to solution.&lt;/p&gt;
&lt;h3 id=&quot;empower-yourself-with-imglys-background-removal&quot;&gt;Empower Yourself with IMG.LY’s Background Removal&lt;/h3&gt;
&lt;p&gt;Whether you are a professional developer or a hobbyist, this open source JavaScript library empowers you to deliver impressive applications and services with ease. Join the growing community of developers who are revolutionizing the way background removal is done.&lt;/p&gt;
&lt;p&gt;Get started with @imgly/background-removal today by visiting &lt;a href=&quot;https://www.npmjs.com/package/@imgly/background-removal&quot;&gt;our official npm package page&lt;/a&gt; and &lt;a href=&quot;https://github.com/imgly/background-removal-js/&quot;&gt;our GitHub repository&lt;/a&gt;. You’ll find comprehensive documentation, examples, and everything you need to unlock the full potential of in-browser background removal.&lt;/p&gt;
&lt;h3 id=&quot;update-nodejs-support&quot;&gt;Update: Node.js Support&lt;/h3&gt;
&lt;p&gt;We have just shipped &lt;a href=&quot;https://www.npmjs.com/package/@imgly/background-removal-node&quot;&gt;Node.js support&lt;/a&gt; for the &lt;a href=&quot;https://www.npmjs.com/package/@imgly/background-removal&quot;&gt;@imgly/background-removal&lt;/a&gt; npm package. In addition to the users’ browser, you can now remove backgrounds from images on your server, making it possible to perform batch processing or bypass memory constraints for larger images.&lt;/p&gt;
&lt;p&gt;Thank you for your support, and we can’t wait to see the incredible projects you’ll create with IMG.LY’s Background Removal. Stay tuned for more updates and enhancements as we continue to improve and expand this powerful library. Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Don’t forget to &lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i&quot;&gt;subscribe&lt;/a&gt; to our newsletter to stay in the loop with the latest news and updates.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Jan</dc:creator><media:content url="https://blog.img.ly/2023/06/bg-removal.jpg" medium="image"/><category>Photo Editing</category><category>App Development</category><category>Photo Editor</category><category>JavaScript</category><category>OpenSource</category><category>Background Removal</category><category>Company</category></item><item><title>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>PE.SDK and VE.SDK 10 for Android and 11 for iOS Release</title><link>https://img.ly/blog/photo-editor-video-editor-sdk-v_10-11-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/photo-editor-video-editor-sdk-v_10-11-release-notes/</guid><description>This major update brings Background Removal and more to PhotoEditor SDK and VideoEditor SDK.</description><pubDate>Wed, 04 May 2022 12:46:21 GMT</pubDate><content:encoded>&lt;p&gt;We are thrilled to announce the release of PhotoEditor SDK and VideoEditor SDK 10 for Android and 11 for iOS. This new major version is packed with features and improvements.&lt;/p&gt;
&lt;p&gt;This release is adding:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Custom Watermarks&lt;/li&gt;
&lt;li&gt;Background Removal for Photos&lt;/li&gt;
&lt;li&gt;Background Removal for Stickers&lt;/li&gt;
&lt;li&gt;Custom Sticker Libraries&lt;/li&gt;
&lt;li&gt;Giphy Integration&lt;/li&gt;
&lt;li&gt;And More Updates for Android and iOS&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;custom-watermarks&quot;&gt;Custom Watermarks&lt;/h2&gt;
&lt;p&gt;With our new support for custom watermarks, you can add your company logo or any other image to photo and video exports. You can place your watermark in either corner or the center of your photo and video. Additionally, you can specify the size of the watermark and determine its distance from the outline if you choose to place it near a corner. Your users will not be able to remove nor modify the watermark.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Set your Custom Watermark for all exports.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 277px) 277px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;277&quot; height=&quot;600&quot; src=&quot;https://img.ly/_astro/watermark-video-editor-custom-sdk_Z12Y3l4.webp&quot; srcset=&quot;/_astro/watermark-video-editor-custom-sdk_Z12Y3l4.webp 277w&quot;&gt;&lt;/p&gt;
&lt;p&gt;For more details on Custom Watermarks, take a look at our documentation for &lt;a href=&quot;https://img.ly/docs/pesdk/android/customization/watermark/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;Android&lt;/a&gt; or &lt;a href=&quot;https://img.ly/docs/pesdk/ios/customization/watermark/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;iOS&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;background-removal-for-photos&quot;&gt;Background Removal for Photos&lt;/h2&gt;
&lt;p&gt;You have unwaveringly requested this feature: we are excited to offer the automatic removal of backgrounds for static content! Background Removal is fully running &lt;strong&gt;on-device&lt;/strong&gt; and currently specializes in images containing a person only. PE.SDK enables this feature exclusively when it detects a person in the photo.&lt;/p&gt;
&lt;p&gt;The removed background will turn transparent if your selected output supports transparency, such as PNG. In other cases, such as JPG, your background removal will be tinted black.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Integrate Background Removal into your application.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 277px) 277px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;277&quot; height=&quot;600&quot; src=&quot;https://img.ly/_astro/background-removal-photo-editor-app-pe-sdk-1_2jocg8.webp&quot; srcset=&quot;/_astro/background-removal-photo-editor-app-pe-sdk-1_2jocg8.webp 277w&quot;&gt;&lt;/p&gt;
&lt;p&gt;This feature is available on Android and iOS 15.0 and higher only. Easily enable Background Removal for Photos with our &lt;a href=&quot;https://img.ly/docs/pesdk/android/features/background_removal/&quot;&gt;Android guide&lt;/a&gt; or &lt;a href=&quot;https://img.ly/docs/pesdk/ios/features/background_removal/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;iOS guide&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;background-removal-for-stickers&quot;&gt;Background Removal for Stickers&lt;/h2&gt;
&lt;p&gt;A more common use case for automatic background removal is with stickers, so we’ve also added this functionality. Select a sticker including a person and tap the &lt;em&gt;Remove BG&lt;/em&gt; button. Simple!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Let your users create beautiful visuals with Sticker Background Removal.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 277px) 277px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;277&quot; height=&quot;600&quot; src=&quot;https://img.ly/_astro/background-removal-photo-editor-app-pe-sdk-video_2nmAzB.webp&quot; srcset=&quot;/_astro/background-removal-photo-editor-app-pe-sdk-video_2nmAzB.webp 277w&quot;&gt;&lt;/p&gt;
&lt;p&gt;This feature is available on Android and iOS 15.0 and higher only. Easily enable Background Removal for Stickers with our &lt;a href=&quot;https://img.ly/docs/vesdk/android/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#background-removal&quot;&gt;Android documentation&lt;/a&gt; or &lt;a href=&quot;https://img.ly/docs/vesdk/ios/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#background-removal&quot;&gt;iOS documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;custom-sticker-libraries&quot;&gt;Custom Sticker Libraries&lt;/h2&gt;
&lt;p&gt;We wanted to make it easier for you to provide your users with more sticker tool content. So far, you were able to create multiple sticker categories with different stickers that could either be part of your app or stored on a server. Additionally, you could &lt;a href=&quot;https://img.ly/docs/pesdk/ios/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#personal-stickers&quot;&gt;enable our personal stickers feature on iOS&lt;/a&gt; or &lt;a href=&quot;https://img.ly/docs/pesdk/ios/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#personal-stickers&quot;&gt;Android&lt;/a&gt;), giving your users the option to select stickers from their camera roll.&lt;/p&gt;
&lt;p&gt;We have now added more ways to provide your users with stickers.&lt;/p&gt;
&lt;h3 id=&quot;android&quot;&gt;Android&lt;/h3&gt;
&lt;p&gt;You can now create sticker categories that do not present our sticker selection interface, but will instead load any arbitrary Fragment. That gives you complete control over the sticker selection screen, and you can use it to load and display any content. When the user selects any of your stickers, all you have to do is pass it back to the SDK with a callback. Get started with your &lt;a href=&quot;https://img.ly/docs/vesdk/android/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#adding-custom-stickers&quot;&gt;Custom Sticker Library with our Android documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;ios&quot;&gt;iOS&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;You can now create sticker categories that do not present our sticker selection interface, but will instead load any arbitrary view controller that conforms to the &lt;code&gt;StickerCollection&lt;/code&gt; protocol. That gives you complete control over the sticker selection screen, and you can use it to load and display any content. When the user selects any of your stickers, simply pass it back to the SDK using a delegate method.&lt;/li&gt;
&lt;li&gt;Additionally, we’ve created a new &lt;code&gt;StickerProviderCategory&lt;/code&gt; that you can pass any object conforming to the &lt;code&gt;StickerProvider&lt;/code&gt; protocol. This category provides most of the features required to interact with sticker content providers, such as search and pagination. You can use this category to very quickly integrate any sticker service.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Find more information on &lt;a href=&quot;https://img.ly/docs/vesdk/ios/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#custom-sticker-view-controller&quot;&gt;Custom Sticker Libraries in the iOS documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;giphy-integration&quot;&gt;GIPHY Integration&lt;/h2&gt;
&lt;p&gt;This online database and search engine for funny GIFs and beautiful animations is a staple in many social applications. Easily integrate GIPHY into your app:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 277px) 277px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;277&quot; height=&quot;600&quot; src=&quot;https://img.ly/_astro/integrate-giphy-video-editor-photo-sdk_ZNfYn8.webp&quot; srcset=&quot;/_astro/integrate-giphy-video-editor-photo-sdk_ZNfYn8.webp 277w&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;android-1&quot;&gt;Android&lt;/h3&gt;
&lt;p&gt;Using our new Custom Sticker Library, we’ve also created an integration for GIPHY on Android. All you have to do is head over to &lt;a href=&quot;https://developers.giphy.com&quot;&gt;GIPHY&lt;/a&gt;, create your API key, pass it to your &lt;code&gt;GiphySettings&lt;/code&gt; and create a &lt;code&gt;GiphyStickerCategoryItem&lt;/code&gt;. Your users will then immediately have access to all the content GIPHY has to offer.&lt;/p&gt;
&lt;p&gt;For more details, visit our &lt;a href=&quot;https://img.ly/docs/vesdk/android/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#adding-giphy&quot;&gt;documentation on adding GIPHY&lt;/a&gt; for Android.&lt;/p&gt;
&lt;h3 id=&quot;ios-1&quot;&gt;iOS&lt;/h3&gt;
&lt;p&gt;Using the new &lt;code&gt;StickerProviderCategory&lt;/code&gt;, we added GIPHY support on iOS. All you have to do is head over to &lt;a href=&quot;https://developers.giphy.com&quot;&gt;GIPHY&lt;/a&gt;, create your API key, and pass this to the GIPHY sticker category. Your users will then immediately have access to all the content GIPHY has to offer.&lt;/p&gt;
&lt;p&gt;For more details, visit our documentation &lt;a href=&quot;https://img.ly/docs/vesdk/ios/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#giphy&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;more-updates-for-android&quot;&gt;More Updates for Android&lt;/h2&gt;
&lt;p&gt;Additionally, we have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Increased the minimum API level for PhotoEditor SDK from 16 (Android 4) to 21 (Android 5), which ensures support for 98% of all phones in use.&lt;/li&gt;
&lt;li&gt;Added support for headless video exporting.&lt;/li&gt;
&lt;li&gt;Increased video playback stability.&lt;/li&gt;
&lt;li&gt;Fixed a number of issues with degraded audio quality in videos.&lt;/li&gt;
&lt;li&gt;And added the ability to choose a theme at runtime.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;more-updates-for-ios&quot;&gt;More Updates for iOS&lt;/h2&gt;
&lt;p&gt;Additionally, we have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Increased our deployment target from iOS 9 to iOS 13.&lt;/li&gt;
&lt;li&gt;Migrated all usage of OpenGL to Metal.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/vesdk/ios/introduction/migration/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;Added a better result API&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/vesdk/ios/introduction/getting_started/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes#swiftui&quot;&gt;Added support for SwiftUI&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Enhanced our video export to display a progress indicator and the option to cancel the export.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;thanks-for-reading-let-us-know-what-you-think-on-twitter-or-stay-in-the-loop-with-our-newsletter&quot;&gt;Thanks for reading! Let us know what you think on &lt;a href=&quot;https://twitter.com/imgly&quot;&gt;Twitter&lt;/a&gt;, or stay in the loop with our &lt;a href=&quot;https://photoeditorsdk.us13.list-manage.com/subscribe?u=dc9f652839dbb620d14d6d28d&amp;#x26;id=04a306e4b2&quot;&gt;Newsletter&lt;/a&gt;.&lt;/h3&gt;</content:encoded><dc:creator>Sascha</dc:creator><media:content url="https://blog.img.ly/2022/05/photo-editor-sdk-video-editor-sdk-background-removal.png" medium="image"/><category>Release Notes</category><category>Photo Editor</category><category>Video Editor</category><category>Android App Development</category><category>iOS App Development</category><category>App Development</category></item><item><title>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>How To Apply Image Filters in WebGL</title><link>https://img.ly/blog/how-to-add-image-filters-in-webgl/</link><guid isPermaLink="true">https://img.ly/blog/how-to-add-image-filters-in-webgl/</guid><description>Learn everything you need to get started with kernel-based image filters in WebGL.</description><pubDate>Fri, 08 Apr 2022 13:06:16 GMT</pubDate><content:encoded>&lt;p&gt;In this article, you will learn how to apply custom filters to an image in WebGL. You can achieve this goal without using any external library. That is because the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL&quot;&gt;HTML5 &lt;code&gt;canvas&lt;/code&gt;&lt;/a&gt; &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL&quot;&gt;element natively supports WebGL&lt;/a&gt; and does not require the use of plug-ins.&lt;/p&gt;
&lt;p&gt;As we have already covered in &lt;a href=&quot;https://img.ly/blog/tag/html5/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;previous articles&lt;/a&gt;, &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt; is a powerful tool that equips you with everything required to manipulate images. This is true regardless of the use of WebGL. So, you can &lt;a href=&quot;https://img.ly/blog/how-to-apply-filters-in-javascript/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;filter images also without using WebGL&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now, let’s see how to filter images in Vanilla JavaScript with WebGL in your browser. Follow this step-by-step tutorial and learn how to build the following &lt;a href=&quot;https://codesandbox.io/s/how-to-filter-an-image-in-webgl-forked-zkgccv&quot;&gt;demo&lt;/a&gt;:&lt;/p&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/how-to-filter-an-image-in-webgl-forked-zkgccv?fontsize=14&amp;#x26;hidenavigation=1&amp;#x26;theme=dark&quot; title=&quot;How To Filter an Image in WebGL (forked)&quot; allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot; sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;getting-started-with-webgl&quot;&gt;Getting Started with WebGL&lt;/h2&gt;
&lt;p&gt;If you are not familiar with &lt;a href=&quot;https://get.webgl.org/&quot;&gt;WebGL&lt;/a&gt;, you need to learn a few things before approaching it. To build an application in WebGL, start with the following three concepts.&lt;/p&gt;
&lt;h3 id=&quot;1-textures&quot;&gt;1. Textures&lt;/h3&gt;
&lt;p&gt;Keep in mind that to draw an image in WebGL you have to use a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Using_textures_in_WebGL&quot;&gt;texture&lt;/a&gt;. To use a texture, WebGL requires you to define the texture coordinates. These coordinates go from 0.0 to 1.0, regardless of the texture size.&lt;/p&gt;
&lt;h3 id=&quot;2-vertex-shader&quot;&gt;2. Vertex shader&lt;/h3&gt;
&lt;p&gt;The vertex shader is a function you have to write in &lt;a href=&quot;https://www.khronos.org/opengl/wiki/OpenGL_Shading_Language&quot;&gt;GLSL&lt;/a&gt; that is in charge of computing the vertex positions. Thanks to it, WebGL can &lt;a href=&quot;https://en.wikipedia.org/wiki/Rasterisation&quot;&gt;rasterize&lt;/a&gt; the draw primitives, which include points, lines, and triangles. When rasterizing these primitives, WebGL calls another user-defined function called fragment shader. In other words, WebGL interpolates the values provided in the vertex shader function while it draws each pixel using the fragment shader function execution.&lt;/p&gt;
&lt;h3 id=&quot;3-fragment-shader&quot;&gt;3. Fragment shader&lt;/h3&gt;
&lt;p&gt;The fragment shader is a function you have to write in GLSL whose goal is to generate a color for each pixel of the draw primitive currently being drawn. This function has little info per pixel, but you can provide it with everything required by using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Data#varyings&quot;&gt;&lt;code&gt;varyings&lt;/code&gt;&lt;/a&gt; variables. These allow you to pass values from the vertex shader function to the fragment shader function.&lt;/p&gt;
&lt;h2 id=&quot;filtering-images-with-kernels-in-webgl-with-canvas&quot;&gt;Filtering Images with Kernels in WebGL with &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;There are many ways to filter images, but the most common one involves the &lt;a href=&quot;https://en.wikipedia.org/wiki/Convolution&quot;&gt;convolution operation&lt;/a&gt;. This is because when used on images, convolution applies a filter by taking the weighted sum of a square of pixels and assigning the resulting value to the current pixel. This logic is applied to every pixel the image consists of. Therefore, you can now imagine why convolution is one of the most relevant concepts when it comes to image processing.&lt;/p&gt;
&lt;p&gt;The coefficients used to perform the weighted sum come from a matrix called &lt;a href=&quot;https://en.wikipedia.org/wiki/Kernel%5F(image_processing)&quot;&gt;&lt;em&gt;kernel&lt;/em&gt;&lt;/a&gt;. The kernel represents the filter you want to apply through the convolution operation. So, by changing the kernel, the resulting image will change accordingly. Some kernels are more useful than others and can be used for blurring, sharpening, performing edge detection, and other operations. You can find a list of the most popular &lt;a href=&quot;https://en.wikipedia.org/wiki/Kernel%5F(image_processing)#Details&quot;&gt;kernels on Wikipedia&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now, let’s see how to implement kernel image filtering in WebGL.&lt;/p&gt;
&lt;p&gt;Clone the &lt;a href=&quot;https://github.com/Tonel/how-to-filter-an-image-in-webgl-imgly&quot;&gt;GitHub repository that supports this article&lt;/a&gt; with the following command:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;git clone https://github.com/Tonel/how-to-filter-an-image-in-webgl-imgly&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Additionally, try the demo application by launching &lt;code&gt;how-to-filter-an-image-in-webgl-imgly/index.html&lt;/code&gt; in your browser.&lt;/p&gt;
&lt;p&gt;Otherwise, you can find the JavaScript function taking care of implementing the filter logic in WebGL below:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; filterImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;canvas&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;originalImage&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;kernel&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // assuming the kernel is a square matrix&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; kernelSize&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; Math.&lt;/span&gt;&lt;span&gt;sqrt&lt;/span&gt;&lt;span&gt;(kernel.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; gl&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; canvas.&lt;/span&gt;&lt;span&gt;getContext&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;webgl&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // clearing the canvas&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;clearColor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;clear&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;COLOR_BUFFER_BIT&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; vertexShaderSource&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; `&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  attribute vec2 position;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  varying vec2 v_coordinate;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  void main() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl_Position = vec4(position, 0, 1);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    v_coordinate = gl_Position.xy * 0.5 + 0.5;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; fragmentShaderSource&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; `&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  precision mediump float;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // the varible defined in the vertex shader above&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  varying vec2 v_coordinate;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  uniform vec2 imageSize;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  uniform sampler2D u_texture;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  void main() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    vec2 position = vec2(v_coordinate.x, 1.0 - v_coordinate.y);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    vec2 onePixel = vec2(1, 1) / imageSize;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    vec4 color = vec4(0);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    mat3 kernel = mat3(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      ${&lt;/span&gt;&lt;span&gt;kernel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;,&apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // implementing the convolution operation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    for(int i = 0; i &amp;#x3C; ${&lt;/span&gt;&lt;span&gt;kernelSize&lt;/span&gt;&lt;span&gt;}; i++) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      for(int j = 0; j &amp;#x3C; ${&lt;/span&gt;&lt;span&gt;kernelSize&lt;/span&gt;&lt;span&gt;}; j++) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // retrieving the sample position pixel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        vec2 samplePosition = position + vec2(i - 1 , j - 1) * onePixel;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // retrieving the sample color&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        vec4 sampleColor = texture2D(u_texture, samplePosition);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        sampleColor *= kernel&lt;/span&gt;&lt;span&gt;\[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;\]&lt;/span&gt;&lt;span&gt;[j];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        color += sampleColor;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    color.a = 1.0;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl_FragColor = color;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; vertexShader&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; compileShader&lt;/span&gt;&lt;span&gt;(gl, gl.&lt;/span&gt;&lt;span&gt;VERTEX_SHADER&lt;/span&gt;&lt;span&gt;, vertexShaderSource);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; fragmentShader&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; compileShader&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;FRAGMENT_SHADER&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    fragmentShaderSource&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // iniziailing the program&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; program&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; createProgram&lt;/span&gt;&lt;span&gt;(gl, vertexShader, fragmentShader);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; positionAttributeLocation&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; gl.&lt;/span&gt;&lt;span&gt;getAttribLocation&lt;/span&gt;&lt;span&gt;(program, &lt;/span&gt;&lt;span&gt;&apos;position&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; imageSizeLocation&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; gl.&lt;/span&gt;&lt;span&gt;getUniformLocation&lt;/span&gt;&lt;span&gt;(program, &lt;/span&gt;&lt;span&gt;&apos;imageSize&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // binding the position buffer to positionBuffer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; positionBuffer&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; gl.&lt;/span&gt;&lt;span&gt;createBuffer&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;bindBuffer&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;ARRAY_BUFFER&lt;/span&gt;&lt;span&gt;, positionBuffer);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // using the program defined above&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;useProgram&lt;/span&gt;&lt;span&gt;(program);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // enabling the texcoord attribute&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;enableVertexAttribArray&lt;/span&gt;&lt;span&gt;(positionAttributeLocation);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // setting up the size of the image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;uniform2f&lt;/span&gt;&lt;span&gt;(imageSizeLocation, canvas.width, canvas.height);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // telling positionAttributeLocation how to retrieve data out of positionBuffer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;vertexAttribPointer&lt;/span&gt;&lt;span&gt;(positionAttributeLocation, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;FLOAT&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // provide the texture coordinates&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;bufferData&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;ARRAY_BUFFER&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    new&lt;/span&gt;&lt;span&gt; Float32Array&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;]),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;STATIC_DRAW&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // loading the original image as a texture&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; texture&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; gl.&lt;/span&gt;&lt;span&gt;createTexture&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  texture.image &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; Image&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // setting the anonymous mode&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // Learn more about it here:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/crossOrigin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  texture.image.crossOrigin &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  texture.image.src &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; originalImage.src;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  texture.image.&lt;/span&gt;&lt;span&gt;onload&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;bindTexture&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;TEXTURE_2D&lt;/span&gt;&lt;span&gt;, texture);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // setting the parameters to be able to render any image,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // regardless of its size&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;texParameteri&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;TEXTURE_2D&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;TEXTURE_WRAP_S&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;CLAMP_TO_EDGE&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;texParameteri&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;TEXTURE_2D&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;TEXTURE_WRAP_T&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;CLAMP_TO_EDGE&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;texParameteri&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;TEXTURE_2D&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;TEXTURE_MAG_FILTER&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;NEAREST&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;texParameteri&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;TEXTURE_2D&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;TEXTURE_MIN_FILTER&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;NEAREST&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // loading the original image as a texture&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;texImage2D&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      gl.&lt;/span&gt;&lt;span&gt;TEXTURE_2D&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      gl.&lt;/span&gt;&lt;span&gt;RGBA&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      gl.&lt;/span&gt;&lt;span&gt;RGBA&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      gl.&lt;/span&gt;&lt;span&gt;UNSIGNED_BYTE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      texture.image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;drawArrays&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;TRIANGLES&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;6&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; compileShader&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;gl&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;shaderSource&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; shader&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; gl.&lt;/span&gt;&lt;span&gt;createShader&lt;/span&gt;&lt;span&gt;(type);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;shaderSource&lt;/span&gt;&lt;span&gt;(shader, shaderSource);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;compileShader&lt;/span&gt;&lt;span&gt;(shader);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; outcome&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; gl.&lt;/span&gt;&lt;span&gt;getShaderParameter&lt;/span&gt;&lt;span&gt;(shader, gl.&lt;/span&gt;&lt;span&gt;COMPILE_STATUS&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (outcome &lt;/span&gt;&lt;span&gt;===&lt;/span&gt;&lt;span&gt; false&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // logging the error message on failure&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;getShaderInfoLog&lt;/span&gt;&lt;span&gt;(shader));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;deleteShader&lt;/span&gt;&lt;span&gt;(shader);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; shader;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; createProgram&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;gl&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;vertexShader&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;fragmentShader&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; program&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; gl.&lt;/span&gt;&lt;span&gt;createProgram&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;attachShader&lt;/span&gt;&lt;span&gt;(program, vertexShader);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;attachShader&lt;/span&gt;&lt;span&gt;(program, fragmentShader);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;linkProgram&lt;/span&gt;&lt;span&gt;(program);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; outcome&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; gl.&lt;/span&gt;&lt;span&gt;getProgramParameter&lt;/span&gt;&lt;span&gt;(program, gl.&lt;/span&gt;&lt;span&gt;LINK_STATUS&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (outcome &lt;/span&gt;&lt;span&gt;===&lt;/span&gt;&lt;span&gt; false&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // logging the error message on failure&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;getProgramInfoLog&lt;/span&gt;&lt;span&gt;(program));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;deleteProgram&lt;/span&gt;&lt;span&gt;(program);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; program;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;filterImage()&lt;/code&gt; function is where the magic happens. It takes the following three parameters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;canvas&lt;/code&gt;: an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element&quot;&gt;&lt;code&gt;Element&lt;/code&gt;&lt;/a&gt; object representing an HTML &lt;code&gt;canvas&lt;/code&gt; element&lt;/li&gt;
&lt;li&gt;&lt;code&gt;originalImage&lt;/code&gt;: an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element&quot;&gt;&lt;code&gt;Element&lt;/code&gt;&lt;/a&gt; object representing an HTML &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img&quot;&gt;&lt;code&gt;img&lt;/code&gt;&lt;/a&gt; element&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kernel&lt;/code&gt;: an array containing the values of the kernel to use in the convolution operation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first part of the function takes care of extracting the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext&quot;&gt;&lt;code&gt;WebGLRenderingContext&lt;/code&gt;&lt;/a&gt; object representing a three-dimensional rendering context from the &lt;code&gt;canvas&lt;/code&gt;  element. Then, the vertex shader and fragment shader functions are defined as strings written in GLSL. Next, they are compiled and finally used to create a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebGLProgram&quot;&gt;WebGL program&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The last part of the function creates a texture starting from the original image passed as a parameter and passes it to the &lt;code&gt;WebGLRenderingContext&lt;/code&gt; to produce the final result. This represents the filtered image and is finally displayed by the browser in the &lt;code&gt;canvas&lt;/code&gt; element.&lt;/p&gt;
&lt;p&gt;The results produced by the &lt;code&gt;filterImage()&lt;/code&gt; function depend on the kernel chosen, as you can verify by playing with the live demo you can find at the beginning of the article.&lt;/p&gt;
&lt;p&gt;Et voilà! You just learned how to filter images in WebGL!&lt;/p&gt;
&lt;h2 id=&quot;final-considerations&quot;&gt;Final Considerations&lt;/h2&gt;
&lt;p&gt;As shown above, you can filter images with WebGL in Vanilla JavaScript with a hundred lines. At the same time, this cannot be considered an easy task to achieve. The reason is that getting into WebGL takes time and effort. Plus, you have to learn how to use GLSL to write the vertex shader and the fragment shader functions. So, things can get more complicated than expected.&lt;/p&gt;
&lt;p&gt;Plus, you learned how to perform non-complex filters, but several filtering techniques are complex and do not involve the convolution operation. That also means that implementing them can be challenging and result in inefficient algorithms.&lt;/p&gt;
&lt;p&gt;To avoid a headache, you should consider a complete and all-in-one solution like &lt;a href=&quot;https://img.ly/products/photo-sdk?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;PhotoEditor SDK&lt;/a&gt;. Commercial solutions make things easier and shield you from all difficulties, offering features that would be complex, time-consuming, and challenging to implement. That is particularly true when it comes to using WebGL, which is &lt;a href=&quot;https://img.ly/docs/pesdk/web/introduction/migration-guide/#canvas-renderer/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;PhotoEditor SDK’s main renderer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You will be able to harness WebGL’s power without writing a single line of GLSL or knowing about its existence. WebGL will be used behind the scene for you! Keep also in mind that you would not be alone, since developers at &lt;a href=&quot;https://img.ly/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;IMG.LY&lt;/a&gt; are happy to provide support.&lt;/p&gt;
&lt;h2 id=&quot;filtering-images-with-photoeditor-sdk&quot;&gt;Filtering Images With PhotoEditor SDK&lt;/h2&gt;
&lt;p&gt;Read the article from &lt;a href=&quot;https://img.ly/docs/pesdk/guides/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;the official documentation&lt;/a&gt; to learn &lt;a href=&quot;https://img.ly/docs/pesdk/web/guides/umd/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;how to get started&lt;/a&gt; with &lt;a href=&quot;https://img.ly/products/photo-sdk&quot;&gt;PhotoEditor SDK&lt;/a&gt; in HTML and Vanilla JavaScript. In detail, the &lt;a href=&quot;https://img.ly/docs/pesdk/web/features/filters/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;Filters&lt;/a&gt; feature gives you more than 60 high-quality filters to play with. Achieve the following result with a few clicks:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;PE.SDK ships with stunning preset filters for aesthetic photo creations.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 600px) 600px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;600&quot; height=&quot;321&quot; src=&quot;https://img.ly/_astro/add-image-filters-webGL-1_1apHk1.webp&quot; srcset=&quot;/_astro/add-image-filters-webGL-1_1apHk1.webp 600w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Check out this feature on the &lt;a href=&quot;https://img.ly/products/photo-sdk/demo&quot;&gt;PhotoEditor SDK demo page&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this article, we looked at how to filter an image in WebGL with the HTML &lt;code&gt;canvas&lt;/code&gt; element. Implementing a feature allowing users to filter images through a kernel-based approach in WebGL involves only a dozen of lines of code. However, understanding how WebGL works and coding in GLSL cannot be considered easy tasks.&lt;/p&gt;
&lt;p&gt;As a result, you might want to avoid dealing with WebGL entirely. In this case, consider a commercial and easy-to-adopt solution using WebGL behind the scene – such as &lt;a href=&quot;https://img.ly/products/photo-sdk?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;PhotoEditor SDK&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks for reading! We hope that you found this article helpful. Feel free to reach out to us on &lt;a href=&quot;https://twitter.com/imgly&quot;&gt;Twitter&lt;/a&gt; with any questions, comments, or suggestions.‌&lt;/p&gt;</content:encoded><dc:creator>Antonello</dc:creator><media:content url="https://blog.img.ly/2022/04/add-filter-image-webgl.png" medium="image"/><category>How-To</category><category>Photo Editing</category><category>Web Development</category><category>App Development</category><category>Photo Editor</category><category>Photo Filter</category><category>Tech</category><category>Tutorial</category></item><item><title>CE.SDK v1.4.0 Release</title><link>https://img.ly/blog/ce-sdk-v140-release/</link><guid isPermaLink="true">https://img.ly/blog/ce-sdk-v140-release/</guid><description>Enhance your user experience with an improved library system, easy UI translation and more.</description><pubDate>Tue, 22 Feb 2022 12:34:56 GMT</pubDate><content:encoded>&lt;p&gt;Six weeks have passed since our &lt;a href=&quot;https://img.ly/blog/ce-sdk-v1-3-0-release-notes/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;last release&lt;/a&gt;, where we shipped our new and improved default UI, Placeholders, and a preview for our new Dashboard.&lt;/p&gt;
&lt;p&gt;This time, we focused heavily on making content discovery and provisioning better for you and your customers, as well as automation and API-driven design. Our release includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Custom Asset Libraries &amp;#x26; Management&lt;/li&gt;
&lt;li&gt;Internationalization&lt;/li&gt;
&lt;li&gt;Headless Mode &amp;#x26; APIs&lt;/li&gt;
&lt;li&gt;Other&lt;/li&gt;
&lt;li&gt;Outlook on upcoming releases&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;asset-libraries--management&quot;&gt;Asset Libraries &amp;#x26; Management&lt;/h2&gt;
&lt;p&gt;With this release, we improve our library system and overall usability. CE.SDK 1.4.0 introduces a new toolbar to let your users quickly access their favorite images, shapes, stickers, or text assets.&lt;/p&gt;
&lt;p&gt;Even more importantly, we added a General Asset Source API that allows you to add any external library sources you like. This way, you can provide custom assets to your users, such as images, stickers, or anything else.&lt;br&gt;
Check out our &lt;a href=&quot;https://img.ly/docs/cesdk/js/import-media-4e3703/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;Documentation on Custom Asset Source Integration&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A new user toolbar to the left - for quick library access. Use the General Asset Source API for external libraries.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1408px) 1408px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1408&quot; height=&quot;792&quot; src=&quot;https://img.ly/_astro/ce-sdk-design-editor-v140_1cQ66o.webp&quot; srcset=&quot;/_astro/ce-sdk-design-editor-v140_15HV7q.webp 640w, /_astro/ce-sdk-design-editor-v140_Z1oTmQU.webp 750w, /_astro/ce-sdk-design-editor-v140_Z1g7GmS.webp 828w, /_astro/ce-sdk-design-editor-v140_Z1YrsWH.webp 1080w, /_astro/ce-sdk-design-editor-v140_ZPrsSq.webp 1280w, /_astro/ce-sdk-design-editor-v140_1cQ66o.webp 1408w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;internationalization-i18n&quot;&gt;Internationalization (i18n)&lt;/h2&gt;
&lt;p&gt;CE.SDK now supports the easy translation of the default UI into any language, including full i18n support. We ship with English and German locales, but have successfully tested it with other languages.&lt;br&gt;
Learn more about &lt;a href=&quot;https://img.ly/docs/cesdk/js/user-interface/localization-508e20/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;adding translations to CE.SDK in our Documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;headless-mode--apis&quot;&gt;Headless Mode &amp;#x26; APIs&lt;/h2&gt;
&lt;p&gt;We are finally extending CE.SDK with a full headless mode that is usable without a user interface in a browser. You can use it to load, modify, and export scene templates programmatically without the need for any user interaction. Use it to create previews of your scenes with custom user content without opening the editor, or export your designs in multiple resolutions on demand.&lt;/p&gt;
&lt;h3 id=&quot;included-apis&quot;&gt;Included APIs&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Scene API&lt;/em&gt;&lt;/strong&gt; lets you create, load, save, or export scenes to a rasterized image format.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Block API&lt;/strong&gt; lets you create, read, update and delete any item (so-called &lt;em&gt;blocks&lt;/em&gt;) in the scene; modifying properties like position, size, or content is guaranteed easy.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Layouts API&lt;/strong&gt; lets you use advanced layout capabilities: choose from modes like absolute positioning, relative positioning in percent relative to the parent, or even auto layout. An even auto-layout lets you auto-adapt the size of a block according to its parent size and siblings.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;other&quot;&gt;Other&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Snapping now works with multiple selected items.&lt;/li&gt;
&lt;li&gt;Slider input values now allow manual input to give you more control.&lt;/li&gt;
&lt;li&gt;Easy asset library access in the UI.&lt;/li&gt;
&lt;li&gt;Changing content in Preview Mode to preview your template settings does not alter your template anymore.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;upcoming&quot;&gt;Upcoming&lt;/h2&gt;
&lt;p&gt;We are currently working hard to improve the overall CE.SDK Editor experience for you and your customers. That includes adding features like strokes, gradients, grouping, but also improving the rendering performance to create more complex designs. Additionally, we are improving asset discovery within the editor.&lt;/p&gt;
&lt;p&gt;Excitingly, we are working hard to bring our &lt;a href=&quot;https://img.ly/products/video-sdk/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;VE.SDK video features&lt;/a&gt; to CE.SDK! In the near future, you can use videos and animated GIFs inside any template and export short videos from within CE.SDK for Web.&lt;/p&gt;
&lt;h3 id=&quot;thanks-for-reading-to-stay-in-the-loop-with-our-latest-articles-and-case-studies-subscribe-to-our-newsletter&quot;&gt;Thanks for reading! To stay in the loop with our latest articles and case studies, subscribe to our &lt;a href=&quot;https://photoeditorsdk.us13.list-manage.com/subscribe?u=dc9f652839dbb620d14d6d28d&amp;#x26;id=04a306e4b2&quot;&gt;Newsletter&lt;/a&gt;.&lt;/h3&gt;</content:encoded><dc:creator>Daniel</dc:creator><media:content url="https://blog.img.ly/2022/02/CE-SDK-design-editor-1-4-0-javascript.png" medium="image"/><category>Release Notes</category><category>Design Editor</category><category>Web Development</category><category>Photo Editor</category><category>App Development</category></item><item><title>How To Manipulate an Image With Jimp in React</title><link>https://img.ly/blog/how-to-manipulate-an-image-with-jimp-in-react/</link><guid isPermaLink="true">https://img.ly/blog/how-to-manipulate-an-image-with-jimp-in-react/</guid><description>Let&apos;s get started with Jimp in React. Easily alter images with a few lines of code.</description><pubDate>Wed, 26 Jan 2022 13:36:27 GMT</pubDate><content:encoded>&lt;p&gt;In this article, you will learn how to use &lt;a href=&quot;https://www.npmjs.com/package/jimp&quot;&gt;&lt;code&gt;jimp&lt;/code&gt;&lt;/a&gt; in &lt;a href=&quot;https://react.dev/&quot;&gt;React&lt;/a&gt; to perform the most common image processing operations. As you are about to learn, this popular JavaScript library allows you to effortlessly manipulate an image with a few lines of code.&lt;/p&gt;
&lt;h2 id=&quot;what-is-jimp&quot;&gt;What is Jimp?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jimp-dev/jimp&quot;&gt;Jimp&lt;/a&gt; stands for &lt;em&gt;JavaScript Image Manipulation Program&lt;/em&gt;, &lt;a href=&quot;https://github.com/jimp-dev/jimp&quot;&gt;&lt;/a&gt;and it is one of the most popular open-source image processing libraries, with more than one million weekly downloads. As stated on &lt;a href=&quot;https://github.com/jimp-dev/jimp&quot;&gt;the official GitHub page&lt;/a&gt;, Jimp is a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;Promise&lt;/a&gt;-based library that relies entirely on Vanilla JavaScript. This means that it has no native or external dependencies, as you can verify &lt;a href=&quot;https://www.npmjs.com/package/jimp&quot;&gt;here&lt;/a&gt;. This makes it more reliable and lightweight.&lt;/p&gt;
&lt;p&gt;Jimp comes with several functions that allows you to transform your images in endless ways. Particularly, it includes the &lt;a href=&quot;https://github.com/jimp-dev/jimp/tree/main/packages/plugin-resize&quot;&gt;&lt;code&gt;resize()&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/jimp-dev/jimp/tree/main/packages/plugin-blur&quot;&gt;&lt;code&gt;blur()&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/jimp-dev/jimp/tree/main/packages/plugin-crop&quot;&gt;&lt;code&gt;crop()&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/jimp-dev/jimp/tree/main/packages/plugin-rotate&quot;&gt;&lt;code&gt;rotate()&lt;/code&gt;&lt;/a&gt; functions and &lt;a href=&quot;https://github.com/jimp-dev/jimp#image-manipulation-methods-default-plugins&quot;&gt;many others&lt;/a&gt;. At the time of writing, these are image formats supported by Jimp:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jimp-dev/jimp/tree/main/packages/type-bmp&quot;&gt;bmp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jimp-dev/jimp/tree/main/packages/type-gif&quot;&gt;gif&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jimp-dev/jimp/tree/main/packages/type-jpeg&quot;&gt;jpeg&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jimp-dev/jimp/tree/main/packages/type-png&quot;&gt;png&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jimp-dev/jimp/tree/main/packages/type-tiff&quot;&gt;tiff&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s now see how to use the Jimp transformation functions.&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;This is the list of prerequisites you need to make the React applications using Jimp we are about to build works:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.npmjs.com/getting-started/&quot;&gt;Node.js and npm&lt;/a&gt; &lt;a href=&quot;https://docs.npmjs.com/getting-started/&quot;&gt;7+&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/react&quot;&gt;&lt;code&gt;react&lt;/code&gt;&lt;/a&gt; &gt;= 17&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/react-dom&quot;&gt;&lt;code&gt;react-dom&lt;/code&gt;&lt;/a&gt; &gt;= 17&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/jimp&quot;&gt;&lt;code&gt;jimp&lt;/code&gt;&lt;/a&gt; &gt;= 0.16&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can add &lt;code&gt;jimp&lt;/code&gt; to your project’s dependencies by launching the following command:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm install jimp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, you have everything required to start getting your hands dirty with Jimp in React.&lt;/p&gt;
&lt;h2 id=&quot;basic-image-processing-in-jimp&quot;&gt;Basic Image Processing in Jimp&lt;/h2&gt;
&lt;p&gt;All the Jimp usage examples presented below share the same logic. So, let’s address it immediately.&lt;/p&gt;
&lt;p&gt;Specifically, this is what a basic &lt;code&gt;JimpDemo&lt;/code&gt; component looks like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; Jimp &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;jimp&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { useEffect, useState } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;react&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; JimpDemo&lt;/span&gt;&lt;span&gt;({ &lt;/span&gt;&lt;span&gt;imageUrl&lt;/span&gt;&lt;span&gt; }) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;jimpImage&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setJimpImage&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; useState&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;undefined&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;image&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setImage&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; useState&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;undefined&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;transformedImage&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setTransformedImage&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; useState&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;undefined&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // loading an image every time imageUrl changes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  useEffect&lt;/span&gt;&lt;span&gt;(() &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; loadImage&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; async&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      // generating the Jimp data structure&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      // loading an image from an URL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      const&lt;/span&gt;&lt;span&gt; jimpImage&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; Jimp.&lt;/span&gt;&lt;span&gt;read&lt;/span&gt;&lt;span&gt;(imageUrl);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      setJimpImage&lt;/span&gt;&lt;span&gt;(jimpImage);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      // transforming jimpImage into its Base64 representation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      // and storing it&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      const&lt;/span&gt;&lt;span&gt; image&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; jimpImage.&lt;/span&gt;&lt;span&gt;getBase64Async&lt;/span&gt;&lt;span&gt;(Jimp.&lt;/span&gt;&lt;span&gt;MIME_JPEG&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      setImage&lt;/span&gt;&lt;span&gt;(image);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    loadImage&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }, [imageUrl]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // generating the transformed image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // as soon as the Jimp data structure is ready&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  useEffect&lt;/span&gt;&lt;span&gt;(() &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; (jimpImage) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      const&lt;/span&gt;&lt;span&gt; transformImage&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; async&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // performing the Jimp image processing operation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // on jimpImage...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // e.g. jimpImage.crop(100, 100)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // storing the transformed image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // in Base64 format&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        const&lt;/span&gt;&lt;span&gt; transformedImage&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; jimpImage.&lt;/span&gt;&lt;span&gt;getBase64Async&lt;/span&gt;&lt;span&gt;(Jimp.&lt;/span&gt;&lt;span&gt;MIME_JPEG&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        setTransformedImage&lt;/span&gt;&lt;span&gt;(transformedImage);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      transformImage&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }, [jimpImage, height, width]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; image &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; jimpImage &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;&lt;/span&gt;&lt;span&gt;h1&lt;/span&gt;&lt;span&gt;&gt;Original Image&amp;#x3C;/&lt;/span&gt;&lt;span&gt;h1&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;&lt;/span&gt;&lt;span&gt;img&lt;/span&gt;&lt;span&gt; className&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;originalImage&quot;&lt;/span&gt;&lt;span&gt; src&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{image} &lt;/span&gt;&lt;span&gt;alt&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;Original&quot;&lt;/span&gt;&lt;span&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;&lt;/span&gt;&lt;span&gt;h1&lt;/span&gt;&lt;span&gt;&gt;Transformed Image&amp;#x3C;/&lt;/span&gt;&lt;span&gt;h1&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;&lt;/span&gt;&lt;span&gt;img&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        className&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;transformedImage&quot;&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&gt;&lt;span&gt;{transformedImage}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        alt&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;Transformed&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ) &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&gt;Loading...&amp;#x3C;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First, the &lt;code&gt;imageUrl&lt;/code&gt; prop value storing the &lt;code&gt;URL&lt;/code&gt; to the image you want to transform is used to generate a Jimp data structure. This happens in the first &lt;a href=&quot;https://legacy.reactjs.org/docs/hooks-effect.html&quot;&gt;&lt;code&gt;useEffect()&lt;/code&gt;&lt;/a&gt; function when launching &lt;code&gt;Jimp.read()&lt;/code&gt;. This function takes the path to a file or a URL and returns a Promise with the Jimp data structure you call the manipulation functions on. Also, the &lt;a href=&quot;https://en.wikipedia.org/wiki/Base64&quot;&gt;Base64&lt;/a&gt; representation of the original image is stored to be able to show it in the HTML &lt;code&gt;&amp;#x3C;img&gt;&lt;/code&gt; tag.&lt;/p&gt;
&lt;p&gt;Keep in mind that the function passed to &lt;code&gt;useEffect()&lt;/code&gt; should not be &lt;code&gt;async&lt;/code&gt;. This is why an internal &lt;code&gt;async&lt;/code&gt; function was defined and then called instead.&lt;/p&gt;
&lt;p&gt;Then, the second &lt;code&gt;useEffect()&lt;/code&gt; function is called as soon as &lt;code&gt;jimpImage&lt;/code&gt; is initialized and takes care of performing the transformation function on the original image. Again, the &lt;a href=&quot;https://en.wikipedia.org/wiki/Base64&quot;&gt;Base64&lt;/a&gt; representation of the transformed image is saved.&lt;/p&gt;
&lt;p&gt;Finally, both the original and transformed images are rendered by the component. As you can imagine, what will change in the following examples will be the Jimp image transform function called, which might also require extra props.&lt;/p&gt;
&lt;h3 id=&quot;cropping-an-image&quot;&gt;Cropping an image&lt;/h3&gt;
&lt;p&gt;The Jimp &lt;a href=&quot;https://github.com/jimp-dev/jimp/tree/main/packages/plugin-crop&quot;&gt;&lt;code&gt;crop()&lt;/code&gt;&lt;/a&gt; function crops an image at a given point to a given size.&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;jimpImage.crop(x, y, width, height)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;x&lt;/code&gt;: the x coordinate to crop from&lt;/li&gt;
&lt;li&gt;&lt;code&gt;y&lt;/code&gt;: the y coordinate to crop from&lt;/li&gt;
&lt;li&gt;&lt;code&gt;width&lt;/code&gt;: the width of the crop region&lt;/li&gt;
&lt;li&gt;&lt;code&gt;height&lt;/code&gt;: the height of the crop region&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See it in action in the live example below:&lt;/p&gt;
&lt;h3 id=&quot;resizing-an-image&quot;&gt;Resizing an image&lt;/h3&gt;
&lt;p&gt;The Jimp &lt;a href=&quot;https://github.com/jimp-dev/jimp/tree/main/packages/plugin-resize&quot;&gt;&lt;code&gt;resize()&lt;/code&gt;&lt;/a&gt; function resizes an image to set width and height using a 2-pass bilinear algorithm.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;jimpImage.&lt;/span&gt;&lt;span&gt;resize&lt;/span&gt;&lt;span&gt;(width, height);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;width&lt;/code&gt;: the width to resize the image&lt;/li&gt;
&lt;li&gt;&lt;code&gt;height&lt;/code&gt;: the height to resize the image to&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See it in action in the live example below:&lt;/p&gt;
&lt;h3 id=&quot;rotating-an-image&quot;&gt;Rotating an image&lt;/h3&gt;
&lt;p&gt;The Jimp &lt;a href=&quot;https://github.com/jimp-dev/jimp/tree/main/packages/plugin-rotate&quot;&gt;&lt;code&gt;rotate()&lt;/code&gt;&lt;/a&gt; function rotates an image clockwise by a number of degrees. Note that the width and height of the image will be resized accordingly by default.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;jimpImage.&lt;/span&gt;&lt;span&gt;rotate&lt;/span&gt;&lt;span&gt;(degrees);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;degrees&lt;/code&gt;: the number of degrees to rotate the image by&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See it in action in the live example below:&lt;/p&gt;
&lt;h3 id=&quot;filtering-an-image&quot;&gt;Filtering an image&lt;/h3&gt;
&lt;p&gt;Although Jimp does not come with a single filtering function, it offers several functions to achieve the desired results. For example, you can implement an image filtering feature by harnessing the &lt;a href=&quot;https://github.com/jimp-dev/jimp/tree/main/packages/plugin-blur&quot;&gt;&lt;code&gt;blur()&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/jimp-dev/jimp/tree/main/packages/plugin-color&quot;&gt;&lt;code&gt;color()&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/jimp-dev/jimp/tree/main/packages/plugin-dither&quot;&gt;&lt;code&gt;dither()&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/jimp-dev/jimp/tree/main/packages/plugin-normalize&quot;&gt;&lt;code&gt;normalize()&lt;/code&gt;&lt;/a&gt;, or &lt;a href=&quot;https://github.com/jimp-dev/jimp/tree/main/packages/plugin-threshold&quot;&gt;&lt;code&gt;threshold()&lt;/code&gt;&lt;/a&gt; functions.&lt;/p&gt;
&lt;p&gt;Let’s see some of them in action in the live demo below:&lt;/p&gt;
&lt;h2 id=&quot;jimp-vs-photoeditor-sdk&quot;&gt;Jimp vs PhotoEditor SDK&lt;/h2&gt;
&lt;p&gt;Undoubtedly, Jimp is a powerful tool. It’s an amazingly lightweight and simple library that offers so many image manipulations. On the other hand, achieving complex results requiring multiple manipulations to be performed on the end user’s needs could become challenging. In detail, this would require an advanced, robust, reliable, and easy-to-use UI that only a commercial solution such as IMG.LY’s &lt;a href=&quot;https://img.ly/products/photo-sdk&quot;&gt;PhotoEditor SDK&lt;/a&gt; can offer.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;photo-editor-sdk-photoeditor-for-web&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 650px) 650px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;650&quot; height=&quot;349&quot; src=&quot;https://img.ly/_astro/photo-editor-sdk-photoeditor-for-web_6tIYg.webp&quot; srcset=&quot;/_astro/photo-editor-sdk-photoeditor-for-web_1sQShB.webp 640w, /_astro/photo-editor-sdk-photoeditor-for-web_6tIYg.webp 650w&quot;&gt;&lt;/p&gt;
&lt;p&gt;You could build such a UI yourself on top of Jimp, but this would take a lot of time and effort. This is especially true if you want to implement a general-purpose application, such as an image processing application. For limited and specific tasks without any user interaction, Jimp is the ideal solution.&lt;/p&gt;
&lt;p&gt;Also, now you can take a look at the &lt;a href=&quot;https://img.ly/products/creative-sdk&quot;&gt;CreativeEditor SDK&lt;/a&gt; which is a more advanced API solution and obvious alternative to Jimp!&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Today we learned about the &lt;code&gt;jimp&lt;/code&gt; JavaScript library, its dependencies, how it works, and how to use it in React real-world scenarios. Specifically, this npm library comes with several image manipulation functions that can be used with a few lines of code. However, building a complex image editing application on top of it would require an entire UI, and you might want to avoid spending time on it. In this case, you should look into a more advanced, fully-featured, and ready-to-use solution – such as &lt;a href=&quot;https://www.npmjs.com/package/photoeditorsdk&quot;&gt;&lt;code&gt;PhotoEditorSDK&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks for reading! We hope that you found this article helpful. Feel free to reach out to us on &lt;a href=&quot;https://twitter.com/imgly&quot;&gt;Twitter&lt;/a&gt; with any questions, comments, or suggestions.&lt;/p&gt;
&lt;h3 id=&quot;&quot;&gt;&lt;/h3&gt;
&lt;p&gt;To stay in the loop with our latest articles and case studies, subscribe to our &lt;a href=&quot;https://img.us13.list-manage.com/subscribe?u=dc9f652839dbb620d14d6d28d&amp;#x26;id=04a306e4b2&quot;&gt;Newsletter&lt;/a&gt;.&lt;/p&gt;</content:encoded><dc:creator>Antonello</dc:creator><media:content url="https://blog.img.ly/2022/01/jimp-npm-react-image-editing.png" medium="image"/><category>How-To</category><category>React</category><category>Photo Editor</category><category>Web Development</category><category>Image Editing</category><category>Tech</category><category>Tutorial</category></item><item><title>CE.SDK v1.3.0 Release</title><link>https://img.ly/blog/ce-sdk-v1-3-0-release-notes/</link><guid isPermaLink="true">https://img.ly/blog/ce-sdk-v1-3-0-release-notes/</guid><description>Including a fantastic dashboard to create and organize designs, we are happy to announce a major update for CE.SDK.</description><pubDate>Mon, 17 Jan 2022 15:07:02 GMT</pubDate><content:encoded>&lt;p&gt;After another six weeks of work, we are happy to ship another update of our &lt;a href=&quot;https://img.ly/creative-sdk?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;CreativeEditor SDK&lt;/a&gt; (CE.SDK). This release is again packed with great features to enhance the developer experience and user experience. It includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;New improved Default UI&lt;/li&gt;
&lt;li&gt;Lockable Design &amp;#x26; Placeholders&lt;/li&gt;
&lt;li&gt;SVG Assets&lt;/li&gt;
&lt;li&gt;Multi Selection&lt;/li&gt;
&lt;li&gt;Nudging (moving elements with arrow and shift key)&lt;/li&gt;
&lt;li&gt;Create scenes from an Image.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;new-improved-default-ui&quot;&gt;New Improved Default UI&lt;/h2&gt;
&lt;p&gt;That is the first release to introduce a new UI type for CE.SDK, which we call &lt;strong&gt;Default UI&lt;/strong&gt;. It comes with a slick interface and focuses on fast design adoption. The Default UI removes the need for inspectors for many editing cases, thus leaving your users undistracted and focused on adapting or creating designs.&lt;/p&gt;
&lt;p&gt;Check our official documentation to learn about &lt;a href=&quot;https://img.ly/docs/cesdk/js/user-interface/overview-41101a/&quot;&gt;configuring the UI Elements&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Minimal user interface for fast design adoption&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 2190px) 2190px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;2190&quot; height=&quot;1331&quot; src=&quot;https://img.ly/_astro/Screenshot-2022-01-05-at-19.03.52_Z1iDWLA.webp&quot; srcset=&quot;/_astro/Screenshot-2022-01-05-at-19.03.52_ZNEAUK.webp 640w, /_astro/Screenshot-2022-01-05-at-19.03.52_2pPIkY.webp 750w, /_astro/Screenshot-2022-01-05-at-19.03.52_Z2aWPwO.webp 828w, /_astro/Screenshot-2022-01-05-at-19.03.52_1hbrTA.webp 1080w, /_astro/Screenshot-2022-01-05-at-19.03.52_MnPWU.webp 1280w, /_astro/Screenshot-2022-01-05-at-19.03.52_Z1c39bY.webp 1668w, /_astro/Screenshot-2022-01-05-at-19.03.52_xEqee.webp 2048w, /_astro/Screenshot-2022-01-05-at-19.03.52_Z1iDWLA.webp 2190w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;lockable-design--placeholders&quot;&gt;Lockable Design &amp;#x26; Placeholders&lt;/h2&gt;
&lt;p&gt;In the previous version, CE.SDK introduced the roles “&lt;strong&gt;creator&lt;/strong&gt;” and “&lt;strong&gt;adopter&lt;/strong&gt;” – differentiating between template creation and adoption. In creator mode, you have the liberty to create a design from scratch or change existing designs.&lt;/p&gt;
&lt;p&gt;When creators are ready to share a design, they define which design elements can be changed when opening the editor in the “adopter” role. Typically, creators will allow adopters to exchange content, but also the options to style or arrange an item can be controlled.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Specify how elements can be altered by adopters.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1087px) 1087px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1087&quot; height=&quot;772&quot; src=&quot;https://img.ly/_astro/2_rtDwW.webp&quot; srcset=&quot;/_astro/2_27fgpW.webp 640w, /_astro/2_ZJnaXH.webp 750w, /_astro/2_pLfu7.webp 828w, /_astro/2_AzR1X.webp 1080w, /_astro/2_rtDwW.webp 1087w&quot;&gt;&lt;/p&gt;
&lt;p&gt;When the editor is opened in the “adopter” role (Default UI), items that are allowed to change will be highlighted and images will be shown with an overlay indicating that the content shall be replaced before exporting or saving the design.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 2187px) 2187px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;2187&quot; height=&quot;1336&quot; src=&quot;https://img.ly/_astro/3_Z2wSzmA.webp&quot; srcset=&quot;/_astro/3_Z1xfDxi.webp 640w, /_astro/3_fL1ec.webp 750w, /_astro/3_Z1UKVY3.webp 828w, /_astro/3_Z17Ikjc.webp 1080w, /_astro/3_Z1i96hT.webp 1280w, /_astro/3_IDAxi.webp 1668w, /_astro/3_a3BfK.webp 2048w, /_astro/3_Z2wSzmA.webp 2187w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Find more information about &lt;a href=&quot;https://img.ly/docs/cesdk/js/create-templates/add-dynamic-content/placeholders-d9ba8a/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;placeholders and constraints&lt;/a&gt; in our official documentation.&lt;/p&gt;
&lt;h2 id=&quot;dashboard&quot;&gt;Dashboard&lt;/h2&gt;
&lt;p&gt;Creating and adopting designs is one part, but organizing designs is another. With this release, we also introduced a dashboard to create and organize your designs for your users. Reach out to us if you want to see a demo of the dashboard in action and understand.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Create, adopt and organize designs in your dashboard.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 2000px) 2000px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;2000&quot; height=&quot;1049&quot; src=&quot;https://img.ly/_astro/dashboard_Z1hUiJy.webp&quot; srcset=&quot;/_astro/dashboard_1SHs7i.webp 640w, /_astro/dashboard_13nXG2.webp 750w, /_astro/dashboard_2cPKul.webp 828w, /_astro/dashboard_147xGm.webp 1080w, /_astro/dashboard_2lqHA4.webp 1280w, /_astro/dashboard_Z24kxQd.webp 1668w, /_astro/dashboard_Z1hUiJy.webp 2000w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;svg-assets&quot;&gt;SVG Assets&lt;/h2&gt;
&lt;p&gt;With this version, we introduced SVG as an asset-type alternative to JPEG and PNG image formats. This has the benefit that standard SVG Stickers can just be used or uploaded in every design. This has the major advantage that stickers will be crisp at any resolution while coming with a very low download size. Reducing the server load and data transfer for you and your users. In this turn, we also replaced all our example stickers with their SVG equivalents.&lt;/p&gt;
&lt;h2 id=&quot;multi-selection&quot;&gt;Multi Selection&lt;/h2&gt;
&lt;p&gt;Positioning multiple items at once has been a pain before this release, but not anymore. With the new multi-selection interaction, users can select two or more items at once. Just hold down the “shift” modifier key and start selecting multiple items. Once selected, they can be moved around simultaneously.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 2184px) 2184px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;2184&quot; height=&quot;1336&quot; src=&quot;https://img.ly/_astro/multi_1fxY3W.webp&quot; srcset=&quot;/_astro/multi_ZJcsql.webp 640w, /_astro/multi_Z1OosUB.webp 750w, /_astro/multi_1ur2dz.webp 828w, /_astro/multi_2ryYzY.webp 1080w, /_astro/multi_wMfG6.webp 1280w, /_astro/multi_eVcmt.webp 1668w, /_astro/multi_Z2hMquq.webp 2048w, /_astro/multi_1fxY3W.webp 2184w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;nudging&quot;&gt;Nudging&lt;/h2&gt;
&lt;p&gt;Always wanted to fine-tune your design and pixel-perfectly align your content?&lt;/p&gt;
&lt;p&gt;You can now use the &lt;em&gt;arrow keys&lt;/em&gt; (⬅️, ➡️, ⬆️ ⬇️) to nudge the selected items to their correct position pixel by pixel. You can also hold down &lt;em&gt;shift&lt;/em&gt; to nudge even further.&lt;/p&gt;
&lt;h2 id=&quot;create-scene-from-image&quot;&gt;Create Scene from Image&lt;/h2&gt;
&lt;p&gt;Before this release, the CE.SDK could either start from an empty or a predefined scene. From now on, there is also an option to start the editor with any image. It will auto-create a page with the size of the given image and insert the image into this one, allowing a more content-driven creation process. Learn &lt;a href=&quot;https://img.ly/docs/cesdk/js/open-the-editor/from-image-ad9b5e/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=releasenotes&quot;&gt;how to create a scene from an image&lt;/a&gt; in our documentation.&lt;/p&gt;
&lt;h2 id=&quot;minor-changes&quot;&gt;Minor changes&lt;/h2&gt;
&lt;p&gt;Besides the major features, there are a ton of small improvements. These include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UI interface to rename items and pages to a user-defined name&lt;/li&gt;
&lt;li&gt;Ability to choose between two UI types, “default” and “advanced”&lt;/li&gt;
&lt;li&gt;Searching in image libraries now uses i18n translations&lt;/li&gt;
&lt;li&gt;Ability to change the UI Font.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Feel free to send us &lt;a href=&quot;https://img.ly/company/contact-us&quot;&gt;any question&lt;/a&gt;s, or let us know what you think on &lt;a href=&quot;https://twitter.com/imgly&quot;&gt;Twitter&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;thank-you-for-your-time&quot;&gt;Thank you for your time!&lt;/h3&gt;
&lt;p&gt;To stay in the loop with our latest articles and case studies, subscribe to our &lt;a href=&quot;https://photoeditorsdk.us13.list-manage.com/subscribe?u=dc9f652839dbb620d14d6d28d&amp;#x26;id=04a306e4b2&quot;&gt;Newsletter&lt;/a&gt;.&lt;/p&gt;</content:encoded><dc:creator>Daniel</dc:creator><media:content url="https://blog.img.ly/2022/02/creative-SDK-photo-design-editor-web.png" medium="image"/><category>Release Notes</category><category>Web Development</category><category>Photo Editor</category><category>Image Editing</category></item><item><title>How To Resize an Image With JavaScript</title><link>https://img.ly/blog/how-to-resize-an-image-with-javascript/</link><guid isPermaLink="true">https://img.ly/blog/how-to-resize-an-image-with-javascript/</guid><description>Today, you will learn how to resize an image in JavaScript, without using any external library. Thanks to the HTML &lt;canvas&gt; element, this is reasonably easy. Let&apos;s go!</description><pubDate>Tue, 20 Jul 2021 09:22:31 GMT</pubDate><content:encoded>&lt;p&gt;In this article, you will learn how to resize an image in JavaScript, without using any external library. Thanks to the HTML &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API&quot;&gt;&lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt;&lt;/a&gt; element, this is a reasonably easy task to accomplish.&lt;/p&gt;
&lt;p&gt;Resizing an image has become increasingly important. That is because the quality of the images and their file sizes have been increasing for years.&lt;br&gt;
For example, when letting users upload an image, you should always consider resizing it before uploading it. Uploading large photos is time-consuming and may cost money in bandwidth.  As we have previously explained you might also want to &lt;a href=&quot;https://img.ly/blog/how-to-compress-an-image-before-uploading-it-in-javascript/&quot;&gt;compress such images&lt;/a&gt;.  As you can imagine, both of these consequences fall on end-users – we want to avoid this.&lt;/p&gt;
&lt;p&gt;Let’s see how to resize an image with Vanilla JavaScript. Follow this step-by-step tutorial to achieve the following result on &lt;a href=&quot;https://codesandbox.io/s/blog-how-to-resize-an-image-with-javascript-forked-mkuri&quot;&gt;CodeSandbox&lt;/a&gt;:&lt;/p&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/blog-how-to-resize-an-image-with-javascript-forked-mkuri&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;resizing-images-using-canvas&quot;&gt;Resizing Images Using &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;You can clone the &lt;a href=&quot;https://github.com/Tonel/resize-image-javascript-imgly&quot;&gt;GitHub repository that supports this article&lt;/a&gt; by launching the following command:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;git clone https://github.com/Tonel/resize-image-javascript-imgly&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Otherwise, you can continue following this tutorial and build the demo application step by step.&lt;/p&gt;
&lt;h3 id=&quot;1-implementing-the-resizing-logic&quot;&gt;1. Implementing the Resizing Logic&lt;/h3&gt;
&lt;p&gt;While in a &lt;a href=&quot;https://img.ly/blog/how-to-resize-an-image-in-react/&quot;&gt;React context we used a library&lt;/a&gt; to do the heavy lifting for us, knowing the HTML &lt;code&gt;[&amp;#x3C;canvas&gt;](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API)&lt;/code&gt; API is the only prerequisites for this approach. Although typically used for animation, game graphics, data visualization, and real-time video processing, you can also employ it as an image manipulation tool. Specifically, it provides everything required to resize an image. Let’s see how:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; resizeImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;imgToResize&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;resizingFactor&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 0.5&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvas&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;createElement&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;canvas&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; context&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; canvas.&lt;/span&gt;&lt;span&gt;getContext&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;2d&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; originalWidth&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; imgToResize.width;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; originalHeight&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; imgToResize.height;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvasWidth&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; originalWidth &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; resizingFactor;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvasHeight&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; originalHeight &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; resizingFactor;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  canvas.width &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; canvasWidth;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  canvas.height &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; canvasHeight;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  context.&lt;/span&gt;&lt;span&gt;drawImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    imgToResize,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    originalWidth &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; resizingFactor,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    originalHeight &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; resizingFactor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; canvas.&lt;/span&gt;&lt;span&gt;toDataURL&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Initialize an in-memory &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt; with a 2D rendering context for the drawing surface.&lt;/li&gt;
&lt;li&gt;Set height and width depending on the size of the original image to resize and the resizing factor.&lt;/li&gt;
&lt;li&gt;Then, the resized image is drawn according to the resizing factor passed by harnessing the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage&quot;&gt;&lt;code&gt;drawImage()&lt;/code&gt;&lt;/a&gt; function.&lt;/li&gt;
&lt;li&gt;Finally, the resized image is returned.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Et voilà! As you can see, resizing an image in Vanilla JavaScript takes only a few lines of code.&lt;/p&gt;
&lt;h3 id=&quot;2-resizing-in-action&quot;&gt;2. Resizing in Action&lt;/h3&gt;
&lt;p&gt;Now, it is time to see the &lt;code&gt;resizeImage()&lt;/code&gt; function in action through a simple example.&lt;br&gt;
&lt;em&gt;index.html&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;!&lt;/span&gt;&lt;span&gt;DOCTYPE&lt;/span&gt;&lt;span&gt; html&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;html&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &amp;#x3C;&lt;/span&gt;&lt;span&gt;body&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;h1&lt;/span&gt;&lt;span&gt;&gt;Image Resizer&amp;#x3C;/&lt;/span&gt;&lt;span&gt;h1&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      Please, upload an image and it will be shown both original and resized by&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      50%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;input&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;upload&quot;&lt;/span&gt;&lt;span&gt; type&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;file&quot;&lt;/span&gt;&lt;span&gt; accept&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;image/*&quot;&lt;/span&gt;&lt;span&gt; required&lt;/span&gt;&lt;span&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;images&quot;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;&lt;/span&gt;&lt;span&gt;h2&lt;/span&gt;&lt;span&gt;&gt;Original image&amp;#x3C;/&lt;/span&gt;&lt;span&gt;h2&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;&lt;/span&gt;&lt;span&gt;img&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;imgToResize&quot;&lt;/span&gt;&lt;span&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;&lt;/span&gt;&lt;span&gt;h2&lt;/span&gt;&lt;span&gt;&gt;Resized image&amp;#x3C;/&lt;/span&gt;&lt;span&gt;h2&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;&lt;/span&gt;&lt;span&gt;img&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;resizedImage&quot;&lt;/span&gt;&lt;span&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt; src&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;src/index.js&quot;&lt;/span&gt;&lt;span&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span&gt;body&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;html&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;src/index.js&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// hiding the div that will contain the images&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; imagesDiv&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;querySelector&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;#images&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;imagesDiv.style.visibility &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;hidden&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; fileInput&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;querySelector&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;#upload&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;fileInput.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;change&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;file&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; fileInput.files;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // displaying the uploaded image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; imageToResize&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;querySelector&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;#imgToResize&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  imageToResize.src &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; fileToDataUri&lt;/span&gt;&lt;span&gt;(file);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // resizing the image and displaying it&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; resizedImage&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;querySelector&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;#resizedImage&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  resizedImage.src &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; resizeImage&lt;/span&gt;&lt;span&gt;(imageToResize, &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // making the div containing the image visible&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  imagesDiv.style.visibility &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;visible&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; fileToDataUri&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;field&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; Promise&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;resolve&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; reader&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; FileReader&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    reader.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;load&apos;&lt;/span&gt;&lt;span&gt;, () &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      resolve&lt;/span&gt;&lt;span&gt;(reader.result);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    reader.&lt;/span&gt;&lt;span&gt;readAsDataURL&lt;/span&gt;&lt;span&gt;(field);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; resizeImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;imgToResize&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;resizingFactor&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 0.5&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvas&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;createElement&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;canvas&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; context&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; canvas.&lt;/span&gt;&lt;span&gt;getContext&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;2d&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; originalWidth&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; imgToResize.width;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; originalHeight&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; imgToResize.height;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvasWidth&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; originalWidth &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; resizingFactor;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvasHeight&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; originalHeight &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; resizingFactor;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  canvas.width &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; canvasWidth;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  canvas.height &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; canvasHeight;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  context.&lt;/span&gt;&lt;span&gt;drawImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    imgToResize,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    originalWidth &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; resizingFactor,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    originalHeight &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; resizingFactor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; canvas.&lt;/span&gt;&lt;span&gt;toDataURL&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;&amp;#x3C;input&gt;&lt;/code&gt; element allows users to upload an image, then passed to the &lt;code&gt;resizeImage()&lt;/code&gt; function. This is in charge of generating the resized image, which is finally shown below the original image. Please, note that this example is the same presented in the fiddle placed at the beginning of the article.&lt;/p&gt;
&lt;h2 id=&quot;final-considerations&quot;&gt;Final Considerations&lt;/h2&gt;
&lt;p&gt;Resizing an image in Vanilla JavaScript is definitely an easy task. No external libraries are required, and you can achieve your goal with just a few lines of code. This is great! On the other hand, &lt;a href=&quot;https://entropymine.com/resamplescope/notes/browsers/&quot;&gt;every browser&lt;/a&gt; applies a different image interpolation algorithm behind the scenes. This leads to results depending on the user’s preferred browser. Not only might this be a problem in terms of consistency, but also a source of quality issues. Plus, such a simple task can turn into a nightmare if you wanted to implement a proper UI, allowing users to resize an image graphically.&lt;/p&gt;
&lt;p&gt;In that case, a commercial and comprehensive solution like &lt;code&gt;[PhotoEditorSDK](https://img.ly/products/photo-sdk)&lt;/code&gt; is a more beneficial approach. In fact, you should no longer have to worry about inconsistencies or quality issues. Moreover, with only one library, you get several tools to treat images without having to implement the application’s UI. Also, whenever you need help, you can ask for support from the &lt;a href=&quot;https://img.ly/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;IMG.LY&lt;/a&gt; developers who built the SDK.&lt;/p&gt;
&lt;h2 id=&quot;resizing-an-image-with-photoeditor-sdk&quot;&gt;Resizing an Image with PhotoEditor SDK&lt;/h2&gt;
&lt;p&gt;First, you should read &lt;a href=&quot;https://img.ly/docs/pesdk/web/guides/umd/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;this&lt;/a&gt; article from &lt;a href=&quot;https://img.ly/docs/pesdk/guides/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;the official documentation&lt;/a&gt; on how to get started with &lt;code&gt;PhotoEditorSDK&lt;/code&gt; in HTML and JavaScript. Then, by using the &lt;a href=&quot;https://img.ly/docs/pesdk/web/features/transform/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;transform tool&lt;/a&gt; you can perform cropping, &lt;a href=&quot;https://img.ly/docs/pesdk/web/features/transform/#image-resizing?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;resizing&lt;/a&gt;, flipping, and rotation operations with just one feature. This way, you should be able to achieve the desired result:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Transform Images with PhotoEditor SDK&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;476&quot; src=&quot;https://img.ly/_astro/resize-image-with-javascript_1gJOFK.webp&quot; srcset=&quot;/_astro/resize-image-with-javascript_Z20b4Fi.webp 640w, /_astro/resize-image-with-javascript_Z1Ep5cX.webp 750w, /_astro/resize-image-with-javascript_1gJOFK.webp 800w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this article, we looked at how to resize an image with JavaScript. Resizing an image by using &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt; is not a complex task, although this solution might introduce quality issues. As we have seen, you can resize an image effortlessly and with only a handful of lines of code. On the other hand, every browser applies a different resizing algorithm, leading to inconsistent results. For consistent and reliable results, you should take advantage of a more advanced and complete solution – such as &lt;code&gt;PhotoEditorSDK&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Thanks for reading! We hope that you found this article helpful. Feel free to reach out to us on &lt;a href=&quot;https://twitter.com/imgly&quot;&gt;Twitter&lt;/a&gt; with any questions, comments, or suggestions.&lt;/p&gt;</content:encoded><dc:creator>Antonello</dc:creator><media:content url="https://blog.img.ly/2021/07/resize-image-with-javascript-pesdk.png" medium="image"/><category>JavaScript</category><category>Photo Editing</category><category>Photo Editor</category><category>Web Development</category><category>Software Development</category><category>App Development</category><category>Developer Tools</category><category>Code</category><category>Tech</category><category>How-To</category><category>Tutorial</category></item><item><title>How To Crop an Image in React</title><link>https://img.ly/blog/how-to-crop-an-image-in-react-with-react-image-crop/</link><guid isPermaLink="true">https://img.ly/blog/how-to-crop-an-image-in-react-with-react-image-crop/</guid><description>In this article, you will learn to crop an image in JavaScript. Specifically, you will see how to achieve this goal with the react-image-crop React library. </description><pubDate>Mon, 28 Jun 2021 17:03:00 GMT</pubDate><content:encoded>&lt;p&gt;In this article, you will learn to crop an image in JavaScript. Specifically, you will see how to achieve this goal with the &lt;code&gt;react-image-crop&lt;/code&gt; React library.&lt;/p&gt;
&lt;p&gt;Over the last few years, providing users with features to deal with images has become more and more common. This is why every developer should know how to deal with basic operations on images, such as cropping. This gives them the possibility to choose only the areas they are interested in.&lt;/p&gt;
&lt;p&gt;So, let’s see how to crop an image in React with &lt;code&gt;react-image-crop&lt;/code&gt;. Follow this step-by-step tutorial to achieve the following result:&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot;&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;This is the list of all the prerequisites for the demo application you are going to build:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.npmjs.com/getting-started/&quot;&gt;Node.js and npm&lt;/a&gt; &lt;a href=&quot;https://docs.npmjs.com/getting-started/&quot;&gt;5.2+ and higher&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/react-image-crop&quot;&gt;&lt;code&gt;react-image-crop&lt;/code&gt;&lt;/a&gt; &gt;= 8.6.12&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;cropping-an-image-with-react-image-crop&quot;&gt;Cropping an Image with &lt;code&gt;react-image-crop&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;You can clone the &lt;a href=&quot;https://github.com/imgly/Blog-How-To-Crop-an-Image-in-React-with-React-Crop-Image&quot;&gt;GitHub repository that supports this article&lt;/a&gt; and try the demo application by launching the following commands:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;git&lt;/span&gt;&lt;span&gt; clone&lt;/span&gt;&lt;span&gt; https://github.com/imgly/Blog-How-To-Crop-an-Image-in-React-with-React-Crop-Image.git&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; Blog-How-To-Crop-an-Image-in-React-with-React-Crop-Image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Otherwise, you can continue following this tutorial and build the demo application step by step.&lt;/p&gt;
&lt;h3 id=&quot;1-creating-a-react-project&quot;&gt;1. Creating a React Project&lt;/h3&gt;
&lt;p&gt;The easiest way to create an empty working project in React is by using &lt;a href=&quot;https://create-react-app.dev/docs/getting-started/&quot;&gt;Create React App&lt;/a&gt;, the officially supported way to create single-page React applications. You can create a new project called &lt;code&gt;react-image-cropper-demo&lt;/code&gt; with the following command:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npx&lt;/span&gt;&lt;span&gt; create-react-app&lt;/span&gt;&lt;span&gt; react-image-cropper-demo&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will now have a demo project located in the &lt;code&gt;react-image-cropper-demo&lt;/code&gt; folder with this file structure:&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;react-image-cropper-demo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── README.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── node_modules&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── package.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── .gitignore&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── public&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── favicon.ico&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── index.html&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── logo192.png&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── logo512.png&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── manifest.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   └── robots.txt&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;    ├── App.css&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── App.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── App.test.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── index.css&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── index.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── logo.svg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── reportWebVitals.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    └── setupTests.js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Move into the &lt;code&gt;react-image-cropper-demo&lt;/code&gt; folder and launch a local server by running:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; react-image-cropper-demo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Visit &lt;a href=&quot;http://localhost:3000/&quot;&gt;http://localhost:3000/&lt;/a&gt; in your browser, and you should be able to see the default Create React App screen.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The default Create React App screen&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 983px) 983px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;983&quot; height=&quot;728&quot; src=&quot;https://img.ly/_astro/s_D2E103F8349A30F6AA8E27CD2BA4B6EDB946A8DEF5B8272009321B4F51D679F9_1624366125534_image_ZvCahg.webp&quot; srcset=&quot;/_astro/s_D2E103F8349A30F6AA8E27CD2BA4B6EDB946A8DEF5B8272009321B4F51D679F9_1624366125534_image_1hpMyh.webp 640w, /_astro/s_D2E103F8349A30F6AA8E27CD2BA4B6EDB946A8DEF5B8272009321B4F51D679F9_1624366125534_image_Zy6hVM.webp 750w, /_astro/s_D2E103F8349A30F6AA8E27CD2BA4B6EDB946A8DEF5B8272009321B4F51D679F9_1624366125534_image_Z184VNu.webp 828w, /_astro/s_D2E103F8349A30F6AA8E27CD2BA4B6EDB946A8DEF5B8272009321B4F51D679F9_1624366125534_image_ZvCahg.webp 983w&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;2-installing-react-image-crop&quot;&gt;2. Installing &lt;code&gt;react-image-crop&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Add the &lt;code&gt;react-image-crop&lt;/code&gt; library to your project’s dependencies by running the following command:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;span&gt; --save&lt;/span&gt;&lt;span&gt; react-image-crop&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your &lt;code&gt;package.json&lt;/code&gt; file will be updated accordingly, and you should now be able to see &lt;code&gt;react-image-crop&lt;/code&gt; as a dependency.&lt;br&gt;
Now, you have everything required to start developing your image cropper component.&lt;/p&gt;
&lt;h3 id=&quot;3-building-the-image-cropper-component&quot;&gt;3. Building the Image Cropper Component&lt;/h3&gt;
&lt;p&gt;First of all, create a &lt;code&gt;components&lt;/code&gt; folder inside &lt;code&gt;src&lt;/code&gt;. Then, make an &lt;code&gt;ImageCropper&lt;/code&gt; folder containing &lt;code&gt;index.js&lt;/code&gt; and &lt;code&gt;index.css&lt;/code&gt;. These two files will contain the cropper component definition and style respectively.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The components folder&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 427px) 427px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;427&quot; height=&quot;120&quot; src=&quot;https://img.ly/_astro/s_D2E103F8349A30F6AA8E27CD2BA4B6EDB946A8DEF5B8272009321B4F51D679F9_1624375236509_image_ZUxoH2.webp&quot; srcset=&quot;/_astro/s_D2E103F8349A30F6AA8E27CD2BA4B6EDB946A8DEF5B8272009321B4F51D679F9_1624375236509_image_ZUxoH2.webp 427w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Initialize &lt;code&gt;index.js&lt;/code&gt; with the following lines of code:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; React &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;react&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; ImageCropper&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; &amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;{&lt;/span&gt;&lt;span&gt;/*TODO*/&lt;/span&gt;&lt;span&gt;}&amp;#x3C;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; default&lt;/span&gt;&lt;span&gt; ImageCropper;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way, you have just created an empty &lt;code&gt;ImageCropper&lt;/code&gt; component.&lt;br&gt;
Now, you need to import &lt;code&gt;ReactCrop&lt;/code&gt;, which is part of the &lt;code&gt;react-image-crop&lt;/code&gt; library. Add it to the &lt;code&gt;ImageCropper&lt;/code&gt; imports:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; ReactCrop &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;react-image-crop&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Plus, do not forget to import &lt;code&gt;dist/ReactCrop.css&lt;/code&gt; or &lt;code&gt;ReactCrop.scss&lt;/code&gt; as follows:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &apos;react-image-crop/dist/ReactCrop.css&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// or scss:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &apos;react-image-crop/lib/ReactCrop.scss&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is what the final &lt;code&gt;ImageCropper&lt;/code&gt; will look like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; React, { useState } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;react&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; ReactCrop &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;react-image-crop&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &apos;react-image-crop/dist/ReactCrop.css&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; demoImage &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;./demo-image.jpg&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; ImageCropper&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;props&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;imageToCrop&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;onImageCropped&lt;/span&gt;&lt;span&gt; } &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; props;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;cropConfig&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setCropConfig&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; useState&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // default crop config&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      unit: &lt;/span&gt;&lt;span&gt;&apos;%&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      width: &lt;/span&gt;&lt;span&gt;30&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      aspect: &lt;/span&gt;&lt;span&gt;16&lt;/span&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt; 9&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;imageRef&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setImageRef&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; useState&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  async&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; cropImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;crop&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; (imageRef &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; crop.width &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; crop.height) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      const&lt;/span&gt;&lt;span&gt; croppedImage&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; getCroppedImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        imageRef,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        crop,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &apos;croppedImage.jpeg&apos;&lt;/span&gt;&lt;span&gt; // destination filename&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      // calling the props function to expose&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      // croppedImage to the parent component&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      onImageCropped&lt;/span&gt;&lt;span&gt;(croppedImage);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  function&lt;/span&gt;&lt;span&gt; getCroppedImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;sourceImage&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;cropConfig&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;fileName&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // creating the cropped image from the source image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; canvas&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;createElement&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;canvas&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; scaleX&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sourceImage.naturalWidth &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; sourceImage.width;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; scaleY&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sourceImage.naturalHeight &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; sourceImage.height;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    canvas.width &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; cropConfig.width;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    canvas.height &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; cropConfig.height;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; ctx&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; canvas.&lt;/span&gt;&lt;span&gt;getContext&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;2d&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ctx.&lt;/span&gt;&lt;span&gt;drawImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      sourceImage,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      cropConfig.x &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; scaleX,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      cropConfig.y &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; scaleY,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      cropConfig.width &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; scaleX,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      cropConfig.height &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; scaleY,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      cropConfig.width,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      cropConfig.height&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; Promise&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;resolve&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;reject&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      canvas.&lt;/span&gt;&lt;span&gt;toBlob&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;blob&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // returning an error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;blob) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          reject&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; Error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;Canvas is empty&apos;&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        blob.name &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; fileName;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // creating a Object URL representing the Blob object given&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        const&lt;/span&gt;&lt;span&gt; croppedImageUrl&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; window.&lt;/span&gt;&lt;span&gt;URL&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;createObjectURL&lt;/span&gt;&lt;span&gt;(blob);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        resolve&lt;/span&gt;&lt;span&gt;(croppedImageUrl);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      }, &lt;/span&gt;&lt;span&gt;&apos;image/jpeg&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;ReactCrop&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&gt;&lt;span&gt;{imageToCrop &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; demoImage}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      crop&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{cropConfig}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      ruleOfThirds&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      onImageLoaded&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{(&lt;/span&gt;&lt;span&gt;imageRef&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; setImageRef&lt;/span&gt;&lt;span&gt;(imageRef)}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      onComplete&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{(&lt;/span&gt;&lt;span&gt;cropConfig&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; cropImage&lt;/span&gt;&lt;span&gt;(cropConfig)}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      onChange&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{(&lt;/span&gt;&lt;span&gt;cropConfig&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; setCropConfig&lt;/span&gt;&lt;span&gt;(cropConfig)}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      crossorigin&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;anonymous&quot;&lt;/span&gt;&lt;span&gt; // to avoid CORS-related problems&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ImageCropper.defaultProps &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  onImageCropped&lt;/span&gt;&lt;span&gt;: () &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; default&lt;/span&gt;&lt;span&gt; ImageCropper;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;imageToCrop&lt;/code&gt; is the source image received from the props. The or statement used when assigning the &lt;code&gt;ReactCrop&lt;/code&gt;’s &lt;code&gt;src&lt;/code&gt; props assures that either &lt;code&gt;imageToCrop&lt;/code&gt; or a default demo image is shown. After being loaded, a reference to the image is saved and then used when performing the cropping operation. Then, whenever a user uses the component to try to crop an image, the &lt;code&gt;cropConfig&lt;/code&gt; object containing the crop settings is updated accordingly. Finally, when the user stops selecting the area to crop, &lt;code&gt;cropImage&lt;/code&gt; is called. This function is in charge of producing the cropped image and passing it to the &lt;code&gt;onImageCropped&lt;/code&gt; function received from the props.&lt;/p&gt;
&lt;h3 id=&quot;4-putting-it-all-together&quot;&gt;4. Putting It All Together&lt;/h3&gt;
&lt;p&gt;Now it is time to see the &lt;code&gt;ImageCropper&lt;/code&gt; component in action. All you need to do, is change the &lt;code&gt;App.js&lt;/code&gt; file as follows:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; React, { useState } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;react&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &apos;./App.css&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; ImageCropper &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;./components/ImageCropper&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; App&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;imageToCrop&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setImageToCrop&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; useState&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;undefined&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;croppedImage&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setCroppedImage&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; useState&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;undefined&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; onUploadFile&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; (event.target.files &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; event.target.files.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span&gt; &gt;&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      const&lt;/span&gt;&lt;span&gt; reader&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; FileReader&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      reader.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;load&apos;&lt;/span&gt;&lt;span&gt;, () &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; setImageToCrop&lt;/span&gt;&lt;span&gt;(reader.result));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      reader.&lt;/span&gt;&lt;span&gt;readAsDataURL&lt;/span&gt;&lt;span&gt;(event.target.files[&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; className&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;app&quot;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;&lt;/span&gt;&lt;span&gt;input&lt;/span&gt;&lt;span&gt; type&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;file&quot;&lt;/span&gt;&lt;span&gt; accept&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;image/*&quot;&lt;/span&gt;&lt;span&gt; onChange&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{onUploadFile} /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;&lt;/span&gt;&lt;span&gt;ImageCropper&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          imageToCrop&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{imageToCrop}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          onImageCropped&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{(&lt;/span&gt;&lt;span&gt;croppedImage&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; setCroppedImage&lt;/span&gt;&lt;span&gt;(croppedImage)}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      {croppedImage &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          &amp;#x3C;&lt;/span&gt;&lt;span&gt;h2&lt;/span&gt;&lt;span&gt;&gt;Cropped Image&amp;#x3C;/&lt;/span&gt;&lt;span&gt;h2&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          &amp;#x3C;&lt;/span&gt;&lt;span&gt;img&lt;/span&gt;&lt;span&gt; alt&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;Cropped Image&quot;&lt;/span&gt;&lt;span&gt; src&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{croppedImage} /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      )}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; default&lt;/span&gt;&lt;span&gt; App;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;input&lt;/code&gt; element allows users to upload an image, then stored it in &lt;code&gt;imageToCrop&lt;/code&gt; and passed to &lt;code&gt;ImageCropper&lt;/code&gt;. Each time a user crops it, the resulting image is saved thanks to the &lt;code&gt;setCroppedImage&lt;/code&gt; function. Then, it is finally displayed in the &lt;em&gt;Cropped Image&lt;/em&gt; section as presented in the fiddle at the beginning of the article.&lt;/p&gt;
&lt;h2 id=&quot;final-considerations-on-react-image-crop&quot;&gt;Final Considerations on &lt;code&gt;react-image-crop&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Cropping an image from scratch is not an easy task. This is why using a library like &lt;code&gt;react-image-crop&lt;/code&gt; is the recommended approach. As you have just seen, you can achieve your goal with just a few lines of code. This is great! On the other hand, these libraries are designed to achieve specific goals, like cropping an image. What if you need to perform or get users the possibility to do other image-related operations? You may be ending up with as many libraries as operations required.&lt;/p&gt;
&lt;p&gt;Not only might they have very different UIs, but it may also be complicated to integrate them all in the same project. This is why in such a circumstance, a commercial and wider solution like &lt;a href=&quot;https://img.ly/products/photo-sdk&quot;&gt;PhotoEditorSDK&lt;/a&gt; should be the preferred approach. In fact, with only one library you get several tools to treat images as you want, while preserving the consistency of your application’s UI. Also, whenever you need help, you can ask for support from the &lt;a href=&quot;https://img.ly/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;img.ly&lt;/a&gt; developers who built the SDK or visit one of the myriad snappy integration guides written by the developers on the blog.&lt;/p&gt;
&lt;h2 id=&quot;cropping-an-image-with-photoeditorsdk&quot;&gt;Cropping an Image with PhotoEditorSDK&lt;/h2&gt;
&lt;p&gt;First, you should read &lt;a href=&quot;https://img.ly/docs/pesdk/web/introduction/getting_started/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;this&lt;/a&gt; article from &lt;a href=&quot;https://img.ly/docs/pesdk/guides/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;the official documentation&lt;/a&gt; on how to get started with &lt;code&gt;PhotoEditorSDK&lt;/code&gt; in React. Then, by using the &lt;a href=&quot;https://img.ly/docs/pesdk/web/features/transform/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;transform tool&lt;/a&gt; you can perform cropping, resizing, flipping, and rotation operations with just one feature. This way, you should be able to achieve the desired result:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;crop-image-react&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1280px) 1280px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1280&quot; height=&quot;766&quot; src=&quot;https://img.ly/_astro/crop-image-react_Z1STIug.webp&quot; srcset=&quot;/_astro/crop-image-react_LfQKm.webp 640w, /_astro/crop-image-react_ZJ9E9a.webp 750w, /_astro/crop-image-react_2g7lwF.webp 828w, /_astro/crop-image-react_2nRxFL.webp 1080w, /_astro/crop-image-react_Z1STIug.webp 1280w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this article, we looked at how to crop an image in React. Cropping an image can turn into a complex task and this is using a library should be the preferred approach. In particular, &lt;code&gt;react-image-crop&lt;/code&gt; allows you to crop an image easily and with only a handful of lines of code, as we have seen. On the other hand, it is a library with a very specific purpose. So, if you needed to perform more than one operation on your images, you might need a more advanced and complete solution like &lt;code&gt;PhotoEditorSDK&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Thanks for reading! We hope that you found this article helpful. Feel free to reach out to us on &lt;a href=&quot;https://twitter.com/imgly&quot;&gt;Twitter&lt;/a&gt; with any questions, comments, or suggestions.&lt;/p&gt;</content:encoded><dc:creator>Antonello</dc:creator><media:content url="https://blog.img.ly/2021/06/crop-image-react-open-source.jpg" medium="image"/><category>React</category><category>crop</category><category>image</category><category>JavaScript</category><category>OpenSource</category><category>Photo Editor</category><category>App Development</category><category>How-To</category><category>Tutorial</category></item><item><title>Flutter: Our new plugins made for Dart developers</title><link>https://img.ly/blog/flutter-native-plugins-made-for-dart-developers/</link><guid isPermaLink="true">https://img.ly/blog/flutter-native-plugins-made-for-dart-developers/</guid><description>We are happy to announce our new official Flutter plugins wrapping our native PhotoEditor SDK and VideoEditor SDK for one of the most popular cross-platform frameworks.</description><pubDate>Thu, 11 Mar 2021 14:12:09 GMT</pubDate><content:encoded>&lt;p&gt;Flutter enables developers to build native iOS and Android applications with a single Dart codebase whilst the application’s performance is kept at a very high native-like level. This is even more ensured by the huge amount of Flutter plugins, which wrap native code for the use in Dart.&lt;/p&gt;
&lt;p&gt;With the rising demand for photo and video editing solutions, we were committed to provide plugins that enable developers to use our &lt;a href=&quot;https://img.ly/docs/pesdk/&quot;&gt;native PhotoEditor SDK&lt;/a&gt; and our &lt;a href=&quot;https://img.ly/docs/vesdk/&quot;&gt;native VideoEditor SDK&lt;/a&gt; within their Flutter applications. This said we are proud to announce that the Flutter plugins &lt;a href=&quot;https://pub.dev/packages/photo_editor_sdk&quot;&gt;&lt;code&gt;photo_editor_sdk&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://pub.dev/packages/video_editor_sdk&quot;&gt;&lt;code&gt;video_editor_sdk&lt;/code&gt;&lt;/a&gt; are now extending our list of cross-platform modules. The combination of both products allows you to add comprehensive image and video editing tools to your Flutter application for iOS and Android - within minutes.&lt;/p&gt;
&lt;h2 id=&quot;usage&quot;&gt;Usage&lt;/h2&gt;
&lt;p&gt;While building the plugins, we focused on making the use and integration of our existing SDKs as easy as possible and minimizing the required platform-specific knowledge and skillset. Therefore, using the plugins is as easy as writing a single line of Dart code:&lt;/p&gt;

&lt;h3 id=&quot;customization&quot;&gt;Customization&lt;/h3&gt;
&lt;p&gt;Furthermore, we wanted to keep the high level of customization options like cropping or resizing that our customers are used to in our products. In this sense, we created a dedicated &lt;a href=&quot;https://pub.dev/documentation/imgly_sdk/latest/imgly_sdk/Configuration-class.html&quot;&gt;&lt;code&gt;Configuration&lt;/code&gt;&lt;/a&gt; Dart class which serves the option to customize the SDK to your needs without ever leaving the Flutter world.&lt;br&gt;
Using the configuration is fast and easy:&lt;/p&gt;

&lt;h2 id=&quot;where-to-go-from-here&quot;&gt;Where to go from here?&lt;/h2&gt;
&lt;p&gt;Feel free to explore our packages, usage examples as well as the API documentation on &lt;a href=&quot;https://pub.dev/publishers/img.ly/packages&quot;&gt;pub.dev&lt;/a&gt; and/ or &lt;a href=&quot;https://github.com/imgly?q=flutter&quot;&gt;GitHub&lt;/a&gt;.&lt;br&gt;
We released our new Flutter plugins under open-source licenses, so feedback and pull requests are welcome.&lt;/p&gt;</content:encoded><dc:creator>Leon</dc:creator><media:content url="https://blog.img.ly/2021/03/flutter-plugin-for-photo-video-editor-dart.jpg" medium="image"/><category>Flutter</category><category>Photo Editor</category><category>Developer</category><category>Video Editor</category><category>Android</category><category>iOS</category><category>Stickers</category><category>Tech</category><category>How-To</category><category>Company</category></item><item><title>Cordova: A plugin made for JavaScript developers</title><link>https://img.ly/blog/cordova-plugin/</link><guid isPermaLink="true">https://img.ly/blog/cordova-plugin/</guid><description>Integrating third-party libraries requires either native platform experience or a time-consuming learning curve. To set you on a smoother path, we are introducing a new Cordova plugin that integrates our native iOS and Android SDK for you!</description><pubDate>Wed, 09 Sep 2020 10:59:07 GMT</pubDate><content:encoded>&lt;p&gt;In a perfect world, Cordova should enable web developers to target multiple platforms with one codebase. Yet in reality, developers using Cordova to build cross-platform apps, need to be experienced with the development tool stacks and programming languages of the native platforms. This is particularly the case when integrating native third-party libraries from scratch, as we detailed in a &lt;a href=&quot;https://img.ly/blog/photoeditor-sdk-cordova-dabe146e6c13/?utm_campaign=wrapper%20support&amp;#x26;utm_medium=blog&amp;#x26;utm_source=ghost&amp;#x26;utm_content=cordova%20plugin&quot;&gt;previous blog post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We are proud to introduce our all-new &lt;strong&gt;Cordova plugin&lt;/strong&gt; integrations &lt;code&gt;[cordova-plugin-photoeditorsdk](https://www.npmjs.com/package/cordova-plugin-photoeditorsdk)&lt;/code&gt; and &lt;code&gt;[cordova-plugin-videoeditorsdk](https://www.npmjs.com/package/cordova-plugin-videoeditorsdk)&lt;/code&gt; for our native &lt;a href=&quot;https://img.ly/products/photo-sdk&quot;&gt;PhotoEditor SDK&lt;/a&gt; and &lt;a href=&quot;https://img.ly/products/video-sdk&quot;&gt;VideoEditor SDK&lt;/a&gt; versions. The interplay of both products allows you to add comprehensive image and video editing tools to your Cordova app for iOS and Android - within minutes.&lt;/p&gt;
&lt;p&gt;While crafting our new plugins, the primary objective was to minimize the required platform-specific knowledge and skillset. We are thrilled to provide a wealth of &lt;a href=&quot;https://github.com/imgly/pesdk-cordova/blob/master/types/configuration.ts&quot;&gt;configuration and customization options&lt;/a&gt; to developers without forcing them to leave their JavaScript tooling and programming environment.&lt;/p&gt;
&lt;h2 id=&quot;bye-bye-native-platform-specific-asset-management&quot;&gt;Bye-bye native platform-specific asset management&lt;/h2&gt;
&lt;p&gt;Our new utility function &lt;code&gt;loadResource()&lt;/code&gt; simplifies the process to pass static assets to the native SDKs. By using it, e.g., in your &lt;code&gt;index.js&lt;/code&gt; file, our plugins will take care of resolving the correct platform-specific asset file paths.&lt;/p&gt;
&lt;p&gt;The following snippet demonstrates this convenience for customizing the sticker tool (lines &lt;code&gt;15&lt;/code&gt; to &lt;code&gt;30&lt;/code&gt;) and for passing an input image to the editor (line &lt;code&gt;33&lt;/code&gt;). The only requirement is to make the corresponding images available in your app’s &lt;code&gt;www/assets&lt;/code&gt; folder.&lt;/p&gt;

&lt;h2 id=&quot;further-examples&quot;&gt;Further examples&lt;/h2&gt;
&lt;p&gt;We created a separate repository each for our &lt;a href=&quot;https://github.com/imgly/pesdk-cordova-demo&quot;&gt;photo editor example project&lt;/a&gt; and &lt;a href=&quot;https://github.com/imgly/vesdk-cordova-demo&quot;&gt;video editor example project&lt;/a&gt; to prevent our sample assets from unnecessarily increasing the size of your &lt;code&gt;node_modules&lt;/code&gt; folder when installing our plugins.&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 for your Ionic application as well. Just take a look at our repositories for our &lt;a href=&quot;https://github.com/imgly/pesdk-ionic-demo&quot;&gt;photo editor example project&lt;/a&gt; and &lt;a href=&quot;https://github.com/imgly/vesdk-ionic-demo&quot;&gt;video editor example project&lt;/a&gt;, to get started with integrating our SDKs with your Ionic app.&lt;/p&gt;
&lt;h3 id=&quot;thank-you-for-your-time-to-stay-in-the-loop-with-our-latest-articles-and-case-studies-subscribe-to-our-newsletter&quot;&gt;Thank you for your time! To stay in the loop with our latest articles and case studies, subscribe to our &lt;a href=&quot;https://photoeditorsdk.us13.list-manage.com/subscribe?u=dc9f652839dbb620d14d6d28d&amp;#x26;id=04a306e4b2&quot;&gt;Newsletter&lt;/a&gt;.&lt;/h3&gt;</content:encoded><dc:creator>Hasan</dc:creator><media:content url="https://blog.img.ly/2020/08/photoeditor_videoeditor_cordova_plugin.jpg" medium="image"/><category>Cordova</category><category>App Development</category><category>Photo Editor</category><category>Video Editor</category><category>Company</category></item><item><title>Announcing PhotoEditor SDK HTML5–v 5.0</title><link>https://img.ly/blog/announcing-photoeditor-sdk-html5-v-5-0-a4d5ee8c13a9/</link><guid isPermaLink="true">https://img.ly/blog/announcing-photoeditor-sdk-html5-v-5-0-a4d5ee8c13a9/</guid><description>We have some great updates to share. After a year of hard work and countless iterations, it is our utmost pleasure to announce that PhotoEditor SDK remake for HTML5 is here. ?</description><pubDate>Thu, 16 Apr 2020 12:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;meet-photoeditor-sdk-50&quot;&gt;Meet PhotoEditor SDK 5.0&lt;/h2&gt;
&lt;p&gt;Last year we decided to meticulously rebuild the PhotoEditor SDK HTML5 from stem to stem. There’s a saying that great software is constantly evolving for the better. PhotoEditor SDK 5 does just that, it is now *&lt;strong&gt;*smaller**&lt;/strong&gt;, *&lt;strong&gt;*faster and easily**&lt;/strong&gt; *&lt;strong&gt;*maintainable.**&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;rethinking-ui-design-for-a-better-user-experience&quot;&gt;Rethinking UI Design for a Better User Experience&lt;/h2&gt;
&lt;p&gt;The User Interface (UI) of the PhotoEditor SDK is visually and conceptually revised taking specific usability and platform guidelines into account. This has resulted in an even more consistent and intuitive UI than before.&lt;/p&gt;
&lt;p&gt;In the course of refactoring, we have standardized the UI structure and arrangement of the individual tools. The UI controls are now displayed according to their context to create a minimalist, clear, and appealing overall image. Find more information on the design improvements &lt;a href=&quot;https://img.ly/docs/pesdk/web/concepts/design/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1400px) 1400px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1400&quot; height=&quot;686&quot; src=&quot;https://img.ly/_astro/1-tXsDcNT2izdNRL3vMwrQlA-1_Zd7wG5.webp&quot; srcset=&quot;/_astro/1-tXsDcNT2izdNRL3vMwrQlA-1_1vKsJ1.webp 640w, /_astro/1-tXsDcNT2izdNRL3vMwrQlA-1_1id5Y0.webp 750w, /_astro/1-tXsDcNT2izdNRL3vMwrQlA-1_ZfLIAS.webp 828w, /_astro/1-tXsDcNT2izdNRL3vMwrQlA-1_wCUOR.webp 1080w, /_astro/1-tXsDcNT2izdNRL3vMwrQlA-1_1eGlaa.webp 1280w, /_astro/1-tXsDcNT2izdNRL3vMwrQlA-1_Zd7wG5.webp 1400w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;lets-talk-metrics&quot;&gt;Let’s talk metrics&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The average TTI (&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/interactive/&quot;&gt;Time to interactive&lt;/a&gt;) changed from 96.8s to 5.5s&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 749px) 749px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;749&quot; height=&quot;290&quot; src=&quot;https://img.ly/_astro/image-25_1524Pn.webp&quot; srcset=&quot;/_astro/image-25_1f3V6d.webp 640w, /_astro/image-25_1524Pn.webp 749w&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;That makes it “fast enough” on mobile networks&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 862px) 862px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;862&quot; height=&quot;452&quot; src=&quot;https://img.ly/_astro/image-26_ZqpQzx.webp&quot; srcset=&quot;/_astro/image-26_ZOeVve.webp 640w, /_astro/image-26_119YVz.webp 750w, /_astro/image-26_Zt718Y.webp 828w, /_astro/image-26_ZqpQzx.webp 862w&quot;&gt;&lt;/p&gt;
&lt;p&gt;These massive speed gains were mainly enabled by our major rewrite and re-architecting of the codebase. Since it has been untouched for years, we have now reconstructed it completely focusing on performance and scalability.&lt;/p&gt;
&lt;h2 id=&quot;configurations-and-customizations&quot;&gt;Configurations and Customizations&lt;/h2&gt;
&lt;p&gt;UI is now supercharged with even more customization options.&lt;/p&gt;
&lt;h3 id=&quot;layouts&quot;&gt;Layouts&lt;/h3&gt;
&lt;p&gt;We will be supporting two UIs as before, but we are now moving away from the terminology Desktop UI and React UI. Instead, they are now called Advanced UI and Basic UI, sharing one and the same code base.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1400px) 1400px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://img.ly/_astro/image-27_ZfrPVp.webp&quot; srcset=&quot;/_astro/image-27_Z1RLbBt.webp 640w, /_astro/image-27_j99ST.webp 750w, /_astro/image-27_Z1EpbNV.webp 828w, /_astro/image-27_Z1L8sat.webp 1080w, /_astro/image-27_25XOf9.webp 1280w, /_astro/image-27_ZfrPVp.webp 1400w&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;themes&quot;&gt;Themes&lt;/h3&gt;
&lt;p&gt;Light theme was one of the most sought out features for the PhotoEditor SDK HTML5. The UI can now be integrated even better into existing systems, thus transitioning seamlessly from the PhotoEditor UI to the rest of the UI. End users are offered an improved holistic experience. With the major version, &lt;strong&gt;dark&lt;/strong&gt; and &lt;strong&gt;light&lt;/strong&gt; themes are supported by default. Moreover, themes can be customized on three levels colors, typography, and shape. More on that &lt;a href=&quot;https://img.ly/docs/pesdk/web/customization/theme/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1400px) 1400px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1400&quot; height=&quot;933&quot; src=&quot;https://img.ly/_astro/image-28_2mHOkl.webp&quot; srcset=&quot;/_astro/image-28_Z1WBokP.webp 640w, /_astro/image-28_eiWax.webp 750w, /_astro/image-28_Z1Jfoxi.webp 828w, /_astro/image-28_Q2d6h.webp 1080w, /_astro/image-28_Zm2Di2.webp 1280w, /_astro/image-28_2mHOkl.webp 1400w&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;component-customization&quot;&gt;Component Customization&lt;/h3&gt;
&lt;p&gt;This has to be the most exciting feature for the major release. You could simply provide a React Component in the configuration and it will be rendered instead of PhotoEditor SDK HTML5 built-in Component. This can help you transform the UI to match the design style of your application. More on that &lt;a href=&quot;https://img.ly/docs/pesdk/web/customization/component/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1239px) 1239px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1239&quot; height=&quot;835&quot; src=&quot;https://img.ly/_astro/image-29_ZleDnP.webp&quot; srcset=&quot;/_astro/image-29_1jbv2v.webp 640w, /_astro/image-29_1PqMCv.webp 750w, /_astro/image-29_csDJJ.webp 828w, /_astro/image-29_K2C4p.webp 1080w, /_astro/image-29_ZleDnP.webp 1239w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;and-more&quot;&gt;And More&lt;/h2&gt;
&lt;p&gt;This is just the tip of the iceberg. This release includes numerous user experience and performance improvements. Moreover, PhotoEditor SDK supports differential serving i.e., we *&lt;strong&gt;*serve**&lt;/strong&gt; different bundles to different browsers, and provides typings.&lt;/p&gt;
&lt;h2 id=&quot;deprecations-and-breaking-changes&quot;&gt;Deprecations and Breaking Changes&lt;/h2&gt;
&lt;p&gt;If you’ve read the post up until to this point, you should be able to notice that there will be breaking changes. Although we have tried to minimize the number of breaking changes and make it backward compatible as much as possible, we believe that some breaking changes in the configuration will be required.&lt;/p&gt;
&lt;p&gt;Hitherto we supported two rendering engines for PhotoEditor SDK UI i.e., WebGL and Canvas. Considering browser support we will here-forth be supporting only WebGL.&lt;/p&gt;
&lt;p&gt;You can find out more about the release, try out some demos, check our &lt;a href=&quot;https://docs.photoeditorsdk.com/guides/html5/v5/introduction/migration-guide&quot;&gt;migration guide&lt;/a&gt;, or simply get started &lt;a href=&quot;https://img.ly/docs/pesdk/web/introduction/getting_started/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We’re looking forward to exploring the new capabilities the PhotoEditor SDK V5 starts to unravel, and we’re excited to continue pushing the boundaries of what’s possible in UI libraries and sharing it with you.&lt;/p&gt;
&lt;p&gt;Ask us anything &lt;a href=&quot;https://imglysdk.atlassian.net/servicedesk/customer/portal/1&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;PS: Yes, most of the images used in the blog post are edited using the PhotoEditor SDK, #That’sSoMeta&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>Priyanka</dc:creator><media:content url="https://blog.img.ly/2020/04/1-vCljWkE1XFiYGo-KPKLEoA-2.jpeg" medium="image"/><category>Release Notes</category><category>Photo Editor</category><category>React</category><category>Components</category><category>SDK</category><category>Tech</category><category>How-To</category><category>Company</category></item><item><title>How to recreate Snapchat’s UI within a single day with the PhotoEditor SDK for Android</title><link>https://img.ly/blog/how-to-recreate-snapchats-ui-within-a-single-day-with-the-photoeditor-sdk-for-android-e985b348c52c/</link><guid isPermaLink="true">https://img.ly/blog/how-to-recreate-snapchats-ui-within-a-single-day-with-the-photoeditor-sdk-for-android-e985b348c52c/</guid><pubDate>Sun, 18 Feb 2018 23:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Is it possible to completely rejig the UI of the &lt;a href=&quot;https://img.ly/photo-sdk&quot;&gt;PhotoEditor SDK&lt;/a&gt; within a day? Principally, everything is possible, however, for me as a prospective Java developer this whole undertaking seemed rather tough at first. The task at hand was to rebuild the SDK’s UI to match popular apps like Snapchat or Instagram Stories in only a few steps. A few weeks ago, we already did something similar with the iOS SDK, however, as there are some differences between the platforms the whole process had to be repeated for Android.&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: 900px) 900px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;900&quot; height=&quot;600&quot; src=&quot;https://img.ly/_astro/image-13_Z155gLz.webp&quot; srcset=&quot;/_astro/image-13_SB6P9.webp 640w, /_astro/image-13_Z1YEFsp.webp 750w, /_astro/image-13_16X6CG.webp 828w, /_astro/image-13_Z155gLz.webp 900w&quot;&gt;&lt;/p&gt;
&lt;p&gt;As my colleague Malte Baumann already pointed out in his &lt;a href=&quot;https://img.ly/blog/how-to-build-instagrams-story-editor-in-a-day-23be9adff9b/&quot;&gt;blog post&lt;/a&gt;, the main idea behind this endeavor is to explore the possibilities and limitations of the SDK’s customizable UI. But above that, it is also a great way of making oneself familiar with the SDK’s architecture and functionalities. Below, I’m going to explain some of the technical aspects as well as the setup of the story UI in a little more detail.&lt;/p&gt;
&lt;h2 id=&quot;the-architecture&quot;&gt;The Architecture&lt;/h2&gt;
&lt;p&gt;The interface is composed of several layers. The first layer is the &lt;code&gt;EditorRootView&lt;/code&gt; that contains all other views and is, therefore, their parent object. Beneath that lies the &lt;code&gt;EditorPreview&lt;/code&gt; that is responsible for the display of the selected image. Following comes the &lt;code&gt;BrushLayer&lt;/code&gt; that can be drawn upon. In this specific layer array, the brush cannot be placed in front of a sticker. The stickers, however, are all generated in dedicated layers which makes it easy to adjust their order. Once selected, a sticker will automatically be brought to the front. The UI elements can be switched visible and invisible at will; they lie at the very top so that no sticker can cover them.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The view hierarchy. The user facing controls are on the bottom, the root window is on the top.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 473px) 473px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;473&quot; height=&quot;579&quot; src=&quot;https://img.ly/_astro/image-14_Z35Yqi.webp&quot; srcset=&quot;/_astro/image-14_Z35Yqi.webp 473w&quot;&gt;&lt;/p&gt;
&lt;p&gt;At the heart of the UI lies the &lt;code&gt;StateHandler&lt;/code&gt; that functions as the communication interface with the SDK. The &lt;code&gt;StateHandler&lt;/code&gt; includes the &lt;code&gt;EditorShowState&lt;/code&gt; and the &lt;code&gt;HistoryState&lt;/code&gt;. The &lt;code&gt;HistoryState&lt;/code&gt; allows for the retrieval of methods that are necessary for the function of the “undo” button. For example, every new brush stroke adds a new memory state that can be retrieved by the &lt;code&gt;HistoryState&lt;/code&gt; and hence reversed. The &lt;code&gt;EditorShowState&lt;/code&gt; manages the &lt;code&gt;EditMode&lt;/code&gt; that allows for the activation of the different SDK tools. To draw with the brush tool, the &lt;code&gt;EditMode&lt;/code&gt; simply has to be set to brush. Color and stroke width are then controlled by the &lt;code&gt;BrushLayerSettings&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;There is a dedicated button to add emojis that displays a &lt;code&gt;RecyclerView&lt;/code&gt; filled with every sticker available in the config upon press. Once a sticker is selected a new layer with matching &lt;code&gt;StickerLayerSettings&lt;/code&gt; is added to the image.&lt;/p&gt;
&lt;p&gt;Although text is realized as a sticker as well within the SDK, it is a little more complicated to generate a text sticker as the required &lt;code&gt;TextStickerConfig&lt;/code&gt; has to be generated first. The text tool can create text stickers through keyboard entries. The text and background color, as well as the text alignment, can be adjusted separately. Those functions can be controlled via different buttons. However, as the SDK has no canned methods for these operations, I had to write widgets that control the buttons. The different button states are interpreted and executed in the &lt;code&gt;TextPanel&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To export an image, you simply have to launch the &lt;code&gt;saveImage&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The customized Story UI in action.&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;581&quot; src=&quot;https://img.ly/_astro/1-o1meOAWBo6YIzb_xRishgQ_O6YP6.webp&quot; srcset=&quot;/_astro/1-o1meOAWBo6YIzb_xRishgQ_O6YP6.webp 300w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-result&quot;&gt;The Result&lt;/h2&gt;
&lt;p&gt;Thanks to the documentation, the execution of the UI revamp was pretty straightforward even without previous knowledge or source code access. As main functionalities like the brush tool or the undo function are already built into the SDK, it was a manageable task to integrate those into the new UI. Against that, the styling of the &lt;code&gt;SeekBar&lt;/code&gt; that is needed to adjust the brush size was a little more time-consuming.&lt;/p&gt;
&lt;p&gt;The design was mainly realized through layouts with fairly simple code. Even though there were some minor hurdles to overcome, the allotted time of a working day should be adequate for a more experienced developer.&lt;/p&gt;
&lt;p&gt;You can find the code for this example UI in &lt;a href=&quot;https://github.com/imgly/pesdk-blog-instagram-ui&quot;&gt;our repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thanks to &lt;a href=&quot;https://medium.com/@Phoenix_Raw&quot;&gt;Felix Rau&lt;/a&gt; and &lt;a href=&quot;https://medium.com/@codingdivision&quot;&gt;Malte Baumann&lt;/a&gt;!&lt;/strong&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>Niklas</dc:creator><media:content url="https://blog.img.ly/2020/04/image-46.png" medium="image"/><category>iOS</category><category>Android</category><category>Photo Editor</category><category>User Interface</category><category>JavaScript</category><category>Tech</category><category>How-To</category><category>Learning</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/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/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/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>