<?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>Image Editing – IMG.LY Blog</title><description>Posts tagged Image Editing on the IMG.LY blog.</description><link>https://img.ly/blog/tag/image-editing/</link><language>en-us</language><image><url>https://img.ly/apple-touch-icon.png</url><title>Image Editing – IMG.LY Blog</title><link>https://img.ly/blog/tag/image-editing/</link></image><atom:link href="https://img.ly/blog/tag/image-editing/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>IMG.LY Partners with Getty Images to Revolutionize Image Integration</title><link>https://img.ly/blog/getty-images-partnership/</link><guid isPermaLink="true">https://img.ly/blog/getty-images-partnership/</guid><description>Discover Getty Images Library SDK - the easy-to-use toolkit that integrates image search, licensing, and editing for efficient content creation.</description><pubDate>Wed, 03 May 2023 13:07:31 GMT</pubDate><content:encoded>&lt;p&gt;We are thrilled to announce our latest partnership with Getty Images, the world’s leading provider of images, clips, and illustrations for visual communication. This collaboration has brought forth the &lt;a href=&quot;https://img.ly/partners/getty-images-sdk&quot;&gt;Getty Images Library SDK&lt;/a&gt; - a bridge that seamlessly integrates image searching, licensing, and editing into your application. This revolutionary toolkit grants access to millions of stock images and enables your teams and users to browse, license, and edit images without ever leaving your application or website.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Empower your users to unleash their creativity with the Getty Images library&amp;#39;s powerful filtering tool. Let them find the perfect visual match for their content with ease.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 519px) 519px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;519&quot; height=&quot;526&quot; src=&quot;https://img.ly/_astro/image_D8Iyi.webp&quot; srcset=&quot;/_astro/image_D8Iyi.webp 519w&quot;&gt;&lt;/p&gt;
&lt;p&gt;By integrating Getty Images Library SDK into your application, you can save precious resources, streamline your workflows, and ensure legal compliance with a broad range of licensed stock images at your fingertips. Imagine not having to switch between different platforms to search, license, and edit images – all while staying in your application.&lt;/p&gt;
&lt;h3 id=&quot;empower-your-developers-and-users&quot;&gt;Empower your Developers and Users&lt;/h3&gt;
&lt;p&gt;At IMG.LY, we are passionate about delivering powerful editing tools with an intuitive interface, providing a creative outlet for users of all skill levels. Teaming up with Getty Images, we strive to provide a toolkit that empowers content creators to communicate their message in the most efficient and effective way possible, while upholding Getty Images’ commitment to quality and diversity in visual images.&lt;/p&gt;
&lt;p&gt;Designed by developers, for developers, the integration is quick and easy to set up. Once integrated, users can effortlessly browse through images, license the visuals they want, and make quick edits such as cropping or rotating images, all within the same application.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Explore the user-friendly interface of the Getty Images Library SDK editor, designed to seamlessly integrate image searching, licensing, and editing into your application.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 854px) 854px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;854&quot; height=&quot;520&quot; src=&quot;https://img.ly/_astro/getty-images-library-integration-app_ZADacA.webp&quot; srcset=&quot;/_astro/getty-images-library-integration-app_1YOhLQ.webp 640w, /_astro/getty-images-library-integration-app_xDMFe.webp 750w, /_astro/getty-images-library-integration-app_i0Kt7.webp 828w, /_astro/getty-images-library-integration-app_ZADacA.webp 854w&quot;&gt;&lt;/p&gt;
&lt;p&gt;We are excited to share this news and look forward to working with Getty Images to bring tools and empower creative expression!&lt;/p&gt;
&lt;h3 id=&quot;get-started&quot;&gt;Get Started&lt;/h3&gt;
&lt;p&gt;Learn more about the &lt;a href=&quot;https://img.ly/partners/getty-images-sdk&quot;&gt;Getty Images Library SDK&lt;/a&gt;, &lt;a href=&quot;https://img.ly/docs/pesdk/web/guides/getty-library/getting-started/&quot;&gt;how to integrate it&lt;/a&gt;, or contact &lt;a href=&quot;https://www.gettyimages.de/api?utm_source=imgly&amp;#x26;utm_medium=referral&quot;&gt;Getty Images&lt;/a&gt; to obtain a license key.&lt;/p&gt;</content:encoded><dc:creator>Klaudia</dc:creator><media:content url="https://blog.img.ly/2023/05/partnership---getty.jpg" medium="image"/><category>App Development</category><category>Web Application</category><category>Web Development</category><category>Image Editing</category><category>Company</category></item><item><title>How to Draw on Images in React Native</title><link>https://img.ly/blog/how-to-draw-on-images-in-react-native/</link><guid isPermaLink="true">https://img.ly/blog/how-to-draw-on-images-in-react-native/</guid><description>Learn how to draw on images in your React Native app – a great tool for annotations or fun image editing!</description><pubDate>Thu, 20 Oct 2022 13:09:38 GMT</pubDate><content:encoded>&lt;p&gt;It has become a commonplace requirement for many applications to manipulate images in one way or another before users are ready to share them. Therefore, it is crucial to foresee end-user needs while working on an app involving any interaction with graphical content. Image annotation can be necessary in various cases, such as simple inspection apps, bug reporting software, or machine learning applications relying on manual user input.&lt;/p&gt;
&lt;p&gt;In this article, we are shedding light on how to draw on images in React Native with the help of a simple HTML5 &lt;canvas&gt; element. We can summarize the drawing process with this checklist:&lt;/canvas&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Enable the characteristics of the &lt;canvas&gt; element by defining the height and width of your drawing area;&lt;/canvas&gt;&lt;/li&gt;
&lt;li&gt;Set the thickness and color of the brush instrument;&lt;/li&gt;
&lt;li&gt;Define at what moment your brush needs to be activated and when the drawing process will finish;&lt;/li&gt;
&lt;li&gt;Start drawing!&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let’s first clear up the purpose of &lt;canvas&gt;.&lt;/canvas&gt;&lt;/p&gt;
&lt;h3 id=&quot;canvas-integration-for-images&quot;&gt;&lt;strong&gt;Canvas Integration for Images&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt; is an HTML component commonly used for creating and manipulating graphics, animation, and other visualization features. This element provides JavaScript APIs enabling image overlays and handling user input to make drawing possible. Moreover, while we have several methods for image manipulation with &lt;canvas&gt; (e.g., &lt;em&gt;boxes, circles, adding text, and other images&lt;/em&gt;), the most crucial attributes are always width and height.&lt;/canvas&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;! -- HTML example of using canvas: --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;canvas id=&quot;myCanvas&quot; width=&quot;200&quot; height=&quot;100&quot;&gt;&amp;#x3C;/canvas&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You might wonder why you cannot easily substitute &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt; with some lines of HTML and CSS in your code. The answer lies on the surface: &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt; creates a single flattened graphic rather than multiple components lying on top of each other (i.e., typically the output of HTML and CSS).&lt;/p&gt;
&lt;p&gt;Now, let’s see how to implement this powerful element in your React Native application:&lt;/p&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/img-ly-how-to-draw-on-images-in-rn-forked-hewo07?fontsize=14&amp;#x26;hidenavigation=1&amp;#x26;theme=dark&quot; title=&quot;IMG.LY_How_to_Draw_on_Images_in_RN (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;h3 id=&quot;drawing-with-canvas&quot;&gt;&lt;strong&gt;Drawing with Canvas&lt;/strong&gt;&lt;/h3&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, { useEffect } &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;// CanvasContext here is used for drawing onto the canvas&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { useCanvas } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;./CanvasContext&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; Canvas&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;canvasRef&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;prepareCanvas&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;startDrawing&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;finishDrawing&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;draw&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;    useCanvas&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;  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;    prepareCanvas&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;  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;canvas&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      onMouseDown&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{startDrawing}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      onMouseUp&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{finishDrawing}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      onMouseMove&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{draw}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      ref&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{canvasRef}&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;We start by enabling the characteristics of our &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt; container, which are meant to render the &lt;code&gt;CanvasContext&lt;/code&gt; component presented below.&lt;/p&gt;
&lt;p&gt;The size of our future canvas is determined with &lt;code&gt;prepareCanvas&lt;/code&gt;, which includes both the height (&lt;code&gt;canvas.height&lt;/code&gt;) and width (&lt;code&gt;canvas.width&lt;/code&gt;) of the HTML element. For the drawing process itself, it is necessary to assign not only the thickness and color of the brush instrument (&lt;code&gt;context&lt;/code&gt;) but also take into account its activation (&lt;code&gt;startDrawing&lt;/code&gt; with &lt;code&gt;onMouseDown&lt;/code&gt;) and how the user can finish a stroke (&lt;code&gt;finishDrawing&lt;/code&gt; with &lt;code&gt;onMouseUp&lt;/code&gt;).&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, { useContext, useRef, 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;// enabling drawing on the blank canvas&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; CanvasContext&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; React.&lt;/span&gt;&lt;span&gt;createContext&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; const&lt;/span&gt;&lt;span&gt; CanvasProvider&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; ({ &lt;/span&gt;&lt;span&gt;children&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;isDrawing&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setIsDrawing&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;false&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; canvasRef&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; useRef&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; contextRef&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; useRef&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // defining width &amp;#x26; height of the canvas&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; prepareCanvas&lt;/span&gt;&lt;span&gt; =&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; canvas&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; canvasRef.current;&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; window.innerWidth &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt;;&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; window.innerHeight &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    canvas.style.width &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; `${&lt;/span&gt;&lt;span&gt;window&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;innerWidth&lt;/span&gt;&lt;span&gt;}px`&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    canvas.style.height &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; `${&lt;/span&gt;&lt;span&gt;window&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;innerHeight&lt;/span&gt;&lt;span&gt;}px`&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;    // defining the thickness and colour of our brush&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;    context.&lt;/span&gt;&lt;span&gt;scale&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    context.lineCap &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;round&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    context.strokeStyle &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;black&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    context.lineWidth &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 5&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    contextRef.current &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; context;&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; startDrawing&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; ({ &lt;/span&gt;&lt;span&gt;nativeEvent&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;offsetX&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;offsetY&lt;/span&gt;&lt;span&gt; } &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; nativeEvent;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    contextRef.current.&lt;/span&gt;&lt;span&gt;beginPath&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    contextRef.current.&lt;/span&gt;&lt;span&gt;moveTo&lt;/span&gt;&lt;span&gt;(offsetX, offsetY);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    setIsDrawing&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  };&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; finishDrawing&lt;/span&gt;&lt;span&gt; =&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;    contextRef.current.&lt;/span&gt;&lt;span&gt;closePath&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    setIsDrawing&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  };&lt;/span&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; draw&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; ({ &lt;/span&gt;&lt;span&gt;nativeEvent&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; (&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;isDrawing) {&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;    const&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;offsetX&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;offsetY&lt;/span&gt;&lt;span&gt; } &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; nativeEvent;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    contextRef.current.&lt;/span&gt;&lt;span&gt;lineTo&lt;/span&gt;&lt;span&gt;(offsetX, offsetY);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    contextRef.current.&lt;/span&gt;&lt;span&gt;stroke&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;  // Once the canvas is cleared it return to the default colour&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; clearCanvas&lt;/span&gt;&lt;span&gt; =&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; canvas&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; canvasRef.current;&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;    context.fillStyle &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;white&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    context.&lt;/span&gt;&lt;span&gt;fillRect&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;, canvas.width, canvas.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; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;CanvasContext.Provider&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      value&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        canvasRef,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        contextRef,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        prepareCanvas,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        startDrawing,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        finishDrawing,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        clearCanvas,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        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;    &gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      {children}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span&gt;CanvasContext.Provider&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; const&lt;/span&gt;&lt;span&gt; useCanvas&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; useContext&lt;/span&gt;&lt;span&gt;(CanvasContext);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;drawbacks-of-the-canvas-method&quot;&gt;Drawbacks of the Canvas Method&lt;/h3&gt;
&lt;p&gt;Despite the canvas component offering powerful features, it is also quite demanding to use in its original form. For example, it may be problematic to adjust the properties of the brush to ensure that you can draw with smooth movements. Thus, implementing any solution for this issue would further increase the coding time and reduce the compatibility between different frameworks. Also, separately defining canvas and brush properties overcomplicates the code and requires advanced sources for successful integration into your React Native app. Although some temporary solutions aim to facilitate this process (such as &lt;a href=&quot;https://github.com/iddan/react-native-canvas&quot;&gt;react-native-image-draw&lt;/a&gt; or &lt;a href=&quot;https://github.com/terrylinla/react-native-sketch-canvas&quot;&gt;react-native-sketch-draw&lt;/a&gt;), none provides a permanent solution with clear documentation and guidance.&lt;/p&gt;
&lt;p&gt;If you wonder about a magic door to avoid this coding nightmare, you can always choose a commercial, all-in-one solution like &lt;a href=&quot;https://img.ly/products/photo-sdk&quot;&gt;PhotoEditor SDK&lt;/a&gt;. Implementing this SDK only takes a few lines of code, saves time and expenses in building an app, and you can expect great support from the developers. This way, you can skirt the hassle of coding an editor and instead focus on creating a great product.&lt;/p&gt;
&lt;h3 id=&quot;photoeditor-sdk-integration-for-drawing-on-your-images&quot;&gt;PhotoEditor SDK Integration for Drawing on Your Images&lt;/h3&gt;
&lt;p&gt;To get started integrating the PhotoEditor SDK in your React Native app, refer to &lt;a href=&quot;https://img.ly/docs/pesdk/web/guides/react-js/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;this guide&lt;/a&gt; from &lt;a href=&quot;https://img.ly/docs/pesdk/guides/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;the official documentation&lt;/a&gt;. You can then ensure comfortable image interaction for your users with the optimized &lt;a href=&quot;https://img.ly/docs/pesdk/web/features/brush/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;brush tool&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; as in the example below.&lt;/p&gt;
&lt;p&gt;&lt;video src=&quot;https://storage.googleapis.com/imgly-static-assets/static/blog/videos/pe-sdk-draw-image-react.mp4&quot; controls autoplay muted loop playsinline&gt;&lt;/video&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This article aimed to examine image editing instruments suitable for React Native framework. The HTML &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt; element could have big potential as it provides fundamental tools for creating graphics or animation. However, its application is time-consuming and requires comprehensive knowledge in the field. Therefore, if you want to guarantee a smooth and easy integration of image drawing tools for your app, consider using advanced software like PhotoEditor SDK.&lt;/p&gt;</content:encoded><dc:creator>Natalia</dc:creator><media:content url="https://blog.img.ly/2022/10/photoeditor-sdk-ract-draw-on-images.png" medium="image"/><category>How-To</category><category>React</category><category>Web Development</category><category>Web Application</category><category>Image Editing</category><category>HTML5</category><category>React Native</category><category>Tech</category><category>Tutorial</category></item><item><title>Comparing the Top 5 Open Source JavaScript Image Manipulation Libraries</title><link>https://img.ly/blog/the-top-5-open-source-javascript-image-manipulation-libraries/</link><guid isPermaLink="true">https://img.ly/blog/the-top-5-open-source-javascript-image-manipulation-libraries/</guid><description>Learn the difference between five major image manipulation libraries and choose the right one for you!</description><pubDate>Tue, 27 Sep 2022 13:29:03 GMT</pubDate><content:encoded>&lt;p&gt;Image Manipulation Libraries (IML) are used to perform various manipulation functions on images: you can increase the brightness of an image, add saturation or filters, crop and resize, and more valuable features that will help you to do almost everything and turn your web browser into an Adobe Lightroom!&lt;br&gt;
We have included libraries for every significant image manipulation task, from simple, low-level operations such as filters, brightness, and saturation to single-purpose libraries for cropping or image composition. To finish up, we wandered into the realm of testing images, since no image manipulation application is complete without a reliable way to test results.&lt;/p&gt;
&lt;h2 id=&quot;sharp&quot;&gt;Sharp&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nodejsera.com/resize-image-using-sharp-nodejs.html#overview&quot;&gt;Sharp&lt;/a&gt; is a high-performance Node.js image processing library to resize different image formats such as JPEG, PNG, WebP, AVIF, SVG, and TIFF. The typical use case for this high-speed Node.js module is to convert large images in standard formats to smaller, web-friendly images.&lt;/p&gt;
&lt;p&gt;Sharp is helpful only if you want to resize a giant file or a variety of them. If, on the other hand, you only want to resize a single small image, then you probably shouldn’t use it. Instead, ordinary HTML and vanilla JavaScript will be more beneficial. Sharp is taking full advantage of multiple CPU cores and L1/L2/L3 cache, allowing you to resize and compress your images much more quickly.&lt;/p&gt;
&lt;h3 id=&quot;use-cases&quot;&gt;Use cases&lt;/h3&gt;
&lt;p&gt;I used it to resize a whole NFT Collection with a size of over 80Gb, which after compression came out at circa 10Gb. So again, if you would like to use it for resizing several large images, then it’s the best choice for you - you’ll do it in the fastest and most efficient way.&lt;/p&gt;
&lt;h3 id=&quot;example&quot;&gt;Example&lt;/h3&gt;
&lt;p&gt;You can install this library by using the command below:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;span&gt; sharp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is how you would resize an image using sharp:&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;const&lt;/span&gt;&lt;span&gt; sharp&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; require&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;sharp&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; fs&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; require&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;fs&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;sharp&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;yellow.png&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;rotate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;180&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;resize&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;200&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;toBuffer&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  .&lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;data&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;    fs.&lt;/span&gt;&lt;span&gt;writeFileSync&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;yellow.png&apos;&lt;/span&gt;&lt;span&gt;, data);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  .&lt;/span&gt;&lt;span&gt;catch&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;err&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;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(err);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  });&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;&quot;&gt;&lt;/h2&gt;
&lt;p&gt;Cropper.js&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/fengyuanchen/cropperjs&quot;&gt;Cropper.js&lt;/a&gt; is another popular JavaScript library for image manipulation. You can use it to crop your images in all possible ways, change aspect ratio, rotate, zoom and work with canvas data. &lt;a href=&quot;https://github.com/fengyuanchen/cropperjs&quot;&gt;Cropper.js&lt;/a&gt; is the right choice for cropping without any extra features.&lt;/p&gt;
&lt;h3 id=&quot;use-cases-1&quot;&gt;Use Cases&lt;/h3&gt;
&lt;p&gt;You can use its flexible API to create a custom image cropping UI in your web app allowing your users to adjust photos to the correct size and aspect ratio. It will be more efficient because it requires almost nothing, doesn’t have any useless features, and is very optimized for cropping!&lt;/p&gt;
&lt;h3 id=&quot;example-1&quot;&gt;Example&lt;/h3&gt;
&lt;p&gt;This library can be installed with the following command:&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;npm install cropperjs&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&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; Cropper &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;cropperjs&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; image&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;getElementById&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;image&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; cropper&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; Cropper&lt;/span&gt;&lt;span&gt;(image, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  aspectRatio: &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;  crop&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(event.detail.x);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(event.detail.y);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(event.detail.width);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(event.detail.height);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(event.detail.rotate);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(event.detail.scaleX);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(event.detail.scaleY);&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;Check out the Cropper.js &lt;a href=&quot;https://fengyuanchen.github.io/cropperjs/&quot;&gt;demo&lt;/a&gt;, click on any property that you want to apply to your image and see the result instantly.&lt;/p&gt;
&lt;p&gt;For an in-depth guide on how to add image cropping to your React app, check out our &lt;a href=&quot;https://img.ly/blog/how-to-crop-an-image-in-react-with-react-image-crop/&quot;&gt;guide on using&lt;/a&gt; &lt;a href=&quot;https://img.ly/blog/how-to-crop-an-image-in-react-with-react-image-crop/&quot;&gt;&lt;code&gt;react-image-crop&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;merge-images&quot;&gt;Merge Images&lt;/h2&gt;
&lt;p&gt;Working with the canvas can be slightly tedious, especially when you need the canvas context to do relatively simple things like merging a few images. &lt;a href=&quot;https://github.com/lukechilds/merge-images&quot;&gt;Merge Images&lt;/a&gt; abstracts all repetitive tasks into simple function calls. It’s a wrapper around the Canvas API, abstracting its low-level functions, which makes this specific task a lot easier. You can also create parameters like positioning, opacity, and several more. You can find them in the docs on &lt;a href=&quot;https://github.com/lukechilds/merge-images&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;use-cases-2&quot;&gt;Use cases&lt;/h3&gt;
&lt;p&gt;It’s a valuable library that can help with several tasks. For example, you can generate an NFT Collection where you can merge all components to have a complete set of variations. Or you can find this library helpful for personal use, for example, combining a few different images to generate a collage.&lt;/p&gt;
&lt;h3 id=&quot;example-2&quot;&gt;Example&lt;/h3&gt;
&lt;p&gt;Install the library itself:&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;npm install &lt;/span&gt;&lt;span&gt;--&lt;/span&gt;&lt;span&gt;save merge&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;images&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then you can use this code to generate a simple image:&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;//write this inside of your javascript 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;import&lt;/span&gt;&lt;span&gt; mergeImages &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;merge-images&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;mergeImages&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;&apos;/body.png&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;/eyes.png&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;/mouth.png&apos;&lt;/span&gt;&lt;span&gt;]).&lt;/span&gt;&lt;span&gt;then&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;b64&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&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;img&apos;&lt;/span&gt;&lt;span&gt;).src &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; b64)&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;//And that would update the img element to show this image:&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, I used it to merge several components to create a final variation (here I used Background, Character, Horns, Emotion, and Accessories).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Merge components for a new variation. I have used Background, Character, Horns, Emotion, and Accessories.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 4000px) 4000px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;4000&quot; height=&quot;5000&quot; src=&quot;https://img.ly/_astro/Cark--0454--1-_ZtQqaO.webp&quot; srcset=&quot;/_astro/Cark--0454--1-_iiCUQ.webp 640w, /_astro/Cark--0454--1-_Z4eEGA.webp 750w, /_astro/Cark--0454--1-_1JCKo3.webp 828w, /_astro/Cark--0454--1-_19SXG5.webp 1080w, /_astro/Cark--0454--1-_1esn2E.webp 1280w, /_astro/Cark--0454--1-_Z22yC93.webp 1668w, /_astro/Cark--0454--1-_2ab9uD.webp 2048w, /_astro/Cark--0454--1-_Z1QdBGV.webp 2560w, /_astro/Cark--0454--1-_ZtQqaO.webp 4000w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;lookssame&quot;&gt;LooksSame&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.npmjs.com/package/looks-same&quot;&gt;LooksSame&lt;/a&gt; is a library for comparing images. If the two images you uploaded are duplicates, the library will let you know. All you have to do is provide a link to the pictures you would like compared. LooksSame is not strictly an image manipulation library, but is helpful for testing purposes.&lt;/p&gt;
&lt;h3 id=&quot;use-cases-3&quot;&gt;Use cases&lt;/h3&gt;
&lt;p&gt;You can use this library and write code for automation and loop cycles that search a directory and compare each pair of your images for duplicates. Additionally, you can delete these duplicates and automate this process as well. It is a splendid library if you’re constantly working with ML algorithms that include large numbers of images.&lt;/p&gt;
&lt;h3 id=&quot;example-3&quot;&gt;Example&lt;/h3&gt;
&lt;p&gt;To start comparing images, you need just to install it by using this command:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span&gt; looks-same&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, you can see how to test this library with &lt;a href=&quot;https://jestjs.io/docs/getting-started&quot;&gt;Jest&lt;/a&gt;:&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;var&lt;/span&gt;&lt;span&gt; looksSame &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; require&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;looks-same&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;//Parameters can be paths to files or buffer with compressed png image&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;test&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;image1 and image2 are the same&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;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  expect&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;looksSame&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;image1.png&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;image2.png&apos;&lt;/span&gt;&lt;span&gt;)).&lt;/span&gt;&lt;span&gt;toBe&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;});&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;//Result will be &quot;image1 and image2 are the same&quot; if they are the same&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;jimp&quot;&gt;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 JavaScript Image Manipulation Program, that allows you to edit your image in almost every possible way. With it, you can invert your image, add some text, resize, use pixelation, clone images, blur them, invert colors, and several other cool features which will increase the image manipulation capabilities of your app.&lt;/p&gt;
&lt;h3 id=&quot;use-cases-4&quot;&gt;Use cases&lt;/h3&gt;
&lt;p&gt;With &lt;a href=&quot;https://github.com/jimp-dev/jimp&quot;&gt;Jimp&lt;/a&gt;, you can build your web application where you’ll be able to edit and manipulate images in almost any possible way. Crop, resize, rotate, and filter features let you create your own photo editor and add an interface on top of it. To streamline this process, you can try &lt;a href=&quot;https://img.ly/products/photo-sdk&quot;&gt;&lt;strong&gt;PhotoEditor SDK&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;(PE.SDK)&lt;/strong&gt;. PE.SDK will provide you with a polished user interface and photo editing features, so you can focus on the application you are building instead.&lt;/p&gt;
&lt;h3 id=&quot;example-4&quot;&gt;Example&lt;/h3&gt;
&lt;p&gt;Here’s the JavaScript code to try this excellent library. There’s an async function in which you can see many types of properties that you can easily change. Such as &lt;em&gt;Add Text&lt;/em&gt;, &lt;em&gt;Resize Image&lt;/em&gt;, &lt;em&gt;Blur the Image&lt;/em&gt;, etc. To use at least one of them, you’ll need to uncomment only part that you need, and your program is ready to run!&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 dependencies&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; Jimp&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; require&lt;/span&gt;&lt;span&gt;(&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;async&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;  // Read the image&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; Jimp.&lt;/span&gt;&lt;span&gt;read&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;images/shapes.png&apos;&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;span&gt;// &amp;#x3C;http://www.example.com/path/to/lenna.jpg&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;  // // Add text&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  const font = await Jimp.loadFont(Jimp.FONT_SANS_16_WHITE); // bitmap fonts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  image.print(font, 0, 0, &apos;Hello world!&apos;); // &amp;#x3C;https://github.com/libgdx/libgdx/wiki/Hiero&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;  //  // Resize the image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  // Resize the image to 250 x 250&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  image.resize(250, 250);&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;  //  // Resize the height to 250 and scale the width accordingly&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  image.resize(Jimp.AUTO, 250);&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;  //  // Resize the width to 250 and scale the height accordingly&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  image.resize(250, Jimp.AUTO);&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;  //  // Add a sepia wash to the image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  image.sepia();&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;  //  // Pixelation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  image.pixelate(5);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  image.pixelate(5, 50, 50, 190, 200); pixe,x, y, w, h&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;  //  // Clone&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  const image2 = image.clone();&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;  //  // Blur the image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  image.gaussian(1);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  image.blur(1);&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;  //  // Inverts the image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  image.invert();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  // Set the brightness&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  image.brightness( 0.5 ); // -1 to +1&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;  //  // Resize the image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  image.resize(256, 256);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  // Set the quality&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  image.quality(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;  //  // Convert to grayscale&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  image.greyscale();&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;  // Save the image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  image.&lt;/span&gt;&lt;span&gt;write&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;images/edited-shapes.png&apos;&lt;/span&gt;&lt;span&gt;); &lt;/span&gt;&lt;span&gt;// writeAsync&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;PS: Don’t forget to uncomment the effects which you want to use and save the file after. :)&lt;/p&gt;
&lt;p&gt;As you can see here, I blurred everything and inverted the colors for the previous image that I showed you, getting the following result:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 2000px) 2000px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;2000&quot; height=&quot;2500&quot; src=&quot;https://img.ly/_astro/edited-shapes--1-_ZYNNbY.webp&quot; srcset=&quot;/_astro/edited-shapes--1-_Z1zlAHs.webp 640w, /_astro/edited-shapes--1-_rXLqj.webp 750w, /_astro/edited-shapes--1-_JK5t4.webp 828w, /_astro/edited-shapes--1-_ZfCEJE.webp 1080w, /_astro/edited-shapes--1-_Z1bDJEA.webp 1280w, /_astro/edited-shapes--1-_ZI62ME.webp 1668w, /_astro/edited-shapes--1-_ZYNNbY.webp 2000w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;That’s it! Now you know the differences between five of the most popular image manipulation libraries for JavaScript. Some of them are useful for only one task, such as resizing images - others can do multiple tasks at once and help you with more processes. You have also met &lt;a href=&quot;https://img.ly/products/photo-sdk&quot;&gt;PE.SDK&lt;/a&gt; to work smarter and save time building photo editing solutions, and focus on building your great product instead.&lt;/p&gt;</content:encoded><dc:creator>Mark</dc:creator><media:content url="https://blog.img.ly/2022/09/image-manipulation-libraries-javascript-1.png" medium="image"/><category>How-To</category><category>Image Manipulation</category><category>Image Editing</category><category>Insights</category></item><item><title>Content Moderation for User-Generated Designs with CE.SDK and Sightengine</title><link>https://img.ly/blog/content-moderation-for-user-generated-designs-with-ce-sdk-and-sightengine/</link><guid isPermaLink="true">https://img.ly/blog/content-moderation-for-user-generated-designs-with-ce-sdk-and-sightengine/</guid><description>Protect your users and your brand reputation without manual content moderation.</description><pubDate>Mon, 13 Jun 2022 14:07:54 GMT</pubDate><content:encoded>&lt;p&gt;Creating content and sharing it with others has become one of the core features offered by online services. As users publish their content to your website, you want to consider implementing a system to prevent inappropriate posts. Ideally, content will be programmatically moderated before it is uploaded on your platform. That is what you will learn in this article!&lt;/p&gt;
&lt;p&gt;Follow this step-by-step tutorial and learn how to integrate content moderation with Sightengine in your design process built with CreativeEditor SDK in React. At the end of this tutorial, you will achieve the &lt;a href=&quot;https://codesandbox.io/s/content-moderation-for-user-generated-designs-with-ce-sdk-and-sightengine-forked-8kc7te&quot;&gt;following result&lt;/a&gt;:&lt;/p&gt;
&lt;h2 id=&quot;why-you-should-moderate-user-generated-content&quot;&gt;Why You Should Moderate User-Generated Content&lt;/h2&gt;
&lt;p&gt;User-generated content represents a large portion of online content, whether text or multimedia. Empowering users with tools and features to create high-quality content is excellent. However, it is a common concern that potentially inappropriate content on your website will be associated with your brand. Naturally, you will want to avoid this.&lt;/p&gt;
&lt;p&gt;A recent example from the web-to-print industry serves as a cautionary tale: the German e-commerce company Spreadshirt neglected to moderate content on its t-shirt printing platform, leading to a wave of &lt;a href=&quot;https://www.beyond-print.net/market-spreadshirt-removes-tasteless-star-of-david-motif/&quot;&gt;outrage on social media&lt;/a&gt;. Even though the company reacted swiftly and stated an apology, Spreadshirt could have avoided most of the damage if it had implemented a system that automatically flags potentially harmful content. Of course, a religious or cultural symbol is not inherently inappropriate, but the misuse is.&lt;/p&gt;
&lt;p&gt;It is highly advisable to take precautions to prevent your company from facing similar adversity. A common problem, however, is the costly and time-consuming manual moderation, epecially when controlling multimedia files like images.&lt;/p&gt;
&lt;p&gt;Luckily, you can use CE.SDK and Sightengine to programmatically integrate moderation into your content design process without manual reviews.&lt;/p&gt;
&lt;h2 id=&quot;what-is-cesdk&quot;&gt;What is CE.SDK?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://img.ly/products/creative-sdk?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;CreativeEditor SDK (CE.SDK)&lt;/a&gt; is a powerful, easy-to-use, and fully customizable design editor. With just a few lines of code, CE.SDK provides your application with template-based workflows and automation.&lt;/p&gt;
&lt;p&gt;The role-specific editing UI focuses on keeping content adaptation dead simple: in &lt;strong&gt;Creator Mode&lt;/strong&gt;, you have the liberty to create a design from scratch or customize existing templates. When creators are ready to share a design for others to use and customize in &lt;strong&gt;Adopter Mode&lt;/strong&gt; (Default UI), creators may decide which elements can be changed. See CE.SDK &lt;a href=&quot;https://img.ly/showcases/cesdk/web/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;in action&lt;/a&gt; or &lt;a href=&quot;https://img.ly/free-trial/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;try it for free&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-is-sightengine&quot;&gt;What is Sightengine?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://sightengine.com/&quot;&gt;Sightengine&lt;/a&gt; is a convenient tool for automatic content moderation. It detects and filters unwanted content in photos, videos, and live streams through fast, accurate, easy-to-integrate, privacy-compliant APIs.&lt;/p&gt;
&lt;p&gt;Sightengine offers you APIs to get moderation results instantly and effectively. The API-centric approach allows you to scale to up to tens of millions of images per month. You can have a look at the Sightengine &lt;a href=&quot;https://sightengine.com/demo&quot;&gt;demo&lt;/a&gt; or &lt;a href=&quot;https://dashboard.sightengine.com/signup&quot;&gt;try it for free&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;integrate-content-moderation-into-cesdk&quot;&gt;Integrate Content Moderation into CE.SDK&lt;/h2&gt;
&lt;p&gt;Let us look at how to implement an image editor with content moderation for your users. For this, you will learn how to use CE.SDK and React to implement an image design component and use the CE.SDK APIs to programmatically moderate the content with Sightengine on a Node.js server. You can try out a &lt;a href=&quot;https://img.ly/showcases/cesdk/web/content-moderation/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;live showcase&lt;/a&gt; of content moderation with CE.SDK.&lt;/p&gt;
&lt;p&gt;With the following steps, you can easily achieve this result with CE.SDK, React, Sightengine, and Node.js.&lt;/p&gt;
&lt;h3 id=&quot;1-get-started-with-cesdk&quot;&gt;1. Get Started with CE.SDK&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/react/get-started/overview-e18f40/&quot;&gt;Integrate CreativeEditor SDK with React&lt;/a&gt; by using the official documentation. As you will see in the final snippet, this takes only a few lines of code.&lt;/p&gt;
&lt;p&gt;Now that you have a working CE.SDK instance, your users may unleash their creativity by designing templates and sharing them with others. The powerful APIs ensure control at every step of the editing process and allow programmatically performing operations, such as content moderation.&lt;/p&gt;
&lt;h2 id=&quot;2-build-a-content-moderation-api-with-sightengine&quot;&gt;2. Build a Content Moderation API with Sightengine&lt;/h2&gt;
&lt;p&gt;Let’s move on to content moderation with Sightengine. Keep in mind that any backend technology will work, but here you will implement a content moderation API based on Sightengine in Node.js.&lt;/p&gt;
&lt;h3 id=&quot;21-getting-started-with-sightengine&quot;&gt;2.1 Getting Started with Sightengine&lt;/h3&gt;
&lt;p&gt;First, you need a Sightengine account. If you do not have one yet, you can &lt;a href=&quot;https://dashboard.sightengine.com/signup&quot;&gt;create a free account&lt;/a&gt;. Fill out the form, click &lt;em&gt;Sign Up&lt;/em&gt;, and receive a verification email in your inbox. Click on the verification link and activate your account.&lt;/p&gt;
&lt;p&gt;Then, navigate to &lt;em&gt;API Keys&lt;/em&gt; on your Sightengine Dashboard page and retrieve your API &lt;code&gt;user&lt;/code&gt; and &lt;code&gt;secret&lt;/code&gt; credentials. You will need them to interact with the Sightengine moderation APIs.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;API-Keys&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1920px) 1920px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1920&quot; height=&quot;939&quot; src=&quot;https://img.ly/_astro/API-Keys_2qJUen.webp&quot; srcset=&quot;/_astro/API-Keys_ZlqYIr.webp 640w, /_astro/API-Keys_Z1w4Wxh.webp 750w, /_astro/API-Keys_133wET.webp 828w, /_astro/API-Keys_Z1wDt5P.webp 1080w, /_astro/API-Keys_Z19TsmB.webp 1280w, /_astro/API-Keys_1IfMS7.webp 1668w, /_astro/API-Keys_2qJUen.webp 1920w&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;22-prerequisites&quot;&gt;2.2 Prerequisites&lt;/h3&gt;
&lt;p&gt;Here is a list of all prerequisites for the backend application you are going to build:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/get-npm&quot;&gt;Node.js and npm 8.x and higher&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/express&quot;&gt;&lt;code&gt;express&lt;/code&gt;&lt;/a&gt; &gt;= 4.x&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/node-fetch&quot;&gt;&lt;code&gt;node-fetch&lt;/code&gt;&lt;/a&gt; &gt;= 3.x&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can add &lt;code&gt;express&lt;/code&gt; and &lt;code&gt;node-fetch&lt;/code&gt; to your project’s dependencies 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;npm install --save express node-fetch&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;23-setting-up-a-nodejs-express-server&quot;&gt;2.3 Setting up a Node.js Express Server&lt;/h3&gt;
&lt;p&gt;Follow &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment&quot;&gt;this&lt;/a&gt; step-by-step guide to set up a Node.js Express development server. You will need this to perform an API call to Sightengine to moderate your content server-side. Any Sightengine API call involves your Sightengine &lt;code&gt;user&lt;/code&gt; and &lt;code&gt;secret&lt;/code&gt; pair of credentials, and you do not want to expose them.&lt;/p&gt;
&lt;p&gt;You may also want to store the result of the moderation API in your database, as well as other data. For example, you might be interested in keeping track of how many times a particular user has violated the moderation rules to warn or ban them.&lt;/p&gt;
&lt;h3 id=&quot;24-implementing-a-content-moderation-api-in-your-nodejs-server&quot;&gt;2.4 Implementing a Content Moderation API in your Node.js Server&lt;/h3&gt;
&lt;p&gt;You can now implement a content moderation API in your Node.js Express server as follows:&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;    const fetch = require(&quot;node-fetch&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    router.get(&apos;/content-moderation&apos;, function (req, res) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      if (!req.query.url) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            res.status(404).send(&quot;Please provide an image url&quot;)&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 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;        // defining the Sightengine API parameters&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        const params = {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            url: req.query.url,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            models: &quot;nudity,wad,offensive&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            api_user: &quot;YOUR_SIGHTENGINE_USER&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            api_secret: &quot;YOUR_SIGHTENGINE_SECRET&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // generating the Sightengine API URL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        const queryString = new URLSearchParams(params).toString();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        const requestOptions = {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            method: &quot;GET&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        const sightengineUrl = &quot;https://api.sightengine.com/1.0/check.json?&quot; + queryString&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;        // calling the Sightengine moderation API&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        const externalRes = await fetch(SightengineUrl, requestOptions)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // retrieving the moderation result from the Sightengine API&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        const moderationResultText = await externalRes.text()&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;        res.append(&quot;Access-Control-Allow-Origin&quot;, [&quot;*&quot;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        res.append(&quot;Access-Control-Allow-Methods&quot;, &quot;GET&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        res.append(&quot;Access-Control-Allow-Headers&quot;, &quot;Content-Type&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // returning the Sightengine moderation result text&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        res.status(200).send(text)&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;Take care of replacing &lt;code&gt;YOUR_SIGHTENGINE_USER&lt;/code&gt; and &lt;code&gt;YOUR_SIGHTENGINE_SECRET&lt;/code&gt; with your Sightengine pair of credentials retrieved before.&lt;/p&gt;
&lt;p&gt;Now, launch your Node.js server and reach the following URL below to use Sightengine to moderate the images specified in the URL query parameter:&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;    http://localhost:3000/content-moderation?url=&amp;#x3C;your_image_url&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;3-moderate-images-made-with-cesdk&quot;&gt;3. Moderate Images Made with CE.SDK&lt;/h2&gt;
&lt;p&gt;We will now use CE.SDK and Sightengine to programmatically moderate user-generated images. Before we can dive in, check the following requirements.&lt;/p&gt;
&lt;h3 id=&quot;31-prerequisites&quot;&gt;3.1 Prerequisites&lt;/h3&gt;
&lt;p&gt;This is the list of all the prerequisites you need to build for the frontend demo application:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/get-npm&quot;&gt;Node.js and npm 8.x and higher&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://reactjs.org/&quot;&gt;React&lt;/a&gt; &gt;= 17&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/@cesdk/cesdk-js&quot;&gt;&lt;code&gt;@cesdk/cesdk-js&lt;/code&gt;&lt;/a&gt; &gt;= 1.5.0&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can add the &lt;code&gt;@cesdk/cesdk-js&lt;/code&gt; library to your project’s dependencies 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;npm install --save @cesdk/cesdk-js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also, the demo application will use other libraries, although they are not strictly required to achieve the goals of this tutorial and can be omitted here.&lt;/p&gt;
&lt;h3 id=&quot;32-getting-started&quot;&gt;3.2 Getting Started&lt;/h3&gt;
&lt;p&gt;You can try out the demo application by cloning the &lt;a href=&quot;https://github.com/Tonel/content-moderation-with-cesdk-and-sightengine&quot;&gt;GitHub repository that supports this article&lt;/a&gt; with the following commands:&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/content-moderation-with-cesdk-and-sightengine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cd content-moderation-with-cesdk-and-sightengine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm i&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Otherwise, keep following this tutorial and build the demo application for content moderation by yourself.&lt;/p&gt;
&lt;p&gt;First, initialize a React project called &lt;code&gt;content-moderation-with-cesdk-and-sightengine&lt;/code&gt; by employing the &lt;a href=&quot;https://create-react-app.dev/docs/getting-started/&quot;&gt;Create React App&lt;/a&gt; command below:&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;    npx content-moderation-with-cesdk-and-sightengine&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, the &lt;code&gt;content-moderation-with-cesdk-and-sightengine&lt;/code&gt; folder should have the following 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;content-moderation-with-cesdk-and-sightengine&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;Enter the &lt;code&gt;content-moderation-with-cesdk-and-sightengine&lt;/code&gt; folder and start a local server with these two commands:&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;cd content-moderation-with-cesdk-and-sightengine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm 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 now be seeing the default Create React App screen below:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;React-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/React-Screen_ZpeFfw.webp&quot; srcset=&quot;/_astro/React-Screen_2jrC6f.webp 640w, /_astro/React-Screen_Z7rdRp.webp 750w, /_astro/React-Screen_Z1UwlqM.webp 828w, /_astro/React-Screen_ZpeFfw.webp 983w&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;33-integrate-the-moderation-check-into-your-design-process&quot;&gt;3.3 Integrate the Moderation Check into your Design Process&lt;/h3&gt;
&lt;p&gt;Notice that the demo application you are about to implement is just a simplified version of the app you can find in &lt;a href=&quot;https://github.com/imgly/cesdk-web-examples/blob/showcases/showcase-content-moderation/&quot;&gt;this GitHub repository&lt;/a&gt;. This demo app integrates the Sightengine moderation functionality with the CE.SDK design capabilities.&lt;/p&gt;
&lt;p&gt;Now, let’s move on to the main component where the integration takes place:&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; CreativeEditorSDK &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@cesdk/cesdk-js&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; ValidationBox &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;../ui/ValidationBox/ValidationBox&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; React, { useCallback, useEffect, useRef, 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; { ReactComponent &lt;/span&gt;&lt;span&gt;as&lt;/span&gt;&lt;span&gt; RefreshIcon } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;./refresh.svg&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; { moderateImages } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;./moderationUtils&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; styles &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;./ImageModerator.module.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; classNames &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;classnames&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; selectBlock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;cesdk&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;blockId&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // deselecting all blocks&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  cesdk.engine.block&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    .&lt;/span&gt;&lt;span&gt;findAllSelected&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;forEach&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;block&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; cesdk.engine.block.&lt;/span&gt;&lt;span&gt;setSelected&lt;/span&gt;&lt;span&gt;(block, &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // selecting the block having the blockId passed as parameter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  cesdk.engine.block.&lt;/span&gt;&lt;span&gt;setSelected&lt;/span&gt;&lt;span&gt;(blockId, &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&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; ImageModerator&lt;/span&gt;&lt;span&gt; =&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; cesdkContainerDiv&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; useRef&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; cesdkRef&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; useRef&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;validationResults&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setValidationResults&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;  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;    // initializing CE.SDK if it has not been initialized yet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; (cesdkContainerDiv.current &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; !&lt;/span&gt;&lt;span&gt;cesdkRef.current) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      const&lt;/span&gt;&lt;span&gt; config&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;        role: &lt;/span&gt;&lt;span&gt;&apos;Adopter&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        theme: &lt;/span&gt;&lt;span&gt;&apos;light&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        initialSceneURL: &lt;/span&gt;&lt;span&gt;`${&lt;/span&gt;&lt;span&gt;window&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;location&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;protocol&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; window&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;location&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;host&lt;/span&gt;&lt;span&gt;}/cases/content-moderation/example.scene`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        ui: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          elements: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            panels: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              settings: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            navigation: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              action: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                save: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        callbacks: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          // calling this function when the&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          // user presses the &quot;Save&quot; button&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          onSave&lt;/span&gt;&lt;span&gt;: () &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; runImageModerationCheck&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;      CreativeEditorSDK.&lt;/span&gt;&lt;span&gt;init&lt;/span&gt;&lt;span&gt;(cesdkContainerDiv.current, config).&lt;/span&gt;&lt;span&gt;then&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;instance&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;          cesdkRef.current &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; instance;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          // running the moderation check on initialization&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          runImageModerationCheck&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return&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; (cesdkRef.current) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        cesdkRef.current.&lt;/span&gt;&lt;span&gt;dispose&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      }&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;  }, [cesdkContainerDiv]);&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; runImageModerationCheck&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; useCallback&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;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;cesdkRef.current) {&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;    // retrieving the moderation results&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; validationResults&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; moderateImages&lt;/span&gt;&lt;span&gt;(cesdkRef.current);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    setValidationResults&lt;/span&gt;&lt;span&gt;(validationResults);&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;{&lt;/span&gt;&lt;span&gt;classNames&lt;/span&gt;&lt;span&gt;(styles.wrapper, &lt;/span&gt;&lt;span&gt;&apos;space-y-2&apos;&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; className&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{styles.header}&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;{styles.headerDiv}&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;h3&lt;/span&gt;&lt;span&gt; className&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;h4&quot;&lt;/span&gt;&lt;span&gt; style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{{ color: &lt;/span&gt;&lt;span&gt;&apos;white&apos;&lt;/span&gt;&lt;span&gt; }}&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              Content Moderation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            &amp;#x3C;/&lt;/span&gt;&lt;span&gt;h3&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; className&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{styles.headerDivMessage}&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              Check images for compliance with your content guidelines before&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              further processing and provide user feedback.&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;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;button&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            onClick&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{() &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; runImageModerationCheck&lt;/span&gt;&lt;span&gt;()}&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;{&lt;/span&gt;&lt;span&gt;&apos;button button--white space-x-2&apos;&lt;/span&gt;&lt;span&gt;}&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;span&lt;/span&gt;&lt;span&gt;&gt;Validate Image Content&amp;#x3C;/&lt;/span&gt;&lt;span&gt;span&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;RefreshIcon&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;button&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;ValidationBox&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          results&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{validationResults}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          onSelect&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{(&lt;/span&gt;&lt;span&gt;blockId&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;            selectBlock&lt;/span&gt;&lt;span&gt;(cesdkRef.current, blockId);&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;        /&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;div&lt;/span&gt;&lt;span&gt; className&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{styles.cesdkWrapper}&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; ref&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{cesdkContainerDiv} &lt;/span&gt;&lt;span&gt;className&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{styles.cesdk}&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;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;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; ImageModerator;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the first &lt;a href=&quot;https://reactjs.org/docs/hooks-effect.html&quot;&gt;&lt;code&gt;useEffect()&lt;/code&gt;&lt;/a&gt; hook, CE.SDK is initialized, and a callback on the save action is registered. This will take care of calling the &lt;code&gt;runImageModerationCheck()&lt;/code&gt; function when the user presses the CE.SDK &lt;em&gt;Save&lt;/em&gt; button. For more information on how callbacks work in CE.SDK, see &lt;a href=&quot;https://img.ly/docs/cesdk/react/concepts/events-353f97/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;the official documentation on observing events&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;runImageModerationCheck()&lt;/code&gt; retrieves the moderation results obtained from Sightengine and then stores it in the &lt;code&gt;validationResults&lt;/code&gt; array variable. This is then passed to the &lt;code&gt;ValidationBox&lt;/code&gt; component, which will show the results of the validation process to the end-user. None of this would be possible without the &lt;code&gt;moderateImages()&lt;/code&gt; function from the &lt;code&gt;moderationUtils.js&lt;/code&gt; file 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;export&lt;/span&gt;&lt;span&gt; const&lt;/span&gt;&lt;span&gt; moderateImages&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;cesdk&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;  // retrieving all image blocks with a name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; imageBlocksData&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; cesdk.engine.block&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    .&lt;/span&gt;&lt;span&gt;findByType&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;image&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;map&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;blockId&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;      blockId,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      url: cesdk.engine.block.&lt;/span&gt;&lt;span&gt;getString&lt;/span&gt;&lt;span&gt;(blockId, &lt;/span&gt;&lt;span&gt;&apos;image/imageFileURI&apos;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      blockType: cesdk.engine.block.&lt;/span&gt;&lt;span&gt;getType&lt;/span&gt;&lt;span&gt;(blockId),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      blockName: cesdk.engine.block.&lt;/span&gt;&lt;span&gt;getName&lt;/span&gt;&lt;span&gt;(blockId),&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;filter&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;block&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&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; block.blockName &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;    });&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;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;Moderation check launched...&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;  // turning the moderation results on each image block into&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // a flat array&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; imagesWithValidity&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; Promise&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;all&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    imageBlocksData.&lt;/span&gt;&lt;span&gt;flatMap&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;imageBlockData&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;      // retrieving the moderation results&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      const&lt;/span&gt;&lt;span&gt; imageModerationResults&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; callSightengineModerationAPI&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        imageBlockData.url&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;      console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(imageBlockData.blockName, imageModerationResults);&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; imageModerationResults.&lt;/span&gt;&lt;span&gt;flatMap&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;checkResult&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;checkResult,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        ...&lt;/span&gt;&lt;span&gt;imageBlockData,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      }));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;Moderation check completed&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; imagesWithValidity.&lt;/span&gt;&lt;span&gt;flat&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;// a cache variable to avoid&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// calling the Sightengine API when not necessary&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; complianceCache&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; {};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; callSightengineModerationAPI&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;url&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 the url is already present in the cache, then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // return the result previously retrieved&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (complianceCache[url]) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; complianceCache[url];&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 Sightengine moderation API&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; response&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; fetch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // your endpoint URL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &apos;https://europe-west3-img-ly.cloudfunctions.net/sightengineApiProxy?url=&apos;&lt;/span&gt;&lt;span&gt; +&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      encodeURIComponent&lt;/span&gt;&lt;span&gt;(url),&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;      method: &lt;/span&gt;&lt;span&gt;&apos;get&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      headers: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        accept: &lt;/span&gt;&lt;span&gt;&apos;application/json&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &apos;Accept-Language&apos;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&apos;en-US,en;q=0.8&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &apos;Content-Type&apos;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&apos;multipart/form-data;&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&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; results&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; response.&lt;/span&gt;&lt;span&gt;json&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; (results.error) {&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;(results.error);&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;else&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; checkResults&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;        name: &lt;/span&gt;&lt;span&gt;&apos;Weapons&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        description: &lt;/span&gt;&lt;span&gt;&apos;Handguns, rifles, machine guns, threatening knives...&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        state: &lt;/span&gt;&lt;span&gt;percentageToState&lt;/span&gt;&lt;span&gt;(results.weapon),&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;        name: &lt;/span&gt;&lt;span&gt;&apos;Alcohol&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        description: &lt;/span&gt;&lt;span&gt;&apos;Wine, beer, cocktails, champagne...&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        state: &lt;/span&gt;&lt;span&gt;percentageToState&lt;/span&gt;&lt;span&gt;(results.alcohol),&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;        name: &lt;/span&gt;&lt;span&gt;&apos;Drugs&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        description: &lt;/span&gt;&lt;span&gt;&apos;Cannabis, syringes, glass pipes, bongs, pills...&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        state: &lt;/span&gt;&lt;span&gt;percentageToState&lt;/span&gt;&lt;span&gt;(results.drugs),&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;        name: &lt;/span&gt;&lt;span&gt;&apos;Nudity&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        description: &lt;/span&gt;&lt;span&gt;&apos;Images that contain either raw nudity or partial nudity.&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        state: &lt;/span&gt;&lt;span&gt;percentageToState&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; results.nudity.safe),&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;    // storing the Sightengine results in the cache&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    complianceCache[url] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; checkResults;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; checkResults;&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; percentageToState&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;percentage&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;  // defining the custom moderation logic based on the&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // percentage returned by Sightengine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (percentage &lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; 0.8&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; &apos;failed&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;else&lt;/span&gt;&lt;span&gt; if&lt;/span&gt;&lt;span&gt; (percentage &lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; 0.4&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; &apos;warning&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;else&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; &apos;success&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we use the CE.SDK reference variable to retrieve all images in the scene through the CE.SDK APIs. Then, these are converted into URLs and passed &lt;code&gt;callSightengineModerationAPI()&lt;/code&gt; function, which takes care of calling the Sightengine moderation API, retrieving the results, using them to produce a new output, and returning it to the caller.&lt;/p&gt;
&lt;p&gt;We used an IMG.LY endpoint here to evade putting together a backend application. In a real-world scenario, replace &lt;code&gt;https://europe-west3-img-ly.cloudfunctions.net/sightengineApiProxy?url=&lt;/code&gt; with the URL of the &lt;code&gt;/content-moderation&lt;/code&gt; endpoint of your backend application. Also, note that a cache system was set up to avoid calling the Sightengine API too many times and using up call credits.&lt;/p&gt;
&lt;p&gt;This is what the demo application will look like after being launched and the moderation check has been executed:&lt;br&gt;
&lt;img alt=&quot;live-action-moderation&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1918px) 1918px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1918&quot; height=&quot;928&quot; src=&quot;https://img.ly/_astro/live-action-moderation_g22UQ.webp&quot; srcset=&quot;/_astro/live-action-moderation_xu23A.webp 640w, /_astro/live-action-moderation_2lOxOG.webp 750w, /_astro/live-action-moderation_Pdqj8.webp 828w, /_astro/live-action-moderation_Z1AnpCm.webp 1080w, /_astro/live-action-moderation_1LCvNP.webp 1280w, /_astro/live-action-moderation_ZQcY5P.webp 1668w, /_astro/live-action-moderation_g22UQ.webp 1918w&quot;&gt;&lt;/p&gt;
&lt;p&gt;As you can see, the Sightengine API correctly detects &lt;em&gt;drugs&lt;/em&gt; and &lt;em&gt;weapons&lt;/em&gt;. Next, remove the rightmost image containing a gun and click &lt;em&gt;Save&lt;/em&gt; to re-run the moderation check.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;detection&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1920px) 1920px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1920&quot; height=&quot;931&quot; src=&quot;https://img.ly/_astro/detection_ZflnCz.webp&quot; srcset=&quot;/_astro/detection_ZBLsO1.webp 640w, /_astro/detection_1CcGPE.webp 750w, /_astro/detection_1ADxoj.webp 828w, /_astro/detection_Z2sj5RQ.webp 1080w, /_astro/detection_Z256mPV.webp 1280w, /_astro/detection_1QiKB5.webp 1668w, /_astro/detection_ZflnCz.webp 1920w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Sightengine no longer detects weapons in the image, proving that the moderation process is working as expected.&lt;/p&gt;
&lt;p&gt;Et voilà! You have learned to implement content moderation for user-generated images with CE.SDK and Sightengine.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;A challenge of user-generated content is avoiding the risk of hosting and displaying offensive or outright illegal content. Inappropriate content affects your user community and brand reputation and may even cause legal action against you.&lt;/p&gt;
&lt;p&gt;In this article, we used CE.SDK to initialize a fully-featured design editor in React. We employed its API to programmatically call a Node.js server using Sightengine to perform content moderation on images. This allows moderation of user-generated content automatically and prevents the upload of inappropriate content to your website.&lt;/p&gt;
&lt;p&gt;We are only scratching the surface of what is possible with CE.SDK – you can implement any UI on top of its powerful image processing API and extend the core functionality with features such as &lt;a href=&quot;https://img.ly/showcases/cesdk/web/placeholders/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;placeholders&lt;/a&gt; and define &lt;a href=&quot;https://img.ly/showcases/cesdk/web/design-validation/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;validation rules&lt;/a&gt; to guide your users’ creation process.&lt;/p&gt;
&lt;p&gt;Thanks for reading! We hope that you found this article helpful. Feel free to reach out on &lt;a href=&quot;https://twitter.com/imgly&quot;&gt;Twitter&lt;/a&gt; with any questions, comments, or suggestions.&lt;/p&gt;</content:encoded><dc:creator>Antonello</dc:creator><media:content url="https://blog.img.ly/2022/09/content-moderation-image-upload.png" medium="image"/><category>How-To</category><category>Automation</category><category>Web Development</category><category>Design Editor</category><category>Image Editing</category><category>Learning</category></item><item><title>How To Add Overlays to a Video in React Native</title><link>https://img.ly/blog/how-to-add-overlays-to-a-video-in-react-native/</link><guid isPermaLink="true">https://img.ly/blog/how-to-add-overlays-to-a-video-in-react-native/</guid><description>Learn how to place text or images over your videos in React Native.</description><pubDate>Mon, 28 Mar 2022 16:23:32 GMT</pubDate><content:encoded>&lt;p&gt;In this article, you will learn to add a text and image overlay to a video with JavaScript in &lt;a href=&quot;https://reactnative.dev/&quot;&gt;React Native&lt;/a&gt;. All you need is &lt;a href=&quot;https://github.com/TheWidlarzGroup/react-native-video&quot;&gt;React Native Video&lt;/a&gt;, the correct styling rules, and just a few lines of code.&lt;/p&gt;
&lt;p&gt;By following this guide, you will easily achieve a logo and text overlay:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;qtNLErZ&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 188px) 188px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;188&quot; height=&quot;400&quot; src=&quot;https://img.ly/_astro/qtNLErZ_Z1IVhSU.webp&quot; srcset=&quot;/_astro/qtNLErZ_Z1IVhSU.webp 188w&quot;&gt;&lt;/p&gt;
&lt;p&gt;First, let’s learn how to implement a React Native component that allows you to add an overlay image and overlay text to a video.&lt;/p&gt;
&lt;h2 id=&quot;what-is-react-native-video&quot;&gt;What is React Native Video?&lt;/h2&gt;
&lt;p&gt;Mobile apps come with several native interfaces and features. This is what makes React Native different from React, which is based on browser rendering. So, &lt;code&gt;&amp;#x3C;div&gt;&lt;/code&gt; becomes &lt;a href=&quot;https://reactnative.dev/docs/view&quot;&gt;&lt;code&gt;&amp;#x3C;View&gt;&lt;/code&gt;&lt;/a&gt;, &lt;code&gt;&amp;#x3C;p&gt;&lt;/code&gt; becomes &lt;a href=&quot;https://reactnative.dev/docs/text&quot;&gt;&lt;code&gt;&amp;#x3C;Text&gt;&lt;/code&gt;&lt;/a&gt;, and so on. In particular, React Native supports only a limited amount of components. You can find the entire list &lt;a href=&quot;https://reactnative.dev/docs/components-and-apis&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To this day, React Native does not have a native &lt;code&gt;&amp;#x3C;Video&gt;&lt;/code&gt; component. That is why &lt;code&gt;react-native-video&lt;/code&gt; was born - a widely used library without considering alternatives. This 500kB package equips you with everything you need to get started with videos in React Native.&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;Here 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;7+&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/react-native&quot;&gt;&lt;code&gt;react-native&lt;/code&gt;&lt;/a&gt; &gt;= 0.6x&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/react-native-video&quot;&gt;&lt;code&gt;react-native-video&lt;/code&gt;&lt;/a&gt; &gt;= 5.x&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can add &lt;code&gt;react-native-video&lt;/code&gt; to your project’s dependencies by launching the following npm 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 react-native-video&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or if you are a yarn user:&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;yarn add react-native-video&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, follow &lt;a href=&quot;https://github.com/TheWidlarzGroup/react-native-video#installation&quot;&gt;this&lt;/a&gt; guide to learn how to link &lt;code&gt;react-native-video&lt;/code&gt; to your project. This step is not required for Android users with React Native 0.60 and above.&lt;/p&gt;
&lt;h2 id=&quot;adding-overlay-image-and-text-to-a-video-in-react-native&quot;&gt;Adding Overlay Image and Text to a Video in React Native&lt;/h2&gt;
&lt;p&gt;You can clone the &lt;a href=&quot;https://github.com/Tonel/how-to-add-overlays-to-videos-in-react-native-imgly&quot;&gt;GitHub repository supporting this article&lt;/a&gt; and launch the following commands to try the demo application:&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-add-overlays-to-videos-in-react-native-imgly&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cd how-to-add-overlays-to-videos-in-react-native-imgly&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm i&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The project is a React Native Create App project, and you can learn more about how it works and how to run it &lt;a href=&quot;https://reactnative.dev/blog/2017/03/13/introducing-create-react-native-app&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Otherwise, keep following this step-by-step tutorial and learn how to build a React Native component for adding overlays to a video.&lt;/p&gt;
&lt;h3 id=&quot;1-initializing-a-react-native-project&quot;&gt;1. Initializing a React Native Project&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://reactnative.dev/blog/2017/03/13/introducing-create-react-native-app&quot;&gt;Create React Native App&lt;/a&gt; is the officially supported and easiest way to create an empty and working React Native application. Install it globally 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;npm install -g create-react-native-app&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, you can initialize a new project called &lt;code&gt;react-native-video-overlays-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;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;create-react-native-app react-native-video-overlays-demo&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;react-native-video-overlays-demo&lt;/code&gt; folder should now contain a demo project with the following 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-native-video-overlays-demo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── .buckconfig&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── .gitattributes&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;├── App.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── app.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── babel.config.js&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;├── metro.config.js&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;├── package-lock.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── yarn.lock&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── android&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   └── ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;└── ios&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;Enter the &lt;code&gt;react-native-video-overlays-demo&lt;/code&gt; folder:&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;cd react-native-video-overlays-demo&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then launch the development server with one of the following commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;for launching an &lt;a href=&quot;https://expo.dev/&quot;&gt;Expo&lt;/a&gt; app&lt;/li&gt;
&lt;/ul&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 start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;for Android development on your phone or an emulator&lt;/li&gt;
&lt;/ul&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 run android&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;for iOS development on your phone or an emulator&lt;/li&gt;
&lt;/ul&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 run ios&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;for &lt;a href=&quot;https://github.com/necolas/react-native-web&quot;&gt;&lt;code&gt;react-native-web&lt;/code&gt;&lt;/a&gt; development&lt;/li&gt;
&lt;/ul&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 run web&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;2-defining-a-component-to-add-overlays-on-a-video&quot;&gt;2. Defining a Component to Add Overlays on a Video&lt;/h3&gt;
&lt;p&gt;Let’s see how to build a &lt;code&gt;VideoWithOverlays&lt;/code&gt; component that allows you to add overlays such as text and an image to a video. You can implement it as follows:&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; React, { 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;import&lt;/span&gt;&lt;span&gt; { Image, StyleSheet, Text, View } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;react-native&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; Video &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;react-native-video&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; default&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; VideoWithOverlays&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  videoComponentProps&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  text&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  imageSrc&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;  const&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    video&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    overlayText&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    videoWithOverlays&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    overlayTextView&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    overlayImageView&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    overlayImage&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  } &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; styles;&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;height&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setHeight&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;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; [&lt;/span&gt;&lt;span&gt;overlayHeight&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setOverlayHeight&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;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 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;    // setting the overlay height to 10px starting&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // from the bottom of the video&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    setOverlayHeight&lt;/span&gt;&lt;span&gt;(height &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt; +&lt;/span&gt;&lt;span&gt; height &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; 3&lt;/span&gt;&lt;span&gt; -&lt;/span&gt;&lt;span&gt; 10&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }, [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;  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;View&lt;/span&gt;&lt;span&gt; style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{videoWithOverlays}&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;Video&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;videoComponentProps}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{video}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        onLayout&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;          const&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;height&lt;/span&gt;&lt;span&gt; } &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; event.nativeEvent.layout;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          setHeight&lt;/span&gt;&lt;span&gt;(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;      /&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;View&lt;/span&gt;&lt;span&gt; style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{{ &lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;overlayTextView, top: overlayHeight }}&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        {text &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; &amp;#x3C;&lt;/span&gt;&lt;span&gt;Text&lt;/span&gt;&lt;span&gt; style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{overlayText}&gt;{text}&amp;#x3C;/&lt;/span&gt;&lt;span&gt;Text&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;View&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;View&lt;/span&gt;&lt;span&gt; style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{{ &lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;overlayImageView, top: overlayHeight }}&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        {imageSrc &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;Image&lt;/span&gt;&lt;span&gt; style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{overlayImage} &lt;/span&gt;&lt;span&gt;source&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{imageSrc} &lt;/span&gt;&lt;span&gt;resizeMode&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;contain&quot;&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;View&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;View&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;const&lt;/span&gt;&lt;span&gt; styles&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; StyleSheet.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  overlayTextView: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    position: &lt;/span&gt;&lt;span&gt;&apos;relative&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    alignItems: &lt;/span&gt;&lt;span&gt;&apos;flex-end&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    justifyContent: &lt;/span&gt;&lt;span&gt;&apos;flex-end&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    right: &lt;/span&gt;&lt;span&gt;5&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;  overlayImageView: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    position: &lt;/span&gt;&lt;span&gt;&apos;relative&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    alignItems: &lt;/span&gt;&lt;span&gt;&apos;flex-start&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    justifyContent: &lt;/span&gt;&lt;span&gt;&apos;flex-end&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    left: &lt;/span&gt;&lt;span&gt;5&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;  overlayImage: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    position: &lt;/span&gt;&lt;span&gt;&apos;absolute&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    height: &lt;/span&gt;&lt;span&gt;40&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;  overlayText: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    fontSize: &lt;/span&gt;&lt;span&gt;25&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    fontWeight: &lt;/span&gt;&lt;span&gt;&apos;bold&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    color: &lt;/span&gt;&lt;span&gt;&apos;white&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;  video: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    position: &lt;/span&gt;&lt;span&gt;&apos;absolute&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    top: &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;    left: &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;    bottom: &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;    right: &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;    marginTop: &lt;/span&gt;&lt;span&gt;&apos;50%&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;  videoWithOverlays: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    position: &lt;/span&gt;&lt;span&gt;&apos;absolute&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    top: &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;    left: &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;    bottom: &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;    right: &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;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;react-native-video&lt;/code&gt; &lt;code&gt;Video&lt;/code&gt; component is used to play the video and its props are exposed thanks to the &lt;code&gt;videoComponentProps&lt;/code&gt; prop. Then, after being placed into the layout, its height depending on the size of the device screen is stored in the &lt;code&gt;height&lt;/code&gt; variable. This is used to calculate the height the overlays should be placed at in the &lt;a href=&quot;https://legacy.reactjs.org/docs/hooks-effect.html&quot;&gt;&lt;code&gt;useEffect&lt;/code&gt;&lt;/a&gt; hook. In detail, the overlays are placed at 10px from the bottom edge of the video.&lt;/p&gt;
&lt;p&gt;The first internal &lt;code&gt;View&lt;/code&gt; represents the optional text overlay. The overlay logic depends entirely on the custom &lt;code&gt;overlayTextView&lt;/code&gt; and &lt;code&gt;overlayText&lt;/code&gt; &lt;a href=&quot;https://reactnative.dev/docs/stylesheet&quot;&gt;StyleSheet&lt;/a&gt; fields, representing the CSS classes responsible for displaying the text passed as a prop with &lt;code&gt;text&lt;/code&gt; as an overlay. By default, the text overlay is placed in the bottom-right corner of the video.&lt;/p&gt;
&lt;p&gt;The second internal &lt;code&gt;View&lt;/code&gt; represents the optional image overlay. The overlay logic depends entirely on the custom &lt;code&gt;overlayImageView&lt;/code&gt; and &lt;code&gt;overlayImage&lt;/code&gt; &lt;a href=&quot;https://reactnative.dev/docs/stylesheet&quot;&gt;StyleSheet&lt;/a&gt; fields, representing the CSS classes taking care of showing the image passed as a prop with &lt;code&gt;imageSrc&lt;/code&gt; as an overlay. By default, the image overlay is placed in the bottom-left corner of the video. As you can see, both overlays are optional.&lt;/p&gt;
&lt;h3 id=&quot;3-putting-it-all-together&quot;&gt;3. Putting It All Together&lt;/h3&gt;
&lt;p&gt;Let’s see the &lt;code&gt;VideoWithOverlays&lt;/code&gt; component defined above in action. All you need to do is replace the &lt;code&gt;App.js&lt;/code&gt; file with this:&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; 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;import&lt;/span&gt;&lt;span&gt; { StyleSheet, View } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;react-native&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; VideoWithOverlays &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;./src/components/VideoWithOverlays/VideoWithOverlays&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; default&lt;/span&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;  // a static image stored into the assets folder&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; imgLy&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; require&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;./src/assets/images/IMG_LY.png&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;View&lt;/span&gt;&lt;span&gt; style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{styles.container}&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;VideoWithOverlays&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        videoComponentProps&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;          // replace this free video source with your video&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          source: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            uri: &lt;/span&gt;&lt;span&gt;&apos;https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          },&lt;/span&gt;&lt;/span&gt;
&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;        // overlay text&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        text&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&apos;IMG.LY&apos;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // overlay image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        imageSrc&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{imgLy}&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;View&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;const&lt;/span&gt;&lt;span&gt; styles&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; StyleSheet.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  container: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    flex: &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;    backgroundColor: &lt;/span&gt;&lt;span&gt;&apos;#fff&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    alignItems: &lt;/span&gt;&lt;span&gt;&apos;center&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    justifyContent: &lt;/span&gt;&lt;span&gt;&apos;center&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, &lt;code&gt;&amp;#x3C;VideoWitOverlays&gt;&lt;/code&gt; is initialized with a free video source retrieved from a public URL and two overlays. The text overlay states “IMG.LY” and it is placed in the bottom-right corner of the video. While the image overlay represents the IMG.LY logo and is placed in the bottom-left corner of the video. This is a screenshot of the &lt;code&gt;VideoWitOverlays&lt;/code&gt; in action:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;react-native-video-add-text-image&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 189px) 189px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;189&quot; height=&quot;400&quot; src=&quot;https://img.ly/_astro/react-native-video-add-text-image_Z1GJNu7.webp&quot; srcset=&quot;/_astro/react-native-video-add-text-image_Z1GJNu7.webp 189w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;final-considerations&quot;&gt;Final Considerations&lt;/h2&gt;
&lt;p&gt;Adding overlays elements to a video in React Native is not complex and takes just a few lines of code. On the other hand, the approach presented above is just a frontend trick and does not modify the video. You are just showing it behind text or an image, giving the illusion to the users that it is a single source of content.&lt;/p&gt;
&lt;p&gt;If you wanted to let users modify their videos by adding overlays or other elements and then export them, this would involve complex logic and require an advanced UI. Building such a React Native component is a time-consuming task that represents a waste of energy. If that is your goal, you should take into consideration a complete and ready-to-use SDK solution, such as &lt;a href=&quot;https://img.ly/products/video-sdk&quot;&gt;VideoEditorSDK&lt;/a&gt;. This would provide your users with the ability to add overlays and use many other cool features.&lt;/p&gt;
&lt;h2 id=&quot;add-overlays-to-a-video-with-react-native-module-for-videoeditor-sdk&quot;&gt;Add Overlays to a Video With &lt;a href=&quot;https://www.npmjs.com/package/react-native-videoeditorsdk&quot;&gt;React Native module for VideoEditor SDK&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Visit &lt;a href=&quot;https://img.ly/docs/pesdk/react-native/getting-started/integration/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;this&lt;/a&gt; page from the official documentation to learn how to get started with VideoEditorSDK in React Native. Then, load your video and start editing it by adding &lt;a href=&quot;https://img.ly/docs/vesdk/android/guides/overlays/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;overlays&lt;/a&gt;, &lt;a href=&quot;https://img.ly/docs/vesdk/android/guides/text-fonts/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;text&lt;/a&gt;, and &lt;a href=&quot;https://img.ly/docs/vesdk/android/guides/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;stickers&lt;/a&gt;. Follow the previous links to learn more about each feature.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;add-image-text-to-video-react-native&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 333px) 333px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;333&quot; height=&quot;685&quot; src=&quot;https://img.ly/_astro/add-image-text-to-video-react-native_1Mw6kk.webp&quot; srcset=&quot;/_astro/add-image-text-to-video-react-native_1Mw6kk.webp 333w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Download our free mobile demo app from the &lt;a href=&quot;https://apps.apple.com/us/app/img-ly-photo-video-editor/id589839231&quot;&gt;App Store&lt;/a&gt; or &lt;a href=&quot;https://play.google.com/store/apps/details?id=com.photoeditorsdk.android.app&quot;&gt;Google Play&lt;/a&gt;, and try an extensive set of tools to edit videos.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial, we learned how to define a React Native component that allows you to reproduce a video and add overlays. Specifically, we used &lt;code&gt;react-native-video&lt;/code&gt; and defined everything required to place text or an image on your video. However, if you intend to export your edit, you will have to build a complex video editing application. In this scenario, you will want to consider a fully-featured, cutting-edge, and easy-to-adopt solution – such as &lt;a href=&quot;https://img.ly/products/video-sdk?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;VideoEditorSDK&lt;/a&gt;.&lt;br&gt;
Looking for more video capabilities? Check out our solution for &lt;a href=&quot;https://img.ly/use-cases/story-reels-short-video-creation&quot;&gt;Short Video Creation&lt;/a&gt;, and &lt;a href=&quot;https://img.ly/products/camera-sdk&quot;&gt;Camera 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/03/add-image-text-to-video-react-native-mobile-3.png" medium="image"/><category>How-To</category><category>Image Editing</category><category>Video Editing</category><category>React Native</category><category>React</category><category>Mobile App Development</category><category>Tech</category><category>Tutorial</category></item><item><title>How To Add a Sticker to a Texture With Three.js</title><link>https://img.ly/blog/how-to-add-a-sticker-to-a-texture-with-three-js/</link><guid isPermaLink="true">https://img.ly/blog/how-to-add-a-sticker-to-a-texture-with-three-js/</guid><description>Learn how to add an overlay image to your textures in WebGL and JavaScript with Three.js.</description><pubDate>Fri, 25 Feb 2022 15:10:58 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;Disclaimer: This article has been updated in June 2023 to reflect the changes introduced by &lt;a href=&quot;https://github.com/mrdoob/three.js/wiki/Migration-Guide#149--150&quot;&gt;Three.js r150&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In this article, you will learn to add a sticker to a texture with &lt;a href=&quot;https://get.webgl.org/&quot;&gt;WebGL&lt;/a&gt;. In detail, you will see how to use the &lt;a href=&quot;https://threejs.org/&quot;&gt;Three.js&lt;/a&gt; JavaScript library to add an overlay image to a texture. Check out our guide to explore other image editing operations, such as &lt;a href=&quot;https://img.ly/blog/how-to-resize-an-image-in-react/&quot;&gt;resizing an image in React&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Dealing with 3D graphics used to be a challenging, complex, and time-consuming task. Thanks to libraries like &lt;code&gt;three.js&lt;/code&gt;, it has become more accessible than ever. Follow this easy step-by-step how-to and achieve the following result:&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;Here are all the prerequisites you need to meet to follow this tutorial and build the demo application shown above:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/en&quot;&gt;Node.js &gt;= 18&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mrdoob/three.js&quot;&gt;Three.js &gt;= r150&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Explore the official documentation page to learn about &lt;a href=&quot;https://threejs.org/docs/#manual/en/introduction/Installation&quot;&gt;how to install &lt;code&gt;three.js&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-is-threejs&quot;&gt;What is Three.js?&lt;/h2&gt;
&lt;p&gt;As stated in the &lt;a href=&quot;https://github.com/mrdoob/three.js/&quot;&gt;GitHub page of the project&lt;/a&gt;, the goal of the Three.js project is to create a lightweight 3D JavaScript library with a very low level of complexity. In other words, Three.js aims to make 3D graphics more accessible, especially considering that Three.js only requires a browser to run.&lt;/p&gt;
&lt;p&gt;To be more specific, it allows you to create a 3D graphics project where you can modify elements in your browser and see visual feedback. The library is currently built on top of a &lt;a href=&quot;https://threejs.org/docs/#api/en/renderers/WebGLRenderer&quot;&gt;WebGL renderer&lt;/a&gt;, but it also supports &lt;a href=&quot;https://en.wikipedia.org/wiki/WebGPU&quot;&gt;WebGPU&lt;/a&gt;, &lt;a href=&quot;https://threejs.org/docs/#examples/en/renderers/SVGRenderer&quot;&gt;SVG&lt;/a&gt;, and &lt;a href=&quot;https://threejs.org/docs/#examples/en/renderers/CSS3DRenderer&quot;&gt;CSS3D&lt;/a&gt; renderers.&lt;/p&gt;
&lt;p&gt;If you are not familiar with these concepts, &lt;a href=&quot;https://en.wikipedia.org/wiki/WebGL&quot;&gt;WebGL&lt;/a&gt; stands for “Web Graphics Library” and is a JavaScript API for rendering high-performance interactive 3D and 2D graphics. You can use it in many web browsers without external plugins or libraries.&lt;/p&gt;
&lt;p&gt;As you can verify from the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API#browser_compatibility&quot;&gt;MDN compatibility page&lt;/a&gt;, browsers currently support the most popular WebGL features. However, keep in mind that the user’s device must meet hardware requirements for some features to work.&lt;/p&gt;
&lt;p&gt;WebGL is undoubtedly a powerful tool but requires a lot of skill and involves a lot of boilerplate code. Here is where Three.js comes into play, making 3D development much easier.&lt;/p&gt;
&lt;p&gt;Now, let’s see it in action!&lt;/p&gt;
&lt;h2 id=&quot;adding-an-overlay-image-to-a-texture-in-webgl&quot;&gt;Adding an Overlay Image to a Texture in WebGL&lt;/h2&gt;
&lt;p&gt;Clone the &lt;a href=&quot;https://github.com/Tonel/how-to-add-a-sticker-with-threejs-imgly&quot;&gt;GitHub repository that supports this article&lt;/a&gt; with the following commands:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;git&lt;/span&gt;&lt;span&gt; clone&lt;/span&gt;&lt;span&gt; https://github.com/Tonel/how-to-add-a-sticker-with-threejs-imgly&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Additionally, try the demo application by launchingthe command below:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; run&lt;/span&gt;&lt;span&gt; start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, visit &lt;code&gt;http://localhost:5000&lt;/code&gt; in the browser.&lt;/p&gt;
&lt;p&gt;Now that you know what the demo app looks like, keep following this tutorial and learn how to build it.&lt;/p&gt;
&lt;p&gt;Specifically, this is the entire JavaScript code required to achieve the goal:&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; *&lt;/span&gt;&lt;span&gt; as&lt;/span&gt;&lt;span&gt; THREE &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;three&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; { OrbitControls } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;three/addons/controls/OrbitControls.js&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;// set up the scene, camera, and renderer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; scene&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; THREE&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Scene&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; camera&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; THREE&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PerspectiveCamera&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  40&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  window.innerWidth &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; window.innerHeight,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&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;  1000&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;camera.position.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;150&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;150&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; OrbitControls&lt;/span&gt;&lt;span&gt;(camera, document.body);&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;// initialize the WebGL renderer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; renderer&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; THREE&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WebGLRenderer&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;renderer.&lt;/span&gt;&lt;span&gt;setSize&lt;/span&gt;&lt;span&gt;(window.innerWidth, window.innerHeight);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;document.body.&lt;/span&gt;&lt;span&gt;appendChild&lt;/span&gt;&lt;span&gt;(renderer.domElement);&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;// add light to the scene to make the texture visible&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; light&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; THREE&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AmbientLight&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0xffffff&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;scene.&lt;/span&gt;&lt;span&gt;add&lt;/span&gt;&lt;span&gt;(light);&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;// add the axes helper indicator to the scene&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;scene.&lt;/span&gt;&lt;span&gt;add&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; THREE&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AxesHelper&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;20&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;// load the base 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; new&lt;/span&gt;&lt;span&gt; THREE&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;TextureLoader&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;load&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;https://threejs.org/examples/textures/hardwood2_diffuse.jpg&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// create a new buffer geometry and place it&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// to the horizontal plane&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; textureGeometry&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; THREE&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PlaneGeometry&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;50&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;50&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;textureGeometry.&lt;/span&gt;&lt;span&gt;rotateX&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;90&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; THREE&lt;/span&gt;&lt;span&gt;.MathUtils.&lt;/span&gt;&lt;span&gt;DEG2RAD&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// translate the plane to the center of the scene&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;textureGeometry.&lt;/span&gt;&lt;span&gt;translate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;25&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;25&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;// create a MeshBasicMaterial with the base texture&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; textureMaterial&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; THREE&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;MeshBasicMaterial&lt;/span&gt;&lt;span&gt;({ map: texture });&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;// create a mesh using the geometry and material&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// and add it to the scene&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; textureMesh&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; THREE&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Mesh&lt;/span&gt;&lt;span&gt;(textureGeometry, textureMaterial);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;scene.&lt;/span&gt;&lt;span&gt;add&lt;/span&gt;&lt;span&gt;(textureMesh);&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;// repeat the same logic to place the sticker image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// over the texture&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; sticker&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; THREE&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;TextureLoader&lt;/span&gt;&lt;span&gt;().&lt;/span&gt;&lt;span&gt;load&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;https://i.imgur.com/IYh17Rv.png&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; stickerGeometry&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; THREE&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PlaneGeometry&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;20&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;20&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;stickerGeometry.&lt;/span&gt;&lt;span&gt;rotateX&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;90&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; THREE&lt;/span&gt;&lt;span&gt;.MathUtils.&lt;/span&gt;&lt;span&gt;DEG2RAD&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;stickerGeometry.&lt;/span&gt;&lt;span&gt;translate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;25&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;25&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; stickerMaterial&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; THREE&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;MeshBasicMaterial&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  map: sticker,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  transparent: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// create a mesh using the image geometry and material&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; imageMesh&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; THREE&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Mesh&lt;/span&gt;&lt;span&gt;(stickerGeometry, stickerMaterial);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;scene.&lt;/span&gt;&lt;span&gt;add&lt;/span&gt;&lt;span&gt;(imageMesh);&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;// adjust the position and rotation of the sticker mesh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// by setting the y-coordinate to 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// in order for the sticker to rest on the texture&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;imageMesh.position.&lt;/span&gt;&lt;span&gt;set&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;1&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// render the scene&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; launchThreeJs&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  requestAnimationFrame&lt;/span&gt;&lt;span&gt;(launchThreeJs);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  renderer.&lt;/span&gt;&lt;span&gt;render&lt;/span&gt;&lt;span&gt;(scene, camera);&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;launchThreeJs&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First, the code imports the necessary components from the Three.js library. Next, it initialize a &lt;a href=&quot;https://threejs.org/docs/#api/en/scenes/Scene&quot;&gt;&lt;code&gt;Scene&lt;/code&gt;&lt;/a&gt; and set up a &lt;a href=&quot;https://threejs.org/docs/#api/en/cameras/PerspectiveCamera&quot;&gt;&lt;code&gt;PerspectiveCamera&lt;/code&gt;&lt;/a&gt; with &lt;a href=&quot;https://threejs.org/docs/#examples/en/controls/OrbitControls&quot;&gt;&lt;code&gt;OrbitsControl&lt;/code&gt;&lt;/a&gt;, allowing the user to move around. Then, it creates a WebGL renderer and sets its size to match the window’s dimensions. The scene is lit by an &lt;a href=&quot;https://threejs.org/docs/#api/en/lights/AmbientLight&quot;&gt;&lt;code&gt;AmbientLight&lt;/code&gt;&lt;/a&gt; instance, which illuminates all objects in the scene equally.&lt;/p&gt;
&lt;p&gt;The snippet loads a base texture using TextureLoader from the given URL, creates a &lt;a href=&quot;https://threejs.org/docs/#api/en/geometries/PlaneGeometry&quot;&gt;&lt;code&gt;PlaneGeometry&lt;/code&gt;&lt;/a&gt;, defines a mesh with some geometries, and then add the resulting element to the scene. This logic will take care of rendering the texture image in the scene.&lt;/p&gt;
&lt;p&gt;To add the sticker to the texture, the same procude gets repeated. This time, Three.js is instructed to load a sticker image and position it over the original texture. Note that the position of the sticker mesh is adjusted by setting its y-coordinate to 1 to ensure the new image rests on top of the old one.&lt;/p&gt;
&lt;p&gt;Et voilà! You just learned how to add a sticker to a WebGL texture with &lt;code&gt;three.js&lt;/code&gt;!&lt;/p&gt;
&lt;h2 id=&quot;adding-a-sticker-with-photoeditorsdk&quot;&gt;Adding a Sticker With &lt;a href=&quot;https://www.npmjs.com/package/photoeditorsdk&quot;&gt;&lt;code&gt;PHOTOEDITORSDK&lt;/code&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&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;PhotoEditorSDK uses WebGL as the main renderer&lt;/a&gt;. You can effortlessly add a sticker to your textures without writing any line of code. WebGL will be used behind the scene. Consequently, you do not need to know WebGL or code in GLSL to harness its power.&lt;/p&gt;
&lt;p&gt;Adding a sticker to an image only takes a few seconds here. Just jump to &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 article&lt;/a&gt; from the official documentation and learn how to get started with PhotoEditorSDK in Vanilla JavaScript. Then, upload your texture image and a sticker with the &lt;a href=&quot;https://img.ly/docs/pesdk/web/features/stickers/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;Sticker feature&lt;/a&gt;. As shown below, you can position a sticker on top of the original image with a point-and-click UI:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;how-add-sticker-to-texture-image-three-js-webgl&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 700px) 700px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;700&quot; height=&quot;376&quot; src=&quot;https://img.ly/_astro/how-add-sticker-to-texture-image-three-js-webgl_1IEwVR.webp&quot; srcset=&quot;/_astro/how-add-sticker-to-texture-image-three-js-webgl_29mIIu.webp 640w, /_astro/how-add-sticker-to-texture-image-three-js-webgl_1IEwVR.webp 700w&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;PhotoEditorSDK demo page&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Today we learned how to add an overlay image to a WebGL texture in JavaScript with &lt;code&gt;three.js&lt;/code&gt;. This tool makes it easier to deal with WebGL and 3D graphics. In particular, by using one of the many plugins supporting the Three.js project, we were able to add a sticker to a texture with just a bunch of lines of code.&lt;/p&gt;
&lt;p&gt;3D graphics remains a complex topic, especially when it comes to developing in the OpenGL Shading Language. Three.js tries to hide this encumbrance as much as possible, but sometimes you still require it. If you want to avoid using WebGL directly to achieve your goal, consider an all-in-one and easy-to-use solution – such as &lt;a href=&quot;https://img.ly/products/photo-sdk&quot;&gt;PhotoEditorSDK&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;p&gt;&lt;strong&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;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Antonello</dc:creator><media:content url="https://blog.img.ly/2022/02/add-sticker-to-image-texture-three-js-threejs.png" medium="image"/><category>How-To</category><category>Image Editing</category><category>Image Processing</category><category>3D</category><category>Photo Editing</category><category>Stickers</category><category>Tech</category><category>Tutorial</category></item><item><title>How To Scale, Crop, Flip, and Filter an Image in CSS</title><link>https://img.ly/blog/how-to-scale-crop-flip-and-filter-an-image-in-css/</link><guid isPermaLink="true">https://img.ly/blog/how-to-scale-crop-flip-and-filter-an-image-in-css/</guid><description>Learn how to use CSS to perform the most common image processing manipulations.</description><pubDate>Wed, 09 Feb 2022 19:41:38 GMT</pubDate><content:encoded>&lt;p&gt;In this article, you will learn how to perform popular image processing operations in CSS. That is possible thanks to the several features introduced by CSS3, which allow you to change how the images look to end-users. To learn instead about image manipulation operations for other frameworks, you can head on here: &lt;a href=&quot;https://img.ly/blog/how-to-resize-an-image-with-javascript/&quot;&gt;React&lt;/a&gt; or &lt;a href=&quot;https://img.ly/blog/how-to-resize-an-image-with-javascript/&quot;&gt;vanilla JS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;First, let’s delve into how image manipulation works in CSS. Then, let’s finally see the most common CSS image processing operations in action.&lt;/p&gt;
&lt;h2 id=&quot;how-css-image-manipulation-work&quot;&gt;How CSS Image Manipulation Work&lt;/h2&gt;
&lt;p&gt;CSS does not allow you to deal with files, data formats, or data transformation. In other words, CSS cannot change an image on a deep level, yet with CSS, you can determine how a browser displays elements.&lt;/p&gt;
&lt;p&gt;As a result, as opposed to what would happen when using an HTML &lt;code&gt;canvas&lt;/code&gt; element, no pixel manipulation will be executed behind-the-scene. Therefore, your CSS rules won’t affect the file that represents your image. What changes is how your image is displayed frontend-side.&lt;/p&gt;
&lt;p&gt;You can flip, blur, and crop an image in CSS, but when downloading the image with the right-click option, the image saved will always be a copy of the original image file. Read &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Replaced_element&quot;&gt;this&lt;/a&gt; page from MDN Web Docs, if you want to learn more about this phenomenon.&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;The CSS properties you will see are widely based on CSS3 and are not supported by Internet Explorer. To verify if your target browsers support a CSS property, visit &lt;a href=&quot;https://developer.mozilla.org/en-US/&quot;&gt;MDN Web Docs&lt;/a&gt; and explore the &lt;em&gt;Browser compatibility&lt;/em&gt; section.&lt;/p&gt;
&lt;h2 id=&quot;image-processing-in-css&quot;&gt;Image Processing in CSS&lt;/h2&gt;
&lt;p&gt;Let’s look at how to perform scaling, cropping, flipping, and filtering an image in CSS.&lt;/p&gt;
&lt;h3 id=&quot;scaling-an-image-with-object-fit-scale-down&quot;&gt;Scaling an image with &lt;code&gt;object-fit: scale-down&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit&quot;&gt;&lt;code&gt;object-fit&lt;/code&gt;&lt;/a&gt; CSS property allows you to define how the content of an HTML &lt;code&gt;&amp;#x3C;img&gt;&lt;/code&gt; element should be resized to fit its container. In particular, &lt;code&gt;scale-down&lt;/code&gt; acts as if &lt;code&gt;none&lt;/code&gt; or &lt;code&gt;contain&lt;/code&gt; were set, depending on which would result in a smaller image.&lt;/p&gt;
&lt;p&gt;When it acts like &lt;code&gt;none&lt;/code&gt;, the image will keep its original intrinsic size and not be scaled down. On the contrary, when it acts like &lt;code&gt;contain&lt;/code&gt; the image will be scaled down to fit the container while maintaining its aspect ratio.&lt;/p&gt;
&lt;p&gt;Test this CSS rule in the live demo below:&lt;/p&gt;
&lt;p&gt;In particular, this is the CSS rule where the magic happens:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;.manipulated-image&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  object-fit&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;scale-down&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  height&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;px&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;h3 id=&quot;cropping-an-image-with-object-fit-and-object-position&quot;&gt;Cropping an image with &lt;code&gt;object-fit&lt;/code&gt; and &lt;code&gt;object-position&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;By employing &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit&quot;&gt;&lt;code&gt;object-fit&lt;/code&gt;&lt;/a&gt; in conjunction with &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/object-position&quot;&gt;&lt;code&gt;object-position&lt;/code&gt;&lt;/a&gt;, you can show a part of your image, just if it has been cropped. In detail, the &lt;code&gt;object-position&lt;/code&gt; CSS property allows you to specify the positioning of your &lt;code&gt;&amp;#x3C;img&gt;&lt;/code&gt; element within its container box. This happens by passing this CSS property a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/position_value&quot;&gt;&lt;code&gt;position&lt;/code&gt;&lt;/a&gt; parameter containing from one to four values. This parameter is what defines the position of the &lt;code&gt;&amp;#x3C;img&gt;&lt;/code&gt; element.&lt;/p&gt;
&lt;p&gt;By using &lt;code&gt;object-fit&lt;/code&gt; to set how your &lt;code&gt;&amp;#x3C;img&gt;&lt;/code&gt; element should fit its container and by positioning it with &lt;code&gt;object-position&lt;/code&gt;, you can show only a part of your image as shown in the live example below:&lt;/p&gt;
&lt;p&gt;This is the CSS rule to look attention to:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;.manipulated-image&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  object-fit&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;cover&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  object-position&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;-150&lt;/span&gt;&lt;span&gt;px&lt;/span&gt;&lt;span&gt; -25&lt;/span&gt;&lt;span&gt;px&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;h3 id=&quot;flipping-an-image-with-transform&quot;&gt;Flipping an image with &lt;code&gt;transform&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/transform&quot;&gt;&lt;code&gt;transform&lt;/code&gt;&lt;/a&gt; CSS property is a powerful tool that gives you the ability to rotate, scale, skew, or translate an&lt;code&gt;&amp;#x3C;img&gt;&lt;/code&gt; element. Specifically, you can flip an image by using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scaleX()&quot;&gt;&lt;code&gt;scaleX()&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scaleY()&quot;&gt;&lt;code&gt;scaleY()&lt;/code&gt;&lt;/a&gt; transformation functions, or by adopting the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/rotateX()&quot;&gt;&lt;code&gt;rotateX()&lt;/code&gt;&lt;/a&gt; or &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/rotateY()&quot;&gt;&lt;code&gt;rotateY()&lt;/code&gt;&lt;/a&gt; functions.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;scaleX()&lt;/code&gt; and &lt;code&gt;scaleY()&lt;/code&gt; define a transformation that resizes an HTML element along the x-axis and y-axis, respectively. Both accept a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/number&quot;&gt;&lt;code&gt;number&lt;/code&gt;&lt;/a&gt; representing the scaling factor as a parameter. Learn how to flip an image vertically with &lt;code&gt;scaleX()&lt;/code&gt; in the example below:&lt;/p&gt;
&lt;p&gt;In detail, this is the CSS rule to flip an image vertically:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;.manipulated-image&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  transform&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;scaleX&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;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Similarly, &lt;code&gt;rotateX()&lt;/code&gt; and &lt;code&gt;rotateY()&lt;/code&gt; define a transformation that rotates an HTML element without deforming it around the horizontal axis and vertical axis, respectively. Both require an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/angle&quot;&gt;&lt;code&gt;angle&lt;/code&gt;&lt;/a&gt; representing the angle of rotation as a parameter. Now, let’s see how to flip an image vertically with &lt;code&gt;rotateY()&lt;/code&gt; in the example below:&lt;/p&gt;
&lt;p&gt;Specifically, this is what the CSS rule to flip an image vertically looks like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;.manipulated-image&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  transform&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;rotateY&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;180&lt;/span&gt;&lt;span&gt;deg&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;h3 id=&quot;filtering-an-image-with-filter&quot;&gt;Filtering an image with &lt;code&gt;filter&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/filter&quot;&gt;&lt;code&gt;filter&lt;/code&gt;&lt;/a&gt; CSS property allows you to apply visual effects on an &lt;code&gt;&amp;#x3C;img&gt;&lt;/code&gt; element. This property provides access to several built-in effects, such as &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/blur()&quot;&gt;&lt;code&gt;blur()&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/grayscale()&quot;&gt;&lt;code&gt;grayscale()&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/contrast()&quot;&gt;&lt;code&gt;contrast()&lt;/code&gt;&lt;/a&gt;, and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/filter#functions&quot;&gt;many others&lt;/a&gt;. If required, you can also define your custom image filtering functions.&lt;/p&gt;
&lt;p&gt;CSS filters are a powerful tool that is typically used to adjust how an image is displayed by the browser and shown to the end-user. Using them is really easy, as shown in the live demo below:&lt;/p&gt;
&lt;p&gt;These are the CSS rules where the filtering operations are defined:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;.blurred-image&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  filter&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;blur&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;px&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;.grayscale-image&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  filter&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;grayscale&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;80&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;.high-contrast-image&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  filter&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;contrast&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;150&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;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;css-only-image-editor-vs-photoeditor-sdk&quot;&gt;CSS-Only Image Editor vs PhotoEditor SDK&lt;/h2&gt;
&lt;p&gt;Image manipulation in CSS is an easy and straightforward way to manipulate how an image is displayed with no effort. On the other hand, you cannot save or export the manipulated images with CSS. This means that it is not possible to implement a file image editor based solely on CSS.&lt;/p&gt;
&lt;p&gt;Therefore, you can rely on CSS only if you are interested in changing how your images are rendered by the browser. Conversely, if you are looking for a way to manipulate your images and then export them as files, then you need a much more advanced tool. In this case, a commercial solution like IMG.LY’s &lt;a href=&quot;https://img.ly/photo-sdk/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;Photo Editor SDK&lt;/a&gt; will provide you with a complete, fast, and easy-to-use image editor.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;manipulate-filter-grayscale-blur-image-css-css3&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;322&quot; src=&quot;https://img.ly/_astro/manipulate-filter-grayscale-blur-image-css-css3_Z1MFnx8.webp&quot; srcset=&quot;/_astro/manipulate-filter-grayscale-blur-image-css-css3_Z1MFnx8.webp 600w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Today we learned how to use CSS to control how browsers display images. In detail, we delved into how to scale, crop, flip, and filter an image in CSS. These represent the most common image manipulation operations and allow you to transform your image CSS-side. As we have learned, these operations only determine how your browser renders an image. They do not change an image as a data structure.&lt;br&gt;
This means that it is not possible to create an image editor that allows users to export manipulated images while using only CSS. So, if this is what you were looking for, you should consider adopting a fast, advanced, 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;. And you can get right into the PhotoEditorSDK or VideoEditorSDK and its myriad integrations by starting with a &lt;a href=&quot;https://img.ly/free-trial&quot;&gt;free trial over here&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;to-stay-in-the-loop-with-our-latest-articles-and-case-studies-subscribe-to-our-newsletter&quot;&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;/h3&gt;</content:encoded><dc:creator>Antonello</dc:creator><media:content url="https://blog.img.ly/2022/02/blur-flip-manipulate-filter-image-css-css3-.png" medium="image"/><category>How-To</category><category>CSS</category><category>Web Development</category><category>Photo Editing</category><category>Image Editing</category><category>Tech</category><category>Tutorial</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 Apply Custom Image Filters Using HTML5 Canvas in JavaScript</title><link>https://img.ly/blog/how-to-apply-filters-in-javascript/</link><guid isPermaLink="true">https://img.ly/blog/how-to-apply-filters-in-javascript/</guid><description>Apply custom filters in JavaScript without external libraries – with the &lt;canvas&gt; element! </description><pubDate>Tue, 14 Sep 2021 15:25:56 GMT</pubDate><content:encoded>&lt;p&gt;In this article, you will learn how to apply custom filters to an image in JavaScript, without using any external library. As you are about to learn, this goal can be achieved by employing only the HTML5 &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.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.instagram.com/&quot;&gt;Instagram&lt;/a&gt; has changed image processing forever. Since its market debut, users have become increasingly interested and accustomed to applying filters to their images and photos. This desirable, valuable, and requested feature might seem complex to implement, but it is not.&lt;/p&gt;
&lt;p&gt;So, let’s see how to implement a feature for users to apply custom filters to an image with Vanilla JavaScript. Follow this step-by-step guide to achieve the following &lt;a href=&quot;https://codesandbox.io/s/blog-how-to-filter-an-image-in-javascript-demo-forked-j3mel?from-embed&quot;&gt;result&lt;/a&gt;:&lt;/p&gt;
&lt;h2 id=&quot;custom-filters-with-canvas&quot;&gt;Custom Filters With &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;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 allows you to edit an image. It natively offers you the possibility to implement several image-processing features, such as &lt;a href=&quot;https://img.ly/blog/how-to-draw-on-an-image-with-javascript/&quot;&gt;implementing a brush&lt;/a&gt;. In other words, it is the only prerequisite required to apply custom filters to an image. All you need to do is load an image, turn it into an array of pixels by using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/getImageData&quot;&gt;&lt;code&gt;getImageData()&lt;/code&gt;&lt;/a&gt; function, and apply a transformation to change their value according to the result you want to achieve. Finally, you can either overwrite the original image or create a new one after applying the filter.&lt;/p&gt;
&lt;p&gt;Now, let’s see everything required to implement such a cool feature.&lt;/p&gt;
&lt;p&gt;Clone the &lt;a href=&quot;https://github.com/Tonel/how-to-apply-custom-image-filters-in-javascript-img-ly&quot;&gt;GitHub repository supporting this tutorial&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;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    git&lt;/span&gt;&lt;span&gt; clone&lt;/span&gt;&lt;span&gt; https://github.com/Tonel/how-to-apply-custom-image-filters-in-javascript-img-ly&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And try the application by opening the &lt;code&gt;index.html&lt;/code&gt; file in your browser.&lt;/p&gt;
&lt;p&gt;Otherwise, continue following this article to learn how to implement the same demo application step by step.&lt;/p&gt;
&lt;h3 id=&quot;1-implementing-simple-filters&quot;&gt;1. Implementing Simple Filters&lt;/h3&gt;
&lt;p&gt;Simple filters can be applied by changing the value of each pixel the image consists of. For example, you can implement a function to apply &lt;a href=&quot;https://en.wikipedia.org/wiki/Thresholding%5F(image_processing)&quot;&gt;thresholding&lt;/a&gt; as follows:&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; applyThreshold&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;sourceImageData&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;threshold&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 127&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; src&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sourceImageData.data;&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;  for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;; i &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; src.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span&gt;; i &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; 4&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; r&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; src[i];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; g&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; src[i &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;    const&lt;/span&gt;&lt;span&gt; b&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; src[i &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; 2&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;    // thresholding the current value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; v&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 0.2126&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; r &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; 0.7152&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; g &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; 0.0722&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; b &lt;/span&gt;&lt;span&gt;&gt;=&lt;/span&gt;&lt;span&gt; threshold &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; 255&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    src[i] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; src[i &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; src[i &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; v;&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;  return&lt;/span&gt;&lt;span&gt; sourceImageData;&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;This simple function receives the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/ImageData/ImageData&quot;&gt;&lt;code&gt;ImageData&lt;/code&gt;&lt;/a&gt; object relative to the image to be thresholded as a parameter. Then, its &lt;code&gt;data&lt;/code&gt; property representing a one-dimensional array with the image data in the RGBA order is accessed. This contains integer values between &lt;code&gt;0&lt;/code&gt; (black) and &lt;code&gt;255&lt;/code&gt; (white). Finally, &lt;code&gt;data&lt;/code&gt; is iterated and modified to apply the thresholding operation, before returning the updated &lt;code&gt;ImageData&lt;/code&gt; object.&lt;/p&gt;
&lt;p&gt;That is just an example, but with this approach, you may implement many other simple filters.&lt;/p&gt;
&lt;h3 id=&quot;2-implementing-convolution-based-filters&quot;&gt;2. Implementing Convolution-Based Filters&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Convolution&quot;&gt;Convolution&lt;/a&gt; is one of the most important concepts when it comes to image processing. Particularly, it allows you to apply a filter by taking the weighted sum of a rectangle of pixels from an image and use it as the output value pixel by pixel. The coefficients used to perform the weighted sum are defined through a matrix, which is 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;. By changing the kernel, the final result will change accordingly. Some kernels are more popular than others and can be used for blurring, sharpening, and edge detection. You can find a list of these well-known kernels &lt;a href=&quot;https://en.wikipedia.org/wiki/Kernel%5F(image_processing)#Details&quot;&gt;here&lt;/a&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;function&lt;/span&gt;&lt;span&gt; applyConvolution&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;sourceImageData&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;outputImageData&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;  const&lt;/span&gt;&lt;span&gt; src&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sourceImageData.data;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; dst&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; outputImageData.data;&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; srcWidth&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sourceImageData.width;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; srcHeight&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sourceImageData.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; side&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; Math.&lt;/span&gt;&lt;span&gt;round&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; halfSide&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; Math.&lt;/span&gt;&lt;span&gt;floor&lt;/span&gt;&lt;span&gt;(side &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; 2&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;  // padding the output by the convolution kernel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; w&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; srcWidth;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; h&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; srcHeight;&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;  // iterating through the output image pixels&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; y &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;; y &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; h; y&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;    for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; x &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;; x &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; w; x&lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      let&lt;/span&gt;&lt;span&gt; r &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;        g &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;        b &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;        a &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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      // calculating the weighed sum of the source image pixels that&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      // fall under the convolution kernel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; cy &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;; cy &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; side; cy&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;        for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; cx &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;; cx &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; side; cx&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;          const&lt;/span&gt;&lt;span&gt; scy&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; y &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; cy &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; halfSide;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          const&lt;/span&gt;&lt;span&gt; scx&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; x &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; cx &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; halfSide;&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; (scy &lt;/span&gt;&lt;span&gt;&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; &amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; scy &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; srcHeight &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; scx &lt;/span&gt;&lt;span&gt;&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; &amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; scx &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; srcWidth) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            let&lt;/span&gt;&lt;span&gt; srcOffset &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (scy &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; srcWidth &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; scx) &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; 4&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            let&lt;/span&gt;&lt;span&gt; wt &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; kernel[cy &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; side &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; cx];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            r &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; src[srcOffset] &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; wt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            g &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; src[srcOffset &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; wt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            b &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; src[srcOffset &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; wt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            a &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; src[srcOffset &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; 3&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; wt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      const&lt;/span&gt;&lt;span&gt; dstOffset&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; (y &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; w &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; x) &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; 4&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;      dst[dstOffset] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; r;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      dst[dstOffset &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; g;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      dst[dstOffset &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; b;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      dst[dstOffset &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; 3&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; a;&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; outputImageData;&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;This function expects the source &lt;code&gt;ImageData&lt;/code&gt; object as a parameter. Similarly, you must provide it with a blank &lt;code&gt;ImageData&lt;/code&gt; object with the same size as the first one to be used as output, and a matrix representing the kernel. Then, the convolution algorithm is applied on the &lt;code&gt;outputImageData&lt;/code&gt; object by iterating on the &lt;code&gt;sourceImageData&lt;/code&gt; one.&lt;/p&gt;
&lt;p&gt;Et voilà! Now, you have the building blocks required to implement a filtering feature in Vanilla JavaScript. Let’s see how in detail.&lt;/p&gt;
&lt;h3 id=&quot;3-filtering-in-action&quot;&gt;3. Filtering in Action&lt;/h3&gt;
&lt;p&gt;Let’s take a look at how to implement a simple application allowing users to upload an image, choose the filter to apply, and see the final result :&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;&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 apply the filter that best suits the image&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; /&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; style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;visibility: hidden;&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;imageToFilter&quot;&lt;/span&gt;&lt;span&gt; style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;max-width: 100%; height: 200px;&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; style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;margin-top: 5px;&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;span&lt;/span&gt;&lt;span&gt;&gt;Filter: &amp;#x3C;/&lt;/span&gt;&lt;span&gt;span&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;radio&quot;&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;filterRadio&quot;&lt;/span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;noFilter&quot;&lt;/span&gt;&lt;span&gt; checked&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;label&lt;/span&gt;&lt;span&gt;&gt;No Filter&amp;#x3C;/&lt;/span&gt;&lt;span&gt;label&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;radio&quot;&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;filterRadio&quot;&lt;/span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;threshold&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;label&lt;/span&gt;&lt;span&gt;&gt;Threshold&amp;#x3C;/&lt;/span&gt;&lt;span&gt;label&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;radio&quot;&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;filterRadio&quot;&lt;/span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;sharpen&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;label&lt;/span&gt;&lt;span&gt;&gt;Sharpen&amp;#x3C;/&lt;/span&gt;&lt;span&gt;label&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;radio&quot;&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;filterRadio&quot;&lt;/span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;blur&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;label&lt;/span&gt;&lt;span&gt;&gt;Blur&amp;#x3C;/&lt;/span&gt;&lt;span&gt;label&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;h2&lt;/span&gt;&lt;span&gt;&gt;Filtered 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;filteredImage&quot;&lt;/span&gt;&lt;span&gt; style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;max-width: 100%;&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;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;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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; imageToFilter &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; null&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; filteredImage&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;#filteredImage&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;// initializing the filter value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; filterElement&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;getElementsByName&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;filterRadio&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;let&lt;/span&gt;&lt;span&gt; filter;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;filterElement.&lt;/span&gt;&lt;span&gt;forEach&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;f&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; (f.checked) filter &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; f.value;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// applying the selected filter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;filterElement.&lt;/span&gt;&lt;span&gt;forEach&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;f&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;  f.&lt;/span&gt;&lt;span&gt;onclick&lt;/span&gt;&lt;span&gt; =&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;    filter &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; f.value;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    filteredImage.src &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; filterImage&lt;/span&gt;&lt;span&gt;(imageToFilter, filter);&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;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;  imageToFilter &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;#imageToFilter&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  imageToFilter.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;  // 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 class=&quot;line&quot;&gt;&lt;span&gt;  // applying the defaul filter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  imageToFilter.&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;    filteredImage.src &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; filterImage&lt;/span&gt;&lt;span&gt;(imageToFilter, filter);&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;  return&lt;/span&gt;&lt;span&gt; false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;});&lt;/span&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; filterImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;imageToFilter&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;filter&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;
&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; canvasWidth&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; imageToFilter.width;&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; imageToFilter.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;  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;(imageToFilter, &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;, canvasWidth, 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;  const&lt;/span&gt;&lt;span&gt; sourceImageData&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; context.&lt;/span&gt;&lt;span&gt;getImageData&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;, canvasWidth, canvasHeight);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; blankOutputImageData&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; context.&lt;/span&gt;&lt;span&gt;createImageData&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    canvasWidth,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    canvasHeight&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;  const&lt;/span&gt;&lt;span&gt; outputImageData&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; applyFilter&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    sourceImageData,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    blankOutputImageData,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    filter&lt;/span&gt;&lt;/span&gt;
&lt;span 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;  context.&lt;/span&gt;&lt;span&gt;putImageData&lt;/span&gt;&lt;span&gt;(outputImageData, &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;
&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;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; applyFilter&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;sourceImageData&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;outputImageData&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;filter&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; (filter &lt;/span&gt;&lt;span&gt;===&lt;/span&gt;&lt;span&gt; &apos;noFilter&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; sourceImageData;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  } &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt; if&lt;/span&gt;&lt;span&gt; (filter &lt;/span&gt;&lt;span&gt;===&lt;/span&gt;&lt;span&gt; &apos;threshold&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; applyThreshold&lt;/span&gt;&lt;span&gt;(sourceImageData);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  } &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt; if&lt;/span&gt;&lt;span&gt; (filter &lt;/span&gt;&lt;span&gt;===&lt;/span&gt;&lt;span&gt; &apos;sharpen&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; applyConvolution&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      sourceImageData,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      outputImageData,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&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&gt;&lt;span&gt;1&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&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;5&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;0&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;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;else&lt;/span&gt;&lt;span&gt; if&lt;/span&gt;&lt;span&gt; (filter &lt;/span&gt;&lt;span&gt;===&lt;/span&gt;&lt;span&gt; &apos;blur&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; applyConvolution&lt;/span&gt;&lt;span&gt;(sourceImageData, outputImageData, [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      1&lt;/span&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt; 16&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      2&lt;/span&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt; 16&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      1&lt;/span&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt; 16&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      2&lt;/span&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt; 16&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      4&lt;/span&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt; 16&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      2&lt;/span&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt; 16&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      1&lt;/span&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt; 16&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      2&lt;/span&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt; 16&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      1&lt;/span&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt; 16&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;else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // fallback option&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; sourceImageData;&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; applyThreshold&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;sourceImageData&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;threshold&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 127&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; src&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sourceImageData.data;&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;  for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;; i &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; src.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span&gt;; i &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; 4&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; r&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; src[i];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; g&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; src[i &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;    const&lt;/span&gt;&lt;span&gt; b&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; src[i &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; 2&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;    // thresholding the current value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; v&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 0.2126&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; r &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; 0.7152&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; g &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; 0.0722&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; b &lt;/span&gt;&lt;span&gt;&gt;=&lt;/span&gt;&lt;span&gt; threshold &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; 255&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;    src[i] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; src[i &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; src[i &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; v;&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; sourceImageData;&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; applyConvolution&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;sourceImageData&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;outputImageData&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;  const&lt;/span&gt;&lt;span&gt; src&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sourceImageData.data;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; dst&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; outputImageData.data;&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; srcWidth&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sourceImageData.width;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; srcHeight&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sourceImageData.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; side&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; Math.&lt;/span&gt;&lt;span&gt;round&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; halfSide&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; Math.&lt;/span&gt;&lt;span&gt;floor&lt;/span&gt;&lt;span&gt;(side &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; 2&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;  // padding the output by the convolution kernel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; w&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; srcWidth;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; h&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; srcHeight;&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;  // iterating through the output image pixels&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; y &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;; y &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; h; y&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;    for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; x &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;; x &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; w; x&lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      let&lt;/span&gt;&lt;span&gt; r &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;        g &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;        b &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;        a &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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      // calculating the weighed sum of the source image pixels that&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      // fall under the convolution kernel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; cy &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;; cy &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; side; cy&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;        for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; cx &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;; cx &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; side; cx&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;          const&lt;/span&gt;&lt;span&gt; scy&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; y &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; cy &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; halfSide;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          const&lt;/span&gt;&lt;span&gt; scx&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; x &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; cx &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; halfSide;&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; (scy &lt;/span&gt;&lt;span&gt;&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; &amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; scy &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; srcHeight &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; scx &lt;/span&gt;&lt;span&gt;&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; &amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; scx &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; srcWidth) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            let&lt;/span&gt;&lt;span&gt; srcOffset &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (scy &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; srcWidth &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; scx) &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; 4&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            let&lt;/span&gt;&lt;span&gt; wt &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; kernel[cy &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; side &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; cx];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            r &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; src[srcOffset] &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; wt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            g &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; src[srcOffset &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; wt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            b &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; src[srcOffset &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; wt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            a &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; src[srcOffset &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; 3&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; wt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      const&lt;/span&gt;&lt;span&gt; dstOffset&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; (y &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; w &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; x) &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; 4&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      dst[dstOffset] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; r;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      dst[dstOffset &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; g;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      dst[dstOffset &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; b;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      dst[dstOffset &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; 3&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; a;&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;  return&lt;/span&gt;&lt;span&gt; outputImageData;&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;As you can see, the HTML page contains everything required to upload an image, and select a filter. There is also a no filter option, allowing users to restore the original image. Also, to better appreciate the effects of each filter, the original image is always shown as well.&lt;/p&gt;
&lt;p&gt;From a technical point of view, what happens is that the &lt;code&gt;input&lt;/code&gt; element is used to upload an optional image. Then, the uploaded image is passed to the &lt;code&gt;applyFilter()&lt;/code&gt; function, which takes care of applying the &lt;code&gt;filter&lt;/code&gt;selected in the HTML radio buttons by calling the right function. This can involve either a simple filter, or a convolution-based one. In this latter case, the appropriate kernel is passed to the &lt;code&gt;applyConvolution()&lt;/code&gt; function as well. Then, the output &lt;code&gt;ImageData&lt;/code&gt; object is used to show the resulting image by using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/putImageData&quot;&gt;&lt;code&gt;putImageData()&lt;/code&gt;&lt;/a&gt; function. Please, note that the example that was just implemented corresponds to the live demo you can find 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;Implementing image filtering is not a simple task and can easily be implemented with Vanilla JavaScript. On the other hand, the more filters you want to add, the more complicated things can get. In this tutorial, you just saw how to implement non-complex filters, but there are filtering techniques that require much more effort. Plus, the majority of them involve iterating through each pixel. As a result, on large images, this can turn into a time-consuming process. So, if you do not want to ruin the user experience, you might be forced to adapt academic and well-known algorithms to make them more efficient. Thus, implementing this feature efficiently can turn into a considerably complex task.&lt;/p&gt;
&lt;p&gt;If you do not want to deal with such unavoidable optimizations, a commercial and all-in-one solution like &lt;a href=&quot;https://img.ly/products/photo-sdk&quot;&gt;PhotoEditorSDK&lt;/a&gt; should be taken into account. This way, you will not have to worry about accomplishing challenging and time-consuming tasks anymore. 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;filter-an-image-with-photoeditorsdk&quot;&gt;Filter an Image with &lt;code&gt;photoeditorsdk&lt;/code&gt;&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;a href=&quot;https://img.ly/products/photo-sdk&quot;&gt;PhotoEditorSDK&lt;/a&gt; in HTML and JavaScript. Then, by using &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, you can start enjoying more than 60 high-quality filters. Moreover, each of them was optimized natively to be lightning fast. This way, you can minimize the processing time, and achieve the following result with a few clicks:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;html5-canva-image-filter&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1213px) 1213px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1213&quot; height=&quot;643&quot; src=&quot;https://img.ly/_astro/html5-canva-image-filter_ZMDvDL.webp&quot; srcset=&quot;/_astro/html5-canva-image-filter_Z2cHfQB.webp 640w, /_astro/html5-canva-image-filter_2dP6Nx.webp 750w, /_astro/html5-canva-image-filter_6Vzw0.webp 828w, /_astro/html5-canva-image-filter_9Guoq.webp 1080w, /_astro/html5-canva-image-filter_ZMDvDL.webp 1213w&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 implement a feature to allows users to apply a filter on an image with JavaScript. Implementing such a feature can be entirely achieved by only using the HTML5 &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt; element. However, making the image processing fast enough not to make users wait can become a problem. This is the real issue when dealing with such a feature, which inevitably involves iterating through each pixel of which an image is composed. Consequently, optimizing well-known filtering algorithms to avoid this issue is what makes implementing the feature challenging. So, if you do not want to deal with this issue, you can adopt an easy, complete, advanced, and all-in-one solution – such as &lt;a href=&quot;https://img.ly/products/photo-sdk&quot;&gt;PhotoEditorSDK&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/2021/09/html5-filter-canva-image-filter.jpg" medium="image"/><category>HTML5</category><category>App Development</category><category>Web Development</category><category>Image Editing</category><category>Photo Editing</category><category>Software Development</category><category>How-To</category><category>Tutorial</category></item><item><title>Inpainting: Removing Distracting Objects in High-Resolution Images</title><link>https://img.ly/blog/image-inpainting/</link><guid isPermaLink="true">https://img.ly/blog/image-inpainting/</guid><description>We teamed up with the Bochumer Institute of Technology to present improved results with deep learning approaches. Here are our experiences from a mission to make editing easier.</description><pubDate>Tue, 08 Dec 2020 15:03:28 GMT</pubDate><content:encoded>&lt;h3 id=&quot;introduction&quot;&gt;Introduction&lt;/h3&gt;
&lt;p&gt;You may know this situation: You are out on a trip when suddenly a unique opportunity for a photograph appears, like a wild animal showing up or sun rays breaking through the rain clouds for a few seconds. Without hesitation, you grab your camera and capture the sight. Later you discover that a distracting object, like a road sign, is ruining your shot. Time for some cumbersome retouching.&lt;/p&gt;
&lt;p&gt;Now, imagine you could erase the distracting object just by highlighting it. Wonderful! From the field of deep learning, a technique for image manipulation called &lt;strong&gt;Image Inpainting&lt;/strong&gt; makes it possible. Image Inpainting aims to cut out undesired parts of an image and &lt;strong&gt;fills up missing information&lt;/strong&gt; with plausible content of patterns, colors, and textures that match the surrounding.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Figure 1: Inpainting example. A) shows the original image; B) the masked (input) image; C) the results of the inpainting.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1496px) 1496px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1496&quot; height=&quot;579&quot; src=&quot;https://img.ly/_astro/1_1Tl2Oq.webp&quot; srcset=&quot;/_astro/1_8J1G8.webp 640w, /_astro/1_Zch4i2.webp 750w, /_astro/1_ZygjVb.webp 828w, /_astro/1_2eNKv8.webp 1080w, /_astro/1_1GfTHz.webp 1280w, /_astro/1_1Tl2Oq.webp 1496w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Today we would like to share experiences that we have gained during the application of deep learning inpainting approaches. Furthermore, we’ll present some quality optimization steps that we have implemented to improve results addressing the transformation to high-resolution outputs. But let us start with a quick introduction: who are we and why are we concerned with these kinds of topics?&lt;/p&gt;
&lt;p&gt;We are a small consortium consisting of the &lt;strong&gt;&lt;a href=&quot;https://bo-i-t.de/&quot;&gt;Bochumer Institute of Technology&lt;/a&gt;&lt;/strong&gt;, a research institute aiming to transfer knowledge from academia into industry, and the company &lt;strong&gt;&lt;a href=&quot;https://img.ly&quot;&gt;IMG.LY&lt;/a&gt;,&lt;/strong&gt; a team of software engineers and designers developing creative tools like the &lt;a href=&quot;https://img.ly/photo-sdk&quot;&gt;PhotoEditor SDK&lt;/a&gt; and the &lt;a href=&quot;https://img.ly/blog/building-the-creative-engine-of-the-world/&quot;&gt;UBQ&lt;/a&gt; engine. Together we are working in the EFRE.NRW funded research project &lt;a href=&quot;https://kidesign.img.ly/&quot;&gt;KI Design&lt;/a&gt; that targets artificial intelligence (AI) and deep learning-based algorithms for image content analysis and modification, as well as a leveraging tool kit for aesthetic improvements.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Image Inpainting&lt;/strong&gt; has been a viable technique in image processing for quite some time, even before “Artificial Intelligence” was on everyone’s lips. Common for most inpainting algorithms is that an area of an image is highlighted to be corrected. Many conventional algorithms then analyze the statistical distribution to fill the resulting gap by finding and using nearest neighbor patches. The most famous and state of the art approach of this method is the &lt;strong&gt;&lt;a href=&quot;https://gfx.cs.princeton.edu/pubs/Barnes_2009_PAR/patchmatch.pdf&quot;&gt;PatchMatch&lt;/a&gt; algorithm&lt;/strong&gt;. It uses a fast, structured randomized search to identify the approximate nearest neighbor patches that will fill in the respective part of the image.&lt;/p&gt;
&lt;p&gt;However, there are two &lt;strong&gt;drawbacks&lt;/strong&gt;: first, regardless of the approximation, performance still might be an issue, and second, the results suffer from a lack of semantic understanding of the scene. Thus, research dived into new ideas and directions and tried the application and implementation of AI- and neural network-based approaches to solving these issues.‌‌‌‌ For us, the removal of annoying background content is a useful feature, as it improves the overall image aesthetic. Having this available on mobile devices would be particularly interesting. Due to performance limitations and ever-improving integrated cameras, a mobile solution requires a fast and lightweight model architecture as well as the ability to process high-resolution images.&lt;/p&gt;
&lt;p&gt;Summarized, our expectation for an AI-based inpainting algorithm are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;removal of (manually highlighted) background objects/persons&lt;/li&gt;
&lt;li&gt;feasibility to process high-resolution images&lt;/li&gt;
&lt;li&gt;fast and lightweight network (applicable for smartphones)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The number of publications addressing this or similar requirements has increased enormously in recent years. After digging into the literature, we identified two promising approaches and tested them.&lt;/p&gt;
&lt;h3 id=&quot;testing-and-comparing-model-architectures&quot;&gt;Testing and Comparing Model Architectures&lt;/h3&gt;
&lt;p&gt;These selected networks were based on the latest scientific findings and appeared to provide high-quality output. Both approaches have well-documented repositories – a special thank you to the authors for their great work (of repositories and papers as well)! The selected networks are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Partial Convolutional Neural Networks (PCONV); [&lt;a href=&quot;https://arxiv.org/abs/1804.07723&quot;&gt;paper&lt;/a&gt;, &lt;a href=&quot;https://github.com/MathiasGruber/PConv-Keras&quot;&gt;github-repository&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;Generative Multi-column Convolutional Neural Networks (GMCNN); [&lt;a href=&quot;http://papers.nips.cc/paper/7316-image-inpainting-via-generative-multi-column-convolutional-neural-networks.pdf&quot;&gt;paper&lt;/a&gt;, &lt;a href=&quot;https://github.com/shepnerd/inpainting_gmcnn&quot;&gt;github-repository&lt;/a&gt;]&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You may be wondering why exactly we chose these models for comparison purposes, as the latest scientific findings sound a bit vague. Indeed, it is considerably difficult to identify the best fitting model architecture. As far as we know, there is no standardized validation method or data set. Most papers demonstrate their results on &lt;em&gt;self-selected&lt;/em&gt; test images and further compare them with again &lt;em&gt;self-selected&lt;/em&gt; approaches. The only option we had was to evaluate models that seemed reasonable to us. A validation method or standardized test set could be a valuable scientific contribution here. Let’s turn back to the selected models.‌‌‌‌ The PCONV network uses multiple convolutional layers and adds a &lt;em&gt;partial convolutional layer&lt;/em&gt;. The key feature is that the convolution does not consider invalid pixels, indicated by an updating mask. This prevents the algorithm from picking up the color of the mask (typically the average color tone of the image) and transmit it into the reconstruction process.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;GMCNN&lt;/strong&gt; – a GAN-based model – is built in a special architecture consisting of 3 networks: a generator, split up into three branches addressing different feature levels, a local and global discriminator, a VGG19 net calculating the implicit diversified Markov random field (ID-MRF), introduced in the paper. This ID-MRF serves as a loss term comparing generated content with nearest-neighbor patches of the ground truth image. While the interaction of all three networks is required in the training phase, only the generative network serves for testing and production. More details and figures regarding the model architecture are available in the official &lt;a href=&quot;http://papers.nips.cc/paper/7316-image-inpainting-via-generative-multi-column-convolutional-neural-networks.pdf&quot;&gt;paper&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Due to the lack of standardized sets, we created our own test sets addressing different levels of complexity. This also included image data requiring an understanding of semantic structures. In our comparison, we paid special attention to ensuring the filled content was harmonious, and a possible artifact interspersion was reduced to a minimum. In particular, image artifacts could raise issues in terms of translation with respect to high-resolution information. Here is an example output of our tests:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Figure 2: Comparison of GMCNN and PCONV model. A) shows the original image; B) the masked (input) image; C) the results of the PCONV network and D) the results of the GMCNN model.&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;1095&quot; src=&quot;https://img.ly/_astro/2_r92Ec.webp&quot; srcset=&quot;/_astro/2_1AEMMW.webp 640w, /_astro/2_ZtiLji.webp 750w, /_astro/2_H1eho.webp 828w, /_astro/2_18mnqN.webp 1080w, /_astro/2_Z1c3kHp.webp 1280w, /_astro/2_1Hu0Sr.webp 1668w, /_astro/2_r92Ec.webp 2000w&quot;&gt;&lt;/p&gt;
&lt;p&gt;In comparison, the inpainting result based on PCONV suffered from some blurred artifacts and erratically deviating shades, cf. Figure 1C, whereas the GMCNN-based result appeared to be more precise and plausible concerning the semantic context, cf. Figure 1D. You can see this clearly when you look at the grille door that was covered by a person. The GMCNN approach, cf Figure 1D, had recognized and respected the grid structure, while the PCONV overlayed this with a uniform (black) color tone. In consideration of all test data results, we decided to follow up with the GMCNN.&lt;/p&gt;
&lt;p&gt;However, we would like to emphasize that this does not mean that one model architecture is better suited for Image Inpainting than the other. The used weights build-up of the PCONV architecture may achieve similar results with further training or different test sets.&lt;/p&gt;
&lt;h3 id=&quot;what-about-high-resolution-inpainting&quot;&gt;What About High-Resolution Inpainting?&lt;/h3&gt;
&lt;p&gt;At the current state of the model, the processing of high-resolution images remains uncovered. Out of all the papers and repositories we found, even papers promising high-resolution often just targeted image sizes of 1024x1024 pixel at maximum. Our expectations were a resolution of substantially more than 2000x2000 pixels. A reason for this issue seemed to be the hardware demanding and time-consuming training phase when processing high-resolution images. ‌‌&lt;br&gt;
Furthermore, the application of a high-resolution inpainting model could entail performance issues. These are not neglectable to us, as we are facing a prospective implementation on smartphones that can’t keep up with the power of a modern graphics card. Thus, an additional challenge is a high-quality transformation of low-resolution outputs to a high-resolution.&lt;/p&gt;
&lt;h3 id=&quot;apply-low-resolution-inpainting-output-to-high-resolution-images&quot;&gt;Apply Low-Resolution Inpainting Output to High-Resolution Images&lt;/h3&gt;
&lt;p&gt;‌‌The GMCNN model was trained with the &lt;a href=&quot;http://places2.csail.mit.edu/index.html&quot;&gt;Places&lt;/a&gt; dataset, formatted in a 512x680 resolution. Feeding in high-resolution images would exceed the training input size by far and further require information of feature dimensions that the model has never seen before. That could result in almost completely distorted reconstructions.&lt;/p&gt;
&lt;p&gt;A straightforward solution is to downscale the high-resolution image before feeding it to the model and then resize the result up to the original image size conclusively. Due to the upscaling (e.g., via bicubic interpolation), the image details suffer from a loss of quality. Therefore a better approach is to take only the masked areas of the upscaled inpainting prediction and stitch it back into the original image. That prevents the loss of initially known details from the unmasked regions. For the maintained inpainting regions, the lack of image details, as well as the artifacts and distortions, pose a complex challenge that we aimed to overcome with the following approaches.‌‌‌‌&lt;/p&gt;
&lt;h3 id=&quot;shrinking-mask-approach&quot;&gt;Shrinking-Mask-Approach&lt;/h3&gt;
&lt;p&gt;While the inpainted area mostly yields realistic-looking content for the more marginal regions, the performance decreases strongly towards the center, cf. Figure 3D. We especially noticed this behavior for larger masks. Conclusively a recursive inpainting procedure with an iteratively shrinking mask, cf. Figure 3E, seems to be a reasonable approach.  With this concept, we try to improve the inpainting results in a progressive manner starting from the boundary to the center of the masked regions while utilizing the generated information of the preceding recursion, cf. Figure 3F.‌‌&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Figure 3: Shrinking-mask-approach. A) shows the original image; B) the final inpainting result after applying the shrinking-mask-approach for 4 iterations; C) shows the original image masked by the original mask (model input for iteration 1); D) the inpainting result of iteration 1; E) the inpainting result of the previous iteration 1 masked by a shrunken mask (model input for iteration 2) and F) the inpainting results of iteration 2.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1062px) 1062px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1062&quot; height=&quot;1479&quot; src=&quot;https://img.ly/_astro/3_Z24j7qw.webp&quot; srcset=&quot;/_astro/3_Z1giTCo.webp 640w, /_astro/3_ZPwLax.webp 750w, /_astro/3_ZAqkG6.webp 828w, /_astro/3_Z24j7qw.webp 1062w&quot;&gt;&lt;/p&gt;
&lt;p&gt;To us, it was essential to have a dynamic method that allows the handling of all mask forms and sizes. Therefore, we decided to apply an erosion kernel to the original mask in a recursive fashion until it is fully eroded. The amount of shrunk masks determines the number of inpainting performed by the network.‌‌‌‌&lt;/p&gt;
&lt;h3 id=&quot;two-step-approach&quot;&gt;Two-Step-Approach&lt;/h3&gt;
&lt;p&gt;While investigating and testing various quality optimization steps, we also fed high-resolution images into our model and discovered that the results for smaller masks were convincing. That led us to the hypothesis that not the resolution but rather the number of pixels to reconstruct seems to be the limiting factor. This finding served as the basis for our two-step-approach.‌‌‌‌&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Figure 4: Two-step-approach. A) shows the original image; B) the final inpainting result after applying the two-step-approach&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;710&quot; src=&quot;https://img.ly/_astro/4_OlLcn.webp&quot; srcset=&quot;/_astro/4_ZcIuQI.webp 640w, /_astro/4_ZPa8Y2.webp 750w, /_astro/4_1peh2d.webp 828w, /_astro/4_ZdIXGY.webp 1080w, /_astro/4_xfsjk.webp 1280w, /_astro/4_uCJLy.webp 1668w, /_astro/4_OlLcn.webp 2000w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Briefly, the approach works as follows. In the first step, we perform inpainting on a downscaled high-resolution image while applying the original mask. In a second step, we transfer the model output of step one into a higher resolution and perform inpainting again. This time we apply a modified mask containing only small coherent mask regions, for which we exploit the provided higher resolution context information. ‌‌&lt;br&gt;
In more detail, the first step is characterized as the baseline approach, cf. Figure 5: We scale the masked image down to the training resolution of 512x680 pixels and fill up the missing information.&lt;/p&gt;
&lt;p&gt;Optionally, the shrinking-mask-approach can be applied in the first step.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Figure 5: Step 1 of the two-step-approach. A) shows the original image masked by the original mask; B) the intermediate low-resolution inpainting result emerging from step 1&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;709&quot; src=&quot;https://img.ly/_astro/5_PAuNW.webp&quot; srcset=&quot;/_astro/5_ZhyHA5.webp 640w, /_astro/5_ZU0lHo.webp 750w, /_astro/5_1ko4iQ.webp 828w, /_astro/5_2oqGyL.webp 1080w, /_astro/5_Z1TL0dQ.webp 1280w, /_astro/5_htj7.webp 1668w, /_astro/5_PAuNW.webp 2000w&quot;&gt;&lt;/p&gt;
&lt;p&gt;In the second step, we quadruplicate the output of step 1 to a resolution of 1024x1360 pixels. To prevent the resolution loss for unmasked regions caused by this upscaling, we stitch the generated content into the same sized (downscaled) input image. The resulting image serves as the model input for step 2. ‌‌&lt;/p&gt;
&lt;p&gt;To avoid/reduce image artifacts in the subsequent inpainting process, we modify the original mask to contain only the small mask regions and the boundaries of the large mask regions. In detail, we temporarily shrink the mask with an erosion kernel to ablate small mask segments and the marginal areas of larger mask sections, cf. Figure 6B. Finally, we calculate the difference between the original mask and the altered mask, resulting in our desired modified mask, cf. Figure 6C.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Figure 6: Mask modification required for step 2 of the two-step-approach. A) shows the original mask; B) the original mask temporarily shrunken by an erosion kernel; and C) the modified mask containing small mask regions and boundary areas only.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1946px) 1946px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1946&quot; height=&quot;536&quot; src=&quot;https://img.ly/_astro/6_Zeoyj0.webp&quot; srcset=&quot;/_astro/6_P3BN5.webp 640w, /_astro/6_Zr5uSS.webp 750w, /_astro/6_ChAk2.webp 828w, /_astro/6_1dIWH7.webp 1080w, /_astro/6_1qfv3T.webp 1280w, /_astro/6_81fGE.webp 1668w, /_astro/6_Zeoyj0.webp 1946w&quot;&gt;&lt;/p&gt;
&lt;p&gt;By re-inpainting, we double the resolution of the generated content for the small contiguous mask regions, cf. Figure 7A bottom right, as well as for the masked boundary areas, cf. Figure 7A upper left. Moreover, through the latter, we achieve smoothing of the intense decay in resolution between the unmasked regions and the generated content arising from step 1. Finally, we scale our image back to the original input resolution and stitch the generated content to the original image to maintain the original resolution for unmasked areas.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Figure 7: Step 2 of the two-step-approach. A) shows the inpainting result of step 1 masked by the modified mask containing only small mask areas and boundary regions; B) final inpainting result arising from step 2&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;717&quot; src=&quot;https://img.ly/_astro/7_3lyip.webp&quot; srcset=&quot;/_astro/7_Z2x2NCb.webp 640w, /_astro/7_QNPLK.webp 750w, /_astro/7_Z1WXR0V.webp 828w, /_astro/7_ZbTJbF.webp 1080w, /_astro/7_Z1nAuf6.webp 1280w, /_astro/7_1GiIWk.webp 1668w, /_astro/7_3lyip.webp 2000w&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;For us, it was impressive to see how AI-based inpainting can successfully and deceptively realistic fill in missing information. Not only the consideration of structural (semantic) content is an advantage compared to conventional approaches, but especially the decreased demand on required hardware. In our view, this opens up the opportunity to reach a much larger group of users of inpainting algorithms: in place of using powerful hardware and professional software, mobile devices could achieve small but decisive changes.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Easy removal of distracting objects with inpainting: Example photo of a red squirrel taking a nap in the trees, distracting twig marked, and inpainted result.&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;667&quot; src=&quot;https://img.ly/_astro/8_l_Z1kJHjL.webp&quot; srcset=&quot;/_astro/8_l_1JTG5u.webp 640w, /_astro/8_l_26Omlu.webp 750w, /_astro/8_l_1GpI0f.webp 828w, /_astro/8_l_ZgiRCz.webp 1080w, /_astro/8_l_Z1Fvu52.webp 1280w, /_astro/8_l_ZAIwwN.webp 1668w, /_astro/8_l_Z1kJHjL.webp 2000w&quot;&gt;&lt;/p&gt;
&lt;p&gt;In summary, we have dealt with the application of high-resolution images, which is undoubtedly gaining in importance due to the ever-improving smartphone cameras. Processing high-resolution images entail an increasing number of pixels to “inpaint” and could further lead to quality as well as performance issues. Thus, we decided to improve the output of low-resolution networks and to provide them with more information to support a subsequent upscaling procedure.&lt;br&gt;
We have implemented two different approaches, shrinking-mask and two-step-approach that can be applied independently or in a combined manner. It turned out that both methods subjectively increased the image quality. However, this comes along with higher computational demands, as models are applied multiple times.&lt;br&gt;
Overall, we think that the combination of these two approaches will represent a good toolkit for AI-based high-resolution image inpainting. But we’ll keep an eye on the upcoming scientific developments.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;This project was funded by the European Regional Development Fund (ERDF).&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 449px) 449px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;449&quot; height=&quot;112&quot; src=&quot;https://img.ly/_astro/9_Zv71r7.webp&quot; srcset=&quot;/_astro/9_Zv71r7.webp 449w&quot;&gt;&lt;/p&gt;</content:encoded><dc:creator>Vivien</dc:creator><dc:creator>Philip</dc:creator><dc:creator>Pascal</dc:creator><media:content url="https://blog.img.ly/2020/12/image_inpainting_deeplearning.gif" medium="image"/><category>Deep Learning</category><category>Artificial Intelligence</category><category>Image Editing</category><category>Tutorial</category></item><item><title>A Photo and Video Editor for React Native Apps</title><link>https://img.ly/blog/a-photo-and-video-editor-for-your-react-native-apps/</link><guid isPermaLink="true">https://img.ly/blog/a-photo-and-video-editor-for-your-react-native-apps/</guid><pubDate>Fri, 29 May 2020 10:30:01 GMT</pubDate><content:encoded>&lt;hr&gt;
&lt;h3 id=&quot;how-to-integrate-a-photo-and-video-editor-into-your-react-native-app&quot;&gt;How to integrate a Photo and Video Editor into your React Native App&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;This tutorial walks you through the integration process of PhotoEditor SDK and VideoEditor SDK into your React Native app for iOS and Android. You’ll learn how to use our React Native modules to facilitate the integration and to customize our editors. For this tutorial we presume that all the necessary development tools for building an iOS and Android app are met, so make sure to complete the official &lt;a href=&quot;https://reactnative.dev/docs/getting-started&quot;&gt;React Native CLI Quickstart&lt;/a&gt; guides for iOS and Android beforehand.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Please make sure to acquire the licenses for &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; before integrating them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/embed/e9JiCMQKrJY?feature=oembed&quot;&gt;https://www.youtube.com/embed/e9JiCMQKrJY?feature=oembed&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In this tutorial, we’re going to show how to integrate PhotoEditor SDK and VideoEditor SDK for iOS and Android into your React Native app. Therefore, we created React Native modules for our products to simplify this process for you as much as possible. We’re going to use &lt;a href=&quot;https://github.com/imgly/vesdk-react-native&quot;&gt;VideoEditor SDK’s README&lt;/a&gt;, which is in most parts identical to the PhotoEditor SDK’s README, and Visual Studio Code. So, let’s get started.&lt;/p&gt;
&lt;p&gt;First, we create a React Native project with the name “Demo” based on the default template by using the command &lt;code&gt;npx react-native init Demo&lt;/code&gt;. The project will now be initialized and automatically install all dependencies of the current React Native version. Afterwards, we can find the new React Native project ready to use in the folder “Demo”. So, we’ll speed this up a little.&lt;/p&gt;
&lt;p&gt;We already prepared another folder with resources and assets that we want to integrate in our app. Here we chose an image, the required licenses for our PhotoEditor SDK and VideoEditor SDK for both target platforms, a video and two logos that we will later use to show how we can customize our editors. We copy these resources into the root of our project to make the resources accessible for our app.&lt;/p&gt;
&lt;p&gt;Now, we switch to the folder of the “Demo” project*.* We can now copy and execute the command &lt;code&gt;yarn add react-native-videoeditorsdk&lt;/code&gt; from the README to install the dependencies to the React Native module for our VideoEditor SDK … and to the React Native module for PhotoEditor SDK by issuing the command &lt;code&gt;yarn add react-native-photoeditorsdk&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now, we’re going to set up the dependencies for our native iOS libraries. We can simply copy the command &lt;code&gt;cd ios &amp;#x26;&amp;#x26; pod install &amp;#x26;&amp;#x26; cd ..&lt;/code&gt; from the README and execute it to install all iOS dependencies. They include the native PhotoEditor SDK and VideoEditor SDK libraries that are required by our React Native modules.&lt;/p&gt;
&lt;p&gt;And now, we set up the dependencies for our native Android libraries. The required steps that we will now take are described in detail in the README.&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;android {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  defaultConfig {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    multiDexEnabled true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;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;dependencies {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  implementation ‘androidx.multidex:multidex:2.0.1’&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We copy the lines and add them at the end of our &lt;code&gt;android/app/build.gradle&lt;/code&gt; file. Now we need to change the superclass of our &lt;code&gt;MainApplication&lt;/code&gt; class to enable Multidex. Next, we add the img.ly repository and the plugin by copying the following lines and add them at the top of our &lt;code&gt;android/build.gradle&lt;/code&gt; file located in our Android folder.&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;buildscript {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  repositories {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    jcenter()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    maven { url &quot;https://plugins.gradle.org/m2/&quot; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    maven { url &quot;https://artifactory.img.ly/artifactory/imgly&quot; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  dependencies {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    classpath &quot;org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.61&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    classpath &apos;ly.img.android.sdk:plugin:7.1.8&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we can configure our PhotoEditor SDK and VideoEditor SDK by opening the &lt;code&gt;android/app/build.gradle&lt;/code&gt; file and add these lines under &lt;code&gt;apply plugin: “com.android.application&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;apply plugin: &apos;ly.img.android.sdk&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;apply plugin: &apos;kotlin-android&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// Comment out the modules you don&apos;t need, to save size.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;imglyConfig {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  modules {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;ui:text&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;ui:focus&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;ui:frame&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;ui:brush&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;ui:filter&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;ui:sticker&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;ui:overlay&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;ui:transform&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;ui:adjustment&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;ui:text-design&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;ui:video-trim&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // This module is big, remove the serializer if you don&apos;t need that feature.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;backend:serializer&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // Remove the asset packs you don&apos;t need, these are also big in size.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;assets:font-basic&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;assets:frame-basic&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;assets:filter-basic&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;assets:overlay-basic&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;assets:sticker-shapes&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;assets:sticker-emoticons&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Getting back to our iOS version, we can now launch our demo project on iOS, which will currently look like a plain React Native project that we initialized with the first command.&lt;/p&gt;
&lt;p&gt;The main difference to an off-the-shelf React Native project is that our React Native modules are installed and ready-to-use in the &lt;code&gt;App.js&lt;/code&gt; file once the native projects are compiled. Then, it won’t be necessary to recompile the native projects for the remainder of this tutorial. We sped up the compilation a little and here we go — our React Native app is running on the iOS simulator. Now, we do the same for the Android version and wait until the project is compiled.&lt;/p&gt;
&lt;p&gt;Now, the demo project launched on both platforms as we can see on the right on the iOS simulator at the top, and on the Android emulator at the bottom of the screen.&lt;/p&gt;
&lt;p&gt;We’ve decided that we want to start our photo editor by pressing a button. So next, we’re going to actually customize our React Native app by adding this button. Therefore, we open the &lt;code&gt;App.js&lt;/code&gt; file and import the &lt;code&gt;Button&lt;/code&gt; component in order to create a button with the title “Edit a sample image”. For now, we leave the &lt;code&gt;onPress&lt;/code&gt; function empty.&lt;/p&gt;
&lt;p&gt;We save the &lt;code&gt;App.js&lt;/code&gt; file to trigger a refresh of the running apps and immediately see the result on the right. The new button appears in both, the iOS and the Android app.&lt;/p&gt;
&lt;p&gt;Now we create a second button with the title “Edit a sample video”. This will respectively start our video editor. And again, we save the &lt;code&gt;App.js&lt;/code&gt; file and see the second button appear on the right side.&lt;/p&gt;
&lt;p&gt;Next, we are going to add the code that actually opens our editors when we press the buttons. Visual Studio Code automatically imported the respective React Native PhotoEditor SDK module for us at the very top of the file, while writing the code that makes use of our SDK. We do the same for the VideoEditor SDK. We use the &lt;code&gt;require&lt;/code&gt; function to make static assets available to our app. Here, we “require” our sample image and our sample video that we copied to the app’s folder in the beginning and pass them as the first argument to our &lt;code&gt;openEditor&lt;/code&gt; functions. The first argument can also be a regular URI.&lt;/p&gt;
&lt;p&gt;We save the &lt;code&gt;App.js&lt;/code&gt; file again and now we can click the buttons to start our photo editor or video editor. There we go! We still see a watermark here. The reason for this watermark is that we haven’t unlocked our SDKs so far which we will do next.&lt;/p&gt;
&lt;p&gt;We unlock both products with our licenses to get rid of the watermark. If not unlocked, the watermark will be on both the image and video previews as well as on the exported images and videos. To unlock the products, we use the &lt;code&gt;unlockWithLicense&lt;/code&gt; function of each SDK. In total, we need four license files, one license file for each product and platform combination. The license files should be named &lt;code&gt;pesdk_license&lt;/code&gt; and &lt;code&gt;vesdk_license&lt;/code&gt; with platform-specific extensions &lt;code&gt;.ios.json&lt;/code&gt; and &lt;code&gt;.android.json&lt;/code&gt;. React Native will then automatically pick the right file for the corresponding platform. After this, the watermarks will be removed for PhotoEditor SDK and VideoEditor SDK on both platforms. And now you can also see it in the simulator —  no watermarks anymore.&lt;/p&gt;
&lt;p&gt;In the next step, we’re going to change the configuration of the editors. If no changes are made to the configuration, our default stickers are available with the editor. To customize them, we need to import the &lt;code&gt;Configuration&lt;/code&gt; from either the PhotoEditor SDK or VideoEditor SDK. The configurations are compatible between both products. So, for this tutorial, we decided to use the VideoEditor SDK configuration which we are now using by adding &lt;code&gt;Configuration&lt;/code&gt; to the &lt;code&gt;react-native-videoeditorsdk&lt;/code&gt; imports. We decided that we want to add custom stickers to our editors. Therefore we define a non-default configuration to the sticker tool.&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;const configuration: Configuration = {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  sticker: {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To customize the sticker assets, we need to define the sticker “categories” array. Here, we define a new category and name the identifier &lt;code&gt;demo_sticker_category&lt;/code&gt;. These asset identifiers must always be unique. Next, we set a name for the category and we name it “Logos”.&lt;/p&gt;
&lt;p&gt;Each category also requires a thumbnail image to be displayed in the editor. For the thumbnail, we use the React logo that we added to the folder of our app at the very beginning. Next, we define the items for this new sticker category. These items are the actual stickers that we can apply to the edited image or video. We now create a new sticker for the React logo. Therefore, we call the identifier &lt;code&gt;demo_sticker_react&lt;/code&gt; and name it “React”. These sticker names won’t appear in the UI, but they are used for accessibility. Now, we need to define the actual image that should be used for that sticker. Here we use the React image again.&lt;/p&gt;
&lt;p&gt;To create a second sticker, we can now copy and paste the code of the first sticker. We create a sticker with our img.ly logo and rename the identifier of the pasted code to &lt;code&gt;demo_sticker_imgly&lt;/code&gt;. Accordingly, we set the name to “img.ly” and change the file to &lt;code&gt;imgly.png&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In addition, we want to specify a non-default tint mode for our second sticker by using &lt;code&gt;tintMode: TintMode.SOLID&lt;/code&gt; which enables us to change the color of the sticker. The &lt;code&gt;TintMode&lt;/code&gt; type is automatically added to the VideoEditor SDK imports for us by Visual Studio Code. Now, that we completed our configuration, we need to pass it as the second argument to the &lt;code&gt;openEditor&lt;/code&gt; functions in order to take effect.&lt;/p&gt;
&lt;p&gt;We save the &lt;code&gt;App.js&lt;/code&gt; file again to refresh the running apps and we can see the result live after starting a new editing session. Please note that you cannot alter the configuration of a running editor instance. You always need to start a new editing session to see configuration changes.&lt;/p&gt;
&lt;p&gt;We want to use another feature of our SDKs which is called serialization. With the serialization feature, we can capture all image and video editing operations that are applied in the editor and export them. This allows us to import the editing operations in later sessions and continue editing. The serializations are compatible between both products as well. The input serialization is the third parameter of the &lt;code&gt;openEditor&lt;/code&gt; functions of our SDKs and the output serialization is optionally part of their result type.&lt;/p&gt;
&lt;p&gt;First, we check if the result is “null”. This is the case when a user clicks the “Discard” button in the editor and thus does not export an image or video. If the result is not ”null”, we know that the user exported an image or video. Then we can assign the exported serialization to the previously defined global serialization variable which will then be input to the next editing session. We copy the code and add it to the video editor as well to enable the serialization function here too.&lt;/p&gt;
&lt;p&gt;Now, one thing is left to enable the actual serialization export in the configuration. The serialization export is disabled per default because not every user needs the serialization feature. Here, we enable it now and also change the export type to &lt;code&gt;object&lt;/code&gt;. By doing so, the result type of the editor will contain the serialization as an &lt;code&gt;object&lt;/code&gt;. Per default, the serialization is exported to a file and that file name is returned as part of the export result. Writing the serialization to a file is a reasonable default as serializations can be quite large, especially if large amounts of binary data for personal stickers are embedded.&lt;/p&gt;
&lt;p&gt;Now, we can run the app on the simulator and use all the parameters that we configured in this tutorial. First, we can add our custom stickers, both the React logo and the img.ly logo. Here we can also change the colors which we enabled with the tint mode.&lt;/p&gt;
&lt;p&gt;We can also use the text design tool to add a phrase to our image. Here we can pick different designs, so we’re trying a couple and place the text design fitting to the image and logo.&lt;/p&gt;
&lt;p&gt;Next, we export our image with the serialization. With the serialization function enabled, it is now possible to import the editing operations into our video editor. This allows us to keep on editing because the serialization is compatible between both products. So here we can add further words to our text design. We can also put filters on our video. For example, we can choose the peach duo tone and increase the contrast a little. And here we go! We successfully integrated PhotoEditor SDK and VideoEditor SDK into our React Native app.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thanks for reading! To stay in the loop, subscribe to our&lt;/strong&gt; &lt;a href=&quot;https://photoeditorsdk.us13.list-manage.com/subscribe?u=dc9f652839dbb620d14d6d28d&amp;#x26;id=04a306e4b2&quot;&gt;&lt;strong&gt;Newsletter&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Julia</dc:creator><dc:creator>Alexander</dc:creator><media:content url="https://blog.img.ly/2020/05/_Integration_--1-.png" medium="image"/><category>App Development</category><category>Code</category><category>Developer Tools</category><category>Developer</category><category>Development</category><category>Image Editing</category><category>JavaScript</category><category>Mobile App Development</category><category>Photo Editing</category><category>React</category><category>React Native</category><category>Software Development</category><category>Tech</category><category>Tutorial</category><category>Video Editing</category><category>How-To</category><category>Company</category></item><item><title>Why our SDK is not Photoshop or Lego.</title><link>https://img.ly/blog/why-our-sdk-is-not-photoshop-or-lego-e2890f9b22b0/</link><guid isPermaLink="true">https://img.ly/blog/why-our-sdk-is-not-photoshop-or-lego-e2890f9b22b0/</guid><pubDate>Sun, 23 Feb 2020 23:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;PhotoEditor SDK&lt;/strong&gt; (Software Development Kit) or more general w&lt;strong&gt;hite-label editor solution&lt;/strong&gt; might sound like big words. And of course, we’d love to tell you that we are a jack of all trades. However, while our standard is to provide you with the most sophisticated editor solution possible, there are challenges to be faced on that path. Now, while I’d be more than happy to talk about all the reasons in favor of using our SDKs, I’m convinced you’ll get the clearest image of whether PhotoEditor SDK is the right solution for you when I tell you what we can’t do. So, let’s jump right in.&lt;/p&gt;
&lt;h3 id=&quot;we-are-no-photoshop&quot;&gt;We are no Photoshop&lt;/h3&gt;
&lt;p&gt;First of all, it has to be said that image editing is a quite flexible concept. It relates to everything that alters the appearance or content of an image. From applying a black &amp;#x26; white filter and adding text to make your Instagram-stories more epic, over cutting out undesired aspects of an image like an ex-boyfriend or altering ratios up to the point where the image does not display what was originally captured, for sure, some Tinder profile pictures.&lt;/p&gt;
&lt;p&gt;Now, tools like Photoshop are built for professionals to edit images and polish them in hours of detail work. In other words: it’s an extremely powerful solution you can do ANYTHING with. And while this is its main appeal, its complexity is also why non-designers who don’t want to spend a lot of time learning how to use it — simply don’t.&lt;/p&gt;
&lt;p&gt;However, that isn’t to say that these users don’t have a need to edit images for different purposes. This is where we come into play, making image editing and design accessible for everyone at the tap of a finger. While our PhotoEditor SDK doesn’t do everything, it delivers the set of tools your users really need and want to see in your app — no matter if it’s a social network, a printing service or a marketing tool — at a very high quality.&lt;/p&gt;
&lt;h3 id=&quot;we-are-no-lego-either&quot;&gt;We are no Lego either&lt;/h3&gt;
&lt;p&gt;I guess many of us remember the joy of playing with Lego when we were little toddlers. No matter how crazy the idea, we put it together brick by brick eventually ending up with a quite colorful but yet solid plane, car or spaceship — thanks to Lego’s incredible modularity.&lt;/p&gt;
&lt;p&gt;Can you approach using PhotoEditor SDK in the same way? No.&lt;br&gt;
Is that a bad thing? No, again — actually quite the opposite. While freedom of design is often viewed as one of the greatest goods to strive for, it adds tons of complexity when building applications. However, right at the top of the must-have list is a smooth and intuitive UX. Hence, not every part of the editor can just be re-attached to any other place within it. Our designers created a well thought out UI that makes operating the editor simple and enjoyable.&lt;/p&gt;
&lt;p&gt;You can think of it as a Lego building instruction. Sure, you could try to assemble that recently bought Lego product without it, by trial and error. However, as you didn’t purchase just a handful of randomly selected bricks, I’m convinced you’d love to successfully complete that flashy Millennium Falcon to proudly place it somewhere in your living room. Therefore, following the steps of the enclosed booklet is similar to editing your way through our well thought out UI.&lt;/p&gt;
&lt;p&gt;Also, back then Lego seemed compatible with almost every other toy we owned, or at least, we didn’t mind mixing them up. However, when it comes to coding, not every brick attaches to any other brick per default. For instance, there used to be only rudimentary demos for the integration of our SDKs with a handful of frameworks available. Thus, making the standard integration as explained in &lt;a href=&quot;https://img.ly/docs/pesdk/&quot;&gt;our docs&lt;/a&gt; the best way for the implementation. That is, until now.&lt;/p&gt;
&lt;p&gt;With our React Native wrapper, we have released the first in a row of framework integrations for &lt;a href=&quot;https://img.ly/photo-sdk&quot;&gt;PhotoEditor SDK&lt;/a&gt;. Feel free to check it out &lt;a href=&quot;https://img.ly/docs/pesdk/&quot;&gt;here&lt;/a&gt;. In addition, you should read the &lt;a href=&quot;https://img.ly/blog/react-native-native-modules-made-for-react-developers-59ca93c41541/&quot;&gt;corresponding blog article&lt;/a&gt; my colleague, Alex, published a few days ago. The good news — our development team doesn’t stop there and will add more wrappers during the coming months. So, stay tuned.&lt;/p&gt;
&lt;p&gt;If you’re interested in implementing the editor into your app or website using a framework, you should let us know which framework you’re interested in.&lt;/p&gt;
&lt;h3 id=&quot;so-what-exactly-can-you-expect-from-us&quot;&gt;So, what exactly can you expect from us?&lt;/h3&gt;
&lt;p&gt;In essence: an editor solution that provides you with…&lt;/p&gt;
&lt;p&gt;*&lt;strong&gt;*·**&lt;/strong&gt; a well-balanced feature selection serving a wide variety of use cases,&lt;/p&gt;
&lt;p&gt;*&lt;strong&gt;*·**&lt;/strong&gt; a degree of customizability ensuring that no one will ever notice that your editor is a third-party library, and&lt;/p&gt;
&lt;p&gt;*&lt;strong&gt;*·**&lt;/strong&gt; ongoing maintenance and support at an easy to calculate price over time.&lt;/p&gt;
&lt;p&gt;To sum things up, ideally, you already know what you expect from a third-party editor solution. So, instead of telling you that we are the best choice for your use-case, I’d like you to be the judge of that.&lt;/p&gt;
&lt;p&gt;We are happy to discuss any and every question you might have. Also, as qualitative feedback is always appreciated, we’d love to talk to you. Don’t hesitate to reach out.&lt;/p&gt;
&lt;p&gt;Until then, cheers and keep it up&lt;br&gt;
Magnus&lt;/p&gt;
&lt;p&gt;*&lt;strong&gt;*Thanks for reading! To stay in the loop, subscribe to our&lt;/strong&gt; &lt;a href=&quot;https://photoeditorsdk.us13.list-manage.com/subscribe?u=dc9f652839dbb620d14d6d28d&amp;#x26;id=04a306e4b2&quot;&gt;&lt;strong&gt;Newsletter&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;.**&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Magnus</dc:creator><media:content url="https://blog.img.ly/2020/04/1-hglER14sKML6hqpet642FQ.jpeg" medium="image"/><category>Photo Editing</category><category>Lego</category><category>Photoshop</category><category>Image Editing</category><category>SDK</category><category>Learning</category></item></channel></rss>