<?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>Antonello – IMG.LY Blog</title><description>I&apos;m a software engineer, but I prefer to call myself a Technology Bishop. Spreading knowledge through writing is my mission.</description><link>https://img.ly/blog/author/antonello/</link><language>en-us</language><image><url>https://img.ly/apple-touch-icon.png</url><title>Antonello – IMG.LY Blog</title><link>https://img.ly/blog/author/antonello/</link></image><atom:link href="https://img.ly/blog/author/antonello/rss.xml" rel="self" type="application/rss+xml"/><generator>Astro</generator><lastBuildDate>Tue, 09 Jun 2026 08:04:23 GMT</lastBuildDate><ttl>60</ttl><item><title>How To: Video Generation With Javascript</title><link>https://img.ly/blog/how-to-video-generation-with-javascript/</link><guid isPermaLink="true">https://img.ly/blog/how-to-video-generation-with-javascript/</guid><description>Learn how to programmatically create videos at scale with Javascript and CreativeEditor SDK.</description><pubDate>Wed, 22 Jan 2025 09:53:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Follow this tutorial to learn how to programmatically create videos in JavaScript directly in the browser.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In 2025 video is firmly established as powerhouse for engagement, gaining even more traction with the rise of short-form videos. After all, as humans, we naturally resonate with video content more than any other type of media.&lt;/p&gt;
&lt;p&gt;The problem is that video generation is challenging—and doing it within the browser through JavaScript makes things even more complex. Fortunately, production-grade solutions like &lt;a href=&quot;https://img.ly/docs/cesdk/js/prebuilt-solutions/video-editor-9e533a/&quot;&gt;CreativeEditor SDK (CE.SDK)&lt;/a&gt; make the process not only possible but also easy to implement.&lt;/p&gt;
&lt;p&gt;In this guide, you will learn how to programmatically generate videos in the browser via JavaScript using CreativeEditor SDK. We will cover various applications, including merging videos, adding audio tracks, and even integrating AI features.&lt;/p&gt;
&lt;p&gt;Let’s dive in!&lt;/p&gt;
&lt;h2 id=&quot;why-programmatic-video-generation-matters&quot;&gt;Why Programmatic Video Generation Matters&lt;/h2&gt;
&lt;p&gt;Videos are dominating social media, marketing, and online platforms such as e-commerce platforms (e.g., to showcase products). Numerous studies have proven that &lt;a href=&quot;https://thesocialshepherd.com/blog/video-marketing-statistics&quot;&gt;video is the most effective form of media&lt;/a&gt; for marketing, as it resonates deeply with us.&lt;/p&gt;
&lt;p&gt;As the demand for personalized and dynamic content increases, traditional video production methods are becoming inefficient. The proliferation of channels with different demands on size and video quality as well as the need to create personalized videos at scale means that automated video creation is becoming indispensable. Most existing solutions run batch processing of videos on the server after gathering input data from various source. However, while server-side processing quickly becomes costly and introduces significant communication overhead client devices have become more powerful than ever.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://img.ly/products/creative-sdk&quot;&gt;CreativeEditor SDK&lt;/a&gt; bridges that gap by simplifying programmatic video generation in JavaScript within modern browsers. With CE.SDK, you can automate repetitive tasks and define scalable, personalized, and engaging video creation workflows, ensuring each generated video resonates with its target audience.&lt;/p&gt;
&lt;h2 id=&quot;get-started-with-cesdk-for-javascript&quot;&gt;Get Started with CE.SDK for JavaScript&lt;/h2&gt;
&lt;p&gt;Now that we established why programmatic video generation is important, you are ready to get started with the tool designed for it: CreativeEditor SDK.&lt;/p&gt;
&lt;p&gt;Learn how to integrate CE.SDK for video editing into a vanilla JavaScript application!&lt;/p&gt;
&lt;p&gt;You can access the code for this tutorial on &lt;a href=&quot;https://github.com/imgly/video-generation-js&quot;&gt;Github&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;requirements&quot;&gt;Requirements&lt;/h3&gt;
&lt;p&gt;The only prerequisites to follow this tutorial are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A modern browser&lt;/strong&gt;: CreativeEditor SDK runs directly in your browser’s JavaScript engine, so no additional setup is required. Any &lt;a href=&quot;https://caniuse.com/wasm&quot;&gt;browser supporting WASM&lt;/a&gt; is enough.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A CreativeEditor SDK license&lt;/strong&gt;: If you do not have one yet, &lt;a href=&quot;https://img.ly/forms/free-trial&quot;&gt;sign up for a free trial&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If your web application uses Node.js, ensure you have the &lt;a href=&quot;https://nodejs.org/en/download&quot;&gt;latest stable versions of both Node.js and NPM installed&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;import-the-library&quot;&gt;Import the library&lt;/h3&gt;
&lt;p&gt;In a vanilla JavaScript application, create a JavaScript module file (e.g., video-editor.js) and import the CreativeEditor SDK engine library inside it:&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; CreativeEngine &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;&amp;#x3C;https://cdn.img.ly/packages/imgly/cesdk-engine/1.42.0/index.js&gt;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: In this example, the SDK is served from our CDN for convenience. In a production environment, it is recommended to host all &lt;a href=&quot;https://img.ly/docs/cesdk/js/serve-assets-b0827c/&quot;&gt;assets and libraries on your own servers&lt;/a&gt; for improved control and performance.&lt;/p&gt;
&lt;p&gt;To use the video-editor.js module in an HTML page, import it with this line:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt; type&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;module&quot;&lt;/span&gt;&lt;span&gt; src&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;video-editor.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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules&quot;&gt;type=“module”&lt;/a&gt; attribute tells the browser to treat the script as an ES6 module, so that you can use import and export statements.&lt;/p&gt;
&lt;p&gt;Alternatively, if you are using a module bundler like Webpack, Rollup, Parcel, or Vite, add the &lt;a href=&quot;https://www.npmjs.com/package/@cesdk/engine&quot;&gt;@cesdk/engine&lt;/a&gt; npm package to your project’s dependencies:&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; @cesdk/cesdk-js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case, you can then import the headless SDK into your JavaScript code as follows:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; CreativeEngine &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@cesdk/engine&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Well done!&lt;/p&gt;
&lt;h2 id=&quot;setting-up-your-environment&quot;&gt;&lt;strong&gt;Setting Up Your Environment&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;In your JavaScript module, right below the library import, initialize the &lt;a href=&quot;https://img.ly/docs/cesdk/node/get-started/overview-e18f40/&quot;&gt;CreativeEditor SDK headless engine&lt;/a&gt; using the following code:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// src/video-editor.js&lt;/span&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; CreativeEngine &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;&amp;#x3C;https://cdn.img.ly/packages/imgly/cesdk-engine/1.42.0/index.js&gt;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// your CE.SDK license and user configs&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;  license: &lt;/span&gt;&lt;span&gt;&apos;&amp;#x3C;YOUR_LICENSE&gt;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;CreativeEngine.&lt;/span&gt;&lt;span&gt;init&lt;/span&gt;&lt;span&gt;(config).&lt;/span&gt;&lt;span&gt;then&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;engine&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;  // attach the engine canvas to the DOM&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&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;cesdk_container&apos;&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;append&lt;/span&gt;&lt;span&gt;(engine.element);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // do something with your instance of CreativeEditor SDK...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // detach the engine and clean up its resource&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  engine.element.&lt;/span&gt;&lt;span&gt;remove&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  engine.&lt;/span&gt;&lt;span&gt;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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace &lt;code&gt;&amp;#x3C;YOUR_LICENSE&gt;&lt;/code&gt; with the license key provided in your CreativeEditor SDK subscription.&lt;/p&gt;
&lt;p&gt;Ensure that the HTML page importing &lt;code&gt;video-editor.js&lt;/code&gt; contains the following &lt;code&gt;&amp;#x3C;div&gt;&lt;/code&gt; element with the &lt;code&gt;cesdk_container&lt;/code&gt; ID:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;cesdk_container&quot;&lt;/span&gt;&lt;span&gt; style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;width: 100%; height: 100vh;&quot;&lt;/span&gt;&lt;span&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;a href=&quot;https://img.ly/docs/cesdk/js/get-started/overview-e18f40/&quot;&gt;&lt;code&gt;CreativeEngine.init()&lt;/code&gt;&lt;/a&gt; method will mount the editor engine component within this div.&lt;/p&gt;
&lt;p&gt;Congratulations! You have successfully integrated the video editing engine.&lt;/p&gt;
&lt;h2 id=&quot;load-a-video&quot;&gt;&lt;strong&gt;Load a Video&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Use the logic below inside the body of the CreativeEndine.init() callback function to load a video in CE.SDK:&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;// initialize a new video scene&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; engine.scene.&lt;/span&gt;&lt;span&gt;createVideo&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 page block and attach 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; page&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;page&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;appendChild&lt;/span&gt;&lt;span&gt;(scene, page);&lt;/span&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 dimensions of the video page&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setWidth&lt;/span&gt;&lt;span&gt;(page, &lt;/span&gt;&lt;span&gt;720&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setHeight&lt;/span&gt;&lt;span&gt;(page, &lt;/span&gt;&lt;span&gt;1280&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 graphic block to hold the video content&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// and set its shape to a rectangle&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; video&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;graphic&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setShape&lt;/span&gt;&lt;span&gt;(video, engine.block.&lt;/span&gt;&lt;span&gt;createShape&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;rect&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;// create a fill type for the video and set the video file URI&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; videoFill&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;createFill&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;video&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setString&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  videoFill,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;fill/video/fileURI&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;&amp;#x3C;https://cdn.img.ly/assets/demo/v2/ly.img.video/videos/pexels-drone-footage-of-a-surfer-barrelling-a-wave-12715991.mp4&gt;&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;// apply the video fill to the video graphic&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setFill&lt;/span&gt;&lt;span&gt;(video, videoFill);&lt;/span&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 track block to manage the video timeline&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// and attache the track to the page and the video graphic&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// to the track&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; track&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;track&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;appendChild&lt;/span&gt;&lt;span&gt;(page, track);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;appendChild&lt;/span&gt;&lt;span&gt;(track, video);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// make the track cover the parent block&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;fillParent&lt;/span&gt;&lt;span&gt;(track);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This initializes a video scene using &lt;a href=&quot;https://img.ly/docs/cesdk/js/concepts/scenes-e8596d/&quot;&gt;&lt;code&gt;createVideo()&lt;/code&gt;&lt;/a&gt; and creates a &lt;code&gt;&quot;graphic&quot;&lt;/code&gt; block to display the video in a rectangle, adding it to the page. Next, it loads a video from a remote resource and appends it as a track to the parent block.&lt;/p&gt;
&lt;p&gt;For a complete explanation of how the above code works, &lt;a href=&quot;https://img.ly/docs/cesdk/js/create-video-c41a08/&quot;&gt;refer to the documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you comment out the cleanup part, this is what you should see in your browser application:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 608px) 608px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;608&quot; height=&quot;697&quot; src=&quot;https://img.ly/_astro/JS-video-generation-video-fill_Z1LSqkq.webp&quot; srcset=&quot;/_astro/JS-video-generation-video-fill_Z1LSqkq.webp 608w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Notice how the video from the remote URI has been loaded into the &lt;/p&gt;&lt;div&gt; element where CreativeEditor SDK is attached to the page’s DOM.Time to explore more programmatic video generation features!&lt;p&gt;&lt;/p&gt;
&lt;h2 id=&quot;programmatic-video-generation-features&quot;&gt;Programmatic Video Generation Features&lt;/h2&gt;
&lt;p&gt;Follow the use cases below to see how CE.SDK makes automated video generation in JavaScript easier.&lt;strong&gt;Generate Video in Different Formats&lt;/strong&gt; CE.SDK supports video export in &lt;a href=&quot;https://img.ly/docs/cesdk/js/file-format-support-3c4b2a/&quot;&gt;MP4 format&lt;/a&gt; &lt;a href=&quot;https://img.ly/docs/cesdk/faq/video-support/?platform=node&quot;&gt;&lt;/a&gt;(with MP3 audio) with different resolutions and aspect ratios.To export a video with a specific aspect ratio, first adjust the width and height of the parent block to which the video block is attached:&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;// specify an aspect ratio of 9:16 (ideal for vertical videos)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setWidth&lt;/span&gt;&lt;span&gt;(page, &lt;/span&gt;&lt;span&gt;720&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setHeight&lt;/span&gt;&lt;span&gt;(page, &lt;/span&gt;&lt;span&gt;1280&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case, the video will be automatically adjusted to fit the specified dimensions. Horizontal videos will be cropped to match the defined vertical outline of the block, while vertical videos will be rendered as they are within the specified block.&lt;/p&gt;
&lt;p&gt;Next, you can export the video with the configured 9:16 aspect ratio and a given resolution with:&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;// define the MIME type for the video export (MP4 format)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; mimeType&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &apos;video/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 class=&quot;line&quot;&gt;&lt;span&gt;// define a callback function to track the progress of video rendering and encoding&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; progressCallback&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;renderedFrames&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;encodedFrames&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;totalFrames&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;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &apos;Rendered&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;// log the number of rendered frames&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    renderedFrames,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &apos;frames and encoded&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;// log the number of encoded frames&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    encodedFrames,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &apos;frames out of&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;// log the total frames to be processed&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    totalFrames&lt;/span&gt;&lt;/span&gt;
&lt;span 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;// define the video export options&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; videoOptions&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;  duration: &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;// video duration in seconds&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  framerate: &lt;/span&gt;&lt;span&gt;30&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;// video framerate (frames per second)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  targetWidth: &lt;/span&gt;&lt;span&gt;480&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;// target video width in pixels (for the resolution)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  targetHeight: &lt;/span&gt;&lt;span&gt;852&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;// target video height in pixels (for the resolution)&lt;/span&gt;&lt;/span&gt;
&lt;span 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 the page as an MP4 video&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; blob&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;exportVideo&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  page, &lt;/span&gt;&lt;span&gt;// the page containing the design video block&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  mimeType, &lt;/span&gt;&lt;span&gt;// the MIME type for the video (MP4)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  progressCallback, &lt;/span&gt;&lt;span&gt;// the callback to track video rendering progress&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  videoOptions &lt;/span&gt;&lt;span&gt;// the options for the video export&lt;/span&gt;&lt;/span&gt;
&lt;span 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 an anchor element to trigger the video download&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; anchor&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;a&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;anchor.href &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;createObjectURL&lt;/span&gt;&lt;span&gt;(blob);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;anchor.download &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;video.mp4&apos;&lt;/span&gt;&lt;span&gt;; &lt;/span&gt;&lt;span&gt;// output video name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;anchor.&lt;/span&gt;&lt;span&gt;click&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;a href=&quot;https://img.ly/docs/cesdk/js/export-save-publish/export/overview-9ed3a8/&quot;&gt;&lt;code&gt;exportVideo()&lt;/code&gt;&lt;/a&gt; function produces a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Blob&quot;&gt;&lt;code&gt;blob video file&lt;/code&gt;&lt;/a&gt; of the specified MIME type. Note that the export occurs over multiple iterations of the update loop, with a frame being encoded in each iteration. &lt;/p&gt;
&lt;p&gt;The &lt;code&gt;targetWidth&lt;/code&gt; and &lt;code&gt;targetHeight&lt;/code&gt; options are optional. If used, the video will be resized to fit the target dimensions while maintaining its aspect ratio. This is useful for setting a specific resolution for the output video while preserving the parent block’s width and height on the output video. If omitted, the produced video will match the resolution of the width and height specified with &lt;code&gt;setWidth()&lt;/code&gt; and &lt;code&gt;setHeight()&lt;/code&gt;, respectively.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;progressCallback()&lt;/code&gt; function will track and display the video generation progress in the browser’s console:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1066px) 1066px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1066&quot; height=&quot;295&quot; src=&quot;https://img.ly/_astro/video-generation-output_2ubce0.webp&quot; srcset=&quot;/_astro/video-generation-output_Z1tfnLU.webp 640w, /_astro/video-generation-output_Z1WemnE.webp 750w, /_astro/video-generation-output_Z2n2XVo.webp 828w, /_astro/video-generation-output_2ubce0.webp 1066w&quot;&gt;&lt;/p&gt;
&lt;p&gt;The final lines of the above code snippet trigger the download operation, mimicking the action of clicking a link to download a resource. This is a common JavaScript technique to programmatically trigger a file download.&lt;/p&gt;
&lt;p&gt;Once the export process completes, the output video file (video.mp4) will be automatically downloaded to the browser’s download directory.  Open its properties and this is what you will see:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 404px) 404px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;404&quot; height=&quot;512&quot; src=&quot;https://img.ly/_astro/js-video-generation-file_HN2N0.webp&quot; srcset=&quot;/_astro/js-video-generation-file_HN2N0.webp 404w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Note the video file’s resolution and the fact that its duration is set to 5 seconds, as defined by the &lt;code&gt;duration&lt;/code&gt; attribute.&lt;/p&gt;
&lt;p&gt;These options enable you to easily create clips with different lengths, aspect ratios, and resolutions, optimized for various audiences and &lt;a href=&quot;https://img.ly/industries/social-media&quot;&gt;social media platforms like LinkedIn, Instagram, Facebook, X, TikTok, YouTube, and more&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;add-audio-tracks&quot;&gt;Add Audio Tracks&lt;/h3&gt;
&lt;p&gt;Adding an audio track for narration or background music to your clip is straightforward. First, create an &lt;a href=&quot;https://img.ly/docs/cesdk/js/create-video-c41a08/&quot;&gt;“audio” block&lt;/a&gt; and add your audio resource to it:&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;const&lt;/span&gt;&lt;span&gt; audio&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;audio&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;appendChild&lt;/span&gt;&lt;span&gt;(page, audio);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setString&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  audio,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;audio/fileURI&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;https://cdn.img.ly/assets/demo/v1/ly.img.audio/audios/far_from_home.m4a&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, you can easily adjust the volume, and apply fade-in and fade-out effects 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;// set the volume level to 80%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setVolume&lt;/span&gt;&lt;span&gt;(audio, &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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// start the audio after 1 second of playback&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setTimeOffset&lt;/span&gt;&lt;span&gt;(audio, &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 class=&quot;line&quot;&gt;&lt;span&gt;// set the audio block&apos;s duration to 5 seconds&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setDuration&lt;/span&gt;&lt;span&gt;(audio, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here is breakdown of the functions used above:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/js/create-video/control-daba54/&quot;&gt;&lt;strong&gt;&lt;code&gt;setVolume()&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;: Adjusts the audio volume of the block, with a range from 0 (0%) to 1 (100%).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;setTimeOffset()&lt;/code&gt;&lt;/strong&gt;: Sets the time offset of the block relative to its parent. This determines when the block starts playing in the timeline.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;setDuration()&lt;/code&gt;&lt;/strong&gt;: Sets the playback duration of the audio block in seconds, defining how long the block will play during the scene.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this example, the audio starts at the 1-second mark and plays for 5 seconds (from 1s to 6s), with the volume set to 80% of the original.&lt;/p&gt;
&lt;h3 id=&quot;merge-videos&quot;&gt;&lt;strong&gt;Merge Videos&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;To stitch multiple video clips together in CE.SDK, you first need to import and create separate video blocks:&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;// create the first video block&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; video1&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;graphic&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setShape&lt;/span&gt;&lt;span&gt;(video1, engine.block.&lt;/span&gt;&lt;span&gt;createShape&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;rect&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; videoFill1&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;createFill&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;video&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setString&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  videoFill1,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;fill/video/fileURI&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;https://cdn.img.ly/assets/demo/v2/ly.img.video/videos/pexels-drone-footage-of-a-surfer-barrelling-a-wave-12715991.mp4&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;engine.block.&lt;/span&gt;&lt;span&gt;setFill&lt;/span&gt;&lt;span&gt;(video1, videoFill1);&lt;/span&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 the second video block&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; video2&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;graphic&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setShape&lt;/span&gt;&lt;span&gt;(video2, engine.block.&lt;/span&gt;&lt;span&gt;createShape&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;rect&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; videoFill2&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engine.block.&lt;/span&gt;&lt;span&gt;createFill&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;video&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.&lt;/span&gt;&lt;span&gt;setString&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  videoFill2,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;fill/video/fileURI&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &apos;https://cdn.img.ly/assets/demo/v2/ly.img.video/videos/pexels-kampus-production-8154913.mp4&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;engine.block.&lt;/span&gt;&lt;span&gt;setFill&lt;/span&gt;&lt;span&gt;(video2, videoFill2);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point, you have two different video clips loaded from separate video files.&lt;/p&gt;
&lt;p&gt;Now, assume you want to produce a 10-second video that includes both clips. Start by setting the duration of the page block to 10 seconds with the &lt;a href=&quot;https://img.ly/docs/cesdk/js/create-video/control-daba54/&quot;&gt;&lt;code&gt;setDuration()&lt;/code&gt;&lt;/a&gt; method:&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;engine.block.&lt;/span&gt;&lt;span&gt;setDuration&lt;/span&gt;&lt;span&gt;(page, &lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, suppose you want the first clip (video1) to play for 7 seconds, and the second clip (video2) to fade in after that and play for 3 seconds (from second 1 to second 4 of the original second clip). This is how you can set that up:&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;// set the duration of the first and second video clips&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.setDuration(video1, 7); // video1 plays for 7 seconds&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.setDuration(video2, 3); // video2 plays for 3 seconds&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// wait for the second video to be fully loaded before applying the trim options&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;await engine.block.forceLoadAVResource(videoFill2);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// trim the second video to start at 1 second and play up to second 4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.setTrimOffset(videoFill2, 1);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.setTrimLength(videoFill2, 4);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// add a fade-in animation to the second video&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const fadeInAnimation = engine.block.createAnimation(&quot;fade&quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.setInAnimation(video2, fadeInAnimation);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These are the methods used above:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;setDuration()&lt;/code&gt;&lt;/strong&gt;: Defines the duration (in seconds) that a video block will be active during playback.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;**forceLoadAVResource()**&lt;/code&gt;: Ensures that the audio or video resource (in this case, &lt;code&gt;video2&lt;/code&gt;) is fully loaded before applying trim operations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;setTrimOffset()&lt;/code&gt;&lt;/strong&gt;: Sets the start point (in seconds) within the video where playback begins.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;setTrimLength()&lt;/code&gt;&lt;/strong&gt;: Defines the length of the video to be played from the trim offset.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/js/animation/overview-6a2ef2/&quot;&gt;&lt;strong&gt;&lt;code&gt;createAnimation()&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;: Creates a fade-in animation for the second video (&lt;code&gt;video2&lt;/code&gt;) to smoothly transition into the clip.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally, add both video blocks to the track block for playback:&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 track = engine.block.create(&quot;track&quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.appendChild(page, track);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.appendChild(track, video1); // add the first video to the track&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.appendChild(track, video2); // add the second video to the track&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.fillParent(track);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The result will be:&lt;/p&gt;
&lt;figure class=&quot;kg-card kg-embed-card&quot;&gt;&lt;iframe width=&quot;225&quot; height=&quot;400&quot; src=&quot;https://blog.img.ly/2025/01/video-1.mp4&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;&lt;/figure&gt;
&lt;p&gt;Note how the second clip fades in after 7 seconds of the first clip, lasting for 3 seconds as specified.&lt;/p&gt;
&lt;h3 id=&quot;incorporate-text-variables&quot;&gt;&lt;a href=&quot;https://img.ly/blog/how-to-video-generation-with-javascript//#Incorporate-Text-Variables&quot;&gt;&lt;/a&gt;Incorporate Text Variables&lt;/h3&gt;
&lt;p&gt;Now, suppose you want to display cool words or messages in your videos. You can easily achieve this by adding a &lt;a href=&quot;https://img.ly/docs/cesdk/js/text/edit-c5106b/&quot;&gt;&lt;code&gt;&quot;text&quot;&lt;/code&gt; block&lt;/a&gt; to your page, as shown 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;const text = engine.block.create(&quot;text&quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// set the vluae of the text variable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.replaceText(text, &quot;Surfing\nis\nCOOL!&quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// set the text color to white and semi-transparent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.setTextColor(text, { r: 255.0, g: 255.0, b: 255.0, a: 0.8 });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// set the font size for the text&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.setTextFontSize(text, 30);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// positioning the text on an absolute position on the video&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.setWidthMode(text, &quot;Auto&quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.setHeightMode(text, &quot;Auto&quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.setPositionX(text, 130);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.setPositionY(text, 800);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// append the text block to the page&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;engine.block.appendChild(page, text);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The video canvas will now display a white “Surfing is COOL!” message as follows:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 514px) 514px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;514&quot; height=&quot;812&quot; src=&quot;https://img.ly/_astro/js-video-generation-surfing_ro7yG.webp&quot; srcset=&quot;/_astro/js-video-generation-surfing_ro7yG.webp 514w&quot;&gt;&lt;/p&gt;
&lt;p&gt;In this example, the content of the text block is static. However, it can easily be retrieved from a database or any other source for programmatic video generation with different messages, including personalized ones for tailored outreach (e.g., for custom greetings or offers).&lt;/p&gt;
&lt;h2 id=&quot;advanced-use-case-prompt-based-video-generation-using-ai&quot;&gt;&lt;a href=&quot;https://img.ly/blog/how-to-video-generation-with-javascript//#Advanced-Use-Case-Prompt-Based-Video-Generation-Using-AI&quot;&gt;&lt;/a&gt;Advanced Use Case: Prompt-Based Video Generation Using AI&lt;/h2&gt;
&lt;p&gt;As highlighted in our &lt;a href=&quot;https://www.linkedin.com/posts/eray-basar-57684711_imagine-building-a-full-video-app-in-a-single-activity-7262806525797089280-S_L8?utm_source=share&amp;#x26;utm_medium=member_desktop&quot;&gt;recent LinkedIn post&lt;/a&gt;, &lt;a href=&quot;https://IMG.LY&quot;&gt;IMG.LY&lt;/a&gt; has just experimented with an MVP that turns keywords into fully edited short videos, complete with a script, voiceover, and visuals—all automated.&lt;/p&gt;
&lt;p&gt;That is made possible by integrating CE.SDK with an LLM for coding and scriptwriting, &lt;a href=&quot;https://elevenlabs.io/&quot;&gt;ElevenLabs&lt;/a&gt; for voice synthesis, and Flux (via &lt;a href=&quot;https://fal.ai/&quot;&gt;fal.ai&lt;/a&gt;) for visuals. Specifically, the LLM uses CE.SDK for video composition, animation, and rendering.&lt;/p&gt;
&lt;p&gt;This is just the beginning, showing how AI can be combined with CE.SDK to programmatically generate video scripts—or even templates. A possible scenario would be to use the &lt;a href=&quot;https://img.ly/docs/cesdk/js/user-interface/ui-extensions-d194d1/&quot;&gt;Creative Editor SDK plugin API&lt;/a&gt; to extend CE.SDK with custom plugins that adds AI directly to the design editor engine.&lt;/p&gt;
&lt;p&gt;For example, you could develop a plugin with an LLM integration that allows users to input a prompt like: &lt;em&gt;“Create a 15-second video with the text ‘Welcome to our App!’ and upbeat background music.”&lt;/em&gt; The LLM will process the request, using Creative Editor SDK to automate video creation by leveraging its powerful features.&lt;/p&gt;
&lt;p&gt;Alternatively, the AI could produce a video that you can then automatically edit and enhance using CE.SDK capabilities. One thing is certain: the possibilities are endless with CE.SDK + AI!&lt;/p&gt;
&lt;h2 id=&quot;conclusion-the-future-of-programmatic-video-generation&quot;&gt;&lt;a href=&quot;https://img.ly/blog/how-to-video-generation-with-javascript//#Conclusion-The-Future-of-Programmatic-Video-Generation&quot;&gt;&lt;/a&gt;Conclusion: The Future of Programmatic Video Generation&lt;/h2&gt;
&lt;p&gt;CE.SDK for JavaScript offers exceptional versatility in automating video workflows, allowing you to easily generate, edit, and render videos with just a few lines of code. You can stitch multiple video files, add background audio tracks, and incorporate dynamic text variables to finally produce videos in the browser—all thanks to the CE.SDK headless engine.&lt;/p&gt;
&lt;p&gt;Looking ahead, AI integration with CE.SDK is unlocking even more powerful possibilities, such as prompt-based video content creation and automatic editing directly in the browser.&lt;/p&gt;
&lt;p&gt;With the headless engine provided by CreativeEditor SDK, programmatic video generation in JavaScript can be implemented in just a few minutes. Explore the video capabilities of CE.SDK and &lt;a href=&quot;https://img.ly/docs/cesdk/js/get-started/overview-e18f40/&quot;&gt;dive into the docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Stay tuned for more updates, and please &lt;a href=&quot;https://img.ly/forms/contact-sales?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=plugins1&quot;&gt;reach out&lt;/a&gt; if you have any questions. Thank you for reading.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Over 3,000 creative professionals gain early access to our new features, demos, and updates—don’t miss out, and&lt;/strong&gt; &lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i?ref=img.ly&quot;&gt;&lt;strong&gt;subscribe&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;to our newsletter.&lt;/strong&gt;&lt;/p&gt;&lt;/div&gt;</content:encoded><dc:creator>Antonello</dc:creator><dc:creator>Jan</dc:creator><media:content url="https://blog.img.ly/2025/01/javascript-generate-video.jpg" medium="image"/><category>Video Editing</category><category>Creative Automation</category><category>CE.SDK</category></item><item><title>A Modern JavaScript Video Editor: Integration Guide</title><link>https://img.ly/blog/a-modern-javascript-video-editor-integration-guide/</link><guid isPermaLink="true">https://img.ly/blog/a-modern-javascript-video-editor-integration-guide/</guid><description>Learn how to integrate IMG.LY&apos;s Javascript video editor into your web app and how to best leverage its capabilities.</description><pubDate>Thu, 16 Jan 2025 15:29:04 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Discover how to integrate&lt;/em&gt; &lt;a href=&quot;https://img.ly/docs/cesdk/js/starterkits/video-editor-e1nlor/&quot;&gt;&lt;em&gt;IMG.LY’s JavaScript video editor&lt;/em&gt;&lt;/a&gt; &lt;em&gt;into your web application and unlock its full range of features.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Video content has always been a powerhouse for engagement, becoming even more impactful with the rise of short-form videos. Platforms like YouTube and TikTok have built their empires on video content, as that remains the preferred medium for both creating and consuming information.&lt;/p&gt;
&lt;p&gt;Not only have those platforms changed how we consume information, but they have also transformed user behavior. We do not just want to watch videos—we want to create them, expecting the process to be both simple and professional.&lt;/p&gt;
&lt;p&gt;Here is why embedding video creation and editing capabilities directly into your website, web or mobile application can significantly boost user engagement and satisfaction.&lt;/p&gt;
&lt;p&gt;In this guide, you will learn how to integrate a JavaScript video editor using CreativeEditor SDK (CE.SDK). We will explore when it is most useful and what customizations it supports to suit your unique needs.&lt;/p&gt;
&lt;p&gt;Want to jump into the code? For a quick start, visit our &lt;a href=&quot;https://github.com/imgly/cesdk-web-examples/tree/main/integrate-with-vanilla-js&quot;&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let’s dive in!&lt;/p&gt;
&lt;h2 id=&quot;why-does-your-javascript-web-app-need-a-video-editor&quot;&gt;Why Does Your JavaScript Web App Need a Video Editor?&lt;/h2&gt;
&lt;p&gt;The world of content is constantly evolving—from text to images, from static visuals to long-form videos, and now from long videos to bite-sized clips. What stays consistent is that &lt;a href=&quot;https://www.idomoo.com/blog/surprising-video-engagement-statistics/&quot;&gt;video content resonates deeply with us as humans&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;No wonder, &lt;a href=&quot;https://www.statista.com/statistics/1285960/top-downloaded-mobile-apps-worldwide/&quot;&gt;TikTok tops global app download charts&lt;/a&gt;, while &lt;a href=&quot;https://www.similarweb.com/top-websites/&quot;&gt;YouTube, Facebook, and Instagram rank among the most visited sites&lt;/a&gt; right after Google. These platforms have not just built their empires on video—they have revolutionized how we think about video production.&lt;/p&gt;
&lt;p&gt;They set the gold standard by enabling anyone to create professional-looking videos with minimal effort, offering tools for adding filters, overlays, audio, and text in just a few clicks. This ease of use has made intuitive video editing a must-have for web applications featuring social media integration, marketing ambitions, or content management capabilities.&lt;/p&gt;
&lt;p&gt;By embedding a user-friendly JavaScript video editor in your application, you can ride this trend, providing a feature billions of users are already familiar with. The payoff? Lower barriers to user-generated content, enhanced engagement, and wider content distribution.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://img.ly/products/creative-sdk&quot;&gt;CreativeEditor SDK&lt;/a&gt; from &lt;a href=&quot;https://IMG.LY&quot;&gt;IMG.LY&lt;/a&gt; delivers a seamless, high-performance, and feature-rich JavaScript solution for in-browser design, video, and photo editing—ready to meet your users’ expectations.&lt;/p&gt;
&lt;h2 id=&quot;getting-started-adding-a-video-editor-in-javascript&quot;&gt;Getting Started: Adding a Video Editor in JavaScript&lt;/h2&gt;
&lt;p&gt;Follow this step-by-step guide to learn how to integrate a JavaScript video editor into your site using CreativeEditor SDK.&lt;/p&gt;
&lt;p&gt;Get started with integrating CE.SDK in a vanilla JavaScript application!&lt;/p&gt;
&lt;h3 id=&quot;requirements&quot;&gt;Requirements&lt;/h3&gt;
&lt;p&gt;CreativeEditor SDK runs directly in your browser’s JavaScript engine, so no specific prerequisites are needed.&lt;/p&gt;
&lt;p&gt;If your web application relies on Node.js, ensure that you have the &lt;a href=&quot;https://nodejs.org/en/download&quot;&gt;latest stable versions of Node.js and NPM installed&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;installation-and-library-import&quot;&gt;Installation and Library Import&lt;/h3&gt;
&lt;p&gt;In a vanilla JavaScript application, create a JavaScript module file (e.g., video-editor.js) and import the CreativeEditorSDK library:&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; CreativeEditorSDK &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;&amp;#x3C;https://cdn.img.ly/packages/imgly/cesdk-js/1.42.0/index.js&gt;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: In this example, the SDK is served from our CDN for convenience. In a production environment, you should &lt;a href=&quot;https://img.ly/docs/cesdk/js/serve-assets-b0827c/&quot;&gt;host assets on your own servers&lt;/a&gt; for improved control and performance.&lt;/p&gt;
&lt;p&gt;Alternatively, if you are using a bundler like Webpack, Rollup, Parcel, or Vite, and you want to integrate the CreativeEditor module within your existing project, simply add the &lt;a href=&quot;https://www.npmjs.com/package/@cesdk/cesdk-js&quot;&gt;@cesdk/cesdk-js&lt;/a&gt; npm package as a dependency to your project:&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; [@cesdk/cesdk-js](&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;https://www.npmjs.com/package/@cesdk/cesdk-js&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can then import it as 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;import&lt;/span&gt;&lt;span&gt; CreativeEditorSDK&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; &quot;@cesdk/cesdk-js&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Well done!&lt;/p&gt;
&lt;h3 id=&quot;initialize-the-video-editor&quot;&gt;Initialize the Video Editor&lt;/h3&gt;
&lt;p&gt;In your JavaScript module, right below the library import, initialize CreativeEditor SDK with the following logic:&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;// src/video-editor.js&lt;/span&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; CreativeEditorSDK &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;&amp;#x3C;https://cdn.img.ly/packages/imgly/cesdk-js/1.42.0/index.js&gt;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// your CE.SDK license and user configs&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;  license: &lt;/span&gt;&lt;span&gt;&apos;&amp;#x3C;YOUR_LICENSE&gt;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  userId: &lt;/span&gt;&lt;span&gt;&apos;&amp;#x3C;YOUR_USER_ID&gt;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;CreativeEditorSDK.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;#cesdk_container&apos;&lt;/span&gt;&lt;span&gt;, config).&lt;/span&gt;&lt;span&gt;then&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;editor&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;  // do something with your instance of CreativeEditor SDK...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // when done, clean up and free up resources&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  editor.&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace &lt;code&gt;&amp;#x3C;YOUR_LICENSE&gt;&lt;/code&gt; with the license key you get from CreativeEditor SDK and &lt;code&gt;&amp;#x3C;YOUR_USER_ID&gt;&lt;/code&gt; with your user ID. The user ID is optional and helps track MAUs (Monthly Active Users) across different devices.&lt;/p&gt;
&lt;p&gt;To integrate the video-editor.js file, import it into your HTML page like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt; type&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;module&quot;&lt;/span&gt;&lt;span&gt; src&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;video-editor.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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules&quot;&gt;type=“module”&lt;/a&gt; attribute. This tells the browser to treat the script as an ES6 module, so that you can use import and export statements within your JavaScript code.&lt;/p&gt;
&lt;p&gt;Make sure the same HTML page includes the following div element where the video editor will be embedded:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;cesdk_container&quot;&lt;/span&gt;&lt;span&gt; style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;width: 100%; height: 100vh;&quot;&lt;/span&gt;&lt;span&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will load the video editor with the default video preset, giving users the ability to trim, cut, apply filters, add text overlays, include music, and more to enhance their videos.&lt;/p&gt;
&lt;p&gt;Congratulations, you have successfully integrated the video editor!&lt;/p&gt;
&lt;h2 id=&quot;creativeeditor-sdk-javascript-video-editing-api-for-web-desktop-and-mobile&quot;&gt;CreativeEditor SDK: JavaScript Video Editing API for Web, Desktop, and Mobile&lt;/h2&gt;
&lt;p&gt;You just saw how to integrate the CE.SDK into a browser application. Yet, do not forget that the SDK supports a wide variety of frameworks and libraries—including mobile and web applications.&lt;/p&gt;
&lt;h3 id=&quot;web-framework-support&quot;&gt;Web Framework Support&lt;/h3&gt;
&lt;p&gt;CE.SDK is designed to work with several popular JavaScript frameworks and libraries. For more detailed integration instructions, take a look at the official page on the documentation for each framework:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/react/get-started/overview-e18f40/&quot;&gt;React&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/angular/get-started/overview-e18f40/&quot;&gt;Angular&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/vue/get-started/overview-e18f40/&quot;&gt;Vue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/svelte/get-started/overview-e18f40/&quot;&gt;Svelte&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/js/get-started/overview-e18f40/&quot;&gt;JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Additionally, the SDK is available for headless mode and works well in a &lt;a href=&quot;https://img.ly/docs/cesdk/node/get-started/overview-e18f40/&quot;&gt;Node.js environment&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;cross-platform-support&quot;&gt;Cross-Platform Support&lt;/h3&gt;
&lt;p&gt;One of the standout features of CreativeEditor SDK is its cross-platform philosophy. This extends beyond JavaScript ecosystems for the web, and includes mobile (iOS and Android) and desktop, thanks to support for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/react-native/get-started/overview-e18f40/&quot;&gt;React Native&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/docs/cesdk/electron/get-started/overview-e18f40/&quot;&gt;Electron&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is made possible through a powerful engine that powers your app via features like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Unified API&lt;/strong&gt;: The same underlying API is shared across web, desktop, iOS, and Android applications.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cross-Platform Feature Parity&lt;/strong&gt;: CE.SDK guarantees that features are available consistently across platforms. Since core functionality is implemented at the engine level, features you use on one platform will be available on others, with only slight differences in release timelines.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Interoperable Designs&lt;/strong&gt;: Designs created in the editor component on one platform work on all platforms supported by CE.SDK. Whether a user is designing on iOS, Android, or the web, their design files can be imported seamlessly between platforms.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Native iOS and Android libraries, along with other frameworks, are also available. &lt;a href=&quot;https://img.ly/docs/cesdk/&quot;&gt;Learn more in our documentation!&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;javascript-video-editor-use-cases&quot;&gt;JavaScript Video Editor Use Cases&lt;/h2&gt;
&lt;p&gt;It is time to explore some key use cases. Let’s see how the unique features of the CreativeEditor SDK can cover many scenarios!&lt;/p&gt;
&lt;h3 id=&quot;social-media-publishing&quot;&gt;Social Media Publishing&lt;/h3&gt;
&lt;p&gt;CreativeEditor SDK features what users need to create engaging and easy-to-share videos optimized for popular social media platforms like Instagram, TikTok, YouTube, LinkedIn, and more. This is possible due to a large set of capabilities, which include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reusable Templates&lt;/strong&gt;: Users can either design their own templates and share them with the community or download those created by others. This variety of ready-to-use templates for different scenarios helps users skip the daunting blank canvas to bring their ideas to life. Explore various templates in our &lt;a href=&quot;https://img.ly/showcases/cesdk/video-ui/web?template=month-in-review&amp;#x26;ref=img.ly&quot;&gt;video editor demo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Music and Audio Library&lt;/strong&gt;: In CE.SDK, adding audio to videos is simple and intuitive. Given the impact of audio, users can set the tone with music or narration in just a few clicks, creating a more immersive atmosphere for their content.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Animations&lt;/strong&gt;: The SDK includes a &lt;a href=&quot;https://img.ly/docs/cesdk/js/animation/overview-6a2ef2/&quot;&gt;wide selection of animations&lt;/a&gt; to enhance the design elements positioned within video scenes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After creating a video within your web app, users can export it directly from CE.SDK in the appropriate formats and aspect ratios for their target social media platforms.&lt;/p&gt;
&lt;h3 id=&quot;product-showcase-for-e-commerce-applications&quot;&gt;Product Showcase for E-Commerce Applications&lt;/h3&gt;
&lt;p&gt;Images have long been a simple yet powerful tool for showcasing products on e-commerce platforms, and sites like eBay, Amazon, AliExpress, and Walmart have relied on them for years (and still do!).&lt;/p&gt;
&lt;p&gt;However, in recent years, customer expectations have shifted. Today’s buyers crave more interactive and immersive ways to visualize products—they want to see how items look and perform in real-world settings.&lt;/p&gt;
&lt;p&gt;Short, dynamic product videos offer a superior presentation experience. According to &lt;a href=&quot;https://www.retaildive.com/spons/the-future-of-e-commerce-is-video-5-undeniable-consumer-stats/711062/&quot;&gt;an analysis by Firework&lt;/a&gt;, video content increases purchase likelihood by 51%, highlighting its undeniable impact on buying decisions. This is why many sellers have already embraced video to enhance product displays.&lt;/p&gt;
&lt;p&gt;With a CE.SDK-powered JavaScript video editor, producing compelling videos that deliver a seamless, multi-device shopping experience becomes effortless. Plus, reusable templates help you generate unique product videos while maintaining brand consistency.&lt;/p&gt;
&lt;h3 id=&quot;engaging-video-messages-for-sales-outreach&quot;&gt;Engaging Video Messages for Sales Outreach&lt;/h3&gt;
&lt;p&gt;Marketers and sales teams know that cold emails often come across as impersonal and boring. The solution to this challenge? Personalized video messages!&lt;/p&gt;
&lt;p&gt;Customized video messages are proving to be an effective outreach tool, with studies showing &lt;a href=&quot;https://www.tavus.io/post/video-marketing-statistics&quot;&gt;significantly higher conversion rates&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With CreativeEditor SDK, sales and marketing teams can easily create personalized videos tailored to individual clients or leads, making their outreach more engaging and impactful. Unlike traditional email campaigns, personalized videos create a sense of real, one-on-one interaction.&lt;/p&gt;
&lt;p&gt;Additionally, the SDK’s translation features help sales teams break down language barriers, allowing them to reach a global audience. This ensures that the personalized messages resonate with clients from different regions.&lt;/p&gt;
&lt;p&gt;Explore this feature in our &lt;a href=&quot;https://img.ly/showcases/cesdk/language/web&quot;&gt;translation and internationalization demo&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;digital-asset-management&quot;&gt;Digital Asset Management&lt;/h3&gt;
&lt;p&gt;DAM, short for &lt;a href=&quot;https://www.ibm.com/think/topics/digital-asset-management&quot;&gt;Digital Asset Management&lt;/a&gt;, is the process of organizing, storing, and managing digital assets, including video content. As your business grows, an effective DAM system becomes key to enabling multiple teams to easily access and collaborate on assets across different projects.&lt;/p&gt;
&lt;p&gt;CreativeEditor SDK backs DAM workflows by offering powerful tools to organize, edit, and repurpose video content through an embeddable, centralized interface. Its core JavaScript video editor component empowers users to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Effortlessly adapt and customize video assets.&lt;/li&gt;
&lt;li&gt;Ensure brand consistency while automating updates across various assets.&lt;/li&gt;
&lt;li&gt;Edit content efficiently within a collaborative environment.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Although CE.SDK does not provide built-in role-based permissions, it integrates smoothly with backend systems to control user access. In particular, its flexible architecture supports the definition of custom hooks for permission checks to customize the editor’s behavior.&lt;/p&gt;
&lt;h3 id=&quot;automated-video-creation&quot;&gt;Automated Video Creation&lt;/h3&gt;
&lt;p&gt;CreativeEditor SDK streamlines the automation of asset creation by enabling users to generate on-brand video content variations for multiple channels. Thanks to adaptable templates, &lt;a href=&quot;https://img.ly/docs/cesdk/js/create-templates/add-dynamic-content/text-variables-7ecb50/&quot;&gt;dynamic text variables&lt;/a&gt;, and lockable designs, the SDK ensures consistency and brand compliance over all produced videos.&lt;/p&gt;
&lt;p&gt;Given a template, the creative engine automates the generation of countless personalized assets by populating them with resources from various data sources. That eliminates manual effort, reduces design bottlenecks, and accelerates production, making it perfect for scaling campaign-specific videos or building dedicated &lt;a href=&quot;https://img.ly/industries/marketing-tech&quot;&gt;marketing tech&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;customizing-your-creativeeditor-sdk-instance&quot;&gt;Customizing your CreativeEditor SDK Instance&lt;/h2&gt;
&lt;p&gt;CreativeEditor SDK is not a one-size-fits-all JavaScript video editor. Instead, it is built for flexibility, offering a wide set of customization options to tailor the editor to your unique requirements and brand identity. These include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Theming Options&lt;/strong&gt;: Match the editor’s look to your app’s style with built-in themes, generate new ones using the &lt;a href=&quot;https://img.ly/docs/cesdk/js/user-interface/appearance/theming-4b0938/#using-the-theme-generator&quot;&gt;theme generator&lt;/a&gt;, or create custom themes manually. Explore theming possibilities in our &lt;a href=&quot;https://img.ly/showcases/cesdk/theming/web&quot;&gt;dedicated demo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom UI&lt;/strong&gt;: Build entirely bespoke JavaScript video editing user interfaces that align with your specific use case.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Media Library Integration&lt;/strong&gt;: Set up sortable, flexible media libraries and integrate popular third-party libraries like &lt;a href=&quot;https://img.ly/showcases/cesdk/unsplash-image-assets/web&quot;&gt;Unsplash and others&lt;/a&gt;. Get easy access to external assets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Localization&lt;/strong&gt;: Adapt the editor to different languages and regions with &lt;a href=&quot;https://img.ly/docs/cesdk/js/user-interface/localization-508e20/&quot;&gt;full i18n support&lt;/a&gt;, letting you extend or overwrite any language setting.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Toolbar Customization&lt;/strong&gt;: Rearrange toolbar elements, update icons, or rename tools to deliver a tailored user experience.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With these customization options, CreativeEditor SDK ensures your video editor is as unique as your JavaScript application.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Implementing a JavaScript video editor in your web app can greatly improve the user experience and provide a powerful feature to drive higher engagement, retention, and even product distribution. This is true whether you are developing an e-commerce platform, a social media app, a tool for influencers, or a SaaS web solution.&lt;/p&gt;
&lt;p&gt;With the CreativeEditor SDK, adding a fully customizable video editing experience to your web application takes only a few minutes. Explore CE.SDK’s video capabilities and &lt;a href=&quot;https://img.ly/docs/cesdk/flutter/prebuilt-solutions/video-editor-9e533a/&quot;&gt;dive into the docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Stay tuned for more updates, and please &lt;a href=&quot;https://img.ly/forms/contact-sales?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=plugins1&quot;&gt;reach out&lt;/a&gt; if you have any questions. Thank you for reading.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Over 3,000 creative professionals gain early access to our new features, demos, and updates—don’t miss out, and&lt;/strong&gt; &lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i?ref=img.ly&quot;&gt;&lt;strong&gt;subscribe&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;to our newsletter.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Antonello</dc:creator><media:content url="https://blog.img.ly/2025/01/video-editor-javascript.jpg" medium="image"/><category>JavaScript</category><category>Video Editor</category><category>CE.SDK</category></item><item><title>A Modern React Design Editor: Integration Guide</title><link>https://img.ly/blog/modern-react-design-editor/</link><guid isPermaLink="true">https://img.ly/blog/modern-react-design-editor/</guid><description>Learn how to integrate IMG.LY&apos;s design editor for React into your web app and how to best leverage its capabilities.</description><pubDate>Thu, 16 Jan 2025 14:38:04 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Learn how to integrate&lt;/em&gt; &lt;a href=&quot;https://img.ly/docs/cesdk/react/starterkits/design-editor-8unj9u/&quot;&gt;&lt;em&gt;IMG.LY’s design editor for React&lt;/em&gt;&lt;/a&gt; &lt;em&gt;into your web app and explore various use cases and customization options.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It is no surprise that content asset generation is a key for businesses in marketing and promotion, as well as for users on social media. Whether it is images or videos, these are the types of posts we engage with and relate to the most as human beings—much more than plain text.&lt;/p&gt;
&lt;p&gt;Most content that resonates with an audience is not created from scratch. Instead, it often comes from pre-designed designs that are reused, repurposed, and adapted to fit different content or goals. That is why adding a design editor to your React application is so valuable.&lt;/p&gt;
&lt;p&gt;In this guide, you will learn how to build a React design editor using the CreativeEditor SDK (also known as &lt;em&gt;CE.SDK&lt;/em&gt;). We will also cover when this is useful and the customization options the editor supports.&lt;/p&gt;
&lt;p&gt;For a quick start, check out the &lt;a href=&quot;https://github.com/imgly/cesdk-web-examples/tree/main/integrate-with-react&quot;&gt;GitHub repository&lt;/a&gt; with the full code integration.&lt;/p&gt;
&lt;p&gt;Let’s dive in!&lt;/p&gt;
&lt;h2 id=&quot;why-add-a-design-editor-to-your-react-app&quot;&gt;Why Add a Design Editor to Your React App?&lt;/h2&gt;
&lt;p&gt;Before answering the question, you must understand what a design is and how helpful it can be. In this context, a design can be defined as a set of predefined assets, text overlays, placeholders, and other elements arranged in a specific layout.&lt;/p&gt;
&lt;p&gt;Users can use designs to create images or videos with a particular structure and for specific use cases at scale. Thus, a &lt;a href=&quot;https://img.ly/blog/what-is-a-design-editor-sdk/&quot;&gt;design editor&lt;/a&gt; would enable your users to create personalized assets—and in the case of a React application, directly within the browser.&lt;/p&gt;
&lt;p&gt;Building such a platform is not a piece of cake. A robust design editor requires numerous features, such as intuitive drag-and-drop functionality, template management, image manipulation tools, and more. It also generally requires integrations with third-party services and dependencies to enhance its capabilities.&lt;/p&gt;
&lt;p&gt;Fortunately, an all-in-one solution like &lt;a href=&quot;https://img.ly/products/creative-sdk&quot;&gt;CreativeEditor SDK&lt;/a&gt; from IMG.LY makes it easy to embed this powerful design editor into your application. It supports various programming languages and technologies, including React. With extensive features and customization options, CE.SDK has no limits on the types of designs users can generate.&lt;/p&gt;
&lt;p&gt;CE.SDK features adaptable design tools for &lt;a href=&quot;https://img.ly/case-studies&quot;&gt;diverse industries and use cases&lt;/a&gt;, such as social media post creation, digital asset management, and AI-assisted content personalization. That is why it is used by &lt;a href=&quot;https://img.ly/customers&quot;&gt;hundreds of customers&lt;/a&gt;, including governments, Fortune 500 companies, and dozens of startups.&lt;/p&gt;
&lt;p&gt;CreativeEditor SDK is trusted by companies like Swiss Post, Brother, &lt;a href=&quot;https://img.ly/case-studies/optimizely&quot;&gt;Optimizely&lt;/a&gt;, HP, and many more.&lt;/p&gt;
&lt;h2 id=&quot;how-to-integrate-a-design-editor-in-react&quot;&gt;How to Integrate a Design Editor in React&lt;/h2&gt;
&lt;p&gt;Follow this step-by-step tutorial to see how to quickly set up a React design editor in your web app using CreativeEditor SDK. For a complete guide, read our tutorial on &lt;a href=&quot;https://img.ly/blog/how-to-build-a-canva-clone-with-ce-sdk/&quot;&gt;building a Canva alternative in React using CE.SDK&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Integrate CE.SDK into your React app using the instructions below!&lt;/p&gt;
&lt;h3 id=&quot;requirements&quot;&gt;&lt;strong&gt;Requirements&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Before getting started, ensure that you meet the following prerequisites:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The latest LTS version of Node.js&lt;/strong&gt;: If you do not have it installed, &lt;a href=&quot;https://nodejs.org/en/download&quot;&gt;download it from the official site&lt;/a&gt; and follow the installation instructions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A React 18+ application&lt;/strong&gt;: If you do not have one set up, follow the instructions below to create it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A CreativeEditor SDK license&lt;/strong&gt;: In case you do not have a license, &lt;a href=&quot;https://img.ly/forms/free-trial&quot;&gt;sign up for a free trial&lt;/a&gt; or &lt;a href=&quot;https://img.ly/pricing&quot;&gt;buy a license&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you do not have a React project set up yet, create a new one using &lt;a href=&quot;https://vite.dev/guide/&quot;&gt;Vite&lt;/a&gt;:&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; create&lt;/span&gt;&lt;span&gt; vite@latest&lt;/span&gt;&lt;span&gt; my-react-video-editor-app&lt;/span&gt;&lt;span&gt; --&lt;/span&gt;&lt;span&gt; --template&lt;/span&gt;&lt;span&gt; react&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Open your project in a JavaScript IDE, and you are all set to start coding!&lt;/p&gt;
&lt;h3 id=&quot;install-cesdk&quot;&gt;&lt;strong&gt;Install CE.SDK&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Install CE.SDK by adding the &lt;a href=&quot;https://www.npmjs.com/package/@cesdk/cesdk-js&quot;&gt;@cesdk/cesdk-js&lt;/a&gt; package to your project’s dependencies:&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; @cesdk/cesdk-js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your package.json file will now list it as a dependency:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;dependencies&quot;&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;@cesdk/cesdk-js&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^1.41.1&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;react&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^18.3.1&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;react-dom&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^18.3.1&quot;&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;create-the-design-editor-component&quot;&gt;&lt;strong&gt;Create the Design Editor Component&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;In the src folder of your React project, create a DesignEditor.jsx file. This will house your CE.SDK-based React design editor component.&lt;/p&gt;
&lt;p&gt;Inside it, import &lt;code&gt;CreativeEditorSDK&lt;/code&gt; from &lt;code&gt;@cesdk/cesdk-js&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; 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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, initialize your video editor React component with the following logic:&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;// src/DesignEditor.jsx&lt;/span&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; 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; { 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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// your CE.SDK license and user configs&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;  license: &lt;/span&gt;&lt;span&gt;&apos;&amp;#x3C;YOUR_LICENSE&gt;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  userId: &lt;/span&gt;&lt;span&gt;&apos;&amp;#x3C;YOUR_USER_ID&gt;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; default&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; DesignEditor&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; cesdk_container&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;cesdk&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setCesdk&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;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;  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 the CE.SDK container has already been initialized&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;cesdk_container.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;    let&lt;/span&gt;&lt;span&gt; cleanedUp &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 class=&quot;line&quot;&gt;&lt;span&gt;    // initialize a CE.SDK instance&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    let&lt;/span&gt;&lt;span&gt; instance;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    CreativeEditorSDK.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(cesdk_container.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;      async&lt;/span&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;        instance &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;        if&lt;/span&gt;&lt;span&gt; (cleanedUp) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          instance.&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;          return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // customize the design editor behavior...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        setCesdk&lt;/span&gt;&lt;span&gt;(instance);&lt;/span&gt;&lt;/span&gt;
&lt;span 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;    // clean up the CE.SDK instance&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; cleanup&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;      cleanedUp &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;      instance?.&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;      setCesdk&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    };&lt;/span&gt;&lt;/span&gt;
&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; cleanup;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }, [cesdk_container]);&lt;/span&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      ref&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{cesdk_container}&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;{{ width: &lt;/span&gt;&lt;span&gt;&apos;100vw&apos;&lt;/span&gt;&lt;span&gt;, height: &lt;/span&gt;&lt;span&gt;&apos;100vh&apos;&lt;/span&gt;&lt;span&gt; }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace &lt;code&gt;&amp;#x3C;YOUR_LICENSE&gt;&lt;/code&gt; with the license key from CreativeEditor SDK, and &lt;code&gt;&amp;#x3C;YOUR_USER_ID&gt;&lt;/code&gt; with your user ID to optionally track monthly active users (MAUs) across different devices.&lt;/p&gt;
&lt;p&gt;The component defined above embeds CreativeEditor SDK into an HTML &lt;code&gt;&amp;#x3C;div&gt;&lt;/code&gt; element. &lt;a href=&quot;https://img.ly/docs/cesdk/react/user-interface/customization/dock-cb916c/&quot;&gt;See how to customize and use it in the docs&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;use-the-component&quot;&gt;&lt;strong&gt;Use the Component&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;You can now import the DesignEditor component as below:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;import DesignEditor from &quot;./DesignEditor&quot;;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Then, add it to the DOM as follows:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;#x3C;DesignEditor /&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This will open the design editor with the preset, enabling users to place assets, set constraints, and perform other tasks to create their final designs.&lt;/p&gt;
&lt;h2 id=&quot;react-design-editor-use-cases&quot;&gt;React Design Editor Use Cases&lt;/h2&gt;
&lt;p&gt;Now that you are familiar with integrating a React design editor into your web app. It is time to explore key use cases and see how CreativeEditorSDK can cover many scenarios.&lt;/p&gt;
&lt;h3 id=&quot;social-media-publishing&quot;&gt;&lt;strong&gt;Social Media Publishing&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;CreativeEditorSDK offers a wide suite of tools to help users easily create high-quality, personalized, on-brand social media assets in your React application.&lt;/p&gt;
&lt;p&gt;With a vast library of professionally designed templates, it streamlines the design process and ensures consistency across multiple platforms. Users can efficiently produce engaging content tailored for&lt;/p&gt;
&lt;p&gt;Key features include customizable dimensions, filters, placeholders, and text overlays. These give users what they need to craft content optimized for various social networks, such as Instagram, X, LinkedIn, and more. That is possible thanks to platform-specific export options to produce ready-to-upload assets.&lt;/p&gt;
&lt;p&gt;The SDK’s capabilities extend beyond static images, supporting the creation of dynamic &lt;a href=&quot;https://img.ly/use-cases/story-reels-short-video-creation&quot;&gt;short videos, stories, and reels&lt;/a&gt;. Do not forget that CE.SDK can also function as a &lt;a href=&quot;https://img.ly/blog/modern-react-design-editor/&quot;&gt;modern React video editor&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;digital-asset-management&quot;&gt;&lt;strong&gt;Digital Asset Management&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;DAM, short for &lt;a href=&quot;https://business.adobe.com/blog/basics/digital-asset-management&quot;&gt;Digital Asset Management&lt;/a&gt;, is the process of organizing, storing, and efficiently retrieving a wide range of digital files.&lt;/p&gt;
&lt;p&gt;CreativeEditorSDK supports DAM by helping teams centralize asset creation and editing directly within an embeddable React design editor—eliminating the need for external tools. This is achieved through features like pre-defining and locking branding elements—including logos, fonts, and color schemes—to ensure brand consistency across all generated content.&lt;/p&gt;
&lt;p&gt;Additionally, CE.SDK offers :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://img.ly/showcases/cesdk/design-validation/web&quot;&gt;Design validation tools&lt;/a&gt; to prevent the creation of misaligned assets.&lt;/li&gt;
&lt;li&gt;Automatic asset generation to streamline content variations.&lt;/li&gt;
&lt;li&gt;Robust asset management features for handling both generated content and external assets retrieved via &lt;a href=&quot;https://support.img.ly/do-you-offer-third-party-integrations-such-as-unsplash&quot;&gt;third-party APIs&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;marketing-automation&quot;&gt;&lt;strong&gt;Marketing Automation&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Businesses can use CreativeEditor SDK to scale marketing campaigns through &lt;a href=&quot;https://img.ly/templates&quot;&gt;dynamic, unique, customizable design templates&lt;/a&gt;. In detail, this design editor allows you to generate campaign materials—like personalized flyers, ads, or banners—quickly and at scale.&lt;/p&gt;
&lt;p&gt;Key features for marketing automation include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Automation&lt;/strong&gt;: Integrate with CRM or marketing tools to auto-populate templates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dynamic Templates&lt;/strong&gt;: Easily create content with placeholders or &lt;a href=&quot;https://img.ly/docs/cesdk/react/create-templates/add-dynamic-content/text-variables-7ecb50/&quot;&gt;custom text variables&lt;/a&gt; for personalized outputs and A/B testing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Brand Compliance&lt;/strong&gt;: Lock assets like logos and fonts for consistent messaging and branding.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;ai-powered-applications&quot;&gt;&lt;strong&gt;AI-Powered Applications&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;AI is rapidly becoming a key component of more and more applications, with many integrating it in some form. Still, a critical step is often overlooked: manual editing and supervision.&lt;/p&gt;
&lt;p&gt;CreativeEditorSDK bridges that gap by seamlessly integrating with AI-powered workflows while guaranteeing users the ability to &lt;a href=&quot;https://img.ly/docs/cesdk/react/create-templates/add-dynamic-content/placeholders-d9ba8a/&quot;&gt;manually define constraints, placeholders, and rules&lt;/a&gt; that the AI-driven automation process must follow.&lt;/p&gt;
&lt;p&gt;Example of how a CE.SDK-powered React design editor could work with AI includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Automated template suggestions based on industry or use case.&lt;/li&gt;
&lt;li&gt;Prompt-based content generation where users describe their needs, and the app delivers a draft design.&lt;/li&gt;
&lt;li&gt;Automated content optimization, where the AI evaluates design elements and suggests improvements for readability and visual appeal.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI-generated content is impressive, but it is essential to find the right balance between automation and manual control in the content generation process for the best results.&lt;/p&gt;
&lt;h3 id=&quot;product-mockups&quot;&gt;&lt;strong&gt;Product Mockups&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;CreativeEditorSDK simplifies the creation of product mockups, packaging designs, and marketing materials, including &lt;a href=&quot;https://img.ly/use-cases/print-personalization&quot;&gt;printable brochures and business cards&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;CE.SDK features powerful customization tools and flexible capabilities, including alignment guides and snap tools to ensure perfect positioning. Additionally, color pickers and vector shape editors enable you to explore and create professional design concepts.&lt;/p&gt;
&lt;h3 id=&quot;e-learning-materials&quot;&gt;&lt;strong&gt;E-Learning Materials&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Thanks to CreativeEditorSDK, you can integrate a design editor into your React e-learning application.&lt;/p&gt;
&lt;p&gt;The embeddable design editor supports the entire process of creating e-learning materials, including custom graphics like annotations, diagrams, and visual explanations, or &lt;a href=&quot;https://img.ly/products/camera-sdk&quot;&gt;videos recorded directly from the camera&lt;/a&gt; by the teachers/educators/coaches. The component also allows for the creation of unique and customized student certificates.&lt;/p&gt;
&lt;p&gt;Those features empower educators and content creators in the education sector to craft visually engaging and impactful learning materials.&lt;/p&gt;
&lt;h2 id=&quot;customization-options-with-creativeeditor-sdk&quot;&gt;Customization Options With CreativeEditor SDK&lt;/h2&gt;
&lt;p&gt;CreativeEditor SDK does not provide a static React design design experience. Instead, it offers extensive customization options to align with your application’s branding and workflow. Key customization options are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Theming&lt;/strong&gt;: Adjust the editor’s theme to match your app’s design. Choose from built-in themes, generate new ones using the &lt;a href=&quot;https://img.ly/docs/cesdk/react/user-interface/appearance/theming-4b0938/&quot;&gt;theme generator&lt;/a&gt;, or create a custom theme manually. Test themes in the &lt;a href=&quot;https://img.ly/showcases/cesdk/theming/web&quot;&gt;demo page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom UI Plugins&lt;/strong&gt;: Add custom UI components to fit your design style through &lt;a href=&quot;https://img.ly/docs/cesdk/react/user-interface/ui-extensions-d194d1/&quot;&gt;custom plugins&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enabling/Disabling Features&lt;/strong&gt;: Tailor the editor by enabling or disabling features like specific fonts, templates, or tools.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Toolbar Customization&lt;/strong&gt;: Reposition toolbar elements, change icons, or rename tools to suit your needs, creating a unique editing experience.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom Templates, Assets, Themes&lt;/strong&gt;: Add your own templates, assets, or themes for a more personalized user experience.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Media Libraries&lt;/strong&gt;: Set up customizable, sortable media libraries. CE.SDK supports integration with third-party libraries, allowing easy access to external media assets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom Integrations via Events&lt;/strong&gt;: Hook into the editor’s events to trigger workflows, save progress, or integrate with external systems.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Internationalization&lt;/strong&gt;: Adapt the design editor component for different languages and regions with &lt;a href=&quot;https://img.ly/docs/cesdk/react/user-interface/localization-508e20/&quot;&gt;full i18n support&lt;/a&gt;. Overwrite and extend text strings in any language.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;CreativeEditor SDK’s compatibility with React’s component-based architecture and large set of features ensures simple integration into any project, making it ideal for a wide range of industries—from marketing and e-learning to e-commerce and social media.&lt;/p&gt;
&lt;p&gt;A CE.SDK-based design editor offers UI customization and unique feature options to adapt to any use case. Additionally, its support for AI workflows ensures your application remains future-proof and ready to meet evolving user needs.&lt;/p&gt;
&lt;p&gt;By following the steps outlined in this blog post, you can bring professional-level design editing features to your web users. Explore CE.SDK’s capabilities and &lt;a href=&quot;https://img.ly/docs/cesdk/&quot;&gt;dive into the docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Stay tuned for more updates, and please &lt;a href=&quot;https://img.ly/forms/contact-sales?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=plugins1&quot;&gt;reach out&lt;/a&gt; if you have any questions. Thank you for reading.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Over 3,000 creative professionals gain early access to our new features, demos, and updates—don’t miss out, and&lt;/strong&gt; &lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i?ref=img.ly&quot;&gt;&lt;strong&gt;subscribe&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;to our newsletter.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Antonello</dc:creator><media:content url="https://blog.img.ly/2025/01/react-web-design-editor.jpg" medium="image"/><category>React</category><category>Design Editor</category><category>CE.SDK</category></item><item><title>A Modern Vue.js Video Editor: Setup Guide</title><link>https://img.ly/blog/a-modern-vue-js-video-editor/</link><guid isPermaLink="true">https://img.ly/blog/a-modern-vue-js-video-editor/</guid><description>Learn how to integrate IMG.LY&apos;s video editor for Vue.js into your web app and how to best leverage its capabilities.</description><pubDate>Wed, 08 Jan 2025 11:24:43 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Discover how to integrate&lt;/em&gt; &lt;a href=&quot;https://img.ly/docs/cesdk/vue/starterkits/video-editor-e1nlor/&quot;&gt;&lt;em&gt;IMG.LY’s video editor&lt;/em&gt;&lt;/a&gt; &lt;em&gt;into your Vue.js application and unlock its full potential.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Platforms like Instagram, YouTube, and TikTok have revolutionized how we engage with content, setting new standards for consuming video media. With the growing popularity of short-form videos, this trend shows no signs of slowing down.&lt;/p&gt;
&lt;p&gt;Users now not only love to watch videos but also expect intuitive video creation and editing features from modern web applications. Here is why adding a video editor to your Vue.js web application can significantly boost user engagement and satisfaction.&lt;/p&gt;
&lt;p&gt;In this guide, you will discover how to integrate a video editor into a Vue.js project using CreativeEditor SDK (also referred to as &lt;em&gt;CE.SDK&lt;/em&gt;). We will also discuss when this functionality is most beneficial and how to customize the editor for your specific needs.&lt;/p&gt;
&lt;p&gt;For a quick setup, take a look at the &lt;a href=&quot;https://github.com/imgly/cesdk-web-examples/tree/main/integrate-with-vue&quot;&gt;GitHub Vue.js video editor integration&lt;/a&gt; repository to kick off your project.&lt;/p&gt;
&lt;p&gt;Let’s dive in!&lt;/p&gt;
&lt;h2 id=&quot;why-you-should-add-a-video-editor-to-your-vuejs-app&quot;&gt;Why You Should Add a Video Editor to Your Vue.js App?&lt;/h2&gt;
&lt;p&gt;The digital landscape is constantly evolving, but one truth has remained steady: video content continues to dominate.&lt;/p&gt;
&lt;p&gt;Statistics about videos are clear. According to &lt;a href=&quot;https://datareportal.com/reports/digital-2022-instagram-headlines&quot;&gt;Datareportal&lt;/a&gt;, over one-third of all Instagram reels are videos. Similarly, YouTube Shorts garners &lt;a href=&quot;https://blog.youtube/inside-youtube/shorts-revenue-sharing-update/&quot;&gt;over 70 billion daily views&lt;/a&gt;, and TikTok boasts more than &lt;a href=&quot;https://www.statista.com/statistics/272014/global-social-networks-ranked-by-number-of-users/&quot;&gt;1.5 billion monthly active users worldwide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The reasons behind these staggering numbers are two:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Videos are incredibly engaging for audiences.&lt;/li&gt;
&lt;li&gt;Social media platforms have made it remarkably easy to create professional-looking content.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Users now expect to be able to add filters, overlays, audio, music, and text with just a few clicks. As a result, not only do we anticipate video editing features in web applications, but we also demand that these features be simple to use.&lt;/p&gt;
&lt;p&gt;By integrating an intuitive video editor, your Vue.js web app can capitalize on that trend. The goal is to provide a feature that billions of users are already familiar with—and likely expect from your application.&lt;/p&gt;
&lt;p&gt;The payoff? Lowering the barriers to user-generated content, increasing engagement, and driving product distribution!&lt;/p&gt;
&lt;h2 id=&quot;how-to-integrate-a-video-editor-in-vuejs&quot;&gt;How to Integrate a Video Editor in Vue.js&lt;/h2&gt;
&lt;p&gt;In this section, you will learn how to set up a Vue.js video editor using CreativeEditor SDK.&lt;/p&gt;
&lt;h3 id=&quot;requirements&quot;&gt;Requirements&lt;/h3&gt;
&lt;p&gt;Before starting, ensure you have the latest LTS version of Node.js installed on your machine. Otherwise, download and install it from the &lt;a href=&quot;https://nodejs.org/en/download&quot;&gt;official Node.js website&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you do not already have a Vue.js project, create a new &lt;a href=&quot;https://vite.dev/&quot;&gt;Vite&lt;/a&gt;-based Vue project by running 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;npm&lt;/span&gt;&lt;span&gt; create&lt;/span&gt;&lt;span&gt; vue@latest&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will install and run &lt;a href=&quot;https://github.com/vuejs/create-vue&quot;&gt;create-vue&lt;/a&gt;, the official Vue project scaffolding tool. During the process, you will be prompted to select optional features like TypeScript and testing support. Below is an example of how you can respond to the prompts:&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;√&lt;/span&gt;&lt;span&gt; Project&lt;/span&gt;&lt;span&gt; name:&lt;/span&gt;&lt;span&gt; ...&lt;/span&gt;&lt;span&gt; my-vue-video-editor-app&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;√&lt;/span&gt;&lt;span&gt; Add&lt;/span&gt;&lt;span&gt; TypeScript?&lt;/span&gt;&lt;span&gt; ...&lt;/span&gt;&lt;span&gt; No&lt;/span&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt; Yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;√&lt;/span&gt;&lt;span&gt; Add&lt;/span&gt;&lt;span&gt; JSX&lt;/span&gt;&lt;span&gt; Support?&lt;/span&gt;&lt;span&gt; ...&lt;/span&gt;&lt;span&gt; No&lt;/span&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt; Yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;√&lt;/span&gt;&lt;span&gt; Add&lt;/span&gt;&lt;span&gt; Vue&lt;/span&gt;&lt;span&gt; Router&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; Single&lt;/span&gt;&lt;span&gt; Page&lt;/span&gt;&lt;span&gt; Application&lt;/span&gt;&lt;span&gt; development?&lt;/span&gt;&lt;span&gt; ...&lt;/span&gt;&lt;span&gt; No&lt;/span&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt; Yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;√&lt;/span&gt;&lt;span&gt; Add&lt;/span&gt;&lt;span&gt; Pinia&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; state&lt;/span&gt;&lt;span&gt; management?&lt;/span&gt;&lt;span&gt; ...&lt;/span&gt;&lt;span&gt; No&lt;/span&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt; Yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;√&lt;/span&gt;&lt;span&gt; Add&lt;/span&gt;&lt;span&gt; Vitest&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; Unit&lt;/span&gt;&lt;span&gt; Testing?&lt;/span&gt;&lt;span&gt; ...&lt;/span&gt;&lt;span&gt; No&lt;/span&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt; Yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;√&lt;/span&gt;&lt;span&gt; Add&lt;/span&gt;&lt;span&gt; an&lt;/span&gt;&lt;span&gt; End-to-End&lt;/span&gt;&lt;span&gt; Testing&lt;/span&gt;&lt;span&gt; Solution?&lt;/span&gt;&lt;span&gt; »&lt;/span&gt;&lt;span&gt; No&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;√&lt;/span&gt;&lt;span&gt; Add&lt;/span&gt;&lt;span&gt; ESLint&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; code&lt;/span&gt;&lt;span&gt; quality?&lt;/span&gt;&lt;span&gt; »&lt;/span&gt;&lt;span&gt; Yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;√&lt;/span&gt;&lt;span&gt; Add&lt;/span&gt;&lt;span&gt; Prettier&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; code&lt;/span&gt;&lt;span&gt; formatting?&lt;/span&gt;&lt;span&gt; ...&lt;/span&gt;&lt;span&gt; No&lt;/span&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt; Yes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you are unsure about an option, simply select “No” by pressing Enter.&lt;/p&gt;
&lt;p&gt;After the project is set up, navigate to the project folder and install CreativeEditor SDK via &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; package with 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; install&lt;/span&gt;&lt;span&gt; @cesdk/cesdk-js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your package.json file will now include the SDK as a dependency:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;dependencies&quot;&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;@cesdk/cesdk-js&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^1.41.1&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;vue&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^3.5.13&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;vue-router&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^4.4.5&quot;&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;Finally, open your project in a JavaScript IDE, and you are ready to start coding!&lt;/p&gt;
&lt;h3 id=&quot;create-the-video-editor-component&quot;&gt;Create the Video Editor Component&lt;/h3&gt;
&lt;p&gt;In the &lt;code&gt;src/components&lt;/code&gt; folder, create a new file named &lt;code&gt;VideoEditor.vue&lt;/code&gt;. This file will serve as your Vue.js single-file component for the CE.SDK-based video editor.&lt;/p&gt;
&lt;p&gt;In the  like 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; 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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, create your video editor component using the following lines of code:&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;!--&lt;/span&gt;&lt;span&gt; src&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;components&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;VideoEditor.vue &lt;/span&gt;&lt;span&gt;--&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;template&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;cesdk_container&quot;&lt;/span&gt;&lt;span&gt; style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;height: 100vh; width: 100vw&quot;&lt;/span&gt;&lt;span&gt;&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;template&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&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;import CreativeEditorSDK from &apos;@cesdk/cesdk-js&apos;&lt;/span&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 default {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  props: { config: Object },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  _cesdk: &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;  mounted: &lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; mounted&lt;/span&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;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;#cesdk_container&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.config).&lt;/span&gt;&lt;span&gt;then&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;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;      this&lt;/span&gt;&lt;span&gt;._cesdk &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;      // customize the editor behavior...&lt;/span&gt;&lt;/span&gt;
&lt;span 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;  methods: {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  watch: {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  beforeUnmount: &lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; beforeDestroy&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // clean up the CE.SDK instance&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;this&lt;/span&gt;&lt;span&gt;._cesdk) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      this&lt;/span&gt;&lt;span&gt;._cesdk.&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;      this&lt;/span&gt;&lt;span&gt;._cesdk &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; null&lt;/span&gt;&lt;/span&gt;
&lt;span 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;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The component defined above embeds the &lt;code&gt;CreativeEditorSDK&lt;/code&gt; JavaScript element into an HTML &lt;code&gt;&amp;#x3C;div&gt;&lt;/code&gt; container.&lt;/p&gt;
&lt;h3 id=&quot;use-the-component&quot;&gt;Use the Component&lt;/h3&gt;
&lt;p&gt;You can now import the &lt;code&gt;VideoEditor&lt;/code&gt; component in the 
&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; VideoEditor &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;./components/VideoEditor.vue&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, include it in the &lt;template&gt; section as shown in this snippet:
&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;VideoEditor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  :config=&quot;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    license:&lt;/span&gt;&lt;span&gt; &apos;&amp;#x3C;YOUR_LICENSE&gt;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    userId:&lt;/span&gt;&lt;span&gt; &apos;&amp;#x3C;YOUR_USER_ID&gt;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace &lt;code&gt;&amp;#x3C;YOUR_LICENSE&gt;&lt;/code&gt; with the license key provided by CreativeEditor SDK and &lt;code&gt;&amp;#x3C;YOUR_USER_ID&gt;&lt;/code&gt; with your user ID to optionally track monthly active users (MAUs) across different devices.&lt;/p&gt;
&lt;p&gt;This setup will launch the video editor with a video preset, enabling users to trim, cut, apply filters, add text overlays, include music, and perform other enhancements to their videos.&lt;/p&gt;
&lt;h2 id=&quot;use-cases-for-the-vuejs-video-editor&quot;&gt;Use Cases for the Vue.js Video Editor&lt;/h2&gt;
&lt;p&gt;Now that you have seen how to build a Vue.js video editor component with a basic CreativeEditor SDK setup, it is time to explore some practical use cases and scenarios.&lt;/p&gt;
&lt;h3 id=&quot;automated-marketing&quot;&gt;Automated Marketing&lt;/h3&gt;
&lt;p&gt;CreativeEditor SDK equips marketers with powerful tools to produce branded videos for multiple campaigns at scale. Key features for this task include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;API Integration&lt;/strong&gt;: Integrate the SDK’s API to automate the creation of videos, reducing manual effort and supporting large-scale video production. This opens the door to automated workflows for marketing campaigns, ad creation, and A/B testing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pre-Designed, Editable Templates&lt;/strong&gt;: Define placeholders, lock or unlock specific design elements, and guide what other users can edit and how. Thanks to this template-based process, it is possible to produce professional assets by leveraging editable &lt;a href=&quot;https://img.ly/showcases/cesdk/video-ui/web&quot;&gt;video templates&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Template Import from Photoshop:&lt;/strong&gt; Configure the SDK to bulk import .PSD files from Adobe Photoshop, converting them into the CE.SDK scene archive format for streamlined design integration and editing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Manage Branded Assets&lt;/strong&gt;: Build &lt;a href=&quot;https://img.ly/docs/cesdk/vue/import-media/asset-panel/customize-c9a4de/&quot;&gt;custom content libraries&lt;/a&gt; to manage brand assets, including logos, vector graphics, stock photos, and templates.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These capabilities make CE.SDK a reliable technology for scalable, efficient, and brand-consistent video marketing automation.&lt;/p&gt;
&lt;h3 id=&quot;informative-videos-for-e-learning&quot;&gt;Informative Videos for E-Learning&lt;/h3&gt;
&lt;p&gt;CreativeEditor SDK gives educators, teachers, and coaches the tools they need to create impactful and information-rich videos. The entire content creation and editing process requires no advanced technical skills. In detail, users can record, edit, and organize videos across desktop, mobile, or tablet devices.&lt;/p&gt;
&lt;p&gt;Beyond simplifying video production, the SDK is based on reusable templates, so that instructors can quickly adapt materials for various topics while maintaining consistency. Additionally, &lt;a href=&quot;https://img.ly/docs/cesdk/vue/user-interface/ui-extensions-d194d1/&quot;&gt;interactivity plugins&lt;/a&gt;—featuring quizzes, polls, and other learner-focused elements—enhances engagement, making lessons more dynamic and personalized.&lt;/p&gt;
&lt;h3 id=&quot;unique-videos-for-lead-outreach&quot;&gt;Unique Videos for Lead Outreach&lt;/h3&gt;
&lt;p&gt;Cold emails often feel dull and impersonal, frequently ending up in the spam or trash folder. In contrast, personalized video messages are revolutionizing lead outreach.&lt;/p&gt;
&lt;p&gt;CreativeEditor SDK empowers sales, marketing, and business development teams to deliver engaging videos that outshine standard email pitches, offering features such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Customized Video Messages for Leads&lt;/strong&gt;: Craft personalized videos for specific clients or prospects, adding a genuine human touch to your messages. Thanks to &lt;a href=&quot;https://img.ly/docs/cesdk/vue/create-templates/add-dynamic-content/text-variables-7ecb50/&quot;&gt;configurable text variables&lt;/a&gt;, you can customize video content at scale to leave a lasting impression compared to traditional cold emails.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Seamless Integration for Scalable Outreach&lt;/strong&gt;: Produce professional and customized video messages at scale, making it easy for sales teams to personalize outreach without sacrificing efficiency.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Translation Capabilities for Global Reach&lt;/strong&gt;: Leverage the SDK’s built-in translation and internationalization features to communicate with audiences worldwide. Adapt your messages to the local customs to convey a truly personalized experience. Test this feature &lt;a href=&quot;https://img.ly/showcases/cesdk/language/web&quot;&gt;in our translation demo&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Take your lead outreach to the next level with these innovative video solutions.&lt;/p&gt;
&lt;h3 id=&quot;social-media-video-content-generation&quot;&gt;Social Media Video Content Generation&lt;/h3&gt;
&lt;p&gt;CE.SDK offers all the tools users need to create captivating videos. It makes it easy to produce shareable content for platforms like Instagram, TikTok, YouTube, LinkedIn, and more.&lt;/p&gt;
&lt;p&gt;Users can take advantage of reusable templates to rapidly bring their ideas to life, without having to start from scratch. They can choose from a variety of pre-designed options, which you can explore in &lt;a href=&quot;https://img.ly/showcases/cesdk/video-ui/web&quot;&gt;our video editor demo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The support for &lt;a href=&quot;https://img.ly/docs/cesdk/vue/animation/overview-6a2ef2/&quot;&gt;configurable animations&lt;/a&gt; increase engagement and improve the visual appealing. In the SDK, users can also set the mood with music or add narration. Once complete, videos can finally be seamlessly exported in the ideal format and aspect ratio for social media platforms.&lt;/p&gt;
&lt;h3 id=&quot;digital-asset-management&quot;&gt;Digital Asset Management&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://business.adobe.com/blog/basics/digital-asset-management&quot;&gt;Digital Asset Management&lt;/a&gt;, commonly referred to as DAM, is the process of organizing, storing, and managing digital assets—such as videos. Given the large volume of assets companies produce and the way employees and users interact with them, DAM has become a key business process for many organizations.&lt;/p&gt;
&lt;p&gt;CreativeEditor SDK supports DAM by offering an embeddable Vue.js video editor UI component, allowing for centralized video organization, production, repurposing, and editing. This component exposes features like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Asset Libraries&lt;/strong&gt;: CE.SDK can load assets from local files or even integrate third-party libraries via API. Users can search and browse local assets as well as remote images from platforms like Pexels, Unsplash, and Getty within the editor. You can explore our &lt;a href=&quot;https://img.ly/showcases/cesdk?tags=assets&quot;&gt;asset library demo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Permissions for Asset Control&lt;/strong&gt;: Although the SDK does not include role-based permissions out of the box, it connects with backend technologies to manage user access and permissions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extendability for Custom Permissions&lt;/strong&gt;: Developers can extend the SDK to create custom hooks that check permissions and modify the editor’s behavior, ensuring the right users have access to and can edit assets.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These features make CreativeEditor SDK a valuable tool for businesses managing video assets while maintaining brand consistency and workflow efficiency.&lt;/p&gt;
&lt;h2 id=&quot;customizing-your-creativeeditor-sdk-instance&quot;&gt;Customizing your CreativeEditor SDK Instance&lt;/h2&gt;
&lt;p&gt;CreativeEditor SDK does not provide a static, pre-configured Vue.js video editor experience. Instead, it supports a large set of customization options to tailor the editor to your specific needs and brand requirements.&lt;/p&gt;
&lt;p&gt;Key customization features include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Build Custom UIs&lt;/strong&gt;: Create fully personalized user interfaces and adapt the editor to your specific use case. This includes repositioning toolbar elements, changing icons, or renaming tools to provide a unique editing experience.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feature Activation&lt;/strong&gt;: Enable or disable features based on default settings, giving you control over what is available to users.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Internationalization (i18n)&lt;/strong&gt;: Tailor the video editor to different languages and regions. CE.SDK &lt;a href=&quot;https://img.ly/docs/cesdk/vue/user-interface/localization-508e20/&quot;&gt;fully supports i18n&lt;/a&gt;, enabling you to overwrite and extend all text strings in any language.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Media Libraries&lt;/strong&gt;: Define custom, sortable, resource-rich media libraries. CE.SDK supports integration with third-party libraries via API for easy access to external media assets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Single Page Mode&lt;/strong&gt;: Configure the editor to display only one active page at a time for a streamlined experience.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Theming&lt;/strong&gt;: Adjust the editor’s theme to align with your app’s design. Choose from built-in themes, generate new ones using the &lt;a href=&quot;https://img.ly/docs/cesdk/vue/user-interface/appearance/theming-4b0938/&quot;&gt;theme generator&lt;/a&gt;, or manually create a custom theme. Test theming in our &lt;a href=&quot;https://img.ly/showcases/cesdk/theming/web&quot;&gt;demo page&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See all of these customizations in action in our &lt;a href=&quot;https://img.ly/showcases/cesdk?tags=customization&quot;&gt;customization demo&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Featuring a Vue.js video editor in your web application can greatly improve the user experience, making it a valuable addition to boosting product success, user reviews, and retention. This is true whether you are building a sales tool, an e-learning platform, or a web app with social media integration.&lt;/p&gt;
&lt;p&gt;With CreativeEditor SDK, you can integrate a fully customizable video editing experience into your Vue.js application in minutes.&lt;/p&gt;
&lt;p&gt;By following the steps outlined in this blog post, you saw how to bring professional-level video editing features to your web users. Explore CE.SDK’s video capabilities and &lt;a href=&quot;https://img.ly/docs/cesdk/vue/prebuilt-solutions/video-editor-9e533a/&quot;&gt;dive into the docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Stay tuned for more updates, and please &lt;a href=&quot;https://img.ly/forms/contact-sales?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=plugins1&quot;&gt;reach out&lt;/a&gt; if you have any questions. Thank you for reading.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Over 3,000 creative professionals gain early access to our new features, demos, and updates—don’t miss out, and&lt;/strong&gt; &lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i?ref=img.ly&quot;&gt;&lt;strong&gt;subscribe&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;to our newsletter.&lt;/strong&gt;&lt;/p&gt;&lt;/template&gt;&lt;/p&gt;</content:encoded><dc:creator>Antonello</dc:creator><media:content url="https://blog.img.ly/2025/01/video-editor-vue_js.jpg" medium="image"/><category>Vue.js</category><category>Video Editor</category><category>How-To</category></item><item><title>A Modern React Video Editor: Integration Guide</title><link>https://img.ly/blog/a-modern-react-video-editor/</link><guid isPermaLink="true">https://img.ly/blog/a-modern-react-video-editor/</guid><description>Learn how to integrate IMG.LY&apos;s video editor for React Native into your app and how to best leverage its capabilities.</description><pubDate>Wed, 08 Jan 2025 09:31:11 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Learn how to integrate&lt;/em&gt; &lt;a href=&quot;https://img.ly/docs/cesdk/react/starterkits/video-editor-e1nlor/&quot;&gt;&lt;em&gt;IMG.LY’s video editor for React&lt;/em&gt;&lt;/a&gt; &lt;em&gt;into your web app and make the most of all its features.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Video content has seen steadily growing demand, especially with the rising popularity of short-form videos. It is no surprise that platforms like YouTube have heavily invested in short-form video content, as video remains a dominant medium for users to create and consume content.&lt;/p&gt;
&lt;p&gt;Platforms like Instagram, TikTok, and YouTube have changed user habits forever. Here is why integrating video creation and editing directly within your web application can dramatically enhance user satisfaction.&lt;/p&gt;
&lt;p&gt;In this guide, you will see how to integrate a video editor into a React app using CreativeEditor SDK (&lt;em&gt;CE.SDK&lt;/em&gt;, for short). We will discuss when it is useful and explain how to customize the editor for your specific use cases.&lt;/p&gt;
&lt;p&gt;For a quick start, check out the &lt;a href=&quot;https://github.com/imgly/cesdk-web-examples/tree/main/integrate-with-react&quot;&gt;GitHub repository&lt;/a&gt; featuring the code for integrating a React video editor.&lt;/p&gt;
&lt;p&gt;Let’s dive in!&lt;/p&gt;
&lt;h2 id=&quot;why-integrate-a-video-editor-in-your-react-web-app&quot;&gt;Why Integrate a Video Editor in Your React Web App?&lt;/h2&gt;
&lt;p&gt;The digital landscape is ever-evolving, but one truth has remained constant for several years: video content reigns supreme.&lt;/p&gt;
&lt;p&gt;The data speaks for itself. Platforms like &lt;a href=&quot;https://newsroom.tiktok.com/en-us/1-billion-people-on-tiktok&quot;&gt;TikTok boast over 1.04 billion monthly active users worldwide&lt;/a&gt;. Similarly, one of most recent &lt;a href=&quot;https://abc.xyz/2024-q1-earnings-call/&quot;&gt;Google’s earnings call&lt;/a&gt; revealed that YouTube Shorts generated approximately 70 billion daily views in just one quarter—a significant leap from 30 billion daily views just two years ago.&lt;/p&gt;
&lt;p&gt;These platforms have set the gold standard by empowering users to create professional-looking videos effortlessly—adding filters, overlays, audio, and text with just a few clicks. This simplicity has made video editing an essential feature across various industries, from social media apps to marketing tools.&lt;/p&gt;
&lt;p&gt;Then, the shift toward shorter, more engaging videos has transformed how users create content and how we consume it. Audiences now demand bite-sized, engaging clips that are easy to produce and share.&lt;/p&gt;
&lt;p&gt;By integrating an easy-to-use video editor, your React web app can tap into this trend. The idea is to offer a feature that billions of users are familiar with—and may already expect from your application.&lt;/p&gt;
&lt;p&gt;The result? Lowering the barrier for user-generated content, boosting engagement, and driving distribution!&lt;/p&gt;
&lt;p&gt;React’s flexibility and component-based architecture make it the perfect match for IMG.LY’s &lt;a href=&quot;https://img.ly/products/creative-sdk&quot;&gt;CreativeEditor SDK&lt;/a&gt;, which guarantees a seamless, high-performance, and feature-rich experience for design, video, and photo editing—all directly in the browser.&lt;/p&gt;
&lt;h2 id=&quot;getting-started-adding-a-video-editor-in-react&quot;&gt;Getting Started: Adding a Video Editor in React&lt;/h2&gt;
&lt;p&gt;Follow this step-by-step tutorial section and learn how to set up a React video editor in your web app using CreativeEditor SDK. For a different approach, see our guide on &lt;a href=&quot;https://img.ly/blog/how-to-build-a-video-editor-with-wasm-in-react/&quot;&gt;how to build a video editor in React with Wasm&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Integrate CE.SDK in React with the following instructions!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Requirements&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Before getting started, make sure you have the latest LTS version of Node.js installed on your machine. Otherwise, &lt;a href=&quot;https://nodejs.org/en/download&quot;&gt;download it from the official website&lt;/a&gt; and install it.&lt;/p&gt;
&lt;p&gt;Next, if you do not already have a React project set up, create a new one using &lt;a href=&quot;https://vite.dev/guide/&quot;&gt;Vite&lt;/a&gt;:&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; create&lt;/span&gt;&lt;span&gt; vite@latest&lt;/span&gt;&lt;span&gt; my-react-video-editor-app&lt;/span&gt;&lt;span&gt; –&lt;/span&gt;&lt;span&gt; --template&lt;/span&gt;&lt;span&gt; react&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Install CE.SDK via the &lt;a href=&quot;https://www.npmjs.com/package/@cesdk/cesdk-js&quot;&gt;@cesdk/cesdk-js&lt;/a&gt; package with 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; install&lt;/span&gt;&lt;span&gt; @cesdk/cesdk-js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your &lt;code&gt;package.json&lt;/code&gt; file will now include it as a dependency:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;dependencies&quot;&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;@cesdk/cesdk-js&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^1.41.1&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;react&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^18.3.1&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;react-dom&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^18.3.1&quot;&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;Load your project in a JavaScript IDE, as you are ready to start coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Create the Video Editor Component&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In the src folder, create a &lt;code&gt;VideoEditor.jsx&lt;/code&gt; file. This will contain your CE.SDK-based React video editor component.&lt;/p&gt;
&lt;p&gt;Import CreativeEditorSDK from &lt;code&gt;@cesdk/cesdk-js&lt;/code&gt; as 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;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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, initialize your video editor React component with this logic:&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;// src/VideoEditor.jsx&lt;/span&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; 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; { 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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// your CE.SDK license and user configs&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;  license: &lt;/span&gt;&lt;span&gt;&apos;&amp;#x3C;YOUR_LICENSE&gt;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  userId: &lt;/span&gt;&lt;span&gt;&apos;&amp;#x3C;YOUR_USER_ID&gt;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; default&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; VideoEditor&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; cesdk_container&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;cesdk&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setCesdk&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;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;  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 the CE.SDK container has already been initialized&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;cesdk_container.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;    let&lt;/span&gt;&lt;span&gt; cleanedUp &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 class=&quot;line&quot;&gt;&lt;span&gt;    // initialize a CE.SDK instance&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    let&lt;/span&gt;&lt;span&gt; instance;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    CreativeEditorSDK.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(cesdk_container.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;      async&lt;/span&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;        instance &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;        if&lt;/span&gt;&lt;span&gt; (cleanedUp) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          instance.&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;          return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // customize the editor behavior...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        setCesdk&lt;/span&gt;&lt;span&gt;(instance);&lt;/span&gt;&lt;/span&gt;
&lt;span 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;    // clean up the CE.SDK instance&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; cleanup&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;      cleanedUp &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;      instance?.&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;      setCesdk&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    };&lt;/span&gt;&lt;/span&gt;
&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; cleanup;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }, [cesdk_container]);&lt;/span&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      ref&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{cesdk_container}&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;{{ width: &lt;/span&gt;&lt;span&gt;&apos;100vw&apos;&lt;/span&gt;&lt;span&gt;, height: &lt;/span&gt;&lt;span&gt;&apos;100vh&apos;&lt;/span&gt;&lt;span&gt; }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace &lt;code&gt;&amp;#x3C;YOUR_LICENSE&gt;&lt;/code&gt; with the license key you obtain from CreativeEditor SDK and &lt;code&gt;&amp;#x3C;YOUR_USER_ID&gt;&lt;/code&gt; with your user ID to optionally track monthly active users (MAUs) across different devices.&lt;/p&gt;
&lt;p&gt;The component defined above loads the &lt;a href=&quot;https://img.ly/docs/cesdk/js/get-started/overview-e18f40/&quot;&gt;CreativeEditorSDK&lt;/a&gt; JavaScript element into an HTML &lt;/p&gt;&lt;div&gt; element.&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Use the Component&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You can now import the VideoEditor component 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; VideoEditor &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;./VideoEditor&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, use it as below:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;#x3C;VideoEditor /&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This will open the video editor with the video preset, allowing users to trim, cut, apply filters, add text overlays, include music, and more to enhance their videos.&lt;/p&gt;
&lt;p&gt;Have a look at our &lt;a href=&quot;https://img.ly/showcases/cesdk/video-ui/web?ref=img.ly&quot;&gt;interactive demo&lt;/a&gt; to see what the resultant editor should look like.&lt;/p&gt;
&lt;h2 id=&quot;react-video-editor-use-cases&quot;&gt;React Video Editor Use Cases&lt;/h2&gt;
&lt;p&gt;Now that you know how to integrate a React video editor into your web app, you are ready to explore some key use cases. See how the specific features of CreativeEditor SDK can support different scenarios.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Social Media Publishing&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;CreativeEditor SDK equips users with the tools they need to create engaging video content. It makes it easier to produce shareable videos for popular social media platforms like Instagram, TikTok, and LinkedIn with features like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reusable Templates&lt;/strong&gt;: Start with video templates downloaded from others or create your own templates and share them with the community. By selecting from a variety of ready-to-use templates for different use cases, users can avoid the blank canvas syndrome and bring their ideas to life quickly. You can explore a range of different templates in our &lt;a href=&quot;https://img.ly/showcases/cesdk/video-ui/web?template=month-in-review&amp;#x26;ref=img.ly&quot;&gt;video editor demo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Music and Audio Library&lt;/strong&gt;: Users can easily add audio files to their videos, setting the tone through music or narration and creating a captivating atmosphere for their content.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Animations&lt;/strong&gt;: The SDK comes with a wide set of &lt;a href=&quot;https://img.ly/docs/cesdk/react/animation/overview-6a2ef2/&quot;&gt;configurable animations&lt;/a&gt; to improve the appearance of design elements within video scenes, significantly boosting engagement.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once a video has been created in your React application, CE.SDK lets users export it in the appropriate formats and aspect ratios for the target social media platforms.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Digital Asset Management&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;DAM, short for &lt;a href=&quot;https://www.ibm.com/think/topics/digital-asset-management&quot;&gt;Digital Asset Management&lt;/a&gt;, refers to the process of organizing, storing, and managing any digital asset—including videos. Over time, DAM has become essential for businesses to maintain efficiency, streamline workflows, and ensure brand consistency across teams.&lt;/p&gt;
&lt;p&gt;CreativeEditor SDK supports DAM by giving your team the ability to organize, edit, and repurpose video content within a centralized, embeddable system. Within the React video editor component, users can easily adapt and edit their assets, ensuring brand consistency while automatically propagating changes across multiple assets.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://img.ly/showcases/cesdk/video-ui/web&quot;&gt;Video templates&lt;/a&gt; support placeholders and permissions to guide users’ designs, guaranteeing that all assets stay on-brand. While CE.SDK does not directly support role-based permissions, it can be integrated with any backend technology or framework to control user access.&lt;/p&gt;
&lt;p&gt;Keep in mind that the SDK is also extendable. That way, developers can create custom hooks that check permissions and customize the editor’s behavior accordingly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Marketing Automation&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;CreativeEditor SDK provides &lt;a href=&quot;https://img.ly/industries/marketing-tech&quot;&gt;marketing tech&lt;/a&gt; to efficiently craft branded, campaign-specific videos at scale.&lt;/p&gt;
&lt;p&gt;Features like pre-designed, editable, and customizable designs help save time in video production and management. Changes to these templates can be automatically propagated, also eliminating the need for manual updates.&lt;/p&gt;
&lt;p&gt;The SDK also supports advanced scenarios like A/B testing, so that your marketing teams can campaign reach by comparing different solutions to see how they perform. Plus, the ability to generate customized videos with &lt;a href=&quot;https://img.ly/docs/cesdk/react/create-templates/add-dynamic-content/text-variables-7ecb50/&quot;&gt;configurable text variables&lt;/a&gt; makes personalizing content easier than ever.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Personalized Videos for Sales Outreach&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We all know how boring and annoying cold emails can be. Marketers and salespeople understand this too, which is why personalized video messages have become the new frontier for pitching.&lt;/p&gt;
&lt;p&gt;Thanks to CreativeEditor SDK, sales teams can easily produce customized videos tailored to specific clients or leads. These videos are far more engaging than standard emails because they feel like a real conversation.&lt;/p&gt;
&lt;p&gt;Also, the translation capabilities offered by the SDK allow sales teams to reach multiple audiences worldwide, breaking down language barriers and personalizing the message for a broader range of targets. Test this feature in our &lt;a href=&quot;https://img.ly/showcases/cesdk/language/web&quot;&gt;translation and internationalization demo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;E-Learning&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;CreativeEditor SDK provides educators with the tools they need to create informative videos. Teachers and coaches can quickly produce professional-quality content without requiring extensive technical skills.&lt;/p&gt;
&lt;p&gt;The SDK enhances the learning experience on your React-based e-learning platform through features like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reusability&lt;/strong&gt;: Build a library of templates that can be easily adapted and integrated into existing materials.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easy video production&lt;/strong&gt;: Record, edit, and arrange videos directly within the editor, accessible on desktop, mobile, or tablet.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Plugins for learner interactivity&lt;/strong&gt;: Boost engagement by &lt;a href=&quot;https://img.ly/docs/cesdk/react/user-interface/ui-extensions-d194d1/&quot;&gt;integrating plugins&lt;/a&gt; that add quizzes, polls, and other interactive components within the videos.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;customizing-your-creativeeditor-sdk-instance&quot;&gt;Customizing your CreativeEditor SDK Instance&lt;/h2&gt;
&lt;p&gt;CreativeEditor SDK does not offer a static, pre-configured React video editor experience. Quite the opposite, it presents several customization features to tailor the editor to your specific needs and brand requirements.&lt;/p&gt;
&lt;p&gt;The key customization options are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Build Custom UIs&lt;/strong&gt;: Define fully custom user interfaces adapted to your specific use case.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Theming&lt;/strong&gt;: Adjust the editor’s theme to match your app’s design. Choose from built-in themes, generate new ones using the &lt;a href=&quot;https://img.ly/docs/cesdk/react/user-interface/appearance/theming-4b0938/&quot;&gt;theme generator&lt;/a&gt;, or manually create a custom theme. Test theming in our &lt;a href=&quot;https://img.ly/showcases/cesdk/theming/web&quot;&gt;dedicated demo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Media Libraries&lt;/strong&gt;: Set up customizable, sortable media libraries. CE.SDK supports integration with third-party libraries accessible via API, such as &lt;a href=&quot;https://img.ly/showcases/cesdk/unsplash-image-assets/web&quot;&gt;Unsplash&lt;/a&gt;, allowing you to easily access and use external media assets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Toolbar Customization&lt;/strong&gt;: Reposition toolbar elements, change icons, or rename tools to suit your needs, providing a unique editing experience.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Internationalization&lt;/strong&gt;: Adapt the video editor component to different languages and regions. CE.SDK offers &lt;a href=&quot;https://img.ly/docs/cesdk/react/user-interface/localization-508e20/&quot;&gt;full i18n support&lt;/a&gt;, enabling you to overwrite and extend all text strings in any language.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Integrating a React video editor into your web app can significantly enhance the user experience and serve as a valuable feature to boost retention, engagement, and potential product distribution. This holds true whether you are building a social media platform, a tool for influencers, a marketing SaaS, or an e-learning system.&lt;/p&gt;
&lt;p&gt;With CreativeEditor SDK, you can quickly add a fully customizable video editing experience to your React application in just minutes.&lt;/p&gt;
&lt;p&gt;By following the steps outlined in this blog post, you can bring professional-level video editing features to your web users. Explore CE.SDK’s video capabilities and &lt;a href=&quot;https://img.ly/docs/cesdk/react/prebuilt-solutions/video-editor-9e533a/&quot;&gt;dive into the docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Stay tuned for more updates, and please &lt;a href=&quot;https://img.ly/forms/contact-sales?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=plugins1&quot;&gt;reach out&lt;/a&gt; if you have any questions. Thank you for reading.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Over 3,000 creative professionals gain early access to our new features, demos, and updates—don’t miss out, and&lt;/strong&gt; &lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i?ref=img.ly&quot;&gt;&lt;strong&gt;subscribe&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;to our newsletter.&lt;/strong&gt;&lt;/p&gt;&lt;/div&gt;</content:encoded><dc:creator>Antonello</dc:creator><media:content url="https://blog.img.ly/2025/01/video-editor-react.jpg" medium="image"/><category>React</category><category>How-To</category><category>Video Editor</category></item><item><title>A Modern Angular Video Editor: Setup Guide</title><link>https://img.ly/blog/a-modern-angular-video-editor/</link><guid isPermaLink="true">https://img.ly/blog/a-modern-angular-video-editor/</guid><description>Learn how to integrate IMG.LY&apos;s video editor for Angular into your web app and how to best leverage its capabilities.</description><pubDate>Wed, 08 Jan 2025 08:19:25 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Learn how to integrate&lt;/em&gt; &lt;a href=&quot;https://img.ly/docs/cesdk/angular/starterkits/video-editor-e1nlor/&quot;&gt;&lt;em&gt;IMG.LY’s video editor&lt;/em&gt;&lt;/a&gt; &lt;em&gt;for Angular into your web application and get the most out of it.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;TikTok, Instagram, Facebook, WhatsApp Messenger, YouTube, and X are among the most popular social media platforms. They consistently rank in the top 10 most visited websites and downloaded mobile apps globally. Have you ever asked what is the common thread between them? Video content!&lt;/p&gt;
&lt;p&gt;These platforms have revolutionized how we consume video content. Videos are now shorter, often include subtitles for silent viewing, and are designed to be engaging, professionally produced, and artfully crafted.The challenge lies in meeting user expectations, as modern web applications are now expected to offer intuitive video creation and editing tools. After all, Instagram and TikTok have set the bar quite high when it comes to seamless video production.&lt;/p&gt;
&lt;p&gt;This guide will walk you through implementing a video editor in your Angular web app using CreativeEditor SDK (&lt;em&gt;CE.SDK&lt;/em&gt;). We will also take a look at some scenarios where this video editing is useful and explain how to customize the editor to meet your unique requirements.To jumpstart your project, check out the &lt;a href=&quot;https://github.com/imgly/cesdk-web-examples/tree/main/integrate-with-angular&quot;&gt;GitHub repository for Angular video editor integration&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let’s dive in!&lt;/p&gt;
&lt;h2 id=&quot;why-add-a-video-editor-to-an-angular-application&quot;&gt;Why Add a Video Editor to an Angular Application?&lt;/h2&gt;
&lt;p&gt;Over the past few months, AI has been revolutionizing the tech industry. It all started with AI-generated text and images, but what is next on the horizon? AI-generated videos!&lt;/p&gt;
&lt;p&gt;The appeal is clear—numerous studies show that video is the most engaging medium, resonating deeply with us as humans. This is no surprise, given that &lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_most-visited_websites&quot;&gt;YouTube and Instagram rank among the top five most visited websites&lt;/a&gt;, and &lt;a href=&quot;https://www.statista.com/statistics/1285960/top-downloaded-mobile-apps-worldwide/&quot;&gt;TikTok is the most downloaded app worldwide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The problem is that users now demand more than just video content. They expect engaging, professionally edited videos. On top of that, platforms like Instagram and TikTok have raised the bar for intuitive video production and editing. &lt;/p&gt;
&lt;p&gt;As a result, we all expect to be able to add filters, overlays, audio, music, and text to videos with just a few clicks. Meeting these expectations is essential for any application offering video generation features.&lt;/p&gt;
&lt;p&gt;Adding an easy-to-use video editor into your Angular project gives users a powerful tool that they are likely to desire and are already familiar with. That will surely boosts user engagement and help you accelerate the distribution of your online product or service!&lt;/p&gt;
&lt;h2 id=&quot;how-to-set-up-a-video-editor-in-angular&quot;&gt;How to Set Up a Video Editor in Angular&lt;/h2&gt;
&lt;p&gt;In this section, you will learn how to integrate an Angular video editor into your wev application through CreativeEditor SDK.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Requirements&lt;/strong&gt;&lt;br&gt;
Before you begin, make sure you have the latest LTS version of Node.js installed on your machine. If that is not your case, download and install it from the &lt;a href=&quot;https://nodejs.org/en/download&quot;&gt;official Node.js website&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Next, open your terminal and run the following command to install the &lt;a href=&quot;https://angular.dev/tools/cli&quot;&gt;Angular CLI&lt;/a&gt; globally:&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; -g&lt;/span&gt;&lt;span&gt; @angular/cli&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will make it easy to create and manage Angular projects.&lt;/p&gt;
&lt;p&gt;Once the installation is complete, if you don’t have an Angular project set up, initialize a new Angular project by running:&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;ng&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; my-angular-video-editor-app&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will be prompted with a few questions:&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;Would you like to share pseudonymous usage data about this project with the Angular Team at Google under Google&apos;s Privacy Policy at https://policies.google.com/privacy. For more details and how to change this setting, see https://angular.dev/cli/analytics.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;No&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Global setting: disabled&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Local setting: No local workspace configuration file.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Effective status: disabled&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;✔ Which stylesheet format would you like to use? CSS [ https://developer.mozilla.org/docs/Web/CSS ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;✔ Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)? No&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you are unsure, press Enter to accept the default answer.&lt;/p&gt;
&lt;p&gt;After the project is created, navigate to the project folder and install the CreativeEditor SDK (&lt;a href=&quot;https://www.npmjs.com/package/@cesdk/cesdk-js&quot;&gt;@cesdk/cesdk-js&lt;/a&gt;) npm package by running:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;npm install @cesdk/cesdk-js&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Your &lt;strong&gt;package.json&lt;/strong&gt; file will now include the SDK as a dependency:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;dependencies&quot;&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;@angular/animations&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^19.0.0&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;@angular/common&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^19.0.0&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;@angular/compiler&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^19.0.0&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;@angular/core&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^19.0.0&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;@angular/forms&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^19.0.0&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;@angular/platform-browser&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^19.0.0&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;@angular/platform-browser-dynamic&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^19.0.0&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;@angular/router&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^19.0.0&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;@cesdk/cesdk-js&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^1.41.1&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;rxjs&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;~7.8.0&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;tslib&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;^2.3.0&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;zone.js&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;~0.15.0&quot;&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;Open your project in a JavaScript IDE, as you are ready to start coding!&lt;/p&gt;
&lt;h3 id=&quot;create-a-video-editor-component&quot;&gt;Create a Video Editor Component&lt;/h3&gt;
&lt;p&gt;First, use the Angular CLI to generate the scaffold for your video editor component:&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;ng&lt;/span&gt;&lt;span&gt; generate&lt;/span&gt;&lt;span&gt; component&lt;/span&gt;&lt;span&gt; video-editor&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Open the &lt;code&gt;video-editor.component.ts&lt;/code&gt; file inside the &lt;code&gt;src/app/video-editor&lt;/code&gt; folder and initialize your CE.SDK-based Angular video editor component as 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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { Component, ElementRef, ViewChild } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@angular/core&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; CreativeEditorSDK, { Configuration } &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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Component&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  selector: &lt;/span&gt;&lt;span&gt;&apos;app-video-editor&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  imports: [],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  templateUrl: &lt;/span&gt;&lt;span&gt;&apos;./video-editor.component.html&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  styleUrl: &lt;/span&gt;&lt;span&gt;&apos;./video-editor.component.css&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;export&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt; VideoEditorComponent&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ViewChild&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;cesdk_container&apos;&lt;/span&gt;&lt;span&gt;) containerRef: ElementRef = {} &lt;/span&gt;&lt;span&gt;as&lt;/span&gt;&lt;span&gt; ElementRef&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;  ngAfterViewInit&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; void&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; config&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; Configuration&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;      license: &lt;/span&gt;&lt;span&gt;&apos;&amp;#x3C;YOUR_LICENSE&gt;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      userId: &lt;/span&gt;&lt;span&gt;&apos;&amp;#x3C;YOUR_USER_ID&gt;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    CreativeEditorSDK.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.containerRef.nativeElement, 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;      async&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;instance&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; any&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // customize the editor behavior...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        await&lt;/span&gt;&lt;span&gt; instance.&lt;/span&gt;&lt;span&gt;createDesignScene&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace &lt;code&gt;&amp;#x3C;YOUR_LICENSE&gt;&lt;/code&gt; with the license key provided by CreativeEditor SDK. Optionally, also set &lt;code&gt;&amp;#x3C;YOUR_USER_ID&gt;&lt;/code&gt; to your user ID to start collecting monthly active user (MAU) data.Then, define video-editor.component.html as below:&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;&amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; #cesdk_container&lt;/span&gt;&lt;span&gt; [style.height.vh]=&quot;&apos;100&apos;&quot;&lt;/span&gt;&lt;span&gt; [style.width.vw]=&quot;&apos;100&apos;&quot;&gt;&amp;#x3C;/div&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way, VideoEditorComponent will be mounted on the above &lt;/p&gt;&lt;div&gt; element.&lt;p&gt;&lt;/p&gt;
&lt;h3 id=&quot;use-the-component&quot;&gt;Use the Component&lt;/h3&gt;
&lt;p&gt;You can now import the component and register it in your &lt;code&gt;app.components.ts&lt;/code&gt; file with these lines of code:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { Component } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@angular/core&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; { RouterOutlet } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@angular/router&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; { VideoEditorComponent } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;./video-editor/video-editor.component&apos;&lt;/span&gt;&lt;span&gt;; &lt;/span&gt;&lt;span&gt;// import the video editor component&lt;/span&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;Component&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  selector: &lt;/span&gt;&lt;span&gt;&apos;app-root&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  imports: [RouterOutlet, VideoEditorComponent], &lt;/span&gt;&lt;span&gt;// register the video editor component&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  templateUrl: &lt;/span&gt;&lt;span&gt;&apos;./app.component.html&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  styleUrl: &lt;/span&gt;&lt;span&gt;&apos;./app.component.css&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;export&lt;/span&gt;&lt;span&gt; class&lt;/span&gt;&lt;span&gt; AppComponent&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  title&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &apos;my-angular-video-editor-app&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, you can use it in app.component.html with:&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;app-video-editor&gt;&amp;#x3C;/app-video-editor&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This setup will open the video editor with a predefined video template, allowing users to trim, cut, apply filters, add text overlays, insert music, and make other video enhancements.&lt;/p&gt;
&lt;p&gt;Have a look at our &lt;a href=&quot;https://img.ly/showcases/cesdk/video-ui/web&quot;&gt;interactive demo&lt;/a&gt; to see what the resultant editor should look like.&lt;/p&gt;
&lt;h2 id=&quot;use-cases-the-your-angular-video-editor&quot;&gt;Use Cases the Your Angular Video Editor&lt;/h2&gt;
&lt;p&gt;After learning how to create an Angular video editor component with a basic CreativeEditor SDK integration, it is time to explore some practical use cases in real-world scenarios.&lt;/p&gt;
&lt;h3 id=&quot;video-messages-for-marketing-outreach&quot;&gt;Video Messages for Marketing Outreach&lt;/h3&gt;
&lt;p&gt;Cold emails often come across as generic and impersonal, often ending up in spam or being ignored. In contrast, personalized &lt;a href=&quot;https://www.linkedin.com/pulse/harnessing-power-video-messages-sales-outreach-oliveira-phd--fqrle/&quot;&gt;video messages are transforming marketing outreach&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;CreativeEditor SDK enables marketers to create compelling videos that stand out from standard email approaches with capabilities like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Personalized Video Messages for Leads&lt;/strong&gt;: Create tailored videos for individual clients or prospects, adding a personal touch to your marketing outreach efforts and make a stronger impact compared to traditional cold emails.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Global Reach with Translation Features&lt;/strong&gt;: Use the SDK’s built-in translation and internationalization tools to engage with a global audience. Customize messages to fit local cultures and ensure a personalized experience. Try out this feature in our &lt;a href=&quot;https://img.ly/showcases/cesdk/language/web&quot;&gt;translation demo&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;educational-videos-for-e-learning-platforms&quot;&gt;Educational Videos for E-Learning Platforms&lt;/h3&gt;
&lt;p&gt;CreativeEditor SDK offers users in the e-learning industry an intuitive tool to create engaging and educational videos. &lt;/p&gt;
&lt;p&gt;Educators, teachers, and coaches do not need technical skills, as video creation is simple and accessible. Specifically, users can record, edit, and organize videos across desktop, mobile, or tablet browsers with just a few clicks. &lt;/p&gt;
&lt;p&gt;The SDK simplifies content creation through reusable templates. Instructors can integrate their materials into those template to maintain consistency while covering different topics. Finally, support for &lt;a href=&quot;https://img.ly/docs/cesdk/angular/user-interface/ui-extensions-d194d1/&quot;&gt;interactive plugins&lt;/a&gt;—such as quizzes, polls, and other engagement tools—adds a dynamic layer to video lessons.&lt;/p&gt;
&lt;h3 id=&quot;video-content-for-social-media&quot;&gt;Video Content for Social Media&lt;/h3&gt;
&lt;p&gt;CreativeEditor SDK simplifies the process of producing shareable videos for social media sites like Instagram, TikTok, YouTube, but also LinkedIn and others. That is possible thanks to features like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reusable Templates&lt;/strong&gt;: Start with video templates from other creators or design your own and share them with the community. By choosing from a variety of pre-designed templates for different needs, users can avoid the frustration of starting from scratch and bring their ideas to life quickly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Animations&lt;/strong&gt;: Access a broad &lt;a href=&quot;https://img.ly/docs/cesdk/angular/animation/overview-6a2ef2/&quot;&gt;selection of customizable animations&lt;/a&gt; to enhance the visual appeal of video elements, driving higher engagement.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Audio Library&lt;/strong&gt;: Effortlessly incorporate audio files into your videos, such as music, voiceovers, or sound effects, to set the mood and create an immersive experience for viewers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once a video is created in Angular application with CE.SDK, users can export it in the ideal formats and aspect ratios for different social media platforms.&lt;/p&gt;
&lt;h3 id=&quot;showcase-products-on-e-commerce-applications&quot;&gt;Showcase Products on E-Commerce Applications&lt;/h3&gt;
&lt;p&gt;Images have long been a simple and effective way to showcase products on e-commerce platforms. Many sites, from eBay to Amazon, have used them for years. At the same time, customer expectations have evolved, and they now seek more engaging ways to visualize products.&lt;/p&gt;
&lt;p&gt;Short, dynamic product videos significantly enhance product presentation. In particular, Amazon data shows that &lt;a href=&quot;https://sellercentral.amazon.com/seller-forums/discussions/t/b031f21d-e8e2-49ea-933c-bef293bf9427&quot;&gt;adding videos can boost sales by up to 9.7%&lt;/a&gt;. It is no surprise that many Amazon sellers have already adopted video to showcase their products.&lt;/p&gt;
&lt;p&gt;With a CE.SDK-based Angular video editor, you can easily create videos that work seamlessly across multiple devices for a unified shopping experience. Thanks to reusable templates, you can customize product videos while maintaining scalability and brand consistency.By leveraging multiple templates and feeding them with diverse data, you can generate automated product video variations at scale.&lt;/p&gt;
&lt;h3 id=&quot;smart-and-automated-workflows&quot;&gt;Smart and Automated Workflows&lt;/h3&gt;
&lt;p&gt;CreativeEditor SDK supports the development of a tool for creating branded videos at scale.&lt;/p&gt;
&lt;p&gt;As it is based on ready-made and editable templates, it simplifies video production and management. The reason is that users can define these templates once through an intuitive point-and-click interface, then effortlessly customize the produced videos via different input resources or &lt;a href=&quot;https://img.ly/docs/cesdk/angular/create-templates/add-dynamic-content/text-variables-7ecb50/&quot;&gt;configurable text variables&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;That automated workflow process boosts productivity and scalability. The SDK also supports advanced features like &lt;a href=&quot;https://www.oracle.com/cx/marketing/what-is-ab-testing/&quot;&gt;A/B testing&lt;/a&gt;. That way, teams can create multiple versions of a campaign video, distribute them on social platforms, and compare their performance.&lt;/p&gt;
&lt;h2 id=&quot;customizing-your-creativeeditor-sdk-instance&quot;&gt;Customizing your CreativeEditor SDK Instance&lt;/h2&gt;
&lt;p&gt;CreativeEditor SDK features a versatile Angular video editor experience that can be easily configured and customized to fit your specific requirements and visual preferences.Key customization options supported by CE.SDK include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Feature Activation&lt;/strong&gt;: Enable or disable features as you need, so that you can control the functionality available to users.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom UIs&lt;/strong&gt;: Create fully personalized user interfaces, adapting the editor to your unique use case. This includes repositioning toolbar elements, changing icons, or renaming tools for a tailored editing experience.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Internationalization&lt;/strong&gt;: Adapt the video editor for different languages and regions. CE.SDK provides &lt;a href=&quot;https://img.ly/docs/cesdk/angular/user-interface/localization-508e20/&quot;&gt;full support for internationalization&lt;/a&gt;, enabling you to customize all text strings in any language.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Export Options&lt;/strong&gt;: Configure which file formats users can select for exporting, along with settings for quality, dimensions, and more.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Role Customization&lt;/strong&gt;: &lt;a href=&quot;https://img.ly/docs/cesdk/angular/configuration-2c1c3d/&quot;&gt;CE.SDK supports roles&lt;/a&gt;, which are a set of global settings and scopes. When the role changes, the default settings for that role are applied. You can also use a callback to adjust configurations whenever the role changes and define custom roles to tailor settings for specific user needs or workflows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Media Libraries:&lt;/strong&gt; Create custom, sortable media libraries. CE.SDK supports integration with third-party libraries via API, offering easy access to external media assets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Choose the Start Video:&lt;/strong&gt; Set the editor to display a predefined video at the start, eliminating the blank canvas effect.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Theming&lt;/strong&gt;: Adjust the editor’s theme to match your app’s design. You can select from built-in themes, generate new ones using the &lt;a href=&quot;https://img.ly/docs/cesdk/angular/user-interface/appearance/theming-4b0938/&quot;&gt;theme generator&lt;/a&gt;, or manually create a custom theme. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See all of these customizations in action in our &lt;a href=&quot;https://img.ly/showcases/cesdk?tags=customization&quot;&gt;customization demo&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Adding an video editor to your Angular site or web application greatly enhances user experience. Such a feature drives product success by improving user reviews and increasing retention. Whether you are creating a marketing tool, an e-learning or e-commerce platform, or any web app with social media functionality, a video editor adds immense value.&lt;/p&gt;
&lt;p&gt;CreativeEditor SDK gives you what you need to implement a fully customizable video editing solution into your Angular application in minutes.&lt;/p&gt;
&lt;p&gt;By following the steps in this guide, you learned how to equip your users with a professional and intuitive video editing experience. Explore CE.SDK’s video capabilities and &lt;a href=&quot;https://img.ly/docs/cesdk/angular/prebuilt-solutions/video-editor-9e533a/&quot;&gt;dive into the docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Stay tuned for more updates, and please &lt;a href=&quot;https://img.ly/forms/contact-sales?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=plugins1&quot;&gt;reach out&lt;/a&gt; if you have any questions. Thank you for reading.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Over 3,000 creative professionals gain early access to our new features, demos, and updates—don’t miss out, and&lt;/strong&gt; &lt;a href=&quot;https://share.hsforms.com/1IgAOV1wASXGPnFG4ZPLejg1hk3i?ref=img.ly&quot;&gt;&lt;strong&gt;subscribe&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;to our newsletter.&lt;/strong&gt;&lt;/p&gt;&lt;/div&gt;</content:encoded><dc:creator>Antonello</dc:creator><media:content url="https://blog.img.ly/2025/01/video-editor-angular.jpg" medium="image"/><category>Angular</category><category>How-To</category><category>Video Editor</category></item><item><title>How To Build a Video Editor With Wasm in React</title><link>https://img.ly/blog/how-to-build-a-video-editor-with-wasm-in-react/</link><guid isPermaLink="true">https://img.ly/blog/how-to-build-a-video-editor-with-wasm-in-react/</guid><description>Use the ffmpeg.wasm library to build a React video editor that performs video processing directly in the browser.</description><pubDate>Mon, 16 Jan 2023 16:31:57 GMT</pubDate><content:encoded>&lt;p&gt;You may think that video processing can only be performed on a server, but this is not true. Thanks to WebAssembly (Wasm), you can run high-performance code written in C or C++ in your browser. This opens up a lot of possibilities and gives you the ability to build a client-side video editor. Let’s now learn how to create a Wasm-based video editor in React.&lt;/p&gt;
&lt;p&gt;Follow this tutorial and learn how to build the application below:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Upload and crop your video, and covert it as a GIF&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 671px) 671px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;671&quot; height=&quot;943&quot; src=&quot;https://img.ly/_astro/ffmpeg-video-editor-wasm_1i2zGn.webp&quot; srcset=&quot;/_astro/ffmpeg-video-editor-wasm_1FMujk.webp 640w, /_astro/ffmpeg-video-editor-wasm_1i2zGn.webp 671w&quot;&gt;&lt;/p&gt;
&lt;p&gt;This React video editor allows users to upload a video, select a portion of it, convert it to GIF, and download the resulting image file – all of this in your browser.&lt;/p&gt;
&lt;h2 id=&quot;what-is-webassembly&quot;&gt;What is WebAssembly?&lt;/h2&gt;
&lt;p&gt;WebAssembly (also called Wasm) is a new type of code that modern web browsers can run and understand. Specifically, Wasm provides new functionality to web development and brings significant performance benefits. This applies to both frontend and backend, since Wasm can be used by both clients and servers.&lt;/p&gt;
&lt;p&gt;Wasm code should not be written by hand. This is because Wasm is a binary instruction format. So, Wasm is designed to be a compilation target for source languages such as C, C++, Rust, and others. Learn more about Wasm on the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/WebAssembly&quot;&gt;WebAssembly MDN Web Docs page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Wasm provides a way to run code written in several languages on the Web at near-native speed. This means that WebAssembly forms can be easily imported and executed by a Web client or server application. In other words, you can use WebAssembly functions via JavaScript and achieve results that were not previously possible on a browser, especially in terms of performance.&lt;/p&gt;
&lt;h2 id=&quot;what-is-ffmpegwasm&quot;&gt;What is &lt;code&gt;ffmpeg.wasm&lt;/code&gt;?&lt;/h2&gt;
&lt;p&gt;As stated on the &lt;a href=&quot;https://github.com/ffmpegwasm/ffmpeg.wasm&quot;&gt;GitHub page of the project&lt;/a&gt;, &lt;code&gt;ffmpeg.wasm&lt;/code&gt; is a WebAssembly and JavaScript port of FFmpeg. If you are not familiar with it, FFmpeg is an open-source software suite that includes several libraries and programs for managing audio, video, streams, and other media files. All of these tools can be invoked and executed via the &lt;code&gt;ffmpeg&lt;/code&gt; command-line instruction.&lt;/p&gt;
&lt;p&gt;Therefore, &lt;code&gt;ffmpeg.wasm&lt;/code&gt; enables video and audio processing in JavaScript-based web applications. In detail, it enables video and audio recording, format transcoding, video and audio editing, and video scaling. Even though it is a WebAssembly-based library, you can use it in your JavaScript code just like any other &lt;code&gt;npm&lt;/code&gt; library. This is the power of Wasm.&lt;/p&gt;
&lt;p&gt;Since it transpiles to Wasm, you can take advantage of &lt;code&gt;ffmpeg.wasm&lt;/code&gt; directly in your browser without performance concerns. This means that &lt;code&gt;ffmpeg.wasm&lt;/code&gt; opens the door to client-side audio and video processing. Let’s now learn how to use &lt;code&gt;ffmpeg.wasm&lt;/code&gt; to build a client-side video editor in React!&lt;/p&gt;
&lt;h2 id=&quot;building-a-video-editor-in-react-with-wasm&quot;&gt;Building a Video Editor in React with WASM&lt;/h2&gt;
&lt;p&gt;In this step-by-step tutorial, you will learn how to build a Wasm-based video editor in React with &lt;code&gt;ffmpeg.wasm&lt;/code&gt;. This React video editor application will allow you to upload a video, trim it, and convert it to GIF in the browser, without using any backend functionality or external API.&lt;/p&gt;
&lt;p&gt;Clone the &lt;a href=&quot;https://github.com/imgly/video-editor-wasm-react&quot;&gt;GitHub repository that supports the tutorial&lt;/a&gt; and try the video editor application by launching the following commands:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;git clone https://github.com/Tonel/video-editor-wasm-react&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cd video-editor-wasm-react&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm install&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm run start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s waste no more time and see how to build a video editor application in React.&lt;/p&gt;
&lt;h3 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h3&gt;
&lt;p&gt;This is the list of libraries the video editor application you are about to build depends on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/en/download/package-manager&quot;&gt;Node.js and npm 8+ and higher&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/facebook/react/blob/main/CHANGELOG.md#1820-june-14-2022&quot;&gt;React 18.2+&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[ffmpeg.wasm](https://github.com/ffmpegwasm/ffmpeg.wasm)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[antd](https://www.npmjs.com/package/antd)&lt;/code&gt; &gt;= 4.3&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[video-react](https://www.npmjs.com/package/video-react)&lt;/code&gt; &gt;= 0.15&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;antd&lt;/code&gt; is one of the most popular UI libraries for React. In this tutorial, its &lt;code&gt;[Slider](https://ant.design/components/slider/)&lt;/code&gt; component will be used to implement the video cutting feature. So, any other UI library including a slider component with a &lt;code&gt;range&lt;/code&gt; option will do.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;video-react&lt;/code&gt; is one of the most advanced and reliable HTML5 video players for React. You can replace it with any other React video player library.&lt;/p&gt;
&lt;h3 id=&quot;initializing-a-react-project&quot;&gt;Initializing a React Project&lt;/h3&gt;
&lt;p&gt;Let’s initialize a new &lt;a href=&quot;https://create-react-app.dev/docs/getting-started/&quot;&gt;Create React App&lt;/a&gt; React project called &lt;code&gt;video-editor-wasm-react&lt;/code&gt; with the 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 create-react-app video-editor-wasm-react&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your &lt;code&gt;video-editor-wasm-react&lt;/code&gt; directory should now contain the following files:&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;video-editor-wasm-react&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;video-editor-wasm-react&lt;/code&gt; folder in your terminal and launch a React local server with the commands 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;cd video-editor-wasm-react&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;Now, visit the &lt;code&gt;[http://localhost:3000/](http://localhost:3000/)&lt;/code&gt; page in your browser, and you should be seeing the default Create React App screen.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The default Create React App screen&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 983px) 983px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;983&quot; height=&quot;728&quot; src=&quot;https://img.ly/_astro/s_D2E103F8349A30F6AA8E27CD2BA4B6EDB946A8DEF5B8272009321B4F51D679F9_1624366125534_image_ZvCahg.webp&quot; srcset=&quot;/_astro/s_D2E103F8349A30F6AA8E27CD2BA4B6EDB946A8DEF5B8272009321B4F51D679F9_1624366125534_image_1hpMyh.webp 640w, /_astro/s_D2E103F8349A30F6AA8E27CD2BA4B6EDB946A8DEF5B8272009321B4F51D679F9_1624366125534_image_Zy6hVM.webp 750w, /_astro/s_D2E103F8349A30F6AA8E27CD2BA4B6EDB946A8DEF5B8272009321B4F51D679F9_1624366125534_image_Z184VNu.webp 828w, /_astro/s_D2E103F8349A30F6AA8E27CD2BA4B6EDB946A8DEF5B8272009321B4F51D679F9_1624366125534_image_ZvCahg.webp 983w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Before installing &lt;code&gt;ffmpeg.wasm&lt;/code&gt;, you need to get your server ready. As stated &lt;a href=&quot;https://github.com/ffmpegwasm/ffmpeg.wasm#installation&quot;&gt;in the official documentation&lt;/a&gt;, &lt;code&gt;fmmpeg.wasm&lt;/code&gt; depends on &lt;code&gt;[SharedArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer)&lt;/code&gt;. This means that only browsers that support &lt;code&gt;SharedArrayBuffer&lt;/code&gt; can run &lt;code&gt;ffmpeg.wasm&lt;/code&gt;. You can find a complete list of all browsers &lt;a href=&quot;https://caniuse.com/sharedarraybuffer&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the most popular browsers, &lt;code&gt;SharedArrayBuffer&lt;/code&gt; is only available to &lt;a href=&quot;https://developer.chrome.com/blog/enabling-shared-array-buffer/#cross-origin-isolation&quot;&gt;cross-origin isolated&lt;/a&gt; webpages. To enable this, you need to set the following headers in your server hosting the React 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;Cross-Origin-Embedder-Policy: require-corp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Cross-Origin-Opener-Policy: same-origin&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In a Create-React-App application, you achieve this by creating a &lt;code&gt;src/setupProxy.js&lt;/code&gt; file and making sure it contains the following code:&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;module.exports = function (app) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    app.use(function (req, res, next) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        res.setHeader(&quot;Cross-Origin-Opener-Policy&quot;, &quot;same-origin&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        res.setHeader(&quot;Cross-Origin-Embedder-Policy&quot;, &quot;require-corp&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        next()&lt;/span&gt;&lt;/span&gt;
&lt;span 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;Your local development server is now ready to use &lt;code&gt;ffmpeg.wasm&lt;/code&gt;!&lt;/p&gt;
&lt;h3 id=&quot;installing-the-projects-dependencies&quot;&gt;Installing the Project’s Dependencies&lt;/h3&gt;
&lt;p&gt;It is now time to add the aforementioned required dependencies to your project.&lt;/p&gt;
&lt;p&gt;First, install &lt;code&gt;ffmpeg.wasm&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;npm install @ffmpeg/ffmpeg @ffmpeg/core&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, let’s install &lt;a href=&quot;https://ant.design/&quot;&gt;Antd Design&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm install antd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, it is time to install &lt;a href=&quot;https://video-react.js.org/&quot;&gt;Video-React&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm install video-react redux&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that &lt;code&gt;video-react&lt;/code&gt; also requires &lt;code&gt;[redux](https://www.npmjs.com/package/redux)&lt;/code&gt; to work.&lt;/p&gt;
&lt;p&gt;You have now everything you need to start developing your React video editor!&lt;/p&gt;
&lt;h3 id=&quot;uploading-a-video-to-the-video-editor&quot;&gt;Uploading a Video to the Video Editor&lt;/h3&gt;
&lt;p&gt;Create a &lt;code&gt;VideoUpload&lt;/code&gt; component as 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;// src/components/VideoUpload.js&lt;/span&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; { Button, Upload } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;antd&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; VideoUpload&lt;/span&gt;&lt;span&gt;({ &lt;/span&gt;&lt;span&gt;disabled&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;onChange&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;onRemove&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;  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;&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;Upload&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        disabled&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{disabled}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        beforeUpload&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;          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;        accept&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;video/*&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        onChange&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{(&lt;/span&gt;&lt;span&gt;info&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; (info.fileList &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; info.fileList.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span&gt; &gt;&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            onChange&lt;/span&gt;&lt;span&gt;(info.fileList[&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;].originFileObj);&lt;/span&gt;&lt;/span&gt;
&lt;span 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;        showUploadList&lt;/span&gt;&lt;span&gt;=&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;      &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;Upload Video&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;Upload&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;        danger&lt;/span&gt;&lt;span&gt;=&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;        disabled&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;disabled}&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; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          onRemove&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&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;        Remove&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;/&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; VideoUpload;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, this component uses the &lt;a href=&quot;https://ant.design/components/upload/&quot;&gt;Antd Design Upload&lt;/a&gt; component to allow users to upload a video file. Then, a “Remove” button gives users the ability to remove the uploaded video. Note that when the &lt;code&gt;Upload&lt;/code&gt; component is enabled, the “Remove” button is disabled and vice versa. This way, users can deal with only one video at a time.&lt;/p&gt;
&lt;h3 id=&quot;playing-a-video-in-react&quot;&gt;Playing a Video in React&lt;/h3&gt;
&lt;p&gt;You now need a &lt;code&gt;VideoPlayer&lt;/code&gt; component to play the uploaded video. You can build it as 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;// src/components/VideoPlayer.js&lt;/span&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; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  BigPlayButton,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ControlBar,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  LoadingSpinner,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Player,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  PlayToggle,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;video-react&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &apos;video-react/dist/video-react.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; { 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; VideoPlayer&lt;/span&gt;&lt;span&gt;({&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  onPlayerChange&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;  onChange&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;  startTime&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&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;player&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setPlayer&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;playerState&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setPlayerState&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;  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; (playerState) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      onChange&lt;/span&gt;&lt;span&gt;(playerState);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }, [playerState]);&lt;/span&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;    onPlayerChange&lt;/span&gt;&lt;span&gt;(player);&lt;/span&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; (player) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      player.&lt;/span&gt;&lt;span&gt;subscribeToStateChange&lt;/span&gt;&lt;span&gt;(setPlayerState);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }, [player]);&lt;/span&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;&apos;video-player&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;Player&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;{(&lt;/span&gt;&lt;span&gt;player&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;          setPlayer&lt;/span&gt;&lt;span&gt;(player);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        startTime&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{startTime}&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;source&lt;/span&gt;&lt;span&gt; src&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{src} /&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;BigPlayButton&lt;/span&gt;&lt;span&gt; position&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;center&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;LoadingSpinner&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;ControlBar&lt;/span&gt;&lt;span&gt; autoHide&lt;/span&gt;&lt;span&gt;=&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;disableDefaultControls&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;true&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;PlayToggle&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;ControlBar&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;Player&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a simple &lt;code&gt;video-react&lt;/code&gt;-based video player component, which only allows playing or stop the video file received with the &lt;code&gt;src&lt;/code&gt; prop.&lt;/p&gt;
&lt;h3 id=&quot;cutting-a-video-in-react&quot;&gt;Cutting a Video in React&lt;/h3&gt;
&lt;p&gt;Your goal is to allow users to select a portion of the video and watch it before converting it into GIF. Implement this with the logic 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;import&lt;/span&gt;&lt;span&gt; { Slider } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &quot;antd&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { sliderValueToVideoTime } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &quot;../utils/utils&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; VideoEditor&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;sliderValues&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setSliderValues&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;100&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;  // logic to handle videoFile, videoPlayer, and videoPlayerState...&lt;/span&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;      const&lt;/span&gt;&lt;span&gt; min&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sliderValues[&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;      // when the slider values are updated, updating the&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      // video time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      if&lt;/span&gt;&lt;span&gt; (min &lt;/span&gt;&lt;span&gt;!==&lt;/span&gt;&lt;span&gt; undefined&lt;/span&gt;&lt;span&gt; &amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; videoPlayerState &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; videoPlayer) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          videoPlayer.&lt;/span&gt;&lt;span&gt;seek&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;sliderValueToVideoTime&lt;/span&gt;&lt;span&gt;(videoPlayerState.duration, min))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }, [sliderValues])&lt;/span&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;      if&lt;/span&gt;&lt;span&gt; (videoPlayer &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; videoPlayerState) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          // allowing users to watch only the portion of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          // the video selected by the slider&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;min&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;max&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; sliderValues&lt;/span&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; minTime&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sliderValueToVideoTime&lt;/span&gt;&lt;span&gt;(videoPlayerState.duration, min)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          const&lt;/span&gt;&lt;span&gt; maxTime&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sliderValueToVideoTime&lt;/span&gt;&lt;span&gt;(videoPlayerState.duration, max)&lt;/span&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; (videoPlayerState.currentTime &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; minTime) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              videoPlayer.&lt;/span&gt;&lt;span&gt;seek&lt;/span&gt;&lt;span&gt;(minTime)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&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; (videoPlayerState.currentTime &lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; maxTime) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              // looping logic&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              videoPlayer.&lt;/span&gt;&lt;span&gt;seek&lt;/span&gt;&lt;span&gt;(minTime)&lt;/span&gt;&lt;/span&gt;
&lt;span 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;  }, [videoPlayerState])&lt;/span&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;          // other video editor components...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          &amp;#x3C;&lt;/span&gt;&lt;span&gt;Slider&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            disabled&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;videoPlayerState}&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;{sliderValues}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            range&lt;/span&gt;&lt;span&gt;=&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;            onChange&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{(&lt;/span&gt;&lt;span&gt;values&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;              setSliderValues&lt;/span&gt;&lt;span&gt;(values)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            tooltip&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;              formatter: &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            }}&lt;/span&gt;&lt;/span&gt;
&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;This component equips users with the ability to select a portion of the uploaded video with the Antd Design &lt;code&gt;Slider&lt;/code&gt; component and watch it in loop, before converting it into a GIF file.&lt;/p&gt;
&lt;p&gt;Specifically, the logic here uses the &lt;code&gt;sliderValueToVideoTime()&lt;/code&gt; function below to transform the slider values into time coordinates:&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;// src/utils/utils.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;export function sliderValueToVideoTime(duration, sliderValue) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return Math.round(duration * sliderValue / 100)&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;Note that the actual video processing slider will be performed by the next component through &lt;code&gt;ffmpeg&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;converting-a-video-to-gif-in-react&quot;&gt;Converting a Video to GIF in React&lt;/h3&gt;
&lt;p&gt;To convert a video to GIF, create a &lt;code&gt;VideoConversionButton&lt;/code&gt; component 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;// src/components/VideoConversionButton.js&lt;/span&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; { Button } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;antd&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; { fetchFile } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@ffmpeg/ffmpeg&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; { sliderValueToVideoTime } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;../utils/utils&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; VideoConversionButton&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  videoPlayerState&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  sliderValues&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  videoFile&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ffmpeg&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  onConversionStart&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;  onConversionEnd&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;  onGifCreated&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;}) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; convertToGif&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;    // starting the conversion process&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    onConversionStart&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 class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; inputFileName&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &apos;gif.mp4&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; outputFileName&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &apos;output.gif&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;    // writing the video file to memory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ffmpeg.&lt;/span&gt;&lt;span&gt;FS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;writeFile&apos;&lt;/span&gt;&lt;span&gt;, inputFileName, &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; fetchFile&lt;/span&gt;&lt;span&gt;(videoFile));&lt;/span&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;min&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;max&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; sliderValues;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; minTime&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sliderValueToVideoTime&lt;/span&gt;&lt;span&gt;(videoPlayerState.duration, min);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; maxTime&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sliderValueToVideoTime&lt;/span&gt;&lt;span&gt;(videoPlayerState.duration, max);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // cutting the video and converting it to GIF with an FFMpeg command&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    await&lt;/span&gt;&lt;span&gt; ffmpeg.&lt;/span&gt;&lt;span&gt;run&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &apos;-i&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      inputFileName,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &apos;-ss&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;minTime&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;      &apos;-to&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;maxTime&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;      &apos;-f&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &apos;gif&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      outputFileName&lt;/span&gt;&lt;/span&gt;
&lt;span 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;    // reading the resulting file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; ffmpeg.&lt;/span&gt;&lt;span&gt;FS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;readFile&apos;&lt;/span&gt;&lt;span&gt;, outputFileName);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // converting the GIF file created by FFmpeg to a valid image URL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; gifUrl&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;createObjectURL&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; Blob&lt;/span&gt;&lt;span&gt;([data.buffer], { type: &lt;/span&gt;&lt;span&gt;&apos;image/gif&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;    onGifCreated&lt;/span&gt;&lt;span&gt;(gifUrl);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // ending the conversion process&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    onConversionEnd&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;  return&lt;/span&gt;&lt;span&gt; &amp;#x3C;&lt;/span&gt;&lt;span&gt;Button&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; convertToGif&lt;/span&gt;&lt;span&gt;()}&gt;Convert to GIF&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;}&lt;/span&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; VideoConversionButton;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This component uses &lt;code&gt;ffmpeg.wasm&lt;/code&gt; to launch an &lt;code&gt;ffmpeg&lt;/code&gt; command. This command takes care of clipping the video to the time limits defined by &lt;code&gt;sliderValues&lt;/code&gt; and converting it to GIF. Note that all these operations are performed client-side in the browser.&lt;/p&gt;
&lt;p&gt;In detail, the &lt;code&gt;ffmpeg&lt;/code&gt; &lt;code&gt;-ss&lt;/code&gt; flag defines the time from which to start reading the video file, while &lt;code&gt;-to&lt;/code&gt; defines the end time. Then, the &lt;code&gt;gif&lt;/code&gt; option specifies that you want to produce a GIF file. Learn more about the flags and options offered by &lt;code&gt;ffmpeg&lt;/code&gt; &lt;a href=&quot;https://www.ffmpeg.org/ffmpeg.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The resulting GIF image is stored in the &lt;code&gt;output.gif&lt;/code&gt; memory file, loaded as a valid &lt;code&gt;&quot;image/gif&quot;&lt;/code&gt; &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Blob&quot;&gt;Blob&lt;/a&gt;, and finally converted to a valid image URL with the &lt;code&gt;[URL.createObjectURL()](https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL_static)&lt;/code&gt; native function.&lt;/p&gt;
&lt;h3 id=&quot;putting-it-all-together&quot;&gt;Putting It All Together&lt;/h3&gt;
&lt;p&gt;Now, let’s see the full code of the &lt;code&gt;VideoEditor&lt;/code&gt; component:&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;// src/components/VideoEditor.js&lt;/span&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; { createFFmpeg } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@ffmpeg/ffmpeg&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;import&lt;/span&gt;&lt;span&gt; { Slider, Spin } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;antd&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; { VideoPlayer } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;./VideoPlayer&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; { sliderValueToVideoTime } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;../utils/utils&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; VideoUpload &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;./VideoUpload&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; VideoConversionButton &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;./VideoConversionButton&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; ffmpeg&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; createFFmpeg&lt;/span&gt;&lt;span&gt;({ log: &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 class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; VideoEditor&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;ffmpegLoaded&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setFFmpegLoaded&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; [&lt;/span&gt;&lt;span&gt;videoFile&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setVideoFile&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;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;videoPlayerState&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setVideoPlayerState&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;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;videoPlayer&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setVideoPlayer&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;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;gifUrl&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setGifUrl&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;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;sliderValues&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setSliderValues&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;100&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;processing&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setProcessing&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;
&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;    // loading ffmpeg on startup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ffmpeg.&lt;/span&gt;&lt;span&gt;load&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;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      setFFmpegLoaded&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&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;    const&lt;/span&gt;&lt;span&gt; min&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sliderValues[&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;    // when the slider values are updated, updating the&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // video time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; (min &lt;/span&gt;&lt;span&gt;!==&lt;/span&gt;&lt;span&gt; undefined&lt;/span&gt;&lt;span&gt; &amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; videoPlayerState &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; videoPlayer) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      videoPlayer.&lt;/span&gt;&lt;span&gt;seek&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;sliderValueToVideoTime&lt;/span&gt;&lt;span&gt;(videoPlayerState.duration, min));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }, [sliderValues]);&lt;/span&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;    if&lt;/span&gt;&lt;span&gt; (videoPlayer &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; videoPlayerState) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      // allowing users to watch only the portion of&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      // the video selected by the slider&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;min&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;max&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; sliderValues;&lt;/span&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; minTime&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sliderValueToVideoTime&lt;/span&gt;&lt;span&gt;(videoPlayerState.duration, min);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      const&lt;/span&gt;&lt;span&gt; maxTime&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; sliderValueToVideoTime&lt;/span&gt;&lt;span&gt;(videoPlayerState.duration, max);&lt;/span&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; (videoPlayerState.currentTime &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; minTime) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        videoPlayer.&lt;/span&gt;&lt;span&gt;seek&lt;/span&gt;&lt;span&gt;(minTime);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&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; (videoPlayerState.currentTime &lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; maxTime) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // looping logic&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        videoPlayer.&lt;/span&gt;&lt;span&gt;seek&lt;/span&gt;&lt;span&gt;(minTime);&lt;/span&gt;&lt;/span&gt;
&lt;span 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;  }, [videoPlayerState]);&lt;/span&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;    // when the current videoFile is removed,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // restoring the default state&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;videoFile) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      setVideoPlayerState&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;      setSliderValues&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;100&lt;/span&gt;&lt;span&gt;]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      setVideoPlayerState&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;      setGifUrl&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&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }, [videoFile]);&lt;/span&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;&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;Spin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        spinning&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{processing &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; !&lt;/span&gt;&lt;span&gt;ffmpegLoaded}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        tip&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;ffmpegLoaded &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; &apos;Waiting for FFmpeg to load...&apos;&lt;/span&gt;&lt;span&gt; :&lt;/span&gt;&lt;span&gt; &apos;Processing...&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;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          {videoFile &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;&lt;/span&gt;&lt;span&gt;VideoPlayer&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;{&lt;/span&gt;&lt;span&gt;URL&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;createObjectURL&lt;/span&gt;&lt;span&gt;(videoFile)}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              onPlayerChange&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{(&lt;/span&gt;&lt;span&gt;videoPlayer&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;                setVideoPlayer&lt;/span&gt;&lt;span&gt;(videoPlayer);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              onChange&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{(&lt;/span&gt;&lt;span&gt;videoPlayerState&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;                setVideoPlayerState&lt;/span&gt;&lt;span&gt;(videoPlayerState);&lt;/span&gt;&lt;/span&gt;
&lt;span 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;          ) &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;&lt;/span&gt;&lt;span&gt;h1&lt;/span&gt;&lt;span&gt;&gt;Upload a video&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;          )}&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;{&lt;/span&gt;&lt;span&gt;&apos;upload-div&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;VideoUpload&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            disabled&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;!!&lt;/span&gt;&lt;span&gt;videoFile}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            onChange&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{(&lt;/span&gt;&lt;span&gt;videoFile&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;              setVideoFile&lt;/span&gt;&lt;span&gt;(videoFile);&lt;/span&gt;&lt;/span&gt;
&lt;span 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;{&lt;/span&gt;&lt;span&gt;&apos;slider-div&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;h3&lt;/span&gt;&lt;span&gt;&gt;Cut Video&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;Slider&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            disabled&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;videoPlayerState}&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;{sliderValues}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            range&lt;/span&gt;&lt;span&gt;=&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;            onChange&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{(&lt;/span&gt;&lt;span&gt;values&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;              setSliderValues&lt;/span&gt;&lt;span&gt;(values);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            tooltip&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;              formatter: &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            }}&lt;/span&gt;&lt;/span&gt;
&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;{&lt;/span&gt;&lt;span&gt;&apos;conversion-div&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;VideoConversionButton&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            onConversionStart&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;              setProcessing&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;            onConversionEnd&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;              setProcessing&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;            ffmpeg&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{ffmpeg}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            videoPlayerState&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{videoPlayerState}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            sliderValues&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{sliderValues}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            videoFile&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{videoFile}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            onGifCreated&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{(&lt;/span&gt;&lt;span&gt;girUrl&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;              setGifUrl&lt;/span&gt;&lt;span&gt;(girUrl);&lt;/span&gt;&lt;/span&gt;
&lt;span 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;        {gifUrl &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          &amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; className&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&apos;gif-div&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;h3&lt;/span&gt;&lt;span&gt;&gt;Resulting GIF&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;img&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;{gifUrl}&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;gif&apos;&lt;/span&gt;&lt;span&gt;}&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;{&lt;/span&gt;&lt;span&gt;&apos;GIF file generated in the client side&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;a&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              href&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{gifUrl}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              download&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&apos;test.gif&apos;&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;ant-btn ant-btn-default&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;              Download&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            &amp;#x3C;/&lt;/span&gt;&lt;span&gt;a&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;      &amp;#x3C;/&lt;/span&gt;&lt;span&gt;Spin&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; VideoEditor;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since &lt;code&gt;ffmpeg&lt;/code&gt; takes time to load, you need to let users know that they need to wait a while before they can use the video editor component. Also, &lt;code&gt;ffmpeg&lt;/code&gt; operations take time to execute. This wait logic is implemented by using the Antd Design &lt;code&gt;[Spin](https://ant.design/components/spin/)&lt;/code&gt; component.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://paper-attachments.dropbox.com/s_C8CCC2508B96793E40906CD26AF4C92ACE1FB33CF33FE115E6ACE3BA49F22F52_1663925760548_chrome-capture-2022-8-23.gif&quot; alt=&quot;Preventing users from using the video editor component before ffmpeg is loaded&quot;&gt;&lt;/p&gt;
&lt;p&gt;Also, note that by passing the &lt;code&gt;log: true&lt;/code&gt; option to the &lt;code&gt;createFFmpeg()&lt;/code&gt; function, &lt;code&gt;ffmpeg&lt;/code&gt; will log useful debug info in the console. For example, after &lt;code&gt;ffmpeg&lt;/code&gt; gets loaded, you should be able to see the following lines in the browser console:&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;[info] use ffmpeg.wasm v0.11.5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;createFFmpeg.js:43 [info] load ffmpeg-core&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;createFFmpeg.js:43 [info] loading ffmpeg-core&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;createFFmpeg.js:43 [info] ffmpeg-core loaded&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What the &lt;code&gt;VideoComponent&lt;/code&gt; does is use all the components presented earlier to allow users to upload a video, select a portion through a slider, convert it to GIF, and download the resulting GIF file.&lt;/p&gt;
&lt;p&gt;Et voilà! You just learned how to build a client-side video editor in React without using any backend functionality!&lt;/p&gt;
&lt;h2 id=&quot;commercial-alternative&quot;&gt;Commercial Alternative&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://img.ly/docs/vesdk/flutter/getting-started/integration/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;VideoEditor SDK&lt;/a&gt; by &lt;a href=&quot;https://img.ly&quot;&gt;IMG.LY&lt;/a&gt; provides powerful video editing features, including cropping and trimming videos in your project. You will receive staples of video editing, including straightening videos, filters, brightness, color adjustments, and more.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Building a client-side video processing and editing application that uses only the browser possible. With WebAssembly, you can run high-performance code written in C or C++ in JavaScript. This allows you to perform complex operations at lightning speed directly in the browser, without having to delegate the work to a server.&lt;/p&gt;
&lt;p&gt;In this tutorial, you learned how to use &lt;code&gt;ffmpeg.wasm&lt;/code&gt; to build a video editor in React. &lt;code&gt;ffmpeg.wasm&lt;/code&gt; is the Wasm port of &lt;code&gt;ffmpeg&lt;/code&gt; and enables video and audio processing and editing directly in the browser. Using it to build a web application to upload a video, cut it, and export it to GIF requires only a few lines of code, and here we have seen how to implement such a video editing application.&lt;/p&gt;
&lt;p&gt;If your app goes beyond merely displaying video, and you want to allow your users to also edit video or create video based templates in the browser, explore our &lt;strong&gt;&lt;a href=&quot;https://img.ly/products/video-sdk&quot;&gt;VideoEditor SDK&lt;/a&gt;&lt;/strong&gt; for the Web – a performant video editing solution based on WASM and WebCodecs. Try the editor for yourself in action with &lt;a href=&quot;https://img.ly/showcases/cesdk/video-ui/web&quot;&gt;our showcases&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thanks for reading! Let us know what you think on &lt;a href=&quot;https://twitter.com/imgly&quot;&gt;Twitter&lt;/a&gt;! To stay in the loop, subscribe to our &lt;a href=&quot;https://photoeditorsdk.us13.list-manage.com/subscribe?u=dc9f652839dbb620d14d6d28d&amp;#x26;id=04a306e4b2&quot;&gt;Newsletter&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Antonello</dc:creator><media:content url="https://blog.img.ly/2023/01/video-editor-ffmpeg-wasm-1.jpg" medium="image"/><category>How-To</category><category>Video Editor</category><category>Web Development</category><category>Web Application</category><category>Video Editing</category><category>Tech</category><category>Tutorial</category></item><item><title>How To Build a Canva Clone with CE.SDK</title><link>https://img.ly/blog/how-to-build-a-canva-clone-with-ce-sdk/</link><guid isPermaLink="true">https://img.ly/blog/how-to-build-a-canva-clone-with-ce-sdk/</guid><description>Design invitations, greeting cards, flyers, postcards, and business cards with a Canva clone built with CE.SDK in React in minutes. </description><pubDate>Wed, 27 Jul 2022 06:43:59 GMT</pubDate><content:encoded>&lt;p&gt;Canva has popularized image editing, and user expectations of creative capabilities have increased accordingly. If your web or mobile application includes any design functionality - for book covers, t-shirt designs, or social media content - it has to be on par with the design experience offered by prosumer creation tools such as Canva.&lt;/p&gt;
&lt;p&gt;Allowing users to edit images through an easy user interface, define high-quality templates, and give them the ability to share them with the community is a great way to boost engagement, add virality, and potentially new revenue streams.&lt;/p&gt;
&lt;p&gt;You might think this requires a lot of time and effort, but that is not the case. CreativeEditor SDK makes it dead simple to build a Canva-like design editor in minutes. I’ll show you how!&lt;/p&gt;
&lt;p&gt;Follow this step-by-step tutorial and learn how to implement a Canva clone in React with CE.SDK. At the end of this tutorial, you will achieve the following result:&lt;/p&gt;
&lt;p&gt;Try the final result live on &lt;a href=&quot;https://codesandbox.io/embed/how-to-build-a-canva-clone-with-ce-sdk-forked-nvxz3w&quot;&gt;CodeSandbox&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-is-canva&quot;&gt;What is Canva?&lt;/h2&gt;
&lt;p&gt;Canva is a free graphic design tool for image editing featuring a drag-and-drop interface for composing different elements on a canvas. You can easily create flyers, invitations, business cards, and more with professionally designed templates. You can think of it as a basic version of Photoshop that anyone can use.&lt;/p&gt;
&lt;p&gt;You can create Canva templates in a web browser or on the official app for iOS or Android, share them and collaborate easily. Templates make Canva a powerful tool - that is also true for CE.SDK, which makes it a perfect harbor to set sail for new horizons and create an excellent editor. Before we learn how to replicate Canva, let us evaluate the SDK in question.&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 fully customizable, user-friendly design editor tool. You can integrate it easily into your application with just a few lines of code and benefit from the template-based editor in no time.&lt;/p&gt;
&lt;p&gt;The role-specific editing UI focuses heavily on content adaptation. CE.SDK offers two modes: in Creator Mode, you can create a design from scratch or customize existing templates. Once ready, creators can share their templates and decide which elements others can change and to what degree. Then, users can import the template and customize it in Adopter Mode (Default UI).&lt;/p&gt;
&lt;p&gt;Try CE.SDK &lt;a href=&quot;https://img.ly/showcases/cesdk&quot;&gt;live demos&lt;/a&gt; or &lt;a href=&quot;https://img.ly/forms/free-trial&quot;&gt;start a free trial&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;designing-and-sharing-a-template-in-creator-mode&quot;&gt;Designing and Sharing a Template in Creator Mode&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://img.ly/docs/cesdk/react/configuration-2c1c3d/&quot;&gt;&lt;code&gt;Creator&lt;/code&gt;&lt;/a&gt; Mode is the most powerful and least restrictive role in CE.SDK. It empowers you to unleash your creativity and create custom templates for every imaginable use case. Add, move, modify, and delete elements as you wish and define constraints. Further elevate your designs with photo editings, such as filters, effects, and background removal.&lt;/p&gt;
&lt;p&gt;The well-rounded text editor also allows you to define variables and programmatically give them a value using the CE.SDK &lt;a href=&quot;https://img.ly/docs/cesdk/react/create-templates/add-dynamic-content/text-variables-7ecb50/&quot;&gt;Variable API&lt;/a&gt;. For example, you may introduce a &lt;code&gt;{{Name}}&lt;/code&gt; Variable and have CESDK import names from a database. This automation is perfect for batch-processing designs, such as greeting cards. Based on this principle, we have built an example &lt;a href=&quot;https://img.ly/blog/how-to-generate-an-nft-art-collection-with-react-using-ce-sdk/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;NFT Art Collection Generator in React with CE.SDK&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the Creator Mode, you also can define &lt;a href=&quot;https://img.ly/docs/cesdk/react/create-templates/add-dynamic-content/placeholders-d9ba8a/&quot;&gt;placeholders&lt;/a&gt;. Turning an element into a placeholder will let you determine if it can be deleted, styled, or duplicated by the adopter.&lt;/p&gt;
&lt;p&gt;This is what the CE.SDK Creator Mode looks like:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;creator-mode-cesdk&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1000px) 1000px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1000&quot; height=&quot;506&quot; src=&quot;https://img.ly/_astro/creator-mode-cesdk_Z1H6JCC.webp&quot; srcset=&quot;/_astro/creator-mode-cesdk_Q0z9g.webp 640w, /_astro/creator-mode-cesdk_1WU4FC.webp 750w, /_astro/creator-mode-cesdk_Z1Ww1nc.webp 828w, /_astro/creator-mode-cesdk_Z1H6JCC.webp 1000w&quot;&gt;&lt;/p&gt;
&lt;p&gt;As you can see, you can use CE.SDK to easily create a wedding invitation card template. This is just an example, and you can find other cool sample templates for greeting cards, flyers, postcards, and business cards on &lt;a href=&quot;https://img.ly/showcases/cesdk?tags=custom-build-uis&quot;&gt;showcase page&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;what-adopter-mode-offers-you&quot;&gt;What Adopter Mode Offers You&lt;/h3&gt;
&lt;p&gt;You can test the adopter view of the wedding invitation card template shown above &lt;a href=&quot;https://ubique.img.ly/main/apps/dashboard/#/template/Hoc0dPRe5l9BfJaqwCI3&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is what the Adopter Mode looks like:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;adopter-mode&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 999px) 999px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;999&quot; height=&quot;485&quot; src=&quot;https://img.ly/_astro/adopter-mode_Z1qq5LI.webp&quot; srcset=&quot;/_astro/adopter-mode_gAVDi.webp 640w, /_astro/adopter-mode_Z1ThvMI.webp 750w, /_astro/adopter-mode_Z22GG6v.webp 828w, /_astro/adopter-mode_Z1qq5LI.webp 999w&quot;&gt;&lt;/p&gt;
&lt;p&gt;As shown above, CE.SDK’s Adopter Mode enables you to add and modify colors, text, and images based on the constraints enabled by the creator of the template. This mode provides the &lt;a href=&quot;https://img.ly/docs/cesdk/js/configuration-2c1c3d/?ref=img.ly#adopter?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;&lt;code&gt;Adopter&lt;/code&gt;&lt;/a&gt; users with a simple interface, narrowed down to the properties that they are allowed to change. This prevents adopters from accidentally changing or deleting parts of a design that should not be modified.&lt;/p&gt;
&lt;h2 id=&quot;implement-a-canva-clone-with-cesdk&quot;&gt;Implement a Canva Clone with CE.SDK&lt;/h2&gt;
&lt;p&gt;Let’s now learn how to use CE.SDK to build a Canva clone in React.&lt;/p&gt;
&lt;h3 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h3&gt;
&lt;p&gt;This is the list of all the prerequisites for the Canva clone 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 8.0+ and higher&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://react.dev/&quot;&gt;React&lt;/a&gt; &gt;= 18&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.6.3&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Add &lt;code&gt;@cesdk/cesdk-js&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 @cesdk/cesdk-js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;initialize-a-react-project&quot;&gt;Initialize a React Project&lt;/h3&gt;
&lt;p&gt;You can try out the Canva clone by cloning the &lt;a href=&quot;https://github.com/imgly/canva-clone-react-cesdk&quot;&gt;GitHub repository supporting the article&lt;/a&gt; and running the demo web application 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/canva-clone-cesdk-imgly&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cd canva-clone-cesdk-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;Otherwise, follow this step-by-step tutorial and learn how to build the Canva clone with CE.SDK by yourself.&lt;/p&gt;
&lt;p&gt;First, you need to initialize a &lt;code&gt;canva-clone-cesdk-imgly&lt;/code&gt; React project. You can do it with &lt;a href=&quot;https://create-react-app.dev/docs/getting-started/&quot;&gt;Create React App&lt;/a&gt; by launching the 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 create-react-app canva-clone-cesdk-imgly&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, the &lt;code&gt;canva-clone-cesdk-imgly&lt;/code&gt; folder will 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;canva-clone-cesdk-imgly&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── README.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── node_modules&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── package.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── .gitignore&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── public&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── favicon.ico&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── index.html&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── logo192.png&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── logo512.png&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── manifest.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   └── robots.txt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;└── src&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── App.css&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── App.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── App.test.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── index.css&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── index.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── logo.svg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── reportWebVitals.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    └── setupTests.js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Move into the &lt;code&gt;canva-clone-cesdk-imgly&lt;/code&gt; folder and start a local development server with:&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 canva-clone-cesdk-imgly&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;Reach &lt;a href=&quot;http://localhost:3000/&quot;&gt;http://localhost:3000/&lt;/a&gt; in your browser and make sure you see the default Create React App screen below:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;react&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_1REyVa.webp&quot; srcset=&quot;/_astro/react_2lRYbq.webp 640w, /_astro/react_Z21FBPj.webp 750w, /_astro/react_OLsOd.webp 828w, /_astro/react_1REyVa.webp 983w&quot;&gt;&lt;/p&gt;
&lt;p&gt;You are now ready to code!&lt;/p&gt;
&lt;h3 id=&quot;build-the-canva-clone-component-with-cesdk&quot;&gt;Build the Canva Clone Component with CE.SDK&lt;/h3&gt;
&lt;p&gt;If you want your image editing component to provide a Canva-like experience, it must include key features, such as template and custom resource management. Let’s see how to implement them all with CE.SDK.&lt;/p&gt;
&lt;h4 id=&quot;configure-cesdk-to-use-templates&quot;&gt;Configure CE.SDK to use templates&lt;/h4&gt;
&lt;p&gt;Managing templates in CE.SDK is easy. All you have to do is configure the set of predefined templates loaded by CE.SDK on initialization, as explained in the &lt;a href=&quot;https://img.ly/docs/cesdk/react/use-templates/library-b3c704/&quot;&gt;official documentation on adding templates&lt;/a&gt;. You can achieve this as 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;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;  let&lt;/span&gt;&lt;span&gt; cesdk;&lt;/span&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; 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;    // initializing CE.SDK with a few templates&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    presets: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      templates: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        postcard_1: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          label: &lt;/span&gt;&lt;span&gt;&apos;Postcard Design&apos;&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;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_postcard_1.scene`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          thumbnailURL: &lt;/span&gt;&lt;span&gt;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_postcard_1.png`&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;        postcard_2: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          label: &lt;/span&gt;&lt;span&gt;&apos;Postcard Tropical&apos;&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;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_postcard_2.scene`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          thumbnailURL: &lt;/span&gt;&lt;span&gt;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_postcard_2.png`&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;        business_card_1: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          label: &lt;/span&gt;&lt;span&gt;&apos;Business card&apos;&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;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_business_card_1.scene`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          thumbnailURL: &lt;/span&gt;&lt;span&gt;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_business_card_1.png`&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;        instagram_photo_1: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          label: &lt;/span&gt;&lt;span&gt;&apos;Instagram photo&apos;&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;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_instagram_photo_1.scene`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          thumbnailURL: &lt;/span&gt;&lt;span&gt;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_instagram_photo_1.png`&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;        instagram_story_1: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          label: &lt;/span&gt;&lt;span&gt;&apos;Instagram story&apos;&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;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_instagram_story_1.scene`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          thumbnailURL: &lt;/span&gt;&lt;span&gt;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_instagram_story_1.png`&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;        poster_1: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          label: &lt;/span&gt;&lt;span&gt;&apos;Poster&apos;&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;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_poster_1.scene`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          thumbnailURL: &lt;/span&gt;&lt;span&gt;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_poster_1.png`&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;        presentation_4: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          label: &lt;/span&gt;&lt;span&gt;&apos;Presentation&apos;&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;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_presentation_1.scene`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          thumbnailURL: &lt;/span&gt;&lt;span&gt;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_presentation_1.png`&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;        collage_1: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          label: &lt;/span&gt;&lt;span&gt;&apos;Collage&apos;&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;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_collage_1.scene`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          thumbnailURL: &lt;/span&gt;&lt;span&gt;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_collage_1.png`&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (cesdkContainer.current) {&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;(cesdkContainer.current, config).&lt;/span&gt;&lt;span&gt;then&lt;/span&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;      cesdk &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;    });&lt;/span&gt;&lt;/span&gt;
&lt;span 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;=&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; (cesdk) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      cesdk.&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;}, [cesdkContainer]);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Thanks to the &lt;code&gt;presets.templates&lt;/code&gt;, you can specify all the CE.SDK templates to be made available to users.&lt;br&gt;
Note that the &lt;code&gt;cesdkContainer&lt;/code&gt; variable stores the &lt;a href=&quot;https://legacy.reactjs.org/docs/refs-and-the-dom.html&quot;&gt;React reference&lt;/a&gt; to the div where to mount CE.SDK.&lt;/p&gt;
&lt;p&gt;This is what the CE.SDK template section will look like:&lt;br&gt;
&lt;img alt=&quot;mount&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1866px) 1866px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1866&quot; height=&quot;893&quot; src=&quot;https://img.ly/_astro/mount_iSSUR.webp&quot; srcset=&quot;/_astro/mount_2jvRJt.webp 640w, /_astro/mount_Zh1IIF.webp 750w, /_astro/mount_aEtiJ.webp 828w, /_astro/mount_Z2irfxL.webp 1080w, /_astro/mount_1YRGvg.webp 1280w, /_astro/mount_CvNzu.webp 1668w, /_astro/mount_iSSUR.webp 1866w&quot;&gt;&lt;/p&gt;
&lt;p&gt;As you can see, all eight templates loaded with &lt;code&gt;presets.templates&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;integrate-external-asset-sources-into-cesdk&quot;&gt;Integrate External Asset Sources Into CE.SDK&lt;/h4&gt;
&lt;p&gt;CE.SDK supports external asset sources, meaning you can give your users a vast library of resources to supercharge their creative workflows. Instead of spending time building a repository of images manually, you can provide your users with image resources retrieved dynamically by connecting to services like Unsplash and Airtable. Learn &lt;a href=&quot;https://img.ly/docs/cesdk/react/import-media/asset-panel/customize-c9a4de/&quot;&gt;how to integrate external asset sources in CE.SDK&lt;/a&gt;, or see a live demo based on the &lt;a href=&quot;https://img.ly/showcases/cesdk/unsplash-image-assets/web?c_asset_library=airtable&quot;&gt;Unsplash and Airtable integration&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&quot;add-custom-images-to-cesdk&quot;&gt;Add Custom Images to CE.SDK&lt;/h4&gt;
&lt;p&gt;You can load custom resources and make them available to users with CE.SDK. For example, you would like to add this &lt;a href=&quot;https://www.flaticon.com/free-icon/programming_1208884&quot;&gt;Flaticon&lt;/a&gt; below to the available images in CE.SDK:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;icon&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 512px) 512px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;512&quot; height=&quot;512&quot; src=&quot;https://img.ly/_astro/icon_7W96.webp&quot; srcset=&quot;/_astro/icon_7W96.webp 512w&quot;&gt;&lt;/p&gt;
&lt;p&gt;All you need to do is define a new asset source as explained in the documentation page on &lt;a href=&quot;https://img.ly/docs/cesdk/react/import-media/asset-panel/customize-c9a4de/&quot;&gt;Integrating Custom Resources into CE.SDK&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can achieve this 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;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;  // path to the local image to load into CE.SDK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; customImagePath&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;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;}/resources/programming.png`&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; cesdk;&lt;/span&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; 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;    // loading the business card template as default template&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    initialSceneURL: &lt;/span&gt;&lt;span&gt;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_business_card_1.scene`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // loading the external asset sources&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    assetSources: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      // loading a custom image into CE.SDK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      custom: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        findAssets&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; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            assets: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                id: &lt;/span&gt;&lt;span&gt;&apos;custom-image-1&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                type: &lt;/span&gt;&lt;span&gt;&apos;ly.img.image&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                locale: &lt;/span&gt;&lt;span&gt;&apos;en&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                label: &lt;/span&gt;&lt;span&gt;&apos;Programming&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                thumbUri: customImagePath,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                size: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                  width: &lt;/span&gt;&lt;span&gt;512&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;512&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;                meta: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                  uri: customImagePath,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                  sourceId: &lt;/span&gt;&lt;span&gt;&apos;custom&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;                credits: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                  name: &lt;/span&gt;&lt;span&gt;&apos;Freepik&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                  url: &lt;/span&gt;&lt;span&gt;&apos;https://www.flaticon.com/free-icon/programming_1208884?related_id=1208782&amp;#x26;origin=search&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;            currentPage: &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;            total: &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;            nextPage: &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&gt;&lt;/span&gt;
&lt;span 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;    // translating the labels associates with the external asset sources&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    i18n: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      en: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &apos;libraries.custom.label&apos;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&apos;Custom&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;    // initializing CE.SDK with a few templates&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    presets: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      templates: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        business_card_1: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          label: &lt;/span&gt;&lt;span&gt;&apos;Business card&apos;&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;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_business_card_1.scene`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          thumbnailURL: &lt;/span&gt;&lt;span&gt;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_business_card_1.png`&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;  };&lt;/span&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; (cesdkContainer.current) {&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;(cesdkContainer.current, config).&lt;/span&gt;&lt;span&gt;then&lt;/span&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;      cesdk &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;    });&lt;/span&gt;&lt;/span&gt;
&lt;span 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;=&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; (cesdk) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      cesdk.&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;}, [cesdkContainer]);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;customImagePath&lt;/code&gt; variable stores the path to the local image file &lt;code&gt;programming.png&lt;/code&gt; located in the &lt;code&gt;public/resources&lt;/code&gt; folder of the React project. This variable is used in the &lt;code&gt;findAssets()&lt;/code&gt; function. This function is important because it defines the complete asset source. In other words, you only need one function to implement the custom asset retrieval logic. Note that providing images with labels is useful to make them searchable through the CE.SDK UI.&lt;/p&gt;
&lt;p&gt;Now, users will be able to use the image in their template.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;icon-template-ce-sdk-create-canva-yourself&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1000px) 1000px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1000&quot; height=&quot;474&quot; src=&quot;https://img.ly/_astro/icon-template-ce-sdk-create-canva-yourself_1F6dsS.webp&quot; srcset=&quot;/_astro/icon-template-ce-sdk-create-canva-yourself_SgMiL.webp 640w, /_astro/icon-template-ce-sdk-create-canva-yourself_Z1zWsKX.webp 750w, /_astro/icon-template-ce-sdk-create-canva-yourself_wOR2.webp 828w, /_astro/icon-template-ce-sdk-create-canva-yourself_1F6dsS.webp 1000w&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;tie-it-together&quot;&gt;Tie it Together&lt;/h4&gt;
&lt;p&gt;This is what the final &lt;code&gt;CanvaClone&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; &apos;./CanvaClone.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; 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; React, { useEffect, useRef } &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; { findAirtableAssets } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;./airtableAssetLibrary&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; { findUnsplashAssets } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;./unsplashAssetLibrary&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; CanvaClone&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // initializing Airtable as default external asset library&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  assetLibrary&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &apos;airtable&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;  const&lt;/span&gt;&lt;span&gt; cesdkContainer&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;  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; externalAssetSources&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;(assetLibrary &lt;/span&gt;&lt;span&gt;===&lt;/span&gt;&lt;span&gt; &apos;airtable&apos;&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;        airtable: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          findAssets: findAirtableAssets,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          credits: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            name: &lt;/span&gt;&lt;span&gt;&apos;Airtable&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            url: &lt;/span&gt;&lt;span&gt;&apos;https://airtable.com/shr4x8s9jqaxiJxm5/tblSLR9GBwiVwFS8z?backgroundColor=orange&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&gt;&lt;span&gt;(assetLibrary &lt;/span&gt;&lt;span&gt;===&lt;/span&gt;&lt;span&gt; &apos;unsplash&apos;&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;        unsplash: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          findAssets: findUnsplashAssets,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          credits: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            name: &lt;/span&gt;&lt;span&gt;&apos;Unsplash&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            url: &lt;/span&gt;&lt;span&gt;&apos;https://unsplash.com/&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;          license: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            name: &lt;/span&gt;&lt;span&gt;&apos;Unsplash license (free)&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            url: &lt;/span&gt;&lt;span&gt;&apos;https://unsplash.com/license&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&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // path to the local image to load into CE.SDK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; customImagePath&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;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;}/resources/programming.png`&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; cesdk;&lt;/span&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; 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;      // loading the business card template as default template&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      initialSceneURL: &lt;/span&gt;&lt;span&gt;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_business_card_1.scene`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      // loading the external asset sources&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      assetSources: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // loading the AirTable or Unsplash asset library&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        ...&lt;/span&gt;&lt;span&gt;externalAssetSources,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // loading a custom image into CE.SDK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        custom: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          findAssets&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; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;              assets: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                  id: &lt;/span&gt;&lt;span&gt;&apos;custom-image-1&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                  type: &lt;/span&gt;&lt;span&gt;&apos;ly.img.image&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                  locale: &lt;/span&gt;&lt;span&gt;&apos;en&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                  label: &lt;/span&gt;&lt;span&gt;&apos;Programming&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                  thumbUri: customImagePath,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                  size: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    width: &lt;/span&gt;&lt;span&gt;512&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;512&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;                  meta: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    uri: customImagePath,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    sourceId: &lt;/span&gt;&lt;span&gt;&apos;custom&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;                  credits: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    name: &lt;/span&gt;&lt;span&gt;&apos;Freepik&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    url: &lt;/span&gt;&lt;span&gt;&apos;https://www.flaticon.com/free-icon/programming_1208884?related_id=1208782&amp;#x26;origin=search&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;              currentPage: &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;              total: &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;              nextPage: &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&gt;&lt;/span&gt;
&lt;span 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;      // translating the labels associates with the external asset sources&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      i18n: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        en: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          &apos;libraries.airtable.label&apos;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&apos;Airtable&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          &apos;libraries.unsplash.label&apos;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&apos;Unsplash&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          &apos;libraries.custom.label&apos;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&apos;Custom&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;      // initializing CE.SDK with a few templates&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      presets: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        templates: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          postcard_1: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            label: &lt;/span&gt;&lt;span&gt;&apos;Postcard Design&apos;&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;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_postcard_1.scene`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            thumbnailURL: &lt;/span&gt;&lt;span&gt;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_postcard_1.png`&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;          postcard_2: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            label: &lt;/span&gt;&lt;span&gt;&apos;Postcard Tropical&apos;&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;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_postcard_2.scene`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            thumbnailURL: &lt;/span&gt;&lt;span&gt;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_postcard_2.png`&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;          business_card_1: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            label: &lt;/span&gt;&lt;span&gt;&apos;Business card&apos;&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;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_business_card_1.scene`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            thumbnailURL: &lt;/span&gt;&lt;span&gt;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_business_card_1.png`&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;          instagram_photo_1: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            label: &lt;/span&gt;&lt;span&gt;&apos;Instagram photo&apos;&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;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_instagram_photo_1.scene`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            thumbnailURL: &lt;/span&gt;&lt;span&gt;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_instagram_photo_1.png`&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;          instagram_story_1: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            label: &lt;/span&gt;&lt;span&gt;&apos;Instagram story&apos;&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;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_instagram_story_1.scene`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            thumbnailURL: &lt;/span&gt;&lt;span&gt;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_instagram_story_1.png`&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;          poster_1: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            label: &lt;/span&gt;&lt;span&gt;&apos;Poster&apos;&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;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_poster_1.scene`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            thumbnailURL: &lt;/span&gt;&lt;span&gt;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_poster_1.png`&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;          presentation_4: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            label: &lt;/span&gt;&lt;span&gt;&apos;Presentation&apos;&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;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_presentation_1.scene`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            thumbnailURL: &lt;/span&gt;&lt;span&gt;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_presentation_1.png`&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;          collage_1: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            label: &lt;/span&gt;&lt;span&gt;&apos;Collage&apos;&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;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_collage_1.scene`&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            thumbnailURL: &lt;/span&gt;&lt;span&gt;`https://cdn.img.ly/packages/imgly/cesdk-js/latest/assets/templates/cesdk_collage_1.png`&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;    if&lt;/span&gt;&lt;span&gt; (cesdkContainer.current) {&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;(cesdkContainer.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;          cesdk &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;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;span&gt;=&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; (cesdk) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        cesdk.&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;  }, [cesdkContainer, assetLibrary]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; className&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;caseContainer&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; className&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;wrapper&quot;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; ref&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{cesdkContainer} &lt;/span&gt;&lt;span&gt;className&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;cesdk&quot;&lt;/span&gt;&lt;span&gt;&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; CanvaClone;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;findAirtableAssets()&lt;/code&gt; and &lt;code&gt;findUnsplashAssets()&lt;/code&gt; functions come from the &lt;a href=&quot;https://github.com/imgly/cesdk-web-examples/tree/showcases/showcase-custom-asset-libraries&quot;&gt;GitHub repo&lt;/a&gt; associated with the &lt;a href=&quot;https://img.ly/showcases/cesdk/unsplash-image-assets/web?c_asset_library=airtable&quot;&gt;Unsplash and Airtable integration showcase page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These functions allow CE.SDK to dynamically retrieve resources from online services. A search for images in the CE.SDK UI will perform a query on Airtable or Unsplash and provides them to your users. With just a few lines of code, you are making massive resources available to your users.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Canva has rapidly become one of the most popular graphic design tools. It is so prevalent that users expect similar features in your web and mobile applications. Building a Canva clone from scratch would take months, but with CreativeEditor SDK, it only takes minutes.&lt;/p&gt;
&lt;p&gt;In this article, we used CE.SDK to initialize an advanced design editor in React. We adopted its API to configure and customize a design editor to build a Canva clone. This would not be possible without the intuitive UI offered by CE.SDK and its advanced features, such as &lt;a href=&quot;https://img.ly/showcases/cesdk/placeholders/web?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;placeholders&lt;/a&gt; and the possibility to define &lt;a href=&quot;https://img.ly/showcases/cesdk/design-validation/web?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;Here we only scratched the surface of what is possible with CE.SDK – you can use its powerful image processing API to implement many more features and make your Canva clone more and more complex. This is only the beginning!&lt;/p&gt;
&lt;p&gt;See how &lt;a href=&quot;https://img.ly/canva-alternative&quot;&gt;IMG.LY compares to Canva Connect API&lt;/a&gt; and check out all the use cases of &lt;a href=&quot;https://img.ly/products/creative-sdk&quot;&gt;CreativeEditor SDK&lt;/a&gt; or &lt;a href=&quot;https://img.ly/forms/contact-sales&quot;&gt;contact sales&lt;/a&gt; to learn more!&lt;/p&gt;</content:encoded><dc:creator>Antonello</dc:creator><media:content url="https://blog.img.ly/2022/07/create-an-app-like-canva.png" medium="image"/><category>How-To</category><category>Canva</category><category>Design Editor</category><category>Creative Editor</category><category>Web Application</category><category>Web Development</category><category>React</category><category>Tutorial</category><category>Learning</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 Generate an NFT Art Collection With React Using CE.SDK</title><link>https://img.ly/blog/how-to-generate-an-nft-art-collection-with-react-using-ce-sdk/</link><guid isPermaLink="true">https://img.ly/blog/how-to-generate-an-nft-art-collection-with-react-using-ce-sdk/</guid><description>Learn how to programmatically build a trading card set for NFT art collections in React with CE.SDK.</description><pubDate>Tue, 17 May 2022 13:48:25 GMT</pubDate><content:encoded>&lt;p&gt;In recent months NFTs have become increasingly popular and now represent a worldwide trend. We all have heard about NFTs at least once, but have you ever wondered how to generate an art collection easily and programmatically? 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 build a trading card image generator representing your NFT art collection in React with CreativeEditor SDK. At the end of the article, you will achieve &lt;a href=&quot;https://codesandbox.io/s/how-to-generate-an-nft-art-collection-with-react-using-ce-sdk-forked-542egi&quot;&gt;the following result&lt;/a&gt;:&lt;/p&gt;
&lt;h2 id=&quot;what-is-an-nft-art-collection&quot;&gt;What is an NFT Art Collection?&lt;/h2&gt;
&lt;p&gt;NFT stands for &lt;a href=&quot;https://en.wikipedia.org/wiki/Non-fungible_token&quot;&gt;Non-Fungible Token&lt;/a&gt; and represents a non-interchangeable unit of data stored on a blockchain that can be traded and sold. We usually associate NFTs with physical or digital assets, such as photos, videos, or audio. You can think of an NFT as a digital work of art.&lt;/p&gt;
&lt;p&gt;Consequently, an NFT art collection is nothing more than a set of NFTs associated with a physical or digital art piece.&lt;/p&gt;
&lt;h2 id=&quot;what-is-creativeeditor-sdk&quot;&gt;What is CreativeEditor 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&lt;/a&gt; (CE.SDK) is a fully customizable, easy-to-use, advanced design editor SDK that lets you add template-based workflows and automation to your app with just a few lines of code.&lt;/p&gt;
&lt;p&gt;CE.SDK is based on a role-specific editing UI and focuses on keeping content adaptation dead simple – all of this, while empowering your creativity with a powerful authoring environment.&lt;/p&gt;
&lt;p&gt;See CE.SDK &lt;a href=&quot;https://img.ly/showcases/cesdk/&quot;&gt;in action&lt;/a&gt; or &lt;a href=&quot;https://img.ly/forms/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;build-an-nft-art-collection-generator-in-react-with-cesdk&quot;&gt;Build an NFT Art Collection Generator in React With CE.SDK&lt;/h2&gt;
&lt;p&gt;Now, let’s learn how to implement an NFT art collection generator using CE.SDK and React. In detail, you will learn how to use CE.SDK to define a dynamic template you can then adopt in React to generate your fancy NFT art collection of trading cards.&lt;/p&gt;
&lt;p&gt;You can have a look at the final CE.SDK template live &lt;a href=&quot;https://ubique.img.ly/demo/nft-blog/apps/cesdk_web/web/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Keep in mind that a CE.SDK template is not a static resource. That is because you can change it programmatically through the CE.SDK APIs, as you are about to learn.&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;You can learn how to get started with CE.SDK in React by following the getting started guide of the official documentation. Notice that you do not need to set up an instance of CE.SDK to follow this article. You can follow this step-by-step tutorial.&lt;/p&gt;
&lt;h3 id=&quot;2-initialize-a-cesdk-design&quot;&gt;2. Initialize a CE.SDK design&lt;/h3&gt;
&lt;p&gt;First of all, you need to create a CE.SDK template. As you are about to see, this is not that difficult. All you have to do is click on the “New Design” button.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;1&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1437px) 1437px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1437&quot; height=&quot;828&quot; src=&quot;https://img.ly/_astro/1_Z1CTvu0.webp&quot; srcset=&quot;/_astro/1_1lpqiL.webp 640w, /_astro/1_AKeBm.webp 750w, /_astro/1_Z1lBgE1.webp 828w, /_astro/1_Z1teaaL.webp 1080w, /_astro/1_szWK6.webp 1280w, /_astro/1_Z1CTvu0.webp 1437w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Give your template a name, such as “NFT Trading Card Collection”.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;2&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 426px) 426px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;426&quot; height=&quot;204&quot; src=&quot;https://img.ly/_astro/2_E8EBe.webp&quot; srcset=&quot;/_astro/2_E8EBe.webp 426w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Click on “Create”. This is what your blank template should look like:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;3&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1432px) 1432px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1432&quot; height=&quot;830&quot; src=&quot;https://img.ly/_astro/3_ZOOT8q.webp&quot; srcset=&quot;/_astro/3_2w3ogS.webp 640w, /_astro/3_2nzr6v.webp 750w, /_astro/3_Z1dR8XA.webp 828w, /_astro/3_10BwRI.webp 1080w, /_astro/3_2qPEIz.webp 1280w, /_astro/3_ZOOT8q.webp 1432w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Here you can unleash your creativity and create the NFT trading card template to your desire.&lt;/p&gt;
&lt;h3 id=&quot;3-make-your-cesdk-design-dynamic-with-variables-and-by-setting-placeholders&quot;&gt;3. Make your CE.SDK design dynamic with variables and by setting placeholders&lt;/h3&gt;
&lt;p&gt;CE.SDK equips you with the ability to define &lt;a href=&quot;https://img.ly/docs/cesdk/js/create-templates/add-dynamic-content/text-variables-7ecb50/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos#content&quot;&gt;variables&lt;/a&gt;. You can then give these variables a value in your frontend code. The CE.SDK variables can then be defined during text editing.&lt;/p&gt;
&lt;p&gt;To add a variable to your design, click on “Text”, select a text element, place it on your page, double-click on it, and select “Add a variable”.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;4&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1438px) 1438px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1438&quot; height=&quot;842&quot; src=&quot;https://img.ly/_astro/4_Z1U9BrF.webp&quot; srcset=&quot;/_astro/4_Z1JnaBe.webp 640w, /_astro/4_Z1RQ7LB.webp 750w, /_astro/4_Z1s0pks.webp 828w, /_astro/4_1vxjeT.webp 1080w, /_astro/4_1uGf62.webp 1280w, /_astro/4_Z1U9BrF.webp 1438w&quot;&gt;&lt;/p&gt;
&lt;p&gt;A CE.SDK variable has the following format:&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;{{variable_name}}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt=&quot;5&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 340px) 340px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;340&quot; height=&quot;188&quot; src=&quot;https://img.ly/_astro/5_Zjo6Te.webp&quot; srcset=&quot;/_astro/5_Zjo6Te.webp 340w&quot;&gt;&lt;/p&gt;
&lt;p&gt;A variable value can be defined programmatically via the CE.SDK &lt;a href=&quot;https://img.ly/docs/cesdk/js/create-templates/add-dynamic-content/text-variables-7ecb50/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos#content&quot;&gt;Variable API&lt;/a&gt;. Use them to set the dynamic text fields you want users to customize in the application layer. For example, you can fill them with data retrieved from an API called by the frontend.&lt;/p&gt;
&lt;p&gt;Also, CE.SDK gives you the possibility to define &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=howtos#content&quot;&gt;placeholders&lt;/a&gt;. Placeholders can be created only by a user with &lt;a href=&quot;https://img.ly/docs/cesdk/js/concepts/editing-workflow-032d27/#creator?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos#creator&quot;&gt;&lt;code&gt;Creator&lt;/code&gt;&lt;/a&gt; role and allow them to specify a set of constraints associated with the element declared as a placeholder. These constraints only apply to users having non-creator roles and define what operations such users can perform on that element.&lt;/p&gt;
&lt;p&gt;You can define a placeholder by selecting an element, clicking &lt;em&gt;Placeholder&lt;/em&gt; and then choosing the constraints you want the non-creator users to have for this element.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;6&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 442px) 442px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;442&quot; height=&quot;277&quot; src=&quot;https://img.ly/_astro/6_Z1daE8H.webp&quot; srcset=&quot;/_astro/6_Z1daE8H.webp 442w&quot;&gt;&lt;/p&gt;
&lt;p&gt;In this case, non-creator users are only allowed to style the &lt;code&gt;name&lt;/code&gt; variable defined above.&lt;/p&gt;
&lt;h3 id=&quot;4-share-your-cesdk-design-as-a-template-and-export-it-to-a-scene&quot;&gt;4. Share your CE.SDK design as a template and export it to a scene&lt;/h3&gt;
&lt;p&gt;Let’s assume you defined the trading card template of your dreams. You spent a lot of time on it, and you now want other users to use it to generate their own NFT art collection. All you have to do, is save, click on the “v” symbol near the Save button, and select “Share as Template”.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;7&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1443px) 1443px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1443&quot; height=&quot;834&quot; src=&quot;https://img.ly/_astro/7_1QicLF.webp&quot; srcset=&quot;/_astro/7_Z1OAJ9N.webp 640w, /_astro/7_ZUaQ2u.webp 750w, /_astro/7_19JVdn.webp 828w, /_astro/7_b4cFp.webp 1080w, /_astro/7_1Bikwg.webp 1280w, /_astro/7_1QicLF.webp 1443w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Now follow the instructions, and non-creator users will be able to access your template with the link the application provided you.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;8&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 431px) 431px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;431&quot; height=&quot;250&quot; src=&quot;https://img.ly/_astro/8_ZjJhb2.webp&quot; srcset=&quot;/_astro/8_ZjJhb2.webp 431w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Users will be able to interact with your CE.SDK template based on the variables and placeholders you defined while creating your design.&lt;/p&gt;
&lt;p&gt;Bear in mind that sharing your design as a template is a nice feature but not mandatory to achieve the goal. In case you want to use your design on your CE.SDK frontend instances, you only have to export it as a &lt;a href=&quot;https://img.ly/docs/cesdk/js/open-the-editor-23a1db/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;scene&lt;/a&gt;, and then load it through the CE.SDK &lt;a href=&quot;https://img.ly/docs/cesdk/js/concepts/scenes-e8596d/?ref=img.ly#saving-a-scene?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;Scene API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To export a design as a scene, click on the “v” symbol, and in the dropdown, select “Export Design File”. You will automatically download the scene file to the directory according to your browser settings. The export feature allows you to download your scene. You can also import your own or another user’s scene.&lt;/p&gt;
&lt;p&gt;You now have everything you need to build an NFT trading card collection generator in React! Let’s delve deeper into how to achieve this.&lt;/p&gt;
&lt;h3 id=&quot;5-use-your-cesdk-scene-in-react-to-programmatically-generate-an-nft-trading-card-art-collection&quot;&gt;5. Use your CE.SDK scene in React to programmatically generate an NFT trading card art collection&lt;/h3&gt;
&lt;h4 id=&quot;51-prerequisites&quot;&gt;5.1 Prerequisites&lt;/h4&gt;
&lt;p&gt;This is the list of all the prerequisites for the demo application you are going to build:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/get-npm&quot;&gt;Node.js and npm&lt;/a&gt; &lt;a href=&quot;https://www.npmjs.com/get-npm&quot;&gt;5.2+ 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;h4 id=&quot;52-getting-started&quot;&gt;5.2 Getting started&lt;/h4&gt;
&lt;p&gt;You can try out the NFT art collection generator by cloning the &lt;a href=&quot;https://github.com/Tonel/resize-image-react-demo-imgly&quot;&gt;GitHub repository supporting the article&lt;/a&gt; and launching the web application 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/how-to-generate-an-nft-art-collection-imgly&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cd how-to-generate-an-nft-art-collection-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;Otherwise, keep following this tutorial and build the NFT trading card art collection generator by yourself.&lt;/p&gt;
&lt;p&gt;First, initialize a React project called &lt;code&gt;nft-art-collection-generator&lt;/code&gt; with &lt;a href=&quot;https://create-react-app.dev/docs/getting-started/&quot;&gt;Create React App&lt;/a&gt; with the 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 create-react-app nft-art-collection-generator&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, your &lt;code&gt;nft-art-collection-generator&lt;/code&gt; 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;nft-art-collection-generator&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;Now move into the &lt;code&gt;nft-art-collection-generator&lt;/code&gt; folder and start a local server by launching 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 nft-art-collection-generator&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;By visiting &lt;a href=&quot;http://localhost:3000/&quot;&gt;http://localhost:3000/&lt;/a&gt; in your browser, you should now be able to see the default Create React App screen:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;9&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/9_Z1wHNVr.webp&quot; srcset=&quot;/_astro/9_ZSdLx0.webp 640w, /_astro/9_Z1NlAYM.webp 750w, /_astro/9_ZRmCsP.webp 828w, /_astro/9_Z1wHNVr.webp 983w&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;53-building-the-nft-art-collection-generator-component&quot;&gt;5.3 Building the NFT Art Collection Generator Component&lt;/h4&gt;
&lt;p&gt;You can use CE.SDK to implement an image generator based on your template 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; CreativeEngine &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;@cesdk/cesdk-js/cesdk-engine.umd.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; LoadingSpinner &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;../LoadingSpinner/LoadingSpinner&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; { DOGS } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;./data&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;./NFTArtCollectionGenerator.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; React, { 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;
&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; NFTArtCollectionGenerator&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; engineRef&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;tradingCardImages&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setTradingCardImages&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;    new&lt;/span&gt;&lt;span&gt; Array&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;DOGS&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;fill&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;initialized&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setInitialized&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // initializing CE.SDK on first rendering&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; 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;      page: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        title: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          show: &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&gt;&lt;/span&gt;
&lt;span 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;    CreativeEngine.&lt;/span&gt;&lt;span&gt;init&lt;/span&gt;&lt;span&gt;(config).&lt;/span&gt;&lt;span&gt;then&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;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;      // importing the CE.SDK scene&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      await&lt;/span&gt;&lt;span&gt; instance.scene.&lt;/span&gt;&lt;span&gt;loadFromURL&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;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;}/assets/cesdk-nft-doggo.scene`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      engineRef.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;      setInitialized&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;    return&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; shutdownCreativeEngine&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      engineRef?.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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  async&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; generateTradingCards&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; cesdk&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; engineRef?.current;&lt;/span&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; (initialized &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; cesdk) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      // setting the image loading state to true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      // to each image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      setTradingCardImages&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;oldImages&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;oldImages.&lt;/span&gt;&lt;span&gt;map&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;=&gt;&lt;/span&gt;&lt;span&gt; ({ &lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;image, isLoading: &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; newTradingCardImages&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;      // iterating over each data entry to generate&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      // its trading card with CE.SDK&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;const&lt;/span&gt;&lt;span&gt; dog&lt;/span&gt;&lt;span&gt; of&lt;/span&gt;&lt;span&gt; DOGS&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // giving each variable defined in the CE.SDK scene&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // a value based on the dog data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        cesdk.variable.&lt;/span&gt;&lt;span&gt;setString&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;name&apos;&lt;/span&gt;&lt;span&gt;, dog.name);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        cesdk.variable.&lt;/span&gt;&lt;span&gt;setString&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;date&apos;&lt;/span&gt;&lt;span&gt;, dog.date);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        cesdk.variable.&lt;/span&gt;&lt;span&gt;setString&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;chain&apos;&lt;/span&gt;&lt;span&gt;, dog.chain);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        cesdk.variable.&lt;/span&gt;&lt;span&gt;setString&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;drool&apos;&lt;/span&gt;&lt;span&gt;, dog.drool);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        cesdk.variable.&lt;/span&gt;&lt;span&gt;setString&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;courage&apos;&lt;/span&gt;&lt;span&gt;, dog.courage);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // retrieving the background block&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        const&lt;/span&gt;&lt;span&gt; backgroundBlock&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; cesdk.block.&lt;/span&gt;&lt;span&gt;findByType&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;page&apos;&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;        if&lt;/span&gt;&lt;span&gt; (backgroundBlock) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          // setting the background to a random color&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          cesdk.block.&lt;/span&gt;&lt;span&gt;setBackgroundColorRGBA&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            backgroundBlock,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            Math.&lt;/span&gt;&lt;span&gt;random&lt;/span&gt;&lt;span&gt;(), &lt;/span&gt;&lt;span&gt;// r (from 0 to 1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            Math.&lt;/span&gt;&lt;span&gt;random&lt;/span&gt;&lt;span&gt;(), &lt;/span&gt;&lt;span&gt;// g (from 0 to 1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            Math.&lt;/span&gt;&lt;span&gt;random&lt;/span&gt;&lt;span&gt;(), &lt;/span&gt;&lt;span&gt;// b (from 0 to 1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            1.0&lt;/span&gt;&lt;span&gt; // alpha (from 0 to 1)&lt;/span&gt;&lt;/span&gt;
&lt;span 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; blob&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; cesdk.block.&lt;/span&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          cesdk.block.&lt;/span&gt;&lt;span&gt;findByType&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;scene&apos;&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;          &apos;image/jpeg&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;        newTradingCardImages.&lt;/span&gt;&lt;span&gt;push&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          isLoading: &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;          src: &lt;/span&gt;&lt;span&gt;URL&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;createObjectURL&lt;/span&gt;&lt;span&gt;(blob),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        });&lt;/span&gt;&lt;/span&gt;
&lt;span 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;      // setting the new trading card images&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      setTradingCardImages&lt;/span&gt;&lt;span&gt;(newTradingCardImages);&lt;/span&gt;&lt;/span&gt;
&lt;span 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;  // generating the trading card images for the first time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // when CE.SDK is initialized&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; (engineRef &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; initialized) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      generateTradingCards&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;  }, [engineRef, initialized]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; className&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;flex flex-col items-center&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;h3&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;`h4 ${&lt;/span&gt;&lt;span&gt;styles&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;headline&lt;/span&gt;&lt;span&gt;}`&lt;/span&gt;&lt;span&gt;}&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          NFT Trading Card Collection Generator&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;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;button&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;{styles.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; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            generateTradingCards&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;        &gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          Generate&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;div&lt;/span&gt;&lt;span&gt; className&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{styles.contentWrapper}&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.imageWrapper}&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          {tradingCardImages.&lt;/span&gt;&lt;span&gt;map&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;i&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; (&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;
&lt;span class=&quot;line&quot;&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 class=&quot;line&quot;&gt;&lt;span&gt;                  width: &lt;/span&gt;&lt;span&gt;160&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;210&lt;/span&gt;&lt;span&gt;,&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;                  backgroundColor: &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;                key&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{i}&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;                {image?.src &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;img&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;&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;{image?.src}&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;{{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                      opacity: image?.isLoading &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; 0.5&lt;/span&gt;&lt;span&gt; :&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                      transition: &lt;/span&gt;&lt;span&gt;&apos;opacity .5s&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                      transitionTimingFunction: &lt;/span&gt;&lt;span&gt;&apos;ease-in-out&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                      objectFit: &lt;/span&gt;&lt;span&gt;&apos;contain&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;                  /&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;                {image?.isLoading &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; &amp;#x3C;&lt;/span&gt;&lt;span&gt;LoadingSpinner&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;        &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;/code&gt;&lt;/pre&gt;
&lt;p&gt;This component uses CE.SDK to generate a trading card set you can transform into your NFT art collection. 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 function takes care of initializing a CE.SDK instance and loading the scene file exported above. To make everything work as expected, create an &lt;code&gt;assets&lt;/code&gt; folder under &lt;code&gt;public&lt;/code&gt;, and put your scene file in it.&lt;br&gt;
Then, the &lt;code&gt;generateTradingCards()&lt;/code&gt; function using CE.SDK is used to generate the trading card image set is defined. This is where the magic happens!&lt;/p&gt;
&lt;p&gt;The trading card images are generated based on the &lt;code&gt;DOGS&lt;/code&gt; variable imported from &lt;code&gt;data&lt;/code&gt; by giving each scene’s variable a value and providing the background with a random color. This way, every time you press “Generate”, the resulting collection of trading cards will have the same data, but always a different color.&lt;br&gt;
If you are wondering, this is what the &lt;code&gt;data&lt;/code&gt; file 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;export&lt;/span&gt;&lt;span&gt; const&lt;/span&gt;&lt;span&gt; DOGS&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;Pancakes&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    date: &lt;/span&gt;&lt;span&gt;&apos;2022&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    chain: &lt;/span&gt;&lt;span&gt;&apos;etherum&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    drool: &lt;/span&gt;&lt;span&gt;&apos;5/10&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    courage: &lt;/span&gt;&lt;span&gt;&apos;10/10&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;    name: &lt;/span&gt;&lt;span&gt;&apos;Clovis III&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    date: &lt;/span&gt;&lt;span&gt;&apos;2020&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    chain: &lt;/span&gt;&lt;span&gt;&apos;flyx&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    drool: &lt;/span&gt;&lt;span&gt;&apos;9/10&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    courage: &lt;/span&gt;&lt;span&gt;&apos;1/10&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;    name: &lt;/span&gt;&lt;span&gt;&apos;Pickles&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    date: &lt;/span&gt;&lt;span&gt;&apos;2019&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    chain: &lt;/span&gt;&lt;span&gt;&apos;cardano&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    drool: &lt;/span&gt;&lt;span&gt;&apos;1/10&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    courage: &lt;/span&gt;&lt;span&gt;&apos;10/10&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;    name: &lt;/span&gt;&lt;span&gt;&apos;Groucho Barks&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    date: &lt;/span&gt;&lt;span&gt;&apos;2018&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    chain: &lt;/span&gt;&lt;span&gt;&apos;solana&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    drool: &lt;/span&gt;&lt;span&gt;&apos;10/10&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    courage: &lt;/span&gt;&lt;span&gt;&apos;5/10&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;    name: &lt;/span&gt;&lt;span&gt;&apos;Puppins&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    date: &lt;/span&gt;&lt;span&gt;&apos;2019&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    chain: &lt;/span&gt;&lt;span&gt;&apos;ethereum&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    drool: &lt;/span&gt;&lt;span&gt;&apos;8/10&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    courage: &lt;/span&gt;&lt;span&gt;&apos;5/10&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;    name: &lt;/span&gt;&lt;span&gt;&apos;Mr. Chow&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    date: &lt;/span&gt;&lt;span&gt;&apos;2019&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    chain: &lt;/span&gt;&lt;span&gt;&apos;flow&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    drool: &lt;/span&gt;&lt;span&gt;&apos;5/10&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    courage: &lt;/span&gt;&lt;span&gt;&apos;9/10&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;    name: &lt;/span&gt;&lt;span&gt;&apos;Dr. Droolz&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    date: &lt;/span&gt;&lt;span&gt;&apos;2020&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    chain: &lt;/span&gt;&lt;span&gt;&apos;eos&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    drool: &lt;/span&gt;&lt;span&gt;&apos;10/10&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    courage: &lt;/span&gt;&lt;span&gt;&apos;10/10&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;    name: &lt;/span&gt;&lt;span&gt;&apos;Snuffles&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    date: &lt;/span&gt;&lt;span&gt;&apos;2018&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    chain: &lt;/span&gt;&lt;span&gt;&apos;ethereum&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    drool: &lt;/span&gt;&lt;span&gt;&apos;4/10&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    courage: &lt;/span&gt;&lt;span&gt;&apos;5/10&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;As you can see, the &lt;code&gt;DOGS&lt;/code&gt; array contains the data generating each card programmatically through CE.SDK’s Variable API. For simplicity, the &lt;code&gt;DOGS&lt;/code&gt; array was hard-coded into the &lt;code&gt;data&lt;/code&gt; file. In a real-world scenario, you can retrieve this data through an API call or however you prefer.&lt;br&gt;
Finally, the trading card collection images are rendered and shown to the user as in the image below:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;10&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 939px) 939px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;939&quot; height=&quot;708&quot; src=&quot;https://img.ly/_astro/10_ZvGX6e.webp&quot; srcset=&quot;/_astro/10_Z11d1AN.webp 640w, /_astro/10_23I3mI.webp 750w, /_astro/10_jDgS2.webp 828w, /_astro/10_ZvGX6e.webp 939w&quot;&gt;&lt;/p&gt;
&lt;p&gt;As you just learned, a CE.SDK template allows you to generate an infinite combination of different images. In this example, you learned how to use variables and change the background colors, but several other options are available. Learn more &lt;a href=&quot;https://img.ly/docs/cesdk/js/overview-8cc730/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The real challenge to entering the NFT world lies in producing a collection of appealing images. Converting them into NFTs takes only a few clicks. In this article, we used CE.SDK to generate a trading card collection of images that all share the same template. Specifically, CE.SDK gives you everything you need to create applications supporting template-based workflows – your users can adapt your templates or programmatically create variations of visually consistent, high-quality images.&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/content-moderation/web?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;content moderation&lt;/a&gt; and define &lt;a href=&quot;https://img.ly/showcases/cesdk/design-validation/web?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 you found this article helpful. Feel free to reach out to us on &lt;a href=&quot;https://x.com/imgly?ref=img.ly&quot;&gt;Twitter&lt;/a&gt; with any questions, comments, or suggestions. For more, stay in the loop with 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/05/nft-batch-auto-generate-auto-fill.png" medium="image"/><category>How-To</category><category>NFT</category><category>Web Development</category><category>React</category><category>Learning</category></item><item><title>How To Apply Image Filters in WebGL</title><link>https://img.ly/blog/how-to-add-image-filters-in-webgl/</link><guid isPermaLink="true">https://img.ly/blog/how-to-add-image-filters-in-webgl/</guid><description>Learn everything you need to get started with kernel-based image filters in WebGL.</description><pubDate>Fri, 08 Apr 2022 13:06:16 GMT</pubDate><content:encoded>&lt;p&gt;In this article, you will learn how to apply custom filters to an image in WebGL. You can achieve this goal without using any external library. That is because the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL&quot;&gt;HTML5 &lt;code&gt;canvas&lt;/code&gt;&lt;/a&gt; &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL&quot;&gt;element natively supports WebGL&lt;/a&gt; and does not require the use of plug-ins.&lt;/p&gt;
&lt;p&gt;As we have already covered in &lt;a href=&quot;https://img.ly/blog/tag/html5/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;previous articles&lt;/a&gt;, &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt; is a powerful tool that equips you with everything required to manipulate images. This is true regardless of the use of WebGL. So, you can &lt;a href=&quot;https://img.ly/blog/how-to-apply-filters-in-javascript/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;filter images also without using WebGL&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now, let’s see how to filter images in Vanilla JavaScript with WebGL in your browser. Follow this step-by-step tutorial and learn how to build the following &lt;a href=&quot;https://codesandbox.io/s/how-to-filter-an-image-in-webgl-forked-zkgccv&quot;&gt;demo&lt;/a&gt;:&lt;/p&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/how-to-filter-an-image-in-webgl-forked-zkgccv?fontsize=14&amp;#x26;hidenavigation=1&amp;#x26;theme=dark&quot; title=&quot;How To Filter an Image in WebGL (forked)&quot; allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot; sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;getting-started-with-webgl&quot;&gt;Getting Started with WebGL&lt;/h2&gt;
&lt;p&gt;If you are not familiar with &lt;a href=&quot;https://get.webgl.org/&quot;&gt;WebGL&lt;/a&gt;, you need to learn a few things before approaching it. To build an application in WebGL, start with the following three concepts.&lt;/p&gt;
&lt;h3 id=&quot;1-textures&quot;&gt;1. Textures&lt;/h3&gt;
&lt;p&gt;Keep in mind that to draw an image in WebGL you have to use a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Using_textures_in_WebGL&quot;&gt;texture&lt;/a&gt;. To use a texture, WebGL requires you to define the texture coordinates. These coordinates go from 0.0 to 1.0, regardless of the texture size.&lt;/p&gt;
&lt;h3 id=&quot;2-vertex-shader&quot;&gt;2. Vertex shader&lt;/h3&gt;
&lt;p&gt;The vertex shader is a function you have to write in &lt;a href=&quot;https://www.khronos.org/opengl/wiki/OpenGL_Shading_Language&quot;&gt;GLSL&lt;/a&gt; that is in charge of computing the vertex positions. Thanks to it, WebGL can &lt;a href=&quot;https://en.wikipedia.org/wiki/Rasterisation&quot;&gt;rasterize&lt;/a&gt; the draw primitives, which include points, lines, and triangles. When rasterizing these primitives, WebGL calls another user-defined function called fragment shader. In other words, WebGL interpolates the values provided in the vertex shader function while it draws each pixel using the fragment shader function execution.&lt;/p&gt;
&lt;h3 id=&quot;3-fragment-shader&quot;&gt;3. Fragment shader&lt;/h3&gt;
&lt;p&gt;The fragment shader is a function you have to write in GLSL whose goal is to generate a color for each pixel of the draw primitive currently being drawn. This function has little info per pixel, but you can provide it with everything required by using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Data#varyings&quot;&gt;&lt;code&gt;varyings&lt;/code&gt;&lt;/a&gt; variables. These allow you to pass values from the vertex shader function to the fragment shader function.&lt;/p&gt;
&lt;h2 id=&quot;filtering-images-with-kernels-in-webgl-with-canvas&quot;&gt;Filtering Images with Kernels in WebGL with &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;There are many ways to filter images, but the most common one involves the &lt;a href=&quot;https://en.wikipedia.org/wiki/Convolution&quot;&gt;convolution operation&lt;/a&gt;. This is because when used on images, convolution applies a filter by taking the weighted sum of a square of pixels and assigning the resulting value to the current pixel. This logic is applied to every pixel the image consists of. Therefore, you can now imagine why convolution is one of the most relevant concepts when it comes to image processing.&lt;/p&gt;
&lt;p&gt;The coefficients used to perform the weighted sum come from a matrix called &lt;a href=&quot;https://en.wikipedia.org/wiki/Kernel%5F(image_processing)&quot;&gt;&lt;em&gt;kernel&lt;/em&gt;&lt;/a&gt;. The kernel represents the filter you want to apply through the convolution operation. So, by changing the kernel, the resulting image will change accordingly. Some kernels are more useful than others and can be used for blurring, sharpening, performing edge detection, and other operations. You can find a list of the most popular &lt;a href=&quot;https://en.wikipedia.org/wiki/Kernel%5F(image_processing)#Details&quot;&gt;kernels on Wikipedia&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now, let’s see how to implement kernel image filtering in WebGL.&lt;/p&gt;
&lt;p&gt;Clone the &lt;a href=&quot;https://github.com/Tonel/how-to-filter-an-image-in-webgl-imgly&quot;&gt;GitHub repository that supports this article&lt;/a&gt; with the following command:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;git clone https://github.com/Tonel/how-to-filter-an-image-in-webgl-imgly&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Additionally, try the demo application by launching &lt;code&gt;how-to-filter-an-image-in-webgl-imgly/index.html&lt;/code&gt; in your browser.&lt;/p&gt;
&lt;p&gt;Otherwise, you can find the JavaScript function taking care of implementing the filter logic in WebGL below:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; filterImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;canvas&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;originalImage&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;kernel&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // assuming the kernel is a square matrix&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; kernelSize&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; Math.&lt;/span&gt;&lt;span&gt;sqrt&lt;/span&gt;&lt;span&gt;(kernel.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; gl&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; canvas.&lt;/span&gt;&lt;span&gt;getContext&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;webgl&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // clearing the canvas&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;clearColor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;clear&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;COLOR_BUFFER_BIT&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; vertexShaderSource&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; `&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  attribute vec2 position;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  varying vec2 v_coordinate;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  void main() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl_Position = vec4(position, 0, 1);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    v_coordinate = gl_Position.xy * 0.5 + 0.5;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; fragmentShaderSource&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; `&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  precision mediump float;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // the varible defined in the vertex shader above&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  varying vec2 v_coordinate;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  uniform vec2 imageSize;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  uniform sampler2D u_texture;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  void main() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    vec2 position = vec2(v_coordinate.x, 1.0 - v_coordinate.y);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    vec2 onePixel = vec2(1, 1) / imageSize;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    vec4 color = vec4(0);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    mat3 kernel = mat3(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      ${&lt;/span&gt;&lt;span&gt;kernel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;,&apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // implementing the convolution operation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    for(int i = 0; i &amp;#x3C; ${&lt;/span&gt;&lt;span&gt;kernelSize&lt;/span&gt;&lt;span&gt;}; i++) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      for(int j = 0; j &amp;#x3C; ${&lt;/span&gt;&lt;span&gt;kernelSize&lt;/span&gt;&lt;span&gt;}; j++) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // retrieving the sample position pixel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        vec2 samplePosition = position + vec2(i - 1 , j - 1) * onePixel;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // retrieving the sample color&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        vec4 sampleColor = texture2D(u_texture, samplePosition);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        sampleColor *= kernel&lt;/span&gt;&lt;span&gt;\[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;\]&lt;/span&gt;&lt;span&gt;[j];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        color += sampleColor;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    color.a = 1.0;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl_FragColor = color;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; vertexShader&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; compileShader&lt;/span&gt;&lt;span&gt;(gl, gl.&lt;/span&gt;&lt;span&gt;VERTEX_SHADER&lt;/span&gt;&lt;span&gt;, vertexShaderSource);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; fragmentShader&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; compileShader&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;FRAGMENT_SHADER&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    fragmentShaderSource&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // iniziailing the program&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; program&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; createProgram&lt;/span&gt;&lt;span&gt;(gl, vertexShader, fragmentShader);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; positionAttributeLocation&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; gl.&lt;/span&gt;&lt;span&gt;getAttribLocation&lt;/span&gt;&lt;span&gt;(program, &lt;/span&gt;&lt;span&gt;&apos;position&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; imageSizeLocation&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; gl.&lt;/span&gt;&lt;span&gt;getUniformLocation&lt;/span&gt;&lt;span&gt;(program, &lt;/span&gt;&lt;span&gt;&apos;imageSize&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // binding the position buffer to positionBuffer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; positionBuffer&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; gl.&lt;/span&gt;&lt;span&gt;createBuffer&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;bindBuffer&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;ARRAY_BUFFER&lt;/span&gt;&lt;span&gt;, positionBuffer);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // using the program defined above&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;useProgram&lt;/span&gt;&lt;span&gt;(program);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // enabling the texcoord attribute&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;enableVertexAttribArray&lt;/span&gt;&lt;span&gt;(positionAttributeLocation);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // setting up the size of the image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;uniform2f&lt;/span&gt;&lt;span&gt;(imageSizeLocation, canvas.width, canvas.height);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // telling positionAttributeLocation how to retrieve data out of positionBuffer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;vertexAttribPointer&lt;/span&gt;&lt;span&gt;(positionAttributeLocation, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;FLOAT&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // provide the texture coordinates&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;bufferData&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;ARRAY_BUFFER&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    new&lt;/span&gt;&lt;span&gt; Float32Array&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;]),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;STATIC_DRAW&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // loading the original image as a texture&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; texture&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; gl.&lt;/span&gt;&lt;span&gt;createTexture&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  texture.image &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; Image&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // setting the anonymous mode&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // Learn more about it here:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/crossOrigin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  texture.image.crossOrigin &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  texture.image.src &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; originalImage.src;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  texture.image.&lt;/span&gt;&lt;span&gt;onload&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;bindTexture&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;TEXTURE_2D&lt;/span&gt;&lt;span&gt;, texture);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // setting the parameters to be able to render any image,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // regardless of its size&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;texParameteri&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;TEXTURE_2D&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;TEXTURE_WRAP_S&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;CLAMP_TO_EDGE&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;texParameteri&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;TEXTURE_2D&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;TEXTURE_WRAP_T&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;CLAMP_TO_EDGE&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;texParameteri&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;TEXTURE_2D&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;TEXTURE_MAG_FILTER&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;NEAREST&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;texParameteri&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;TEXTURE_2D&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;TEXTURE_MIN_FILTER&lt;/span&gt;&lt;span&gt;, gl.&lt;/span&gt;&lt;span&gt;NEAREST&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // loading the original image as a texture&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;texImage2D&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      gl.&lt;/span&gt;&lt;span&gt;TEXTURE_2D&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      gl.&lt;/span&gt;&lt;span&gt;RGBA&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      gl.&lt;/span&gt;&lt;span&gt;RGBA&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      gl.&lt;/span&gt;&lt;span&gt;UNSIGNED_BYTE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      texture.image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;drawArrays&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;TRIANGLES&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;6&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; compileShader&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;gl&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;shaderSource&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; shader&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; gl.&lt;/span&gt;&lt;span&gt;createShader&lt;/span&gt;&lt;span&gt;(type);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;shaderSource&lt;/span&gt;&lt;span&gt;(shader, shaderSource);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;compileShader&lt;/span&gt;&lt;span&gt;(shader);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; outcome&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; gl.&lt;/span&gt;&lt;span&gt;getShaderParameter&lt;/span&gt;&lt;span&gt;(shader, gl.&lt;/span&gt;&lt;span&gt;COMPILE_STATUS&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (outcome &lt;/span&gt;&lt;span&gt;===&lt;/span&gt;&lt;span&gt; false&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // logging the error message on failure&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;getShaderInfoLog&lt;/span&gt;&lt;span&gt;(shader));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;deleteShader&lt;/span&gt;&lt;span&gt;(shader);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; shader;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; createProgram&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;gl&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;vertexShader&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;fragmentShader&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; program&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; gl.&lt;/span&gt;&lt;span&gt;createProgram&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;attachShader&lt;/span&gt;&lt;span&gt;(program, vertexShader);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;attachShader&lt;/span&gt;&lt;span&gt;(program, fragmentShader);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  gl.&lt;/span&gt;&lt;span&gt;linkProgram&lt;/span&gt;&lt;span&gt;(program);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; outcome&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; gl.&lt;/span&gt;&lt;span&gt;getProgramParameter&lt;/span&gt;&lt;span&gt;(program, gl.&lt;/span&gt;&lt;span&gt;LINK_STATUS&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (outcome &lt;/span&gt;&lt;span&gt;===&lt;/span&gt;&lt;span&gt; false&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // logging the error message on failure&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(gl.&lt;/span&gt;&lt;span&gt;getProgramInfoLog&lt;/span&gt;&lt;span&gt;(program));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    gl.&lt;/span&gt;&lt;span&gt;deleteProgram&lt;/span&gt;&lt;span&gt;(program);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; program;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;filterImage()&lt;/code&gt; function is where the magic happens. It takes the following three parameters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;canvas&lt;/code&gt;: an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element&quot;&gt;&lt;code&gt;Element&lt;/code&gt;&lt;/a&gt; object representing an HTML &lt;code&gt;canvas&lt;/code&gt; element&lt;/li&gt;
&lt;li&gt;&lt;code&gt;originalImage&lt;/code&gt;: an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element&quot;&gt;&lt;code&gt;Element&lt;/code&gt;&lt;/a&gt; object representing an HTML &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img&quot;&gt;&lt;code&gt;img&lt;/code&gt;&lt;/a&gt; element&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kernel&lt;/code&gt;: an array containing the values of the kernel to use in the convolution operation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first part of the function takes care of extracting the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext&quot;&gt;&lt;code&gt;WebGLRenderingContext&lt;/code&gt;&lt;/a&gt; object representing a three-dimensional rendering context from the &lt;code&gt;canvas&lt;/code&gt;  element. Then, the vertex shader and fragment shader functions are defined as strings written in GLSL. Next, they are compiled and finally used to create a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebGLProgram&quot;&gt;WebGL program&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The last part of the function creates a texture starting from the original image passed as a parameter and passes it to the &lt;code&gt;WebGLRenderingContext&lt;/code&gt; to produce the final result. This represents the filtered image and is finally displayed by the browser in the &lt;code&gt;canvas&lt;/code&gt; element.&lt;/p&gt;
&lt;p&gt;The results produced by the &lt;code&gt;filterImage()&lt;/code&gt; function depend on the kernel chosen, as you can verify by playing with the live demo you can find at the beginning of the article.&lt;/p&gt;
&lt;p&gt;Et voilà! You just learned how to filter images in WebGL!&lt;/p&gt;
&lt;h2 id=&quot;final-considerations&quot;&gt;Final Considerations&lt;/h2&gt;
&lt;p&gt;As shown above, you can filter images with WebGL in Vanilla JavaScript with a hundred lines. At the same time, this cannot be considered an easy task to achieve. The reason is that getting into WebGL takes time and effort. Plus, you have to learn how to use GLSL to write the vertex shader and the fragment shader functions. So, things can get more complicated than expected.&lt;/p&gt;
&lt;p&gt;Plus, you learned how to perform non-complex filters, but several filtering techniques are complex and do not involve the convolution operation. That also means that implementing them can be challenging and result in inefficient algorithms.&lt;/p&gt;
&lt;p&gt;To avoid a headache, you should consider a complete and all-in-one solution like &lt;a href=&quot;https://img.ly/products/photo-sdk?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;PhotoEditor SDK&lt;/a&gt;. Commercial solutions make things easier and shield you from all difficulties, offering features that would be complex, time-consuming, and challenging to implement. That is particularly true when it comes to using WebGL, which is &lt;a href=&quot;https://img.ly/docs/pesdk/web/introduction/migration-guide/#canvas-renderer/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;PhotoEditor SDK’s main renderer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You will be able to harness WebGL’s power without writing a single line of GLSL or knowing about its existence. WebGL will be used behind the scene for you! Keep also in mind that you would not be alone, since developers at &lt;a href=&quot;https://img.ly/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;IMG.LY&lt;/a&gt; are happy to provide support.&lt;/p&gt;
&lt;h2 id=&quot;filtering-images-with-photoeditor-sdk&quot;&gt;Filtering Images With PhotoEditor SDK&lt;/h2&gt;
&lt;p&gt;Read the article from &lt;a href=&quot;https://img.ly/docs/pesdk/guides/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;the official documentation&lt;/a&gt; to learn &lt;a href=&quot;https://img.ly/docs/pesdk/web/guides/umd/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;how to get started&lt;/a&gt; with &lt;a href=&quot;https://img.ly/products/photo-sdk&quot;&gt;PhotoEditor SDK&lt;/a&gt; in HTML and Vanilla JavaScript. In detail, the &lt;a href=&quot;https://img.ly/docs/pesdk/web/features/filters/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;Filters&lt;/a&gt; feature gives you more than 60 high-quality filters to play with. Achieve the following result with a few clicks:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;PE.SDK ships with stunning preset filters for aesthetic photo creations.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 600px) 600px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;600&quot; height=&quot;321&quot; src=&quot;https://img.ly/_astro/add-image-filters-webGL-1_1apHk1.webp&quot; srcset=&quot;/_astro/add-image-filters-webGL-1_1apHk1.webp 600w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Check out this feature on the &lt;a href=&quot;https://img.ly/products/photo-sdk/demo&quot;&gt;PhotoEditor SDK demo page&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this article, we looked at how to filter an image in WebGL with the HTML &lt;code&gt;canvas&lt;/code&gt; element. Implementing a feature allowing users to filter images through a kernel-based approach in WebGL involves only a dozen of lines of code. However, understanding how WebGL works and coding in GLSL cannot be considered easy tasks.&lt;/p&gt;
&lt;p&gt;As a result, you might want to avoid dealing with WebGL entirely. In this case, consider a commercial and easy-to-adopt solution using WebGL behind the scene – such as &lt;a href=&quot;https://img.ly/products/photo-sdk?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;PhotoEditor SDK&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks for reading! We hope that you found this article helpful. Feel free to reach out to us on &lt;a href=&quot;https://twitter.com/imgly&quot;&gt;Twitter&lt;/a&gt; with any questions, comments, or suggestions.‌&lt;/p&gt;</content:encoded><dc:creator>Antonello</dc:creator><media:content url="https://blog.img.ly/2022/04/add-filter-image-webgl.png" medium="image"/><category>How-To</category><category>Photo Editing</category><category>Web Development</category><category>App Development</category><category>Photo Editor</category><category>Photo Filter</category><category>Tech</category><category>Tutorial</category></item><item><title>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 Resize and Compress an Image in JavaScript for Upload</title><link>https://img.ly/blog/how-to-compress-an-image-before-uploading-it-in-javascript/</link><guid isPermaLink="true">https://img.ly/blog/how-to-compress-an-image-before-uploading-it-in-javascript/</guid><description>Learn how to downscale an image in JavaScript by reducing its size and quality before uploading it to your server.</description><pubDate>Fri, 04 Mar 2022 16:13:56 GMT</pubDate><content:encoded>&lt;p&gt;In this article, you will learn to compress an image in JavaScript and then upload it to &lt;a href=&quot;https://imgur.com/&quot;&gt;Imgur&lt;/a&gt;. Similar to our previous guide on resizing images, and the one on drawing on images, you can accomplish everything with 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 and we will involve any external libraries for this.&lt;/p&gt;
&lt;p&gt;Smartphones cameras have become increasingly accurate and enhanced their photo quality for years. Consequently, their file size has grown as well. Since the speed of the average network has not improved at the same pace, it is essential to compress the images before uploading them.&lt;/p&gt;
&lt;p&gt;Compressing is about downscaling an image. In other words, you want to reduce either its size or quality or both. By doing so, you can avoid uploading large images, saving the end-user time and money.&lt;/p&gt;
&lt;h2 id=&quot;compressing-an-image-with-canvas&quot;&gt;Compressing an Image With &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;You can clone the &lt;a href=&quot;https://github.com/Tonel/how-to-compress-an-image-in-javascript-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;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;git clone https://github.com/Tonel/how-to-compress-an-image-in-javascript-imgly&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, you can try the demo application by opening the &lt;code&gt;index.html&lt;/code&gt; file in your browser.&lt;/p&gt;
&lt;p&gt;Otherwise, keep following this step-by-step tutorial and learn how to build the demo application.&lt;/p&gt;
&lt;h3 id=&quot;1-implementing-the-compression-logic&quot;&gt;1. Implementing the Compression Logic&lt;/h3&gt;
&lt;p&gt;You can compress an image by solely using the HTML &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API&quot;&gt;&lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt;&lt;/a&gt; element. This is a powerful image manipulation tool that allows you to achieve many results, as we have already explored &lt;a href=&quot;https://img.ly/blog/tag/javascript/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;in our blog&lt;/a&gt;.&lt;br&gt;
Now, let’s delve into how to compress an image with &lt;code&gt;canvas&lt;/code&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; compressImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;imgToCompress&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;resizingFactor&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;quality&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // resizing 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; canvas&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;createElement&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;canvas&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; context&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; canvas.&lt;/span&gt;&lt;span&gt;getContext&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;2d&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; originalWidth&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; imgToCompress.width;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; originalHeight&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; imgToCompress.height;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvasWidth&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; originalWidth &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; resizingFactor;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvasHeight&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; originalHeight &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; resizingFactor;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  canvas.width &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; canvasWidth;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  canvas.height &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; canvasHeight;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  context.&lt;/span&gt;&lt;span&gt;drawImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    imgToCompress,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    originalWidth &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; resizingFactor,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    originalHeight &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; resizingFactor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // reducing the quality of the image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  canvas.&lt;/span&gt;&lt;span&gt;toBlob&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    (&lt;/span&gt;&lt;span&gt;blob&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      if&lt;/span&gt;&lt;span&gt; (blob) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // showing the compressed image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        resizedImage.src &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; URL&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;createObjectURL&lt;/span&gt;&lt;span&gt;(resizedImageBlob);&lt;/span&gt;&lt;/span&gt;
&lt;span 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;    &apos;image/jpeg&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    quality&lt;/span&gt;&lt;/span&gt;
&lt;span 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;This function is an extension of the &lt;code&gt;resizeImage()&lt;/code&gt; function defined in &lt;a href=&quot;https://img.ly/blog/how-to-resize-an-image-with-javascript/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;this&lt;/a&gt; article. So, follow the link to that tutorial to learn more about it.&lt;/p&gt;
&lt;p&gt;What is new here are the last few lines, which take care of reducing the quality of the uploaded image based on the &lt;code&gt;quality&lt;/code&gt; parameter. As you can see, the last part of the &lt;code&gt;compressImage()&lt;/code&gt;is based on the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob&quot;&gt;&lt;code&gt;toBlob()&lt;/code&gt;&lt;/a&gt; function. This transforms the image stored in the canvas into a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Blob&quot;&gt;&lt;code&gt;Blob&lt;/code&gt;&lt;/a&gt; object and compresses it based on the last parameter passed to the function. This last parameter represents the quality of the target image file.&lt;/p&gt;
&lt;p&gt;Just like &lt;code&gt;resizingFactor&lt;/code&gt;, &lt;code&gt;quality&lt;/code&gt; must contain a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number&quot;&gt;&lt;code&gt;Number&lt;/code&gt;&lt;/a&gt; between 0 and 1.&lt;/p&gt;
&lt;p&gt;Also, since the &lt;code&gt;toBlob()&lt;/code&gt; function returns a &lt;code&gt;Blob&lt;/code&gt; object, you can store it in a global variable. Then, you can use the &lt;code&gt;blob&lt;/code&gt; object representing the compressed image file to upload it to your server. Let’s see how.&lt;/p&gt;
&lt;h3 id=&quot;2-uploading-an-image-to-imgur&quot;&gt;2. Uploading an Image to Imgur&lt;/h3&gt;
&lt;p&gt;First, you need an Imgur account. If you already have one, log in &lt;a href=&quot;https://imgur.com/signin&quot;&gt;here&lt;/a&gt;. Otherwise, create a new account for free &lt;a href=&quot;https://imgur.com/register&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now, register an application &lt;a href=&quot;https://imgur.com/signin?redirect=https%3A%2F%2Fapi.imgur.com%2Foauth2%2Faddclient&quot;&gt;here&lt;/a&gt; to have access to the &lt;a href=&quot;https://apidocs.imgur.com/&quot;&gt;Imgur API program&lt;/a&gt;. Fill out the form as follows:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Registering an application on Imgur&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 749px) 749px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;749&quot; height=&quot;926&quot; src=&quot;https://img.ly/_astro/n118lrk_Z23SXGl.webp&quot; srcset=&quot;/_astro/n118lrk_ZpISqw.webp 640w, /_astro/n118lrk_Z23SXGl.webp 749w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Then, click on “Submit” and you should get access to this page.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The Client-ID Imgur page&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 732px) 732px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;732&quot; height=&quot;392&quot; src=&quot;https://img.ly/_astro/6wGxX79_1YAY5d.webp&quot; srcset=&quot;/_astro/6wGxX79_7amGE.webp 640w, /_astro/6wGxX79_1YAY5d.webp 732w&quot;&gt;&lt;/p&gt;
&lt;p&gt;Store your &lt;code&gt;Client-ID&lt;/code&gt; in a safe place. You will need it later.&lt;br&gt;
Now, you have everything required to start uploading images to your Imgur application.&lt;/p&gt;
&lt;p&gt;Uploading an image to Imgur in JavaScript is easy and can be achieved with just a bunch of lines of code, as 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;// compressedImageBlob represents the compressed image Blob to upload&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; formdata&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; FormData&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;formdata.&lt;/span&gt;&lt;span&gt;append&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;image&apos;&lt;/span&gt;&lt;span&gt;, compressedImageBlob);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;fetch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;https://api.imgur.com/3/image/&apos;&lt;/span&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;POST&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;    Authorization: &lt;/span&gt;&lt;span&gt;&apos;Client-ID YOUR_CLIENT_ID&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;  body: formdata,&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;response&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; (response?.status &lt;/span&gt;&lt;span&gt;===&lt;/span&gt;&lt;span&gt; 403&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;error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;Unvalid Client-ID!&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; (response?.status &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;    // retrieving the URL of the image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // just uploaded to Imgur&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    response.&lt;/span&gt;&lt;span&gt;json&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;jsonResponse&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;(&lt;/span&gt;&lt;span&gt;`URL: ${&lt;/span&gt;&lt;span&gt;jsonResponse&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;link&lt;/span&gt;&lt;span&gt;}`&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  } &lt;/span&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;    console.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(response);&lt;/span&gt;&lt;/span&gt;
&lt;span 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;Replace &lt;code&gt;YOUR_CLIENT_ID&lt;/code&gt; with the &lt;code&gt;Client-ID&lt;/code&gt; retrieved before, and you should now be able to use this snippet to upload your images to Imgur.&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;Now it is time to see the &lt;code&gt;compressImage()&lt;/code&gt; function in action through a simple example.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;!&lt;/span&gt;&lt;span&gt;DOCTYPE&lt;/span&gt;&lt;span&gt; html&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;html&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &amp;#x3C;&lt;/span&gt;&lt;span&gt;body&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;h1&lt;/span&gt;&lt;span&gt;&gt;Compress and Resize an 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;p&lt;/span&gt;&lt;span&gt;&gt;Upload an image and compress it or use the following demo image&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;&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;
&lt;span class=&quot;line&quot;&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;originalImage&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;&quot;demo.jpg&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        crossorigin&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;anonymous&quot;&lt;/span&gt;&lt;/span&gt;
&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; 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;Resizing: &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;range&quot;&lt;/span&gt;&lt;span&gt; min&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;1&quot;&lt;/span&gt;&lt;span&gt; max&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;100&quot;&lt;/span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;80&quot;&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;resizingRange&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;div&lt;/span&gt;&lt;span&gt; style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;margin-top: 5px; margin-left: 8px;&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;Quality: &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;range&quot;&lt;/span&gt;&lt;span&gt; min&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;1&quot;&lt;/span&gt;&lt;span&gt; max&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;100&quot;&lt;/span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;80&quot;&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;qualityRange&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;h2&lt;/span&gt;&lt;span&gt;&gt;Compressed 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;div&lt;/span&gt;&lt;span&gt;&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&gt;Size:&amp;#x3C;/&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&gt; &amp;#x3C;&lt;/span&gt;&lt;span&gt;span&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;size&quot;&lt;/span&gt;&lt;span&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;span&lt;/span&gt;&lt;span&gt;&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;img&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;compressedImage&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;button&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;uploadButton&quot;&lt;/span&gt;&lt;span&gt;&gt;Upload to Imgur&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;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;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;const&lt;/span&gt;&lt;span&gt; originalImage&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;#originalImage&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; compressedImage&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;#compressedImage&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; resizingElement&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;#resizingRange&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; qualityElement&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;#qualityRange&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; uploadButton&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;#uploadButton&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; compressedImageBlob;&lt;/span&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; resizingFactor &lt;/span&gt;&lt;span&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;let&lt;/span&gt;&lt;span&gt; quality &lt;/span&gt;&lt;span&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// initializing the compressed image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;compressImage&lt;/span&gt;&lt;span&gt;(originalImage, resizingFactor, quality);&lt;/span&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;  // storing the original image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  originalImage.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;  // compressing the uplodaded image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  originalImage.&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;    compressImage&lt;/span&gt;&lt;span&gt;(originalImage, resizingFactor, quality);&lt;/span&gt;&lt;/span&gt;
&lt;span 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; 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;resizingElement.&lt;/span&gt;&lt;span&gt;oninput&lt;/span&gt;&lt;span&gt; =&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;  resizingFactor &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; parseInt&lt;/span&gt;&lt;span&gt;(e.target.value) &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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  compressImage&lt;/span&gt;&lt;span&gt;(originalImage, resizingFactor, quality);&lt;/span&gt;&lt;/span&gt;
&lt;span 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;qualityElement.&lt;/span&gt;&lt;span&gt;oninput&lt;/span&gt;&lt;span&gt; =&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;  quality &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; parseInt&lt;/span&gt;&lt;span&gt;(e.target.value) &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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  compressImage&lt;/span&gt;&lt;span&gt;(originalImage, resizingFactor, quality);&lt;/span&gt;&lt;/span&gt;
&lt;span 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;uploadButton.&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;  // uploading the compressed image to&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // Imgur (if present)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (compressedImageBlob) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; formdata&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; FormData&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    formdata.&lt;/span&gt;&lt;span&gt;append&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;image&apos;&lt;/span&gt;&lt;span&gt;, compressedImageBlob);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    fetch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;https://api.imgur.com/3/image/&apos;&lt;/span&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;POST&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;        Authorization: &lt;/span&gt;&lt;span&gt;&apos;Client-ID YOUR_CLIENT_ID&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;      body: formdata,&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;response&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; (response?.status &lt;/span&gt;&lt;span&gt;===&lt;/span&gt;&lt;span&gt; 403&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        alert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;Unvalid Client-ID!&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; (response?.status &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;        // retrieving the URL of the image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // just uploaded to Imgur&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        response.&lt;/span&gt;&lt;span&gt;json&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;jsonResponse&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;          alert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;`URL: ${&lt;/span&gt;&lt;span&gt;jsonResponse&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;link&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;        alert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;Upload completed succesfully!&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;        console.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(response);&lt;/span&gt;&lt;/span&gt;
&lt;span 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;else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    alert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;Rezind and compressed image missing!&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; compressImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;imgToCompress&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;resizingFactor&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;quality&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // showing the compressed image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvas&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;createElement&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;canvas&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; context&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; canvas.&lt;/span&gt;&lt;span&gt;getContext&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;2d&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; originalWidth&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; imgToCompress.width;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; originalHeight&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; imgToCompress.height;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvasWidth&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; originalWidth &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; resizingFactor;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvasHeight&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; originalHeight &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; resizingFactor;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  canvas.width &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; canvasWidth;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  canvas.height &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; canvasHeight;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  context.&lt;/span&gt;&lt;span&gt;drawImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    imgToCompress,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    originalWidth &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; resizingFactor,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    originalHeight &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; resizingFactor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // reducing the quality of the image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  canvas.&lt;/span&gt;&lt;span&gt;toBlob&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    (&lt;/span&gt;&lt;span&gt;blob&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      if&lt;/span&gt;&lt;span&gt; (blob) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        compressedImageBlob &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; blob;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        compressedImage.src &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;createObjectURL&lt;/span&gt;&lt;span&gt;(compressedImageBlob);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&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;#size&apos;&lt;/span&gt;&lt;span&gt;).innerHTML &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; bytesToSize&lt;/span&gt;&lt;span&gt;(blob.size);&lt;/span&gt;&lt;/span&gt;
&lt;span 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;    &apos;image/jpeg&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    quality&lt;/span&gt;&lt;/span&gt;
&lt;span 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; 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;// source: https://stackoverflow.com/a/18650828&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; bytesToSize&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;bytes&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  var&lt;/span&gt;&lt;span&gt; sizes &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;&apos;Bytes&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;KB&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;MB&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;GB&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;TB&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;  if&lt;/span&gt;&lt;span&gt; (bytes &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;    return&lt;/span&gt;&lt;span&gt; &apos;0 Byte&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;  const&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; parseInt&lt;/span&gt;&lt;span&gt;(Math.&lt;/span&gt;&lt;span&gt;floor&lt;/span&gt;&lt;span&gt;(Math.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(bytes) &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; Math.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1024&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; Math.&lt;/span&gt;&lt;span&gt;round&lt;/span&gt;&lt;span&gt;(bytes &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; Math.&lt;/span&gt;&lt;span&gt;pow&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1024&lt;/span&gt;&lt;span&gt;, i), &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; &apos; &apos;&lt;/span&gt;&lt;span&gt; +&lt;/span&gt;&lt;span&gt; sizes[i];&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;input&lt;/code&gt; element allows users to upload an image. This is then passed to the &lt;code&gt;compressImage()&lt;/code&gt; function along with the &lt;code&gt;resizingFactor&lt;/code&gt; and &lt;code&gt;quality&lt;/code&gt; values retrieved from the respective &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/range&quot;&gt;range &lt;code&gt;input&lt;/code&gt;&lt;/a&gt; HTML elements. This function takes care of compressing the image, displaying it, and storing its &lt;code&gt;Blob&lt;/code&gt; representation to the global &lt;code&gt;compressedImageBlob&lt;/code&gt; variable. Finally, &lt;code&gt;compressedImageBlob&lt;/code&gt; is uploaded to Imgur when the “Upload to Imgur” button is clicked.&lt;br&gt;
Notice that these two snippets are what allow you to implement the live example 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;Compressing an image in Vanilla JavaScript is easy. You can achieve this with no extra libraries and in a dozen of lines of code. At the same time, the resizing part of the process relies on an &lt;a href=&quot;https://entropymine.com/resamplescope/notes/browsers/&quot;&gt;image interpolation algorithm&lt;/a&gt; that changes according to the browser in use. This can lead to different results based on the end-user’s browser. Also, compressing while preserving quality is always tricky and can easily become a grueling goal to achieve.&lt;br&gt;
If you want to avoid this stress, consider adopting a commercial and browser-consistent solution like &lt;a href=&quot;https://img.ly/products/photo-sdk&quot;&gt;PhotoEditorSDK&lt;/a&gt;. This library provides access to a wide set of tools that allow you to manipulate your images in many ways and with an advanced and easy-to-use UI.&lt;/p&gt;
&lt;h2 id=&quot;resizing-an-image-with-photoeditor-sdk&quot;&gt;Resizing an Image with PhotoEditor SDK&lt;/h2&gt;
&lt;p&gt;First, 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; to get started with &lt;code&gt;PhotoEditorSDK&lt;/code&gt; in HTML and JavaScript. Then, you can use the &lt;a href=&quot;https://img.ly/docs/pesdk/web/features/transform/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;transform tool&lt;/a&gt; to &lt;a href=&quot;https://img.ly/docs/pesdk/web/features/transform/#image-resizing/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;resize&lt;/a&gt; your image, as shown below:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;resize-compress-javascript&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1206px) 1206px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1206&quot; height=&quot;647&quot; src=&quot;https://img.ly/_astro/resize-compress-javascript_Z1qzgpW.webp&quot; srcset=&quot;/_astro/resize-compress-javascript_ZkEPQy.webp 640w, /_astro/resize-compress-javascript_A4gEv.webp 750w, /_astro/resize-compress-javascript_1bihsS.webp 828w, /_astro/resize-compress-javascript_NDXgO.webp 1080w, /_astro/resize-compress-javascript_Z1qzgpW.webp 1206w&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?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&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;In this article, we learned how to downscale an image in JavaScript before uploading it to your server. In detail, we resized and reduced the quality of an uploaded image before uploading it to Imgur. Everything was achieved by using only the HTML5 &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt; element. This is a powerful tool supported by most browsers that allows you to resize and change the quality of an image with just a few lines of code. On the other hand, this process may not be browser-consistent. That is why we also introduced a commercial and more reliable 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. 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/03/compress-resize-images-javascript-2.png" medium="image"/><category>How-To</category><category>JavaScript</category><category>Photo Editing</category><category>Web Development</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>How to Add a Watermark to an Image in JavaScript</title><link>https://img.ly/blog/how-to-add-watermark-javascript/</link><guid isPermaLink="true">https://img.ly/blog/how-to-add-watermark-javascript/</guid><description>Create watermarks in Vanilla JavaScript and with watermarkjs!</description><pubDate>Tue, 07 Dec 2021 15:54:32 GMT</pubDate><content:encoded>&lt;p&gt;In this tutorial, you will learn how to watermark an image in both Vanilla JavaScript and with &lt;a href=&quot;https://www.npmjs.com/package/watermarkjs&quot;&gt;&lt;code&gt;watermarkjs&lt;/code&gt;&lt;/a&gt;. The first approach is primarily based on 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 which can be used for applying filters or &lt;a href=&quot;https://img.ly/blog/how-to-compress-an-image-before-uploading-it-in-javascript/&quot;&gt;resizing an image&lt;/a&gt;, while the second one involves a popular npm library.&lt;/p&gt;
&lt;p&gt;A watermark is a marker deliberately embedded in an audio, video, or image data source, generally used to claim ownership of that source. In the case of an image, a watermark can be represented by text or another image. So, image watermarking is the process of placing an overlay image or text on top of the original image, usually in one of the corners.&lt;/p&gt;
&lt;p&gt;Now, let’s see two methods to watermark an image in JavaScript. Follow this step-by-step tutorial and learn how to implement this demo:&lt;/p&gt;
&lt;h2 id=&quot;watermarking-images-in-javascript&quot;&gt;Watermarking Images in JavaScript&lt;/h2&gt;
&lt;p&gt;Keep following this step-by-step tutorial to learn how to watermarker an image in JavaScript. Otherwise, clone the following &lt;a href=&quot;https://github.com/Tonel/how-to-watermark-an-image-img-ly&quot;&gt;GitHub repository supporting the article&lt;/a&gt; by launching this command:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;git clone https://github.com/Tonel/how-to-watermark-an-image-img-ly&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, open the &lt;code&gt;index.html&lt;/code&gt; file in your browser to give a look at the real-world demo you are about to see how to build.&lt;/p&gt;
&lt;h3 id=&quot;1a-implementing-the-watermarking-logic-using-html5-canvas&quot;&gt;1.A Implementing the watermarking logic using HTML5 &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;With this approach, you can achieve the watermarking goal by employing solely 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. In other words, there are no prerequisites.&lt;/p&gt;
&lt;p&gt;Let’s see in detail how to use a watermark image and a watermark text to an image in JavaScript:&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;async&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; watermarkImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;originalImage&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;watermarkImagePath&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvas&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;createElement&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;canvas&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; context&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; canvas.&lt;/span&gt;&lt;span&gt;getContext&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;2d&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvasWidth&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; originalImage.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; originalImage.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;  // initializing the canvas with the original image&lt;/span&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;(originalImage, &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;  // loading the watermark image and transforming it into a pattern&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; result&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;(watermarkImagePath);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; blob&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; result.&lt;/span&gt;&lt;span&gt;blob&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; image&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; createImageBitmap&lt;/span&gt;&lt;span&gt;(blob);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; pattern&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; context.&lt;/span&gt;&lt;span&gt;createPattern&lt;/span&gt;&lt;span&gt;(image, &lt;/span&gt;&lt;span&gt;&apos;no-repeat&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;  // translating the watermark image to the bottom right corner&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  context.&lt;/span&gt;&lt;span&gt;translate&lt;/span&gt;&lt;span&gt;(canvasWidth &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; image.width, canvasHeight &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; image.height);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  context.&lt;/span&gt;&lt;span&gt;rect&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;  context.fillStyle &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; pattern;&lt;/span&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; watermarkImageWithText&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;originalImage&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;watermarkText&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvas&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;createElement&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;canvas&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; context&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; canvas.&lt;/span&gt;&lt;span&gt;getContext&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;2d&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvasWidth&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; originalImage.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; originalImage.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;  // initializing the canvas with the original image&lt;/span&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;(originalImage, &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;  // adding a blue watermark text in the bottom right corner&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;blue&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  context.textBaseline &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;middle&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  context.font &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;bold 25px serif&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;fillText&lt;/span&gt;&lt;span&gt;(watermarkText, canvasWidth &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; 100&lt;/span&gt;&lt;span&gt;, canvasHeight &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;  return&lt;/span&gt;&lt;span&gt; canvas.&lt;/span&gt;&lt;span&gt;toDataURL&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In both cases, an in-memory HTML &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt; with a 2D rendering context having the same size as the original image is created. Then, it is filled by drawing the original image inside it. From that point, the two functions follow different approaches to achieve the watermarking goal.&lt;/p&gt;
&lt;p&gt;In the &lt;code&gt;watermarkImage()&lt;/code&gt; function, the watermark image path passed as a parameter is used to load the image file. Then, it is transformed into an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap&quot;&gt;&lt;code&gt;ImageBitmap&lt;/code&gt;&lt;/a&gt; object by using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/createImageBitmap&quot;&gt;&lt;code&gt;createImageBitmap()&lt;/code&gt;&lt;/a&gt; function. This is necessary because the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/createPattern&quot;&gt;&lt;code&gt;createPattern()&lt;/code&gt;&lt;/a&gt; function requires such a data structure to create a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CanvasPattern&quot;&gt;&lt;code&gt;CanvasPattern&lt;/code&gt;&lt;/a&gt; object that can be used to draw a particular image over a non-empty canvas. In particular, the drawing operation involves a rectangle containing the pattern created with the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/rect&quot;&gt;&lt;code&gt;rect()&lt;/code&gt;&lt;/a&gt; function. This is first translated to the required position and finally drawn with the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fill&quot;&gt;&lt;code&gt;fill()&lt;/code&gt;&lt;/a&gt; function.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;watermarkImageWithText()&lt;/code&gt; function is simpler. This is because the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D&quot;&gt;&lt;code&gt;CanvasRenderingContext2D&lt;/code&gt;&lt;/a&gt; natively comes with the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillText&quot;&gt;&lt;code&gt;fillText()&lt;/code&gt;&lt;/a&gt; function, which allows you to add text to an image with no effort.&lt;/p&gt;
&lt;p&gt;If you want to learn more on how to style the watermark image or text, reading &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillStyle&quot;&gt;this&lt;/a&gt; page from &lt;a href=&quot;https://developer.mozilla.org/en-US/&quot;&gt;MDN Web Docs&lt;/a&gt; is recommended.&lt;/p&gt;
&lt;h3 id=&quot;1b-implementing-the-watermarking-logic-using-watermarkjs&quot;&gt;1.B Implementing the watermarking logic using &lt;code&gt;watermarkjs&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The same result can be achieved by using the &lt;a href=&quot;https://www.npmjs.com/package/watermarkjs&quot;&gt;&lt;code&gt;watermarkjs&lt;/code&gt;&lt;/a&gt; library with just a bunch of lines of code. In this case, you have to add it as a dependency to your project and you can learn how to do it &lt;a href=&quot;https://www.npmjs.com/package/watermarkjs&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The two aforementioned function can now be implemented 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; watermarkImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;originalImageFile&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;watermarkImagePath&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;destinationImage&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  watermark&lt;/span&gt;&lt;span&gt;([originalImageFile, watermarkImagePath])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    .&lt;/span&gt;&lt;span&gt;image&lt;/span&gt;&lt;span&gt;(watermark.image.&lt;/span&gt;&lt;span&gt;lowerRight&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;function&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;watermarkedImage&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      destinationImage &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; watermarkedImage.src;&lt;/span&gt;&lt;/span&gt;
&lt;span 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; watermarkImageWithText&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;originalImageFile&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;watermarkText&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;destinationImage&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  watermark&lt;/span&gt;&lt;span&gt;([originalImageFile, watermarkImagePath])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    .&lt;/span&gt;&lt;span&gt;image&lt;/span&gt;&lt;span&gt;(watermark.text.&lt;/span&gt;&lt;span&gt;lowerRight&lt;/span&gt;&lt;span&gt;(watermarkText, &lt;/span&gt;&lt;span&gt;&quot;bold 25px serif&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;#0000ff&quot;&lt;/span&gt;&lt;span&gt;)))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    .&lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;watermarkedImage&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      destinationImage &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; watermarkedImage.src;&lt;/span&gt;&lt;/span&gt;
&lt;span 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 main difference from the first method is that the &lt;code&gt;watermark&lt;/code&gt; object coming with the library accepts either a URL path to the image or its &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/File&quot;&gt;&lt;code&gt;File&lt;/code&gt;&lt;/a&gt; object. Then, it requires the destination image to write the generated watermarked image.&lt;/p&gt;
&lt;p&gt;You can find more demos on the library’s &lt;a href=&quot;https://github.com/brianium/watermarkjs&quot;&gt;GitHub page&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;2-watermarking-in-action&quot;&gt;2. Watermarking in action&lt;/h3&gt;
&lt;p&gt;Let’s now see how to employ the &lt;code&gt;watermarkImage()&lt;/code&gt; and &lt;code&gt;watermarkImageWithText()&lt;/code&gt; functions to build a real-word example.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;!&lt;/span&gt;&lt;span&gt;DOCTYPE&lt;/span&gt;&lt;span&gt; html&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;html&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &amp;#x3C;&lt;/span&gt;&lt;span&gt;body&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;h1&lt;/span&gt;&lt;span&gt;&gt;Image Watermarker&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;Please, upload an image and a watermark will be added&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;originalImage&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;Watermarked image 1 (image watermark)&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;watermarkedImage&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;Watermarked image 2 (text watermark)&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;watermarkedImageWithText&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;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;  // displaying the uploaded image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; originalImage&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;#originalImage&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  originalImage.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;  // adding the image watermark to the original image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // and showing the watermarked image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; watermarkedImage&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;#watermarkedImage&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; watermarkedImageWithText&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &apos;#watermarkedImageWithText&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;  originalImage.&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;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;    watermarkedImage.src &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; watermarkImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      originalImage,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &apos;./src/IMG.LY.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;    watermarkedImageWithText.src &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; watermarkImageWithText&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      originalImage,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &apos;IMG.LY&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;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;  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;
&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;async&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; watermarkImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;originalImage&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;watermarkImagePath&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvas&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;createElement&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;canvas&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; context&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; canvas.&lt;/span&gt;&lt;span&gt;getContext&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;2d&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvasWidth&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; originalImage.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; originalImage.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;  // initializing the canvas with the original image&lt;/span&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;(originalImage, &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;  // loading the watermark image and transforming it into a pattern&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; result&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;(watermarkImagePath);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; blob&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; result.&lt;/span&gt;&lt;span&gt;blob&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; image&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; createImageBitmap&lt;/span&gt;&lt;span&gt;(blob);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; pattern&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; context.&lt;/span&gt;&lt;span&gt;createPattern&lt;/span&gt;&lt;span&gt;(image, &lt;/span&gt;&lt;span&gt;&apos;no-repeat&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;  // translating the watermark image to the bottom right corner&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  context.&lt;/span&gt;&lt;span&gt;translate&lt;/span&gt;&lt;span&gt;(canvasWidth &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; image.width, canvasHeight &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; image.height);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  context.&lt;/span&gt;&lt;span&gt;rect&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;  context.fillStyle &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; pattern;&lt;/span&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; watermarkImageWithText&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;originalImage&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;watermarkText&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvas&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;createElement&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;canvas&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; context&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; canvas.&lt;/span&gt;&lt;span&gt;getContext&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;2d&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvasWidth&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; originalImage.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; originalImage.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;  // initializing the canvas with the original image&lt;/span&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;(originalImage, &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;  // adding a blue watermark text in the bottom right corner&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;blue&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  context.textBaseline &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;middle&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  context.font &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;bold 25px serif&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;fillText&lt;/span&gt;&lt;span&gt;(watermarkText, canvasWidth &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; 100&lt;/span&gt;&lt;span&gt;, canvasHeight &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;  return&lt;/span&gt;&lt;span&gt; canvas.&lt;/span&gt;&lt;span&gt;toDataURL&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The second snipper represents the &lt;code&gt;src/index.js&lt;/code&gt; file and this is where the complete logic is implemented. First, users can upload an image thanks to the &lt;code&gt;&amp;#x3C;input&gt;&lt;/code&gt; tag. Then, the two aforementioned functions are used to produce two watermarked images that are finally shown on the page. To make this application works, note that the &lt;code&gt;&quot;./src/IMG.LY.jpg&quot;&lt;/code&gt; path should be replaced with the relative path to your watermark image.&lt;/p&gt;
&lt;h2 id=&quot;final-considerations&quot;&gt;Final Considerations&lt;/h2&gt;
&lt;p&gt;Although watermarking does not involve complex logic, it does present some challenges. In fact, the approaches presented above cannot but be considered basic. This is because to properly implement watermarking, you should allow users to choose where precisely to place the watermark, with what style and colors, and with the desired size. Otherwise, the final result may be inaccurate and completely alter the original image.&lt;/p&gt;
&lt;p&gt;In other words, giving users the ability to add a watermark to an image requires an advanced UI. Building it may be complex, time-consuming, and represent a waste of energy. Especially considering how such a feature may be marginal in your application. This is why you should take into consideration an advanced SDK solution, such as &lt;a href=&quot;https://img.ly/products/photo-sdk?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;PhotoEditorSDK&lt;/a&gt;. This allows you to provide users with watermarking, and many other cool features.&lt;/p&gt;
&lt;h2 id=&quot;adding-a-watermark-to-an-image-with-photoeditorsdk&quot;&gt;Adding a Watermark to an Image 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;First, 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 article&lt;/a&gt; from the official documentation on how to get started with PhotoEditorSDK in Vanilla JavaScript. By uploading an image 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;, you can place another image on top of the original one whenever you want. This allows you to achieve a watermark effect with no effort.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;add-watermark-sticker-javascript&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1206px) 1206px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1206&quot; height=&quot;647&quot; src=&quot;https://img.ly/_astro/add-watermark-sticker-javascript_Z1SEjng.webp&quot; srcset=&quot;/_astro/add-watermark-sticker-javascript_ZsYh8o.webp 640w, /_astro/add-watermark-sticker-javascript_Z45T6H.webp 750w, /_astro/add-watermark-sticker-javascript_Z2lloyt.webp 828w, /_astro/add-watermark-sticker-javascript_1cCj3Q.webp 1080w, /_astro/add-watermark-sticker-javascript_Z1SEjng.webp 1206w&quot;&gt;&lt;br&gt;
Check out this feature in the &lt;a href=&quot;https://img.ly/products/photo-sdk/demo?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;demo&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial, we learned how to watermark an image in both Vanilla JavaScript and &lt;code&gt;watermarkjs&lt;/code&gt;. The first approach involved the HTML5 &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt;, which makes adding a watermark to an image easy. The second is even more straightforward and requires just a few lines of code. In both cases, the task is almost effortless. On the other hand, implementing a watermark feature that allows users to deal with the watermark image with freedom requires an entire UI. Building it takes time and effort, and may do not want to waste time on it. In this case, you should adopt a more complete, advanced, and ready-to-use solution – such as &lt;a href=&quot;https://img.ly/products/photo-sdk?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;PhotoEditorSDK&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&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;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Antonello</dc:creator><media:content url="https://blog.img.ly/2021/12/watermark-sticker-javascript-1.png" medium="image"/><category>How-To</category><category>JavaScript</category><category>Photo Editing</category><category>Stickers</category><category>App Development</category><category>Web Development</category><category>Tutorial</category></item><item><title>How To Pixelate an Image in JavaScript</title><link>https://img.ly/blog/how-to-pixelate-an-image-in-javascript/</link><guid isPermaLink="true">https://img.ly/blog/how-to-pixelate-an-image-in-javascript/</guid><description>Pixelate an image in Vanilla JavaScript without any libraries – with the &lt;canvas&gt; element!</description><pubDate>Thu, 14 Oct 2021 12:20:03 GMT</pubDate><content:encoded>&lt;p&gt;In this tutorial, you will learn how to pixelate an image in Vanilla JavaScript, without any libraries. As you are about to see, you can achieve this easily by using 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;Recently, websites and applications have implemented policies to prevent users from accidentally stumbling across explicit content. The most common approach to avoid this when it comes to images and photos is to pixelate them. Such a solution is so common that every frontend developer should know how to pixelate an image.&lt;/p&gt;
&lt;p&gt;So, let’s learn how to make an image pixelated with JavaScript. By following this step-by-step tutorial, you will be able to implement the following &lt;a href=&quot;https://codesandbox.io/s/how-to-pixelate-an-image-in-javascript-forked-0kpqe&quot;&gt;demo&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;pixelating-images-using-html5-canvas&quot;&gt;Pixelating Images Using HTML5 &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Clone the &lt;a href=&quot;https://github.com/Tonel/crop-image-react-demo-imgly&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://github.com/Tonel/how-to-pixelate-an-image-img-ly&quot;&gt;GitHub repository supporting this article&lt;/a&gt; by launching 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-pixelate-an-image-img-ly&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, open the &lt;code&gt;index.html&lt;/code&gt; file to immediately try the demo application.&lt;/p&gt;
&lt;p&gt;Or keep reading this tutorial and build that demo application step by step.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Implementing the pixelation logic&lt;/strong&gt;&lt;br&gt;
Since, you can achieve the desired goal with 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, there are no prerequisites. Specifically, this HTML element allows you to extract the array of pixels representing an image 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 this is what is needed to pixelate an image. Let’s see how in detail:&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; pixelateImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;originalImage&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;pixelationFactor&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvas&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;createElement&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;canvas&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; context&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; canvas.&lt;/span&gt;&lt;span&gt;getContext&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;2d&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; originalWidth&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; originalImage.width;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; originalHeight&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; originalImage.height;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvasWidth&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; originalWidth;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvasHeight&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; originalHeight;&lt;/span&gt;&lt;/span&gt;
&lt;span 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;  context.&lt;/span&gt;&lt;span&gt;drawImage&lt;/span&gt;&lt;span&gt;(originalImage, &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;, originalWidth, originalHeight);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; originalImageData&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    originalWidth,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    originalHeight&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ).data;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (pixelationFactor &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;    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; originalHeight; y &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; pixelationFactor) {&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; originalWidth; x &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; pixelationFactor) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // extracting the position of the sample pixel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        const&lt;/span&gt;&lt;span&gt; pixelIndexPosition&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; (x &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; y &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; originalWidth) &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;        // drawing a square replacing the current pixels&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; `rgba(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          ${&lt;/span&gt;&lt;span&gt;originalImageData&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;pixelIndexPosition&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;originalImageData&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;pixelIndexPosition&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          ${&lt;/span&gt;&lt;span&gt;originalImageData&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;pixelIndexPosition&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          ${&lt;/span&gt;&lt;span&gt;originalImageData&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;pixelIndexPosition&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        )`&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        context.&lt;/span&gt;&lt;span&gt;fillRect&lt;/span&gt;&lt;span&gt;(x, y, pixelationFactor, pixelationFactor);&lt;/span&gt;&lt;/span&gt;
&lt;span 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;  originalImage.src &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; canvas.&lt;/span&gt;&lt;span&gt;toDataURL&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First, an in-memory HTML &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt; with a 2D rendering context having the same size as the original image to be pixelated is initialized. Next, the original image is drawn into the canvas with the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage&quot;&gt;&lt;code&gt;drawImage()&lt;/code&gt;&lt;/a&gt; function. This is required to call the &lt;code&gt;getImageData()&lt;/code&gt; function, which allows you to retrieve the list of pixels. Do this by accessing the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/ImageData/data&quot;&gt;&lt;code&gt;data&lt;/code&gt;&lt;/a&gt; attribute. You will get a one-dimensional array containing the value of the pixels in RGBA order. Particularly, it stores values as an integer between 0 and 255, and each pixel is represented by 4 consecutive values. So, the size of this array will be 4 times of the number pixels.&lt;/p&gt;
&lt;p&gt;Then, the pixels are iterated by using &lt;code&gt;pixelFactor&lt;/code&gt; as the increment factor. In other words, this variable is used to extract the sample pixel, whose four RGBA values will be employed to draw a square. These squares will give the image the pixelated effect. So, at the end of the cycles, the image will look pixelated.&lt;/p&gt;
&lt;p&gt;Et voilà! As you just learned, pixelating an image in Vanilla JavaScript requires only a bunch of lines of code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Pixelation in action&lt;/strong&gt;&lt;br&gt;
Let’s now see how to use the &lt;code&gt;pixelateImage()&lt;/code&gt; function to implement a real-world example.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;!&lt;/span&gt;&lt;span&gt;DOCTYPE&lt;/span&gt;&lt;span&gt; html&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;html&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &amp;#x3C;&lt;/span&gt;&lt;span&gt;body&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;h1&lt;/span&gt;&lt;span&gt;&gt;Pixelate an 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;p&lt;/span&gt;&lt;span&gt;&gt;Upload an image or pixelate the following demo image&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;&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;        style&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;margin-top: 5px;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;pixelatedImage&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;&quot;demo.jpg&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        crossorigin&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;anonymous&quot;&lt;/span&gt;&lt;/span&gt;
&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; 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;Pixelation: &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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        type&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;range&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        min&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;0&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        max&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;10&quot;&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;&quot;0&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        step&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;1&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;pixelation&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;pixelationRange&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;/&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;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;const&lt;/span&gt;&lt;span&gt; pixelatedImage&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;#pixelatedImage&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// storying a copy of the original image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; originalImage&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; pixelatedImage.&lt;/span&gt;&lt;span&gt;cloneNode&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;const&lt;/span&gt;&lt;span&gt; pixelationElement&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;#pixelationRange&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;fileInput.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;change&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;file&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; fileInput.files;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // showing the uploaded image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  pixelatedImage.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;  // storing the original image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  originalImage.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;  pixelationElement.value &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; 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;pixelationElement.&lt;/span&gt;&lt;span&gt;oninput&lt;/span&gt;&lt;span&gt; =&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;  pixelateImage&lt;/span&gt;&lt;span&gt;(originalImage, &lt;/span&gt;&lt;span&gt;parseInt&lt;/span&gt;&lt;span&gt;(e.target.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;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;function&lt;/span&gt;&lt;span&gt; pixelateImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;originalImage&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;pixelationFactor&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvas&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;createElement&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;canvas&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; context&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; canvas.&lt;/span&gt;&lt;span&gt;getContext&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;2d&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; originalWidth&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; originalImage.width;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; originalHeight&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; originalImage.height;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvasWidth&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; originalWidth;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvasHeight&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; originalHeight;&lt;/span&gt;&lt;/span&gt;
&lt;span 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;  context.&lt;/span&gt;&lt;span&gt;drawImage&lt;/span&gt;&lt;span&gt;(originalImage, &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;, originalWidth, originalHeight);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; originalImageData&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    originalWidth,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    originalHeight&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ).data;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (pixelationFactor &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;    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; originalHeight; y &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; pixelationFactor) {&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; originalWidth; x &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; pixelationFactor) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        // extracting the position of the sample pixel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        const&lt;/span&gt;&lt;span&gt; pixelIndexPosition&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; (x &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; y &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; originalWidth) &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;        // drawing a square replacing the current pixels&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; `rgba(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          ${&lt;/span&gt;&lt;span&gt;originalImageData&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;pixelIndexPosition&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;originalImageData&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;pixelIndexPosition&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          ${&lt;/span&gt;&lt;span&gt;originalImageData&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;pixelIndexPosition&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          ${&lt;/span&gt;&lt;span&gt;originalImageData&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;pixelIndexPosition&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        )`&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        context.&lt;/span&gt;&lt;span&gt;fillRect&lt;/span&gt;&lt;span&gt;(x, y, pixelationFactor, pixelationFactor);&lt;/span&gt;&lt;/span&gt;
&lt;span 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;  pixelatedImage.src &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; canvas.&lt;/span&gt;&lt;span&gt;toDataURL&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;demo.jpg&lt;/code&gt; image is loaded by default, but users can also upload their images thanks to the &lt;code&gt;input&lt;/code&gt; element. Then, using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input/range&quot;&gt;range &lt;code&gt;input&lt;/code&gt;&lt;/a&gt; they can change the pixelation and see the effects on the original image. What happens behind the scene is that the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/change_event&quot;&gt;&lt;code&gt;change&lt;/code&gt;&lt;/a&gt; event on the range &lt;code&gt;input&lt;/code&gt; is intercepted and used to call the &lt;code&gt;pixelateImage()&lt;/code&gt; function. This takes care of pixelating the original image unless &lt;code&gt;pixelationFactor&lt;/code&gt; is 0. In this last case, the original image will be restored. Note that the application implemented here is the same presented in the fiddle above.&lt;/p&gt;
&lt;h2 id=&quot;final-considerations&quot;&gt;Final Considerations&lt;/h2&gt;
&lt;p&gt;No external libraries are required to implement pixelation logic on images in JavaScript. Moreover, this requires nothing more than a few lines of code. This could be used in conjunction with explicit content identification tools, such as &lt;a href=&quot;https://cloud.google.com/vision/docs/detecting-safe-search&quot;&gt;Google SafeSearch&lt;/a&gt;. On the other hand, performance is a problem. Pixelating an image frontend side takes time and resources. This could put a strain on the end user’s device, consequently introducing delays in displaying the pixelated images.&lt;/p&gt;
&lt;p&gt;If the pixelation effect did not have to be applied programmatically, you should consider adopting a commercial solution. In this case, performance would not be a problem. There will be no issues because an experienced team of developers would have already optimized the algorithms for you. In this case, you could take advantage of an advanced SDK. And &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;CreativeEditorSDK&lt;/a&gt; is the right solution for you. This all-in-one SDK comes with many features, allowing your users to unleash their creativity. So, they will be able to go beyond pixelating an image. Also, if you needed help, you could directly ask &lt;a href=&quot;https://img.ly/company/team?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;the team who built it&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;pixelating-an-image-with-cesdk-js&quot;&gt;Pixelating an Image with &lt;a href=&quot;https://www.npmjs.com/package/@cesdk/cesdk-js&quot;&gt;&lt;code&gt;cesdk-js&lt;/code&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First, read article from &lt;a href=&quot;https://img.ly/docs/cesdk/js/get-started/overview-e18f40/&quot;&gt;the official documentation&lt;/a&gt; on how to get started with &lt;code&gt;CreativeEditorSDK&lt;/code&gt; in Vanilla JavaScript. Then, by selecting an image and applying the &lt;em&gt;Pixelize&lt;/em&gt; effect, and changing the horizontal and vertical size of the pixels, you will get the desired result. You can check out this feature in the demo &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;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;pixelate-with-javascript-html5&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 900px) 900px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;900&quot; height=&quot;524&quot; src=&quot;https://img.ly/_astro/pixelate-with-javascript-html5_Z2ihz29.webp&quot; srcset=&quot;/_astro/pixelate-with-javascript-html5_1FpOK7.webp 640w, /_astro/pixelate-with-javascript-html5_Z1noC4h.webp 750w, /_astro/pixelate-with-javascript-html5_Z2prnOK.webp 828w, /_astro/pixelate-with-javascript-html5_Z2ihz29.webp 900w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this tutorial, we learned how to pixelate an image in JavaScript. By using the HTML5 &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt;, it was a reasonably smooth task. With just a few lines of code and by harnessing the HTML5 &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt; functions, you can quickly obtain your desired result. On the other hand, achieving decent performance on large images may quickly become a challenge. Also, you might not want to spend too much time optimizing your algorithms. In this case, you should adopt a more performant, advanced, and complete solution – such as &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;CreativeEditorSDK&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://x.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/10/how-to-pixelate-image-html-js.jpg" medium="image"/><category>How-To</category><category>JavaScript</category><category>App Development</category><category>Photo Editing</category><category>HTML5</category><category>Photo Filter</category><category>Tutorial</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>How to Draw on an Image With JavaScript</title><link>https://img.ly/blog/how-to-draw-on-an-image-with-javascript/</link><guid isPermaLink="true">https://img.ly/blog/how-to-draw-on-an-image-with-javascript/</guid><description>Easily implement a brush to draw on an image in JavaScript, without using any external library!</description><pubDate>Mon, 23 Aug 2021 15:20:14 GMT</pubDate><content:encoded>&lt;p&gt;In this article, you will learn to implement a brush to draw on an image in JavaScript, without using any dedicated external libraries, like those of &lt;a href=&quot;https://img.ly/blog/how-to-crop-an-image-in-react-with-react-image-crop/&quot;&gt;React for image manipulations&lt;/a&gt;. As you are going to see, this can be achieved effortlessly using 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;In the last few years, touchscreens have become more and more common. This technology has made drawing on screens much easier and accessible to everyone. Thus, allowing users to draw on photos or pictures is a more common feature than ever before. For example, we all expect to be able to modify pictures we took before sending them in messaging applications. This is just one of the several real-world case scenarios where you may need to implement this increasingly valuable feature.&lt;/p&gt;
&lt;p&gt;So, let’s see how to draw on an image with Vanilla JavaScript. Follow this step-by-step guide to achieve the following result:&lt;/p&gt;
&lt;h2 id=&quot;drawing-on-images-with-canvas&quot;&gt;Drawing on Images With &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Clone the &lt;a href=&quot;https://github.com/Tonel/how-to-draw-on-an-image-with-javascript-img-ly&quot;&gt;GitHub repository that supports this article&lt;/a&gt; by launching the following command:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;git clone https://github.com/Tonel/how-to-draw-on-an-image-with-javascript-img-ly&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, launch the &lt;code&gt;index.html&lt;/code&gt; page to try the demo application.&lt;/p&gt;
&lt;p&gt;Otherwise, continue following this tutorial to see how to implement the demo application step by step.&lt;/p&gt;
&lt;h3 id=&quot;1-implementing-the-brush-feature&quot;&gt;1. Implementing the Brush Feature&lt;/h3&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 natively offers everything required to implement a brush feature. So, it is actually the only prerequisites. Despite it is typically used for game graphics, animations, real-time video processing, and data visualization, you can also employ it as a tool to draw on images. This powerful tool allows you to implement many cool features, such as resizing an image. Follow &lt;a href=&quot;https://img.ly/blog/how-to-resize-an-image-with-javascript/&quot;&gt;this&lt;/a&gt; link to find out how.&lt;br&gt;
In this case, it takes only a handful of lines of code to implement a brush. Let’s see how together:&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; drawOnImage&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; 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; canvasElement&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;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; canvasElement.&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;  // if an image is present,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // the image passed as a parameter is drawn in the canvas&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (image) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; imageWidth&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; image.width;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; imageHeight&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; image.height;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // rescaling the canvas element&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    canvasElement.width &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; imageWidth;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    canvasElement.height &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; imageHeight;&lt;/span&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;(image, &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;, imageWidth, imageHeight);&lt;/span&gt;&lt;/span&gt;
&lt;span 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;  let&lt;/span&gt;&lt;span&gt; isDrawing;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  canvasElement.&lt;/span&gt;&lt;span&gt;onmousedown&lt;/span&gt;&lt;span&gt; =&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;    isDrawing &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;    context.&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;    context.lineWidth &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;    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.lineJoin &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.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.&lt;/span&gt;&lt;span&gt;moveTo&lt;/span&gt;&lt;span&gt;(e.clientX, e.clientY);&lt;/span&gt;&lt;/span&gt;
&lt;span 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;  canvasElement.&lt;/span&gt;&lt;span&gt;onmousemove&lt;/span&gt;&lt;span&gt; =&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;    if&lt;/span&gt;&lt;span&gt; (isDrawing) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      context.&lt;/span&gt;&lt;span&gt;lineTo&lt;/span&gt;&lt;span&gt;(e.clientX, e.clientY);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      context.&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&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  canvasElement.&lt;/span&gt;&lt;span&gt;onmouseup&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    isDrawing &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;    context.&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;  };&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, a canvas already presents on the HTML page is retrieved. Then, a 2D rendering context is initialized. This will be used to draw on the surface of the blank canvas or on the optional image passed as a parameter. In this last case, the canvas element is resized to fit the image dimensions. Also, the image is drawn by employing the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage&quot;&gt;&lt;code&gt;drawImage()&lt;/code&gt;&lt;/a&gt; function. Next, the logic necessary to draw is implemented.&lt;/p&gt;
&lt;p&gt;On &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/mousedown_event&quot;&gt;&lt;code&gt;mousedown&lt;/code&gt;&lt;/a&gt;, brush color, thickness, and opacity are defined. Also, the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineJoin&quot;&gt;&lt;code&gt;lineJoin&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineCap&quot;&gt;&lt;code&gt;lineCap&lt;/code&gt;&lt;/a&gt; properties are set to &lt;code&gt;round&lt;/code&gt; to make edges less sharp and more rounded. Then, the pointer is moved to the coordinates corresponding to the mouse click position employing the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/moveTo&quot;&gt;&lt;code&gt;moveTo&lt;/code&gt;&lt;/a&gt; function.&lt;/p&gt;
&lt;p&gt;On &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/mousemove_event&quot;&gt;&lt;code&gt;mousemove&lt;/code&gt;&lt;/a&gt;, a line to the new coordinates of the mouse position is drawn by harnessing &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineTo&quot;&gt;&lt;code&gt;lineTo&lt;/code&gt;&lt;/a&gt; and then &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/stroke&quot;&gt;&lt;code&gt;stroke&lt;/code&gt;&lt;/a&gt;. Since the mouse position was moved on the &lt;code&gt;mousedown&lt;/code&gt; event, a straight line connecting the new &lt;code&gt;(x, y)&lt;/code&gt; coordinates is drawn.&lt;/p&gt;
&lt;p&gt;Finally, on &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/mouseup_event&quot;&gt;&lt;code&gt;mouseup&lt;/code&gt;&lt;/a&gt;, the drawing operation is stopped by assigning the &lt;code&gt;isDrawing&lt;/code&gt; variable to &lt;code&gt;false&lt;/code&gt;. This flag was introduced to avoid drawing when moving the mouse on canvas without clicking on it first.&lt;/p&gt;
&lt;p&gt;Note that the two just mentioned event-handler functions used to draw are enclosed by &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/beginPath&quot;&gt;&lt;code&gt;beginPath&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/closePath&quot;&gt;&lt;code&gt;closePath&lt;/code&gt;&lt;/a&gt;. This ensures that every line drawn represents a new sub-path for the canvas. This allows each line to be completely independent of the others and to be plotted in the canvas as an unmodifiable drawing element.&lt;/p&gt;
&lt;p&gt;Et voilà! As you can see, implementing a brush to draw on an image in Vanilla JavaScript takes only a few lines of code.&lt;/p&gt;
&lt;h3 id=&quot;2-drawing-in-action&quot;&gt;2. Drawing in Action&lt;/h3&gt;
&lt;p&gt;Now, let’s take a look at the &lt;code&gt;drawOnImage()&lt;/code&gt; function in action through a complete real-world example:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;!&lt;/span&gt;&lt;span&gt;DOCTYPE&lt;/span&gt;&lt;span&gt; html&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;html&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &amp;#x3C;&lt;/span&gt;&lt;span&gt;body&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;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;canvas&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;canvas&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        width&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;500&quot;&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;&quot;200&quot;&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;&quot;border: 1px solid black;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;canvas&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; 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;Size: &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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        type&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;range&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        min&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;1&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        max&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;50&quot;&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;&quot;10&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        class&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;size&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;sizeRange&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;/&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; 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;Color: &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;colorRadio&quot;&lt;/span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;black&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; for&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;black&quot;&lt;/span&gt;&lt;span&gt;&gt;Black&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;colorRadio&quot;&lt;/span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;white&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; for&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;black&quot;&lt;/span&gt;&lt;span&gt;&gt;White&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;colorRadio&quot;&lt;/span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;red&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; for&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;black&quot;&lt;/span&gt;&lt;span&gt;&gt;Red&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;colorRadio&quot;&lt;/span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;green&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; for&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;black&quot;&lt;/span&gt;&lt;span&gt;&gt;Green&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;colorRadio&quot;&lt;/span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;blue&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; for&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;black&quot;&lt;/span&gt;&lt;span&gt;&gt;Blue&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;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;button&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;clear&quot;&lt;/span&gt;&lt;span&gt;&gt;Clear&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;br&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;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      Start drawing on the blank canvas or upload an image and use the brush to&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      modify on it&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;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;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;// enabling drawing on the blank canvas&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;drawOnImage&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;fileInput.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;change&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;file&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; fileInput.files;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // displaying the uploaded image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; image&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;img&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  image.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;  // enabling the brush after the image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // has been uploaded&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  image.&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;    drawOnImage&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;  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;const&lt;/span&gt;&lt;span&gt; sizeElement&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;#sizeRange&apos;&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; size &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; sizeElement.value;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sizeElement.&lt;/span&gt;&lt;span&gt;oninput&lt;/span&gt;&lt;span&gt; =&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;  size &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; e.target.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;const&lt;/span&gt;&lt;span&gt; colorElement&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;colorRadio&apos;&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; color;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;colorElement.&lt;/span&gt;&lt;span&gt;forEach&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;c&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; (c.checked) color &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; c.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;colorElement.&lt;/span&gt;&lt;span&gt;forEach&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;c&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;  c.&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;    color &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; c.value;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;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; drawOnImage&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; 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; canvasElement&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;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; canvasElement.&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;  // if an image is present,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // the image passed as parameter is drawn in the canvas&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (image) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; imageWidth&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; image.width;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; imageHeight&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; image.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;    // rescaling the canvas element&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    canvasElement.width &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; imageWidth;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    canvasElement.height &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; imageHeight;&lt;/span&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;(image, &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;, imageWidth, imageHeight);&lt;/span&gt;&lt;/span&gt;
&lt;span 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; clearElement&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;clear&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  clearElement.&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;    context.&lt;/span&gt;&lt;span&gt;clearRect&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;, canvasElement.width, canvasElement.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;  let&lt;/span&gt;&lt;span&gt; isDrawing;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  canvasElement.&lt;/span&gt;&lt;span&gt;onmousedown&lt;/span&gt;&lt;span&gt; =&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;    isDrawing &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;    context.&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;    context.lineWidth &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; size;&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; color;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    context.lineJoin &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.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.&lt;/span&gt;&lt;span&gt;moveTo&lt;/span&gt;&lt;span&gt;(e.clientX, e.clientY);&lt;/span&gt;&lt;/span&gt;
&lt;span 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;  canvasElement.&lt;/span&gt;&lt;span&gt;onmousemove&lt;/span&gt;&lt;span&gt; =&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;    if&lt;/span&gt;&lt;span&gt; (isDrawing) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      context.&lt;/span&gt;&lt;span&gt;lineTo&lt;/span&gt;&lt;span&gt;(e.clientX, e.clientY);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      context.&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&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  canvasElement.&lt;/span&gt;&lt;span&gt;onmouseup&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    isDrawing &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;    context.&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;  };&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 needed to change brush size, and color. By interacting with them, users can achieve several possibilities and unleash their creativity. Also, in case of errors, they can press the &lt;em&gt;Clear&lt;/em&gt; button and return to the initial conditions.&lt;/p&gt;
&lt;p&gt;From a technical point of view is that the &lt;code&gt;input&lt;/code&gt; element is used to upload an optional image. Then, it is passed to the aforementioned &lt;code&gt;drawOnImage()&lt;/code&gt; function. This enables the brush feature on the image or the blank canvas and lets users draw on it. Please, note that the example that was just implemented corresponds to the fiddle 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;Although implementing a brush feature to draw on an image in Vanilla JavaScript is definitely an easy task, there are a few downsides that must be addressed. First, making the drawing process smooth while moving the pointer quickly is tricky. This is an optimization problem, which may require you to adopt caching or debouncing techniques. Thus, implementing this feature effectively and efficiently can easily turn into a nightmare. Second, whenever you want to add a new style to the brush, you must spend time implementing all the front-end components required to enhance this feature. Despite not being difficult, this definitely involves boilerplate code.&lt;/p&gt;
&lt;p&gt;When you do not want to spend hours writing boring yet unavoidable code to add new colors or brushes, a commercial and all-in-one solution like &lt;a href=&quot;https://img.ly/products/photo-sdk&quot;&gt;&lt;code&gt;PhotoEditorSDK&lt;/code&gt;&lt;/a&gt; should be the preferred approach. In fact, it allows you to no longer stressing due to having to tackle these tedious and time-consuming tasks. Plus, 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;drawing-on-an-image-with-photoeditorsdk&quot;&gt;Drawing on 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;integration tutorial&lt;/a&gt; article from &lt;a href=&quot;https://img.ly/docs/pesdk/guides/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;the official documentation&lt;/a&gt; on how to get started with &lt;code&gt;PhotoEditorSDK&lt;/code&gt; in HTML and JavaScript. Then, by using the &lt;a href=&quot;https://img.ly/docs/pesdk/web/features/brush/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;&lt;em&gt;Brush Engine&lt;/em&gt;&lt;/a&gt; you can start enjoying a brush feature optimized for touch screen interaction. Moreover, it natively supports different brush strokes. They can also be tweaked in terms of color, hardness, size, and opacity. This way, you should be able to achieve the desired result:&lt;br&gt;
&lt;img src=&quot;https://user-images.githubusercontent.com/72130027/130465683-41d7bcc6-0261-4959-befb-f70633bbd0a3.gif&quot; alt=&quot;draw_with_PESDK&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 draw on an image with JavaScript. Implementing a brush to draw on images by using the &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt; HTML element is not complex. However, it inevitably involves boilerplate code. Specifically, when implementing all the minor options such a feature should offer to the end-users. Also, making the brush smooth and optimized for touch screen and fast movements is quite complex. In fact, this requires optimizing or devising an intelligent algorithm aimed at not wasting resources. So, if you want to avoid these issues and use an easy an all-in-one solution, you should consider using more advanced and complete software – such as &lt;a href=&quot;https://img.ly/products/creative-sdk&quot;&gt;CreativeEditor 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;br&gt;
Like to try out our product? &lt;a href=&quot;https://img.ly/forms/contact-sales&quot;&gt;Get in touch&lt;/a&gt; or start a &lt;a href=&quot;https://img.ly/forms/free-trial&quot;&gt;free trail&lt;/a&gt; today!&lt;/p&gt;</content:encoded><dc:creator>Antonello</dc:creator><media:content url="https://blog.img.ly/2021/08/draw-with-javascript-psdk.png" medium="image"/><category>JavaScript</category><category>App Development</category><category>HTML5</category><category>Web Development</category><category>Photo Editing</category><category>Developer Tools</category><category>Code</category><category>Tutorial</category><category>Tech</category><category>Software Development</category><category>How-To</category></item></channel></rss>