<?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>Code – IMG.LY Blog</title><description>Posts tagged Code on the IMG.LY blog.</description><link>https://img.ly/blog/tag/code/</link><language>en-us</language><image><url>https://img.ly/apple-touch-icon.png</url><title>Code – IMG.LY Blog</title><link>https://img.ly/blog/tag/code/</link></image><atom:link href="https://img.ly/blog/tag/code/rss.xml" rel="self" type="application/rss+xml"/><generator>Astro</generator><lastBuildDate>Fri, 19 Jun 2026 11:26:05 GMT</lastBuildDate><ttl>60</ttl><item><title>How to Trim and Crop Video in Swift</title><link>https://img.ly/blog/trim-and-crop-video-in-swift/</link><guid isPermaLink="true">https://img.ly/blog/trim-and-crop-video-in-swift/</guid><description>Learn how to use Swift and AVKit to crop a video clip and trim a video timeline. </description><pubDate>Tue, 31 Aug 2021 16:03:25 GMT</pubDate><content:encoded>&lt;p&gt;In this article, you will see how to use Swift and &lt;code&gt;AVKit&lt;/code&gt; to crop a video clip and how to trim a video’s timeline. Then you will learn how to use &lt;code&gt;AVAssetExportSession&lt;/code&gt; to write your edited video to disk. The code in this article uses Swift 5 and Xcode 12.5. Clone &lt;a href=&quot;https://github.com/waltertyree/trim-crop-video&quot;&gt;this repository&lt;/a&gt; for a sample project and example code.&lt;/p&gt;
&lt;h2 id=&quot;anatomy-of-a-video-file&quot;&gt;Anatomy of a Video File&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;AVFoundation&lt;/code&gt; and &lt;code&gt;AVKit&lt;/code&gt; frameworks are what Swift and iOS use to manage audio and video. When starting out, you may use an &lt;code&gt;AVPlayerViewController&lt;/code&gt; for playback with the same controls and features as the native players. You can also use an &lt;code&gt;AVPlayer&lt;/code&gt; object and provide your own playback and editing controls. Whichever you choose, you begin by loading a media file (&lt;code&gt;.mp3&lt;/code&gt;, &lt;code&gt;.mov&lt;/code&gt;, etc.) into an &lt;code&gt;AVPlayerItem&lt;/code&gt;. Inside the &lt;code&gt;AVPlayerItem&lt;/code&gt;, the media becomes an &lt;code&gt;AVAsset&lt;/code&gt; which may have many &lt;code&gt;tracks&lt;/code&gt; of video, audio, text, closed captions etc.&lt;/p&gt;
&lt;p&gt;To manipulate an &lt;code&gt;AVAsset&lt;/code&gt;, Apple provides the &lt;code&gt;AVComposition&lt;/code&gt; class. The &lt;code&gt;AVComposition&lt;/code&gt; can act on a single track or many tracks to filter and mix underlying media and produces a single output. An &lt;code&gt;AVPlayer&lt;/code&gt; shows the output of an &lt;code&gt;AVComposition&lt;/code&gt; on a device. When it is time to export, you can use an &lt;code&gt;AVAssetExportSession&lt;/code&gt; with the same &lt;code&gt;AVComposition&lt;/code&gt; to write to disk or upload to a server.&lt;/p&gt;
&lt;h2 id=&quot;cropping-video-to-a-rectangle&quot;&gt;Cropping Video to a Rectangle&lt;/h2&gt;
&lt;p&gt;Apple provides some different &lt;code&gt;AVComposition&lt;/code&gt; classes optimized for common tasks. Apple recommends using one of these classes instead of writing custom &lt;code&gt;AVComposition&lt;/code&gt; classes whenever possible. The reason for this is that when Apple introduces new technologies (like HDR Video), they will ensure it works with their classes. If you’ve written your own, you will have to update it to work with the new technologies. In this article you will crop the video to a rectangle and let the audio pass through as recorded. A good class to use for this task will be the &lt;code&gt;AVMutableVideoComposition&lt;/code&gt; with the &lt;code&gt;init(asset: AVAsset, applyingCIFiltersWithHandler applier: @escaping (AVAsynchronousCIImageFilteringRequest) -&gt; Void)&lt;/code&gt; initializer. This will allow you to apply a &lt;code&gt;CIFilter&lt;/code&gt; to each frame of the video. Apple provides an efficient cropping filter called &lt;code&gt;CICrop&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;func&lt;/span&gt;&lt;span&gt; transformVideo&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;item&lt;/span&gt;&lt;span&gt;: AVPlayerItem, &lt;/span&gt;&lt;span&gt;cropRect&lt;/span&gt;&lt;span&gt;: CGRect) {&lt;/span&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; cropScaleComposition &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; AVMutableVideoComposition&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;asset&lt;/span&gt;&lt;span&gt;: item.asset, &lt;/span&gt;&lt;span&gt;applyingCIFiltersWithHandler&lt;/span&gt;&lt;span&gt;: {request &lt;/span&gt;&lt;span&gt;in&lt;/span&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; cropFilter &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; CIFilter&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;CICrop&quot;&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 class=&quot;line&quot;&gt;&lt;span&gt;    cropFilter.&lt;/span&gt;&lt;span&gt;setValue&lt;/span&gt;&lt;span&gt;(request.sourceImage, &lt;/span&gt;&lt;span&gt;forKey&lt;/span&gt;&lt;span&gt;: kCIInputImageKey) &lt;/span&gt;&lt;span&gt;//2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    cropFilter.&lt;/span&gt;&lt;span&gt;setValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;CIVector&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;cgRect&lt;/span&gt;&lt;span&gt;: cropRect), &lt;/span&gt;&lt;span&gt;forKey&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;inputRectangle&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 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; imageAtOrigin &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; cropFilter.outputImage&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;transformed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;by&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;CGAffineTransform&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;translationX&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;cropRect.origin.x, &lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;cropRect.origin.y)) &lt;/span&gt;&lt;span&gt;//3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    request.&lt;/span&gt;&lt;span&gt;finish&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;with&lt;/span&gt;&lt;span&gt;: imageAtOrigin, &lt;/span&gt;&lt;span&gt;context&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;nil&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;//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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  cropScaleComposition.renderSize &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; cropRect.&lt;/span&gt;&lt;span&gt;size&lt;/span&gt;&lt;span&gt; //5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  item.videoComposition &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; cropScaleComposition  &lt;/span&gt;&lt;span&gt;//6&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;applyingCIFiltersWithHandler&lt;/code&gt; will execute for every frame in the &lt;code&gt;asset&lt;/code&gt; of the &lt;code&gt;AVPlayerItem&lt;/code&gt;. Here is what the code above will do:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a CICrop filter (note that this demo uses &lt;code&gt;!&lt;/code&gt; to force unwrap, production code should handle failure)&lt;/li&gt;
&lt;li&gt;Add the &lt;code&gt;.sourceImage&lt;/code&gt; (a &lt;code&gt;CIImage&lt;/code&gt;) from the request to the filter.&lt;/li&gt;
&lt;li&gt;Move the cropped image to the origin of the video frame. When you resize the frame (step 4) it will resize from the origin.&lt;/li&gt;
&lt;li&gt;Output the transformed frame image&lt;/li&gt;
&lt;li&gt;Set the size of the video frame to the cropped size&lt;/li&gt;
&lt;li&gt;Attach the composition to the &lt;code&gt;videoComposition&lt;/code&gt; property of the &lt;code&gt;asset&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Notice that the transformation does not alter the underlying asset. It creates a &lt;code&gt;videoComposition&lt;/code&gt; filter to attach to the item during playback. After the transformation, &lt;code&gt;AVPlayer&lt;/code&gt; will display the new creation when executing its &lt;code&gt;.play()&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;Sharp eyed readers will have noticed that the &lt;code&gt;init&lt;/code&gt; method mentions “applying &lt;em&gt;CIFilters&lt;/em&gt;” plural. Instead of one filter, you can create an entire pipeline of &lt;code&gt;CIFilter&lt;/code&gt; objects to manipulate the visual properties of the frames. The &lt;code&gt;request&lt;/code&gt; object also contains the &lt;code&gt;compositionTime&lt;/code&gt; so filters can change at different parts of the video.&lt;/p&gt;
&lt;h2 id=&quot;trimming-the-time-of-a-video&quot;&gt;Trimming the Time of a Video&lt;/h2&gt;
&lt;p&gt;When an &lt;code&gt;AVPlayer&lt;/code&gt; loads an &lt;code&gt;AVItem&lt;/code&gt; the start time of the video will be at &lt;code&gt;CMTime.zero&lt;/code&gt;. The end will be the &lt;code&gt;duration&lt;/code&gt; property of the &lt;code&gt;AVItem&lt;/code&gt;. To adjust the playback times, you call the &lt;code&gt;.seek&lt;/code&gt; function to move to the new start time and set the &lt;code&gt;forwardPlaybackEndTime&lt;/code&gt; to the new end time. Now the player will only play the part of the clip between those times.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;//The player object is already created and configured to play video in the ViewController&lt;/span&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 a video .mov file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;self&lt;/span&gt;&lt;span&gt;.player &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; AVPlayer&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;: Bundle.main.&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;forResource&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;grocery-train&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;withExtension&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;mov&quot;&lt;/span&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;//Set the start time to 5 seconds.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; startTime &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; CMTimeMakeWithSeconds&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;preferredTimescale&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;600&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;//Convert the duration of the video to seconds&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; videoDurationInSeconds &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; self&lt;/span&gt;&lt;span&gt;.player&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;.currentItem&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;.duration.seconds&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;//Subtract 5 seconds from the end time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; endTime &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; CMTimeMakeWithSeconds&lt;/span&gt;&lt;span&gt;(videoDurationInSeconds &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;preferredTimescale&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;600&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;//Assign the new values to the start and end time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;self&lt;/span&gt;&lt;span&gt;.player&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;seek&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;to&lt;/span&gt;&lt;span&gt;: startTime)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;self&lt;/span&gt;&lt;span&gt;.player&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.currentItem&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.forwardPlaybackEndTime &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; endTime&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;//Play the video&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;self&lt;/span&gt;&lt;span&gt;.player&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;play&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;CMTime&lt;/code&gt; (Core Media Time) object uses timescales and &lt;code&gt;Int&lt;/code&gt; values to map to the individual frames of tracks. Video tracks commonly come to your app with 24, 30, 60 or 120 frames per second. Converting between these different formats using Floats or Doubles would be imprecise. When converting seconds to &lt;code&gt;CMTime&lt;/code&gt; with video, &lt;code&gt;600&lt;/code&gt; is the commonly used timescale because it is a common multiple of all of the standard frames per second.&lt;/p&gt;
&lt;h2 id=&quot;exporting-the-video&quot;&gt;Exporting the Video&lt;/h2&gt;
&lt;p&gt;As with the &lt;code&gt;videoComposition&lt;/code&gt; property, setting the start and end times of the player only modifies the playback of the video clip. The underlying asset remains unchanged. When you use the &lt;code&gt;AVAssetExportSession&lt;/code&gt;, the new video file will have the change. The export session applies time range and video composition objects as it writes the file. A function to export might look like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;func&lt;/span&gt;&lt;span&gt; export&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt; asset: AVAsset, &lt;/span&gt;&lt;span&gt;to&lt;/span&gt;&lt;span&gt; outputMovieURL: URL, &lt;/span&gt;&lt;span&gt;startTime&lt;/span&gt;&lt;span&gt;: CMTime, &lt;/span&gt;&lt;span&gt;endTime&lt;/span&gt;&lt;span&gt;: CMTime, &lt;/span&gt;&lt;span&gt;composition&lt;/span&gt;&lt;span&gt;: AVVideoComposition) {&lt;/span&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 trim range&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  let&lt;/span&gt;&lt;span&gt; timeRange &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; CMTimeRangeFromTimeToTime&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;start&lt;/span&gt;&lt;span&gt;: startTime, &lt;/span&gt;&lt;span&gt;end&lt;/span&gt;&lt;span&gt;: endTime)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    //delete any old file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  do&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    try&lt;/span&gt;&lt;span&gt; FileManager.default.&lt;/span&gt;&lt;span&gt;removeItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;at&lt;/span&gt;&lt;span&gt;: outputMovieURL)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  } &lt;/span&gt;&lt;span&gt;catch&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Could not remove file &lt;/span&gt;&lt;span&gt;\(error.&lt;/span&gt;&lt;span&gt;localizedDescription&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    //create exporter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  let&lt;/span&gt;&lt;span&gt; exporter &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; AVAssetExportSession&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;asset&lt;/span&gt;&lt;span&gt;: asset, &lt;/span&gt;&lt;span&gt;presetName&lt;/span&gt;&lt;span&gt;: AVAssetExportPresetHighestQuality)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    //configure exporter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  exporter&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.videoComposition &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; composition&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  exporter&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.outputURL &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; outputMovieURL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  exporter&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.outputFileType &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; .mov&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  exporter&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.timeRange &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; timeRange&lt;/span&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  exporter&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;exportAsynchronously&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;completionHandler&lt;/span&gt;&lt;span&gt;: { [&lt;/span&gt;&lt;span&gt;weak&lt;/span&gt;&lt;span&gt; exporter] &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    DispatchQueue.main.&lt;/span&gt;&lt;span&gt;async&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; let&lt;/span&gt;&lt;span&gt; error &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; exporter&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;failed &lt;/span&gt;&lt;span&gt;\(error.&lt;/span&gt;&lt;span&gt;localizedDescription&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      } &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Video saved to &lt;/span&gt;&lt;span&gt;\(outputMovieURL)&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;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;h2 id=&quot;going-further&quot;&gt;Going Further&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;AVKit&lt;/code&gt; and &lt;code&gt;AVFoundation&lt;/code&gt; provide simple objects for manipulating video files. The difficulty when working with video and audio tracks usually comes while providing editing controls for a user. The image below shows how the original video dimensions might change from creation to display.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;different screen dimensions of video during different stages of editing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1453px) 1453px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1453&quot; height=&quot;716&quot; src=&quot;https://img.ly/_astro/resizing_1kxMMH.webp&quot; srcset=&quot;/_astro/resizing_ZD5fcE.webp 640w, /_astro/resizing_w8gz1.webp 750w, /_astro/resizing_160u1K.webp 828w, /_astro/resizing_1mGc6g.webp 1080w, /_astro/resizing_22qr8E.webp 1280w, /_astro/resizing_1kxMMH.webp 1453w&quot;&gt;&lt;/p&gt;
&lt;p&gt;The original 2160x3840 video appears on an iPhone in a 357x635 frame. Additionally the origin point (green dot) of the video file and the origin point of the UIViews are not equal. Passing the frame of the red, cropping rectangle to an &lt;code&gt;AVComposition&lt;/code&gt; would not work as expected. Inside of the &lt;code&gt;AVComposition&lt;/code&gt; the video resumes it’s 720x1280 dimensions while the 250x250 cropping rectangle would remain 250x250.&lt;/p&gt;
&lt;p&gt;Before using a UIView rectangle with an &lt;code&gt;AVComposition&lt;/code&gt; it needs to resize and the origin point needs to align to the video’s origin. Your app must apply a &lt;code&gt;CGAffineTransform&lt;/code&gt; to reorient the origin points.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;flip and slide rectangle&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1209px) 1209px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1209&quot; height=&quot;793&quot; src=&quot;https://img.ly/_astro/transform-rect_28A6Vy.webp&quot; srcset=&quot;/_astro/transform-rect_ZbJbv8.webp 640w, /_astro/transform-rect_Z25Ixcl.webp 750w, /_astro/transform-rect_Z9DQt7.webp 828w, /_astro/transform-rect_VNLLC.webp 1080w, /_astro/transform-rect_28A6Vy.webp 1209w&quot;&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; cropRect &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; self&lt;/span&gt;&lt;span&gt;.croppingView.frame &lt;/span&gt;&lt;span&gt;//1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; originFlipTransform &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; CGAffineTransform&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;y&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;let&lt;/span&gt;&lt;span&gt; frameTranslateTransform &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; CGAffineTransform&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;translationX&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;y&lt;/span&gt;&lt;span&gt;: renderingSize.height)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cropRect &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; cropRect.&lt;/span&gt;&lt;span&gt;applying&lt;/span&gt;&lt;span&gt;(originFlipTransform) &lt;/span&gt;&lt;span&gt;//2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cropRect &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; cropRect.&lt;/span&gt;&lt;span&gt;applying&lt;/span&gt;&lt;span&gt;(frameTranslateTransform) &lt;/span&gt;&lt;span&gt;//3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you apply regular ratio math to the dimensions of the cropping rectangle to match the video dimensions.&lt;br&gt;
&lt;img alt=&quot;resize rectangle to video dimensions&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 359px) 359px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;359&quot; height=&quot;494&quot; src=&quot;https://img.ly/_astro/translate-resize_54OyH.webp&quot; srcset=&quot;/_astro/translate-resize_54OyH.webp 359w&quot;&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;swift&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; renderingSize &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; playerItem.presentationSize&lt;/span&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; xFactor &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; renderingSize.width &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; playerView.bounds.&lt;/span&gt;&lt;span&gt;size&lt;/span&gt;&lt;span&gt;.width&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; yFactor &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; renderingSize.height &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; playerView.bounds.&lt;/span&gt;&lt;span&gt;size&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 class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; newX &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; croppingView.frame.origin.x &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; xFactor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; newW &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; croppingView.frame.width &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; xFactor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; newY &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; croppingView.frame.origin.y &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; yFactor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; newH &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; croppingView.frame.height &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; yFactor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; cropRect &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; CGRect&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;: newX, &lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;: newY, &lt;/span&gt;&lt;span&gt;width&lt;/span&gt;&lt;span&gt;: newW, &lt;/span&gt;&lt;span&gt;height&lt;/span&gt;&lt;span&gt;: newH)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The transformations above are standard when working with &lt;code&gt;AVKit&lt;/code&gt; and &lt;code&gt;UIKit&lt;/code&gt; or &lt;code&gt;SwiftUI&lt;/code&gt; in an app. The math is not complex, but it is tedious. Unless your app is a custom video editing application, you may find that using a commercial solution such as &lt;a href=&quot;https://img.ly/products/video-sdk/&quot;&gt;VideoEditorSDK&lt;/a&gt; is a better approach. By adding the &lt;a href=&quot;https://img.ly/products/video-sdk/&quot;&gt;VideoEditorSDK&lt;/a&gt;, your app can have professional appearing trim and crop controls as well as filtering, text and more.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;trim crop and other controls&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1131px) 1131px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1131&quot; height=&quot;779&quot; src=&quot;https://img.ly/_astro/crop-trim-and-others_3Iidn.webp&quot; srcset=&quot;/_astro/crop-trim-and-others_Z2jzuUp.webp 640w, /_astro/crop-trim-and-others_1dym89.webp 750w, /_astro/crop-trim-and-others_B0bOy.webp 828w, /_astro/crop-trim-and-others_Z1WfCJ7.webp 1080w, /_astro/crop-trim-and-others_3Iidn.webp 1131w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this article, you saw how to crop a video image and how to trim time from a track, all in Swift. Further, you saw how using an SDK such as &lt;a href=&quot;https://img.ly/products/video-sdk/&quot;&gt;VideoEditorSDK&lt;/a&gt; allows you to provide full-featured video editing for any application.&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/video-sdk-mobile/&quot;&gt;Camera SDK&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thanks for reading! We hope that you found this tutorial 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>Walter</dc:creator><media:content url="https://blog.img.ly/2021/08/resize-swift.jpg" medium="image"/><category>Swift</category><category>Software Development</category><category>Mobile App Development</category><category>Video Editing</category><category>Video Editor</category><category>Code</category><category>Developer Tools</category><category>Tutorial</category><category>App Development</category><category>How-To</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/docs/cesdk/&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><item><title>How To Resize an Image in React</title><link>https://img.ly/blog/how-to-resize-an-image-in-react/</link><guid isPermaLink="true">https://img.ly/blog/how-to-resize-an-image-in-react/</guid><description>Quickly resize an image with the `react-image-file-resizer` React library.</description><pubDate>Fri, 30 Jul 2021 10:57:19 GMT</pubDate><content:encoded>&lt;p&gt;In this article, you will see how to resize an image in JavaScript. In particular, here you will learn to achieve this goal with the &lt;code&gt;react-image-file-resizer&lt;/code&gt; React library. If you are looking for a pure Javascript solution, &lt;a href=&quot;https://img.ly/blog/how-to-resize-an-image-with-javascript/&quot;&gt;here’s a quick rundown of the HTML API usage&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Providing users with features to resize images has become almost unavoidable. This is because images are larger than ever. It is not a secret that the quality of the images and therefore their file sizes have been increasing for years.&lt;/p&gt;
&lt;p&gt;The problem is that dealing with large files is time-consuming. Plus, it may cost money in bandwidth when uploading or downloading them. This is why it is so important to shrink the size of images by resizing them. Also, these issues fall on end-users, and this should be avoided.&lt;/p&gt;
&lt;p&gt;So, let’s see how to resize an image in React with &lt;code&gt;react-image-file-resizer&lt;/code&gt;. By following this step-by-step tutorial, you will achieve the following &lt;a href=&quot;https://codesandbox.io/s/how-to-resize-an-image-in-react-demo-forked-ip6fi&quot;&gt;result&lt;/a&gt;:&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;This is the list of all the prerequisites for the demo application you are going to build:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.npmjs.com/getting-started/&quot;&gt;Node.js and npm 5.2+ and higher&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/react-resize-image&quot;&gt;&lt;code&gt;react-image-file-resizer&lt;/code&gt;&lt;/a&gt; &gt;= 0.4.7&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;resizing-an-image-with-react-image-file-resizer&quot;&gt;Resizing an Image with &lt;code&gt;react-image-file-resizer&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;You can clone the &lt;a href=&quot;https://github.com/imgly/Blog-How-To-Resize-an-Image-in-React&quot;&gt;GitHub repository that supports this article&lt;/a&gt; and try the demo application by launching the following commands:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;git clone https://github.com/Tonel/resize-image-react-demo-imgly&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cd resize-image-react-demo-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, you can continue following this tutorial and build the demo application step by step.&lt;/p&gt;
&lt;h2 id=&quot;1-creating-a-react-project&quot;&gt;1. Creating a React Project&lt;/h2&gt;
&lt;p&gt;Generate an empty working project in React with &lt;a href=&quot;https://create-react-app.dev/docs/getting-started/&quot;&gt;Create React App&lt;/a&gt;, the officially supported way to create single-page React applications. You can initialize a new project called &lt;code&gt;react-image-resizer-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;npx create-react-app react-image-resizer-demo&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will now have a demo project located in the &lt;code&gt;react-image-resizer-demo&lt;/code&gt; folder 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-image-resizer-demo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── README.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── node_modules&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── package.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── .gitignore&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── public&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── favicon.ico&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── index.html&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── logo192.png&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── logo512.png&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── manifest.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   └── robots.txt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;└── src&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── App.css&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── App.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── App.test.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── index.css&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── index.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── logo.svg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ├── reportWebVitals.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    └── setupTests.js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Move into the &lt;code&gt;react-image-resizer-demo&lt;/code&gt; folder and start a local server by launching these 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 react-image-resizer-demo&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. You should now be able to see the default Create React App screen, as follows:&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;h2 id=&quot;2-installing-react-image-file-resizer&quot;&gt;2. Installing &lt;code&gt;react-image-file-resizer&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;First, you have to add the &lt;code&gt;react-image-file-resizer&lt;/code&gt; library to your project’s dependencies. You can do it by running 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 react-image-file-resizer&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Thus, your &lt;code&gt;package.json&lt;/code&gt; file will be updated accordingly. You should now be able to spot &lt;code&gt;react-image-file-resizer&lt;/code&gt; as a dependency.&lt;/p&gt;
&lt;p&gt;Now, all prerequisites have been met. So, you can start building your image resizer component. Let’s see together how.&lt;/p&gt;
&lt;h2 id=&quot;3-building-the-image-resizer-component&quot;&gt;3. Building the Image Resizer Component&lt;/h2&gt;
&lt;p&gt;First, make a &lt;code&gt;components&lt;/code&gt; folder inside &lt;code&gt;src&lt;/code&gt;. Then, create an &lt;code&gt;ImageResizer&lt;/code&gt; folder containing &lt;code&gt;index.js&lt;/code&gt; and &lt;code&gt;index.css&lt;/code&gt;. These two files will contain the resizer component definition and style respectively.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://paper-attachments.dropbox.com/s_0C9FF6F84F9D5BBDC6112B53688A82A0D901A542FB0DD0CC04FE4E4B7D0590ED_1626875270825_image.png&quot; alt=&quot;The components folder&quot;&gt;&lt;/p&gt;
&lt;p&gt;Initialize &lt;code&gt;index.js&lt;/code&gt; with the following snippet:&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;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; ImageResizer&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; &amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;{&lt;/span&gt;&lt;span&gt;/*TODO*/&lt;/span&gt;&lt;span&gt;}&amp;#x3C;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; default&lt;/span&gt;&lt;span&gt; ImageResizer;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way, you have just defined an empty &lt;code&gt;ImageResizer&lt;/code&gt; component.&lt;br&gt;
Now, import the &lt;code&gt;Resizer&lt;/code&gt; utility from the &lt;code&gt;react-image-file-resizer&lt;/code&gt; library. Add it to the &lt;code&gt;ImageResizer&lt;/code&gt; imports:&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;import Resizer from &apos;react-image-file-resizer&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is what the final &lt;code&gt;ImageResizer&lt;/code&gt; will look like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import React, {useEffect, useState} from &quot;react&quot;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import Resizer from &quot;react-image-file-resizer&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;function ImageResize(props) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const {imageToResize, onImageResized, resizeAspect, resizeQuality} = props;&lt;/span&gt;&lt;/span&gt;
&lt;span 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 [imageToResizeUri, setImageToResizeUri] = useState();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const [imageToResizeWidth, setImageToResizeWidth] = useState();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const [imageToResizeHeight, setImageToResizeHeight] = useState();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    useEffect(() =&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        if (imageToResize) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            const reader = new FileReader();&lt;/span&gt;&lt;/span&gt;
&lt;span 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.addEventListener(&apos;load&apos;, () =&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                setImageToResizeUri(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&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            reader.readAsDataURL(imageToResize);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }, [imageToResize])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    useEffect(() =&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        if (imageToResize &amp;#x26;&amp;#x26; imageToResizeWidth &amp;#x26;&amp;#x26; imageToResizeHeight) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            Resizer.imageFileResizer(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                imageToResize,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                imageToResizeWidth * resizeAspect,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                imageToResizeWidth * resizeAspect,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                &quot;JPEG&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                resizeQuality,&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 class=&quot;line&quot;&gt;&lt;span&gt;                (uri) =&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                    onImageResized(uri)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                &quot;base64&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;    }, [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        imageToResize, imageToResizeWidth, imageToResizeHeight,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        onImageResized, resizeAspect, resizeQuality&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;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 class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;img&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            src={imageToResizeUri}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            onLoad= {(e) =&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                const img = e.target;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                setImageToResizeWidth(img.width);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                setImageToResizeHeight(img.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;            crossorigin=&quot;anonymous&quot; // to avoid CORS-related problems&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ImageResize.defaultProps = {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    onImageResized: () =&gt; {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    resizeAspect: 0.5,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    resizeQuality: 100&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;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;export default ImageResize;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;imageToResize&lt;/code&gt; is the source &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Blob&quot;&gt;Blob&lt;/a&gt; representing the image received from the props. First, &lt;code&gt;imageToResize&lt;/code&gt; is transformed into a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Base64&quot;&gt;&lt;code&gt;Base64&lt;/code&gt;&lt;/a&gt; URI by 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, and then showed. After being loaded by the &lt;code&gt;&amp;#x3C;img&gt;&lt;/code&gt; HTML tag, the image’s width and height are saved to be used during the resizing operation. This is done by the second &lt;code&gt;useEffect()&lt;/code&gt; function, which takes care of resizing the Blob image received by employing the &lt;code&gt;Resizer&lt;/code&gt; utility.&lt;/p&gt;
&lt;p&gt;Please, note that &lt;code&gt;resizeAspect&lt;/code&gt; and &lt;code&gt;resizeQuality&lt;/code&gt; are two props in charge of defining the resize aspect and quality percentage, respectively. By default, they are assigned to 0.5 and 100. This means that the resized image will be 50% smaller and no compression will be applied during the resizing process.&lt;/p&gt;
&lt;h2 id=&quot;4-putting-it-all-together&quot;&gt;4. Putting It All Together&lt;/h2&gt;
&lt;p&gt;Now, let’s see the &lt;code&gt;ImageResizer&lt;/code&gt; component defined above in action. All you need to do, is change the &lt;code&gt;App.js&lt;/code&gt; file as follows:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; React, { useState } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;react&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &apos;./App.css&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; ImageResize &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;./components/ImageResizer&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; App&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;imageToResize&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setImageToResize&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;resizedImage&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;setResizedImage&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; useState&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;undefined&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; onUploadFile&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; (event.target.files &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; event.target.files.&lt;/span&gt;&lt;span&gt;length&lt;/span&gt;&lt;span&gt; &gt;&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      setImageToResize&lt;/span&gt;&lt;span&gt;(event.target.files[&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; className&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;app&quot;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;&lt;/span&gt;&lt;span&gt;h1&lt;/span&gt;&lt;span&gt;&gt;Image Resizer&amp;#x3C;/&lt;/span&gt;&lt;span&gt;h1&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        Please, upload an image and it will be showed both original and resized&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        by 50%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;&lt;/span&gt;&lt;span&gt;input&lt;/span&gt;&lt;span&gt; type&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;file&quot;&lt;/span&gt;&lt;span&gt; accept&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;image/*&quot;&lt;/span&gt;&lt;span&gt; onChange&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{onUploadFile} /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;&lt;/span&gt;&lt;span&gt;ImageResize&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          imageToResize&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{imageToResize}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          onImageResized&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{(&lt;/span&gt;&lt;span&gt;resizedImage&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; setResizedImage&lt;/span&gt;&lt;span&gt;(resizedImage)}&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;      {resizedImage &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          &amp;#x3C;&lt;/span&gt;&lt;span&gt;h2&lt;/span&gt;&lt;span&gt;&gt;Resized Image&amp;#x3C;/&lt;/span&gt;&lt;span&gt;h2&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;          &amp;#x3C;&lt;/span&gt;&lt;span&gt;img&lt;/span&gt;&lt;span&gt; alt&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;Resize Image&quot;&lt;/span&gt;&lt;span&gt; src&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{resizedImage} /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        &amp;#x3C;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      )}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; default&lt;/span&gt;&lt;span&gt; App;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;input&lt;/code&gt; element allows users to upload an image. This is stored in the &lt;code&gt;imageToResize&lt;/code&gt; state variable, and then passed to &lt;code&gt;ImageResizer&lt;/code&gt; as a props. This will take care of resizing it accordingly. The resulting resized image is saved thanks to the &lt;code&gt;setResizedImage&lt;/code&gt; function, and finally displayed in the &lt;em&gt;Resize Image&lt;/em&gt; section.&lt;/p&gt;
&lt;p&gt;If you are a Next.js user, you can use the &lt;a href=&quot;https://writech.run/blog/how-to-make-next-js-image-optimization-work-on-aws-elastic-beanstalk-2776ea255eff/&quot;&gt;&lt;code&gt;&amp;#x3C;Image /&gt;&lt;/code&gt; component to make it resize images for you&lt;/a&gt;. React will then render resized images automatically.&lt;/p&gt;
&lt;h2 id=&quot;final-considerations-on-react-image-file-resizer&quot;&gt;Final Considerations on &lt;code&gt;react-image-file-resizer&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Resizing an image cannot be considered a complex task. However, using a library like &lt;code&gt;react-image-file-resizer&lt;/code&gt; makes everything easier. In fact, you can achieve your goal with just a handful of lines of code. On the other hand, you should take into account what using such specific libraries implies. In fact, when you need to perform many image-related operations, you may be ending up with as many libraries as operations required.&lt;/p&gt;
&lt;p&gt;Not only might they be complex to make them coexist, but they may have very different UIs as well. This is why, harnessing a commercial and more complete solution such as &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;&lt;code&gt;PhotoEditorSDK&lt;/code&gt;&lt;/a&gt; could be a better approach. With only one library, you would get several tools to deal with images as you need. This, while preserving the consistency of your application’s UI. 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;resizing-an-image-with-photoeditorsdk&quot;&gt;Resizing an Image with PhotoEditorSDK&lt;/h2&gt;
&lt;p&gt;First, you should read &lt;a href=&quot;https://img.ly/docs/pesdk/web/introduction/getting_started/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;this&lt;/a&gt; article from &lt;a href=&quot;https://img.ly/docs/pesdk/guides/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;the official documentation&lt;/a&gt; on how to get started with &lt;code&gt;PhotoEditorSDK&lt;/code&gt; in React. Then, by using the &lt;a href=&quot;https://img.ly/docs/pesdk/web/features/transform/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;transform tool&lt;/a&gt; you can perform cropping, &lt;a href=&quot;https://img.ly/docs/pesdk/web/features/transform/#image-resizing?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;resizing&lt;/a&gt;, flipping, and rotation operations with just one feature. This way, you should be able to achieve the desired result&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;resize-image-with-pesdk-react&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1095px) 1095px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1095&quot; height=&quot;652&quot; src=&quot;https://img.ly/_astro/resize-image-with-pesdk-react_Z2rpOL5.webp&quot; srcset=&quot;/_astro/resize-image-with-pesdk-react_Z25Tfyt.webp 640w, /_astro/resize-image-with-pesdk-react_21L4Vs.webp 750w, /_astro/resize-image-with-pesdk-react_Zk4j8T.webp 828w, /_astro/resize-image-with-pesdk-react_WzXl1.webp 1080w, /_astro/resize-image-with-pesdk-react_Z2rpOL5.webp 1095w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this article, we looked at how to resize an image in React. Although this cannot be considered a complex feature to implement, using a library such as &lt;code&gt;react-image-file-resizer&lt;/code&gt; is recommended. As we have seen, you can resize an image effortlessly and with only a few lines of code. On the other hand, it is a library with a very specific and limited purpose. So, if you needed to perform more than one operation on your images, you might want to take advantage of a more advanced and complete solution – such as &lt;code&gt;PhotoEditorSDK&lt;/code&gt;.&lt;/p&gt;</content:encoded><dc:creator>Antonello</dc:creator><media:content url="https://blog.img.ly/2021/07/resize-image-with-react-1.png" medium="image"/><category>React</category><category>App Development</category><category>Mobile App Development</category><category>Photo Editing</category><category>Tutorial</category><category>Tech</category><category>Developer</category><category>Code</category><category>Developer Tools</category><category>React Native</category><category>Software Development</category><category>How-To</category></item><item><title>How To Resize an Image With JavaScript</title><link>https://img.ly/blog/how-to-resize-an-image-with-javascript/</link><guid isPermaLink="true">https://img.ly/blog/how-to-resize-an-image-with-javascript/</guid><description>Today, you will learn how to resize an image in JavaScript, without using any external library. Thanks to the HTML &lt;canvas&gt; element, this is reasonably easy. Let&apos;s go!</description><pubDate>Tue, 20 Jul 2021 09:22:31 GMT</pubDate><content:encoded>&lt;p&gt;In this article, you will learn how to resize an image in JavaScript, without using any external library. Thanks to the HTML &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API&quot;&gt;&lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt;&lt;/a&gt; element, this is a reasonably easy task to accomplish.&lt;/p&gt;
&lt;p&gt;Resizing an image has become increasingly important. That is because the quality of the images and their file sizes have been increasing for years.&lt;br&gt;
For example, when letting users upload an image, you should always consider resizing it before uploading it. Uploading large photos is time-consuming and may cost money in bandwidth.  As we have previously explained you might also want to &lt;a href=&quot;https://img.ly/blog/how-to-compress-an-image-before-uploading-it-in-javascript/&quot;&gt;compress such images&lt;/a&gt;.  As you can imagine, both of these consequences fall on end-users – we want to avoid this.&lt;/p&gt;
&lt;p&gt;Let’s see how to resize an image with Vanilla JavaScript. Follow this step-by-step tutorial to achieve the following result on &lt;a href=&quot;https://codesandbox.io/s/blog-how-to-resize-an-image-with-javascript-forked-mkuri&quot;&gt;CodeSandbox&lt;/a&gt;:&lt;/p&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/blog-how-to-resize-an-image-with-javascript-forked-mkuri&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;resizing-images-using-canvas&quot;&gt;Resizing Images Using &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;You can clone the &lt;a href=&quot;https://github.com/Tonel/resize-image-javascript-imgly&quot;&gt;GitHub repository that supports this article&lt;/a&gt; by launching the following command:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;git clone https://github.com/Tonel/resize-image-javascript-imgly&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Otherwise, you can continue following this tutorial and build the demo application step by step.&lt;/p&gt;
&lt;h3 id=&quot;1-implementing-the-resizing-logic&quot;&gt;1. Implementing the Resizing Logic&lt;/h3&gt;
&lt;p&gt;While in a &lt;a href=&quot;https://img.ly/blog/how-to-resize-an-image-in-react/&quot;&gt;React context we used a library&lt;/a&gt; to do the heavy lifting for us, knowing the HTML &lt;code&gt;[&amp;#x3C;canvas&gt;](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API)&lt;/code&gt; API is the only prerequisites for this approach. Although typically used for animation, game graphics, data visualization, and real-time video processing, you can also employ it as an image manipulation tool. Specifically, it provides everything required to resize an image. Let’s see how:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; resizeImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;imgToResize&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;resizingFactor&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 0.5&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvas&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;createElement&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;canvas&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; context&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; canvas.&lt;/span&gt;&lt;span&gt;getContext&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;2d&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; originalWidth&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; imgToResize.width;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; originalHeight&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; imgToResize.height;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvasWidth&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; originalWidth &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; resizingFactor;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvasHeight&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; originalHeight &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; resizingFactor;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  canvas.width &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; canvasWidth;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  canvas.height &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; canvasHeight;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  context.&lt;/span&gt;&lt;span&gt;drawImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    imgToResize,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    originalWidth &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; resizingFactor,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    originalHeight &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; resizingFactor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; canvas.&lt;/span&gt;&lt;span&gt;toDataURL&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Initialize an in-memory &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt; with a 2D rendering context for the drawing surface.&lt;/li&gt;
&lt;li&gt;Set height and width depending on the size of the original image to resize and the resizing factor.&lt;/li&gt;
&lt;li&gt;Then, the resized image is drawn according to the resizing factor passed by harnessing the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage&quot;&gt;&lt;code&gt;drawImage()&lt;/code&gt;&lt;/a&gt; function.&lt;/li&gt;
&lt;li&gt;Finally, the resized image is returned.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Et voilà! As you can see, resizing an image in Vanilla JavaScript takes only a few lines of code.&lt;/p&gt;
&lt;h3 id=&quot;2-resizing-in-action&quot;&gt;2. Resizing in Action&lt;/h3&gt;
&lt;p&gt;Now, it is time to see the &lt;code&gt;resizeImage()&lt;/code&gt; function in action through a simple example.&lt;br&gt;
&lt;em&gt;index.html&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;!&lt;/span&gt;&lt;span&gt;DOCTYPE&lt;/span&gt;&lt;span&gt; html&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;html&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &amp;#x3C;&lt;/span&gt;&lt;span&gt;body&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;h1&lt;/span&gt;&lt;span&gt;&gt;Image Resizer&amp;#x3C;/&lt;/span&gt;&lt;span&gt;h1&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      Please, upload an image and it will be shown both original and resized by&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      50%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;input&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;upload&quot;&lt;/span&gt;&lt;span&gt; type&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;file&quot;&lt;/span&gt;&lt;span&gt; accept&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;image/*&quot;&lt;/span&gt;&lt;span&gt; required&lt;/span&gt;&lt;span&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;images&quot;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;&lt;/span&gt;&lt;span&gt;h2&lt;/span&gt;&lt;span&gt;&gt;Original image&amp;#x3C;/&lt;/span&gt;&lt;span&gt;h2&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;&lt;/span&gt;&lt;span&gt;img&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;imgToResize&quot;&lt;/span&gt;&lt;span&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;&lt;/span&gt;&lt;span&gt;h2&lt;/span&gt;&lt;span&gt;&gt;Resized image&amp;#x3C;/&lt;/span&gt;&lt;span&gt;h2&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;&lt;/span&gt;&lt;span&gt;img&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;resizedImage&quot;&lt;/span&gt;&lt;span&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span&gt;div&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt; src&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&quot;src/index.js&quot;&lt;/span&gt;&lt;span&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;script&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span&gt;body&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;html&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;src/index.js&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// hiding the div that will contain the images&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; imagesDiv&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;querySelector&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;#images&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;imagesDiv.style.visibility &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;hidden&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; fileInput&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;querySelector&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;#upload&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;fileInput.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;change&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;file&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; fileInput.files;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // displaying the uploaded image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; imageToResize&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;querySelector&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;#imgToResize&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  imageToResize.src &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; fileToDataUri&lt;/span&gt;&lt;span&gt;(file);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // resizing the image and displaying it&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; resizedImage&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;querySelector&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;#resizedImage&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  resizedImage.src &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; resizeImage&lt;/span&gt;&lt;span&gt;(imageToResize, &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // making the div containing the image visible&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  imagesDiv.style.visibility &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;visible&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; fileToDataUri&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;field&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; Promise&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;resolve&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; reader&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; FileReader&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    reader.&lt;/span&gt;&lt;span&gt;addEventListener&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;load&apos;&lt;/span&gt;&lt;span&gt;, () &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      resolve&lt;/span&gt;&lt;span&gt;(reader.result);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    reader.&lt;/span&gt;&lt;span&gt;readAsDataURL&lt;/span&gt;&lt;span&gt;(field);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; resizeImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;imgToResize&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;resizingFactor&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 0.5&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvas&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; document.&lt;/span&gt;&lt;span&gt;createElement&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;canvas&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; context&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; canvas.&lt;/span&gt;&lt;span&gt;getContext&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;2d&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; originalWidth&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; imgToResize.width;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; originalHeight&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; imgToResize.height;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvasWidth&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; originalWidth &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; resizingFactor;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; canvasHeight&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; originalHeight &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; resizingFactor;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  canvas.width &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; canvasWidth;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  canvas.height &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; canvasHeight;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  context.&lt;/span&gt;&lt;span&gt;drawImage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    imgToResize,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    originalWidth &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; resizingFactor,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    originalHeight &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; resizingFactor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  return&lt;/span&gt;&lt;span&gt; canvas.&lt;/span&gt;&lt;span&gt;toDataURL&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;&amp;#x3C;input&gt;&lt;/code&gt; element allows users to upload an image, then passed to the &lt;code&gt;resizeImage()&lt;/code&gt; function. This is in charge of generating the resized image, which is finally shown below the original image. Please, note that this example is the same presented in the fiddle placed at the beginning of the article.&lt;/p&gt;
&lt;h2 id=&quot;final-considerations&quot;&gt;Final Considerations&lt;/h2&gt;
&lt;p&gt;Resizing an image in Vanilla JavaScript is definitely an easy task. No external libraries are required, and you can achieve your goal with just a few lines of code. This is great! On the other hand, &lt;a href=&quot;https://entropymine.com/resamplescope/notes/browsers/&quot;&gt;every browser&lt;/a&gt; applies a different image interpolation algorithm behind the scenes. This leads to results depending on the user’s preferred browser. Not only might this be a problem in terms of consistency, but also a source of quality issues. Plus, such a simple task can turn into a nightmare if you wanted to implement a proper UI, allowing users to resize an image graphically.&lt;/p&gt;
&lt;p&gt;In that case, a commercial and comprehensive solution like &lt;code&gt;[PhotoEditorSDK](https://img.ly/products/photo-sdk/)&lt;/code&gt; is a more beneficial approach. In fact, you should no longer have to worry about inconsistencies or quality issues. Moreover, with only one library, you get several tools to treat images without having to implement the application’s UI. Also, whenever you need help, you can ask for support from the &lt;a href=&quot;https://img.ly/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;IMG.LY&lt;/a&gt; developers who built the SDK.&lt;/p&gt;
&lt;h2 id=&quot;resizing-an-image-with-photoeditor-sdk&quot;&gt;Resizing an Image with PhotoEditor SDK&lt;/h2&gt;
&lt;p&gt;First, you should read &lt;a href=&quot;https://img.ly/docs/pesdk/web/guides/umd/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;this&lt;/a&gt; article from &lt;a href=&quot;https://img.ly/docs/pesdk/guides/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;the official documentation&lt;/a&gt; on how to get started with &lt;code&gt;PhotoEditorSDK&lt;/code&gt; in HTML and JavaScript. Then, by using the &lt;a href=&quot;https://img.ly/docs/pesdk/web/features/transform/?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;transform tool&lt;/a&gt; you can perform cropping, &lt;a href=&quot;https://img.ly/docs/pesdk/web/features/transform/#image-resizing?utm_source=imgly&amp;#x26;utm_medium=blog&amp;#x26;utm_campaign=howtos&quot;&gt;resizing&lt;/a&gt;, flipping, and rotation operations with just one feature. This way, you should be able to achieve the desired result:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Transform Images with PhotoEditor SDK&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 800px) 800px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;800&quot; height=&quot;476&quot; src=&quot;https://img.ly/_astro/resize-image-with-javascript_1gJOFK.webp&quot; srcset=&quot;/_astro/resize-image-with-javascript_Z20b4Fi.webp 640w, /_astro/resize-image-with-javascript_Z1Ep5cX.webp 750w, /_astro/resize-image-with-javascript_1gJOFK.webp 800w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this article, we looked at how to resize an image with JavaScript. Resizing an image by using &lt;code&gt;&amp;#x3C;canvas&gt;&lt;/code&gt; is not a complex task, although this solution might introduce quality issues. As we have seen, you can resize an image effortlessly and with only a handful of lines of code. On the other hand, every browser applies a different resizing algorithm, leading to inconsistent results. For consistent and reliable results, you should take advantage of a more advanced and complete solution – such as &lt;code&gt;PhotoEditorSDK&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Thanks for reading! We hope that you found this article helpful. Feel free to reach out to us on &lt;a href=&quot;https://twitter.com/imgly&quot;&gt;Twitter&lt;/a&gt; with any questions, comments, or suggestions.&lt;/p&gt;</content:encoded><dc:creator>Antonello</dc:creator><media:content url="https://blog.img.ly/2021/07/resize-image-with-javascript-pesdk.png" medium="image"/><category>JavaScript</category><category>Photo Editing</category><category>Photo Editor</category><category>Web Development</category><category>Software Development</category><category>App Development</category><category>Developer Tools</category><category>Code</category><category>Tech</category><category>How-To</category><category>Tutorial</category></item><item><title>My digital journey to #nfts</title><link>https://img.ly/blog/my-digital-journey-to-nfts/</link><guid isPermaLink="true">https://img.ly/blog/my-digital-journey-to-nfts/</guid><pubDate>Fri, 26 Mar 2021 11:07:26 GMT</pubDate><content:encoded>&lt;h2 id=&quot;the-beginning&quot;&gt;&lt;strong&gt;The Beginning&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;In my first years as a graphic designer, my world consisted mainly of paper, books and magazines. To give you an example, my bachelor and master thesis were both printed books (Yes - I am that old). So i was born analog, but i wanted to become more digital.&lt;/p&gt;
&lt;p&gt;In the last three years, I have done my own personal digitalization and transformed from the analog design world into a digital one to the point that last weekend I created and launched my first crypto art - an NFT.&lt;/p&gt;
&lt;h2 id=&quot;but-first--what-is-an-nft&quot;&gt;But First – What is an NFT?&lt;/h2&gt;
&lt;p&gt;I have read about NFTs before from time to time. Then, two weeks ago, the internet went wild about the news that a well-known New York gallery sold a digital painting worth $69 million for the first time. And this made me thinking a bit more about the subject again and I decided to join the hype. Let’s get rich!&lt;/p&gt;
&lt;p&gt;But what is a NFT and how does it work? NFT stands for &lt;strong&gt;N&lt;/strong&gt;on-&lt;strong&gt;F&lt;/strong&gt;ungible &lt;strong&gt;T&lt;/strong&gt;oken which is secured by the Ethereum blockchain. 1 ETH is a fungible token – like bitcoin – a digital currency that is exchangeable. However, in contrast to ETH, a NFT can represent ownership of unique items. These unique items can be digital art like an image or a video, or any other digital asset. Within the process of creating an NFT, the digital asset will get connected to the token - which is called “minting”. Even though that image can easily be copied or recreated, the NFT can prove to a third-party that a specific person or entity owns this token. This makes digital art verifiable and unique.&lt;/p&gt;
&lt;p&gt;What excites me so much about NFTs is that they make it possible to give digital art a real value. In addition it gives digital artists the opportunity to be perceived as artists in the same way as their colleagues who paint with brush and paint on canvas. So this means that digital art can finally step up to it’s physical counterpart. The beginning of a whole new era of art.&lt;/p&gt;
&lt;p&gt;Currently it feels like that one can basically mint everything to an NFT and people go crazy about it. Why? Because people always liked to collect special and rare things like stamps, pokemon cards, oil paintings and so on - the list is basically endless.&lt;/p&gt;
&lt;h2 id=&quot;going-digital&quot;&gt;&lt;strong&gt;Going digital&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Circling back to my own story about transforming from an analog world to a digital one, the first step was to make my work more digital. Three years ago I gave up being self-employment and started working as an art director at &lt;a href=&quot;https://img.ly&quot;&gt;IMG.LY&lt;/a&gt;. We do develop software for photo and video editing. Our first product was the &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;Photoeditor SDK&lt;/a&gt; later followed by our &lt;a href=&quot;https://img.ly/products/video-sdk/&quot;&gt;Videoeditor SDK&lt;/a&gt;. However, last year we started defining our goals and begin the journey to transform our editor into a completely new tool that combines photo editing with automatic layouting. Automated and simplified processes make it possible for designer to focus more on the development of cool concepts instead of struggling with the technology itself.&lt;/p&gt;
&lt;p&gt;Some time ago - while testing the functions of our tool, I created a series of pixel-art images. In my opinion this pixel-art style fits the topic of NFTs quite well, so that I created a small series with three matching images, which got the name “Life behind Pixels”.&lt;/p&gt;
&lt;p&gt;One of these pictures was supposed to be my first NFT, but I had to realize that my digital transformation still has some gaps that I need to fill. There are various marketplaces that function like galleries, where one can upload their digital art for everyone to see and be verified as an official artist. I chose &lt;a href=&quot;https://rarible.com/&quot;&gt;Rarible&lt;/a&gt; because it has a rather small community compared to the big ones like e.g. &lt;a href=&quot;https://opensea.io/&quot;&gt;OpenSea&lt;/a&gt; and it is possible for everyone to join. Other marketplaces tend to select artists they work with based on the number of followers and how well-known they are in the community.&lt;/p&gt;
&lt;p&gt;If you want to create an NFT –  so called “minting” it, you have to connect your digital wallet to one of these platforms and pay a fee (gas) of about $60 in Ethereum. Unfortunately I don’t have a wallet or even digital money, so what can I do? I asked my boyfriend who works as firmware engineer in the &lt;a href=&quot;https://9elements.com/&quot;&gt;9elements&lt;/a&gt; cyber security department and who was of course already deep in the crypto universe and bang: My first NFT was minted. Now I’m even more fired up.&lt;/p&gt;
&lt;p&gt;And although this NFT topic is on everyone’s lips in the digital scene right now, I recently noticed in a clubhouse talk with other designers that this hasn’t arrived everywhere yet.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;here can you find our latest NFT art on &amp;quot;Rarible&amp;quot;: https://rarible.com/ellly&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1184px) 1184px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1184&quot; height=&quot;1120&quot; src=&quot;https://img.ly/_astro/rarible_screenshot_Z1O12ww.webp&quot; srcset=&quot;/_astro/rarible_screenshot_Z2ncPiV.webp 640w, /_astro/rarible_screenshot_3tJNG.webp 750w, /_astro/rarible_screenshot_Z1MBnja.webp 828w, /_astro/rarible_screenshot_Z2fYRIY.webp 1080w, /_astro/rarible_screenshot_Z1O12ww.webp 1184w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;and-now-what&quot;&gt;And now what?&lt;/h2&gt;
&lt;p&gt;First we are curious to see what happens with our first NFT and we are trying to find out what else is possible with it. Instead of attaching unique information to a simple image file and making it unique, there is a way more potential behind it: NFTs can be minted in a way that allows them to react to their environment using their integrated code. For example they can show a different state in the morning, at noon and in the evening or their appearance changes due to the number of attached wallets.&lt;/p&gt;
&lt;p&gt;Right now we’re looking at everything there is to know about NFT and blockchain to develop more crypto art and be part of the new era. Our plan is to create a new piece of crypto art every month. I’m trying to figure out what’s hot in crypto design right now. What do we need to stand out and be visually and technically unique?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;OpenSea Marketplace&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 1631px) 1631px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;1631&quot; height=&quot;1152&quot; src=&quot;https://img.ly/_astro/opensa_screenshot_GfjqP.webp&quot; srcset=&quot;/_astro/opensa_screenshot_1ByYTL.webp 640w, /_astro/opensa_screenshot_Z1dpIHX.webp 750w, /_astro/opensa_screenshot_97NoO.webp 828w, /_astro/opensa_screenshot_Z1HIrX8.webp 1080w, /_astro/opensa_screenshot_1MY9dU.webp 1280w, /_astro/opensa_screenshot_GfjqP.webp 1631w&quot;&gt;&lt;/p&gt;
&lt;p&gt;And what are the options if you don’t have a friend working in the tech area?I think besides a monthly NFT, there could also be a monthly blogpost ;)&lt;/p&gt;
&lt;p&gt;Also check out Instagram and Twitter for daily updates!&lt;br&gt;
&lt;a href=&quot;https://www.instagram.com/ellly_pix&quot;&gt;https://www.instagram.com/ellly_pix&lt;/a&gt;  &lt;a href=&quot;https://twitter.com/ellly_pix&quot;&gt;https://twitter.com/ellly_pix&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A more technical deep dive can be found &lt;a href=&quot;https://ethereum.org/en/nft/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Despite the fact that I am super thrilled about NFTs and that I finally generated my own, there is also a lot of controversial discussion going on about the climate impact of NFTs and the energy consumed to mint digital assets. If you like to follow up with this discussion, I put together some interesting links where you can also find some alternatives to the “minting” process:&lt;/p&gt;
&lt;p&gt;Calculate the CO2 Footprint of your Ethereum address: &lt;a href=&quot;https://carbon.fyi/&quot;&gt;https://carbon.fyi/&lt;/a&gt;&lt;br&gt;
&lt;a href=&quot;https://www.greenpeace.org.uk/news/the-biggest-problem-with-carbon-offsetting-is-that-it-doesnt-really-work/&quot;&gt;h&lt;/a&gt;&lt;a href=&quot;https://www.greenpeace.org.uk/news/the-biggest-problem-with-carbon-offsetting-is-that-it-doesnt-really-work/&quot;&gt;ttps://www.greenpeace.org.uk/news/the-biggest-problem-with-carbon-offsetting-is-that-it-doesnt-really-work/&lt;/a&gt;&lt;br&gt;
&lt;a href=&quot;https://memoakten.medium.com/the-unreasonable-ecological-cost-of-cryptoart-2221d3eb2053&quot;&gt;https://memoakten.medium.com/the-unreasonable-ecological-cost-of-cryptoart-2221d3eb2053&lt;/a&gt;&lt;br&gt;
&lt;a href=&quot;https://www.hicetnunc.xyz/&quot;&gt;https://www.hicetnunc.xyz/&lt;/a&gt;&lt;br&gt;
&lt;a href=&quot;https://xtz.news/latest-tezos-news/getting-started-as-an-nft-artist-on-tezos-using-hicetnunc/&quot;&gt;https://xtz.news/latest-tezos-news/getting-started-as-an-nft-artist-on-tezos-using-hicetnunc/&lt;/a&gt;&lt;/p&gt;</content:encoded><dc:creator>Vanessa</dc:creator><media:content url="https://blog.img.ly/2021/03/ellly_blog_Zeichenfla-che-1.png" medium="image"/><category>Design</category><category>Creativity</category><category>Code</category><category>Technology</category><category>Insights</category></item><item><title>A Photo and Video Editor for React Native Apps</title><link>https://img.ly/blog/a-photo-and-video-editor-for-your-react-native-apps/</link><guid isPermaLink="true">https://img.ly/blog/a-photo-and-video-editor-for-your-react-native-apps/</guid><pubDate>Fri, 29 May 2020 10:30:01 GMT</pubDate><content:encoded>&lt;hr&gt;
&lt;h3 id=&quot;how-to-integrate-a-photo-and-video-editor-into-your-react-native-app&quot;&gt;How to integrate a Photo and Video Editor into your React Native App&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;This tutorial walks you through the integration process of PhotoEditor SDK and VideoEditor SDK into your React Native app for iOS and Android. You’ll learn how to use our React Native modules to facilitate the integration and to customize our editors. For this tutorial we presume that all the necessary development tools for building an iOS and Android app are met, so make sure to complete the official &lt;a href=&quot;https://reactnative.dev/docs/getting-started&quot;&gt;React Native CLI Quickstart&lt;/a&gt; guides for iOS and Android beforehand.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Please make sure to acquire the licenses for &lt;a href=&quot;https://img.ly/products/photo-sdk/&quot;&gt;PhotoEditor SDK&lt;/a&gt; and &lt;a href=&quot;https://img.ly/products/video-sdk/&quot;&gt;VideoEditor SDK&lt;/a&gt; before integrating them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/embed/e9JiCMQKrJY?feature=oembed&quot;&gt;https://www.youtube.com/embed/e9JiCMQKrJY?feature=oembed&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In this tutorial, we’re going to show how to integrate PhotoEditor SDK and VideoEditor SDK for iOS and Android into your React Native app. Therefore, we created React Native modules for our products to simplify this process for you as much as possible. We’re going to use &lt;a href=&quot;https://github.com/imgly/vesdk-react-native&quot;&gt;VideoEditor SDK’s README&lt;/a&gt;, which is in most parts identical to the PhotoEditor SDK’s README, and Visual Studio Code. So, let’s get started.&lt;/p&gt;
&lt;p&gt;First, we create a React Native project with the name “Demo” based on the default template by using the command &lt;code&gt;npx react-native init Demo&lt;/code&gt;. The project will now be initialized and automatically install all dependencies of the current React Native version. Afterwards, we can find the new React Native project ready to use in the folder “Demo”. So, we’ll speed this up a little.&lt;/p&gt;
&lt;p&gt;We already prepared another folder with resources and assets that we want to integrate in our app. Here we chose an image, the required licenses for our PhotoEditor SDK and VideoEditor SDK for both target platforms, a video and two logos that we will later use to show how we can customize our editors. We copy these resources into the root of our project to make the resources accessible for our app.&lt;/p&gt;
&lt;p&gt;Now, we switch to the folder of the “Demo” project*.* We can now copy and execute the command &lt;code&gt;yarn add react-native-videoeditorsdk&lt;/code&gt; from the README to install the dependencies to the React Native module for our VideoEditor SDK … and to the React Native module for PhotoEditor SDK by issuing the command &lt;code&gt;yarn add react-native-photoeditorsdk&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now, we’re going to set up the dependencies for our native iOS libraries. We can simply copy the command &lt;code&gt;cd ios &amp;#x26;&amp;#x26; pod install &amp;#x26;&amp;#x26; cd ..&lt;/code&gt; from the README and execute it to install all iOS dependencies. They include the native PhotoEditor SDK and VideoEditor SDK libraries that are required by our React Native modules.&lt;/p&gt;
&lt;p&gt;And now, we set up the dependencies for our native Android libraries. The required steps that we will now take are described in detail in the README.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;android {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  defaultConfig {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    multiDexEnabled true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;dependencies {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  implementation ‘androidx.multidex:multidex:2.0.1’&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We copy the lines and add them at the end of our &lt;code&gt;android/app/build.gradle&lt;/code&gt; file. Now we need to change the superclass of our &lt;code&gt;MainApplication&lt;/code&gt; class to enable Multidex. Next, we add the img.ly repository and the plugin by copying the following lines and add them at the top of our &lt;code&gt;android/build.gradle&lt;/code&gt; file located in our Android folder.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;buildscript {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  repositories {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    jcenter()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    maven { url &quot;https://plugins.gradle.org/m2/&quot; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    maven { url &quot;https://artifactory.img.ly/artifactory/imgly&quot; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  dependencies {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    classpath &quot;org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.61&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    classpath &apos;ly.img.android.sdk:plugin:7.1.8&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we can configure our PhotoEditor SDK and VideoEditor SDK by opening the &lt;code&gt;android/app/build.gradle&lt;/code&gt; file and add these lines under &lt;code&gt;apply plugin: “com.android.application&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;apply plugin: &apos;ly.img.android.sdk&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;apply plugin: &apos;kotlin-android&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// Comment out the modules you don&apos;t need, to save size.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;imglyConfig {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  modules {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;ui:text&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;ui:focus&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;ui:frame&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;ui:brush&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;ui:filter&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;ui:sticker&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;ui:overlay&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;ui:transform&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;ui:adjustment&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;ui:text-design&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;ui:video-trim&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // This module is big, remove the serializer if you don&apos;t need that feature.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;backend:serializer&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    // Remove the asset packs you don&apos;t need, these are also big in size.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;assets:font-basic&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;assets:frame-basic&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;assets:filter-basic&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;assets:overlay-basic&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;assets:sticker-shapes&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    include &apos;assets:sticker-emoticons&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Getting back to our iOS version, we can now launch our demo project on iOS, which will currently look like a plain React Native project that we initialized with the first command.&lt;/p&gt;
&lt;p&gt;The main difference to an off-the-shelf React Native project is that our React Native modules are installed and ready-to-use in the &lt;code&gt;App.js&lt;/code&gt; file once the native projects are compiled. Then, it won’t be necessary to recompile the native projects for the remainder of this tutorial. We sped up the compilation a little and here we go — our React Native app is running on the iOS simulator. Now, we do the same for the Android version and wait until the project is compiled.&lt;/p&gt;
&lt;p&gt;Now, the demo project launched on both platforms as we can see on the right on the iOS simulator at the top, and on the Android emulator at the bottom of the screen.&lt;/p&gt;
&lt;p&gt;We’ve decided that we want to start our photo editor by pressing a button. So next, we’re going to actually customize our React Native app by adding this button. Therefore, we open the &lt;code&gt;App.js&lt;/code&gt; file and import the &lt;code&gt;Button&lt;/code&gt; component in order to create a button with the title “Edit a sample image”. For now, we leave the &lt;code&gt;onPress&lt;/code&gt; function empty.&lt;/p&gt;
&lt;p&gt;We save the &lt;code&gt;App.js&lt;/code&gt; file to trigger a refresh of the running apps and immediately see the result on the right. The new button appears in both, the iOS and the Android app.&lt;/p&gt;
&lt;p&gt;Now we create a second button with the title “Edit a sample video”. This will respectively start our video editor. And again, we save the &lt;code&gt;App.js&lt;/code&gt; file and see the second button appear on the right side.&lt;/p&gt;
&lt;p&gt;Next, we are going to add the code that actually opens our editors when we press the buttons. Visual Studio Code automatically imported the respective React Native PhotoEditor SDK module for us at the very top of the file, while writing the code that makes use of our SDK. We do the same for the VideoEditor SDK. We use the &lt;code&gt;require&lt;/code&gt; function to make static assets available to our app. Here, we “require” our sample image and our sample video that we copied to the app’s folder in the beginning and pass them as the first argument to our &lt;code&gt;openEditor&lt;/code&gt; functions. The first argument can also be a regular URI.&lt;/p&gt;
&lt;p&gt;We save the &lt;code&gt;App.js&lt;/code&gt; file again and now we can click the buttons to start our photo editor or video editor. There we go! We still see a watermark here. The reason for this watermark is that we haven’t unlocked our SDKs so far which we will do next.&lt;/p&gt;
&lt;p&gt;We unlock both products with our licenses to get rid of the watermark. If not unlocked, the watermark will be on both the image and video previews as well as on the exported images and videos. To unlock the products, we use the &lt;code&gt;unlockWithLicense&lt;/code&gt; function of each SDK. In total, we need four license files, one license file for each product and platform combination. The license files should be named &lt;code&gt;pesdk_license&lt;/code&gt; and &lt;code&gt;vesdk_license&lt;/code&gt; with platform-specific extensions &lt;code&gt;.ios.json&lt;/code&gt; and &lt;code&gt;.android.json&lt;/code&gt;. React Native will then automatically pick the right file for the corresponding platform. After this, the watermarks will be removed for PhotoEditor SDK and VideoEditor SDK on both platforms. And now you can also see it in the simulator —  no watermarks anymore.&lt;/p&gt;
&lt;p&gt;In the next step, we’re going to change the configuration of the editors. If no changes are made to the configuration, our default stickers are available with the editor. To customize them, we need to import the &lt;code&gt;Configuration&lt;/code&gt; from either the PhotoEditor SDK or VideoEditor SDK. The configurations are compatible between both products. So, for this tutorial, we decided to use the VideoEditor SDK configuration which we are now using by adding &lt;code&gt;Configuration&lt;/code&gt; to the &lt;code&gt;react-native-videoeditorsdk&lt;/code&gt; imports. We decided that we want to add custom stickers to our editors. Therefore we define a non-default configuration to the sticker tool.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const configuration: Configuration = {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  sticker: {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To customize the sticker assets, we need to define the sticker “categories” array. Here, we define a new category and name the identifier &lt;code&gt;demo_sticker_category&lt;/code&gt;. These asset identifiers must always be unique. Next, we set a name for the category and we name it “Logos”.&lt;/p&gt;
&lt;p&gt;Each category also requires a thumbnail image to be displayed in the editor. For the thumbnail, we use the React logo that we added to the folder of our app at the very beginning. Next, we define the items for this new sticker category. These items are the actual stickers that we can apply to the edited image or video. We now create a new sticker for the React logo. Therefore, we call the identifier &lt;code&gt;demo_sticker_react&lt;/code&gt; and name it “React”. These sticker names won’t appear in the UI, but they are used for accessibility. Now, we need to define the actual image that should be used for that sticker. Here we use the React image again.&lt;/p&gt;
&lt;p&gt;To create a second sticker, we can now copy and paste the code of the first sticker. We create a sticker with our img.ly logo and rename the identifier of the pasted code to &lt;code&gt;demo_sticker_imgly&lt;/code&gt;. Accordingly, we set the name to “img.ly” and change the file to &lt;code&gt;imgly.png&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In addition, we want to specify a non-default tint mode for our second sticker by using &lt;code&gt;tintMode: TintMode.SOLID&lt;/code&gt; which enables us to change the color of the sticker. The &lt;code&gt;TintMode&lt;/code&gt; type is automatically added to the VideoEditor SDK imports for us by Visual Studio Code. Now, that we completed our configuration, we need to pass it as the second argument to the &lt;code&gt;openEditor&lt;/code&gt; functions in order to take effect.&lt;/p&gt;
&lt;p&gt;We save the &lt;code&gt;App.js&lt;/code&gt; file again to refresh the running apps and we can see the result live after starting a new editing session. Please note that you cannot alter the configuration of a running editor instance. You always need to start a new editing session to see configuration changes.&lt;/p&gt;
&lt;p&gt;We want to use another feature of our SDKs which is called serialization. With the serialization feature, we can capture all image and video editing operations that are applied in the editor and export them. This allows us to import the editing operations in later sessions and continue editing. The serializations are compatible between both products as well. The input serialization is the third parameter of the &lt;code&gt;openEditor&lt;/code&gt; functions of our SDKs and the output serialization is optionally part of their result type.&lt;/p&gt;
&lt;p&gt;First, we check if the result is “null”. This is the case when a user clicks the “Discard” button in the editor and thus does not export an image or video. If the result is not ”null”, we know that the user exported an image or video. Then we can assign the exported serialization to the previously defined global serialization variable which will then be input to the next editing session. We copy the code and add it to the video editor as well to enable the serialization function here too.&lt;/p&gt;
&lt;p&gt;Now, one thing is left to enable the actual serialization export in the configuration. The serialization export is disabled per default because not every user needs the serialization feature. Here, we enable it now and also change the export type to &lt;code&gt;object&lt;/code&gt;. By doing so, the result type of the editor will contain the serialization as an &lt;code&gt;object&lt;/code&gt;. Per default, the serialization is exported to a file and that file name is returned as part of the export result. Writing the serialization to a file is a reasonable default as serializations can be quite large, especially if large amounts of binary data for personal stickers are embedded.&lt;/p&gt;
&lt;p&gt;Now, we can run the app on the simulator and use all the parameters that we configured in this tutorial. First, we can add our custom stickers, both the React logo and the img.ly logo. Here we can also change the colors which we enabled with the tint mode.&lt;/p&gt;
&lt;p&gt;We can also use the text design tool to add a phrase to our image. Here we can pick different designs, so we’re trying a couple and place the text design fitting to the image and logo.&lt;/p&gt;
&lt;p&gt;Next, we export our image with the serialization. With the serialization function enabled, it is now possible to import the editing operations into our video editor. This allows us to keep on editing because the serialization is compatible between both products. So here we can add further words to our text design. We can also put filters on our video. For example, we can choose the peach duo tone and increase the contrast a little. And here we go! We successfully integrated PhotoEditor SDK and VideoEditor SDK into our React Native app.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thanks for reading! To stay in the loop, subscribe to our&lt;/strong&gt; &lt;a href=&quot;https://photoeditorsdk.us13.list-manage.com/subscribe?u=dc9f652839dbb620d14d6d28d&amp;#x26;id=04a306e4b2&quot;&gt;&lt;strong&gt;Newsletter&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;.&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Julia</dc:creator><dc:creator>Alexander</dc:creator><media:content url="https://blog.img.ly/2020/05/_Integration_--1-.png" medium="image"/><category>App Development</category><category>Code</category><category>Developer Tools</category><category>Developer</category><category>Development</category><category>Image Editing</category><category>JavaScript</category><category>Mobile App Development</category><category>Photo Editing</category><category>React</category><category>React Native</category><category>Software Development</category><category>Tech</category><category>Tutorial</category><category>Video Editing</category><category>How-To</category><category>Company</category></item><item><title>Rebuild or Report?</title><link>https://img.ly/blog/rebuild-or-report-211d6ac6e787/</link><guid isPermaLink="true">https://img.ly/blog/rebuild-or-report-211d6ac6e787/</guid><description>On helping yourself and others through precise Bug Reports </description><pubDate>Thu, 26 Apr 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Nowadays, every code project depends on various third party and additional libraries. Truth be told, we wouldn’t be able to create apps or webpages that fast if we would have to build everything from scratch. Typically, we add a library via our favored package manager and give it a go. We start using that specific library, read the docs, figure out how it works and use it for our purposes. Best case, that’s it. Unfortunately, in practice, it may turn out differently.&lt;/p&gt;
&lt;h2 id=&quot;make-no-mistake-mistakeshappen&quot;&gt;&lt;strong&gt;Make no Mistake, Mistakes happen&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;While we work with a specific library, we may encounter some roadblocks. Sometimes that’s due to missing or bad documentation. Or it might be due to our missing knowledge about some things. Anyway, sometimes, we eventually realize that it is not us, it was them all along. We found a mistake, a so-called bug.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A (software) bug is an error, flaw, failure or fault in a computer program or system that causes it to produce an incorrect or unexpected result, or to behave in unintended ways.&lt;/p&gt;
&lt;p&gt;— Wikipedia&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If we’re honest, our first reaction may be that we get angry at the library itself or the author, but, after acknowledging that we never wrote flawless or bug-free code, we look for a solution.&lt;/p&gt;
&lt;h2 id=&quot;we-found-a-bug-nowwhat&quot;&gt;&lt;strong&gt;We found a Bug! Now what?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Logically, some of us start to follow the most obvious path. We throw that library away and write a replacement ourselves…&lt;strong&gt;not&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Ok, honestly, we may think about that, but it in most cases that is neither the right nor the best way to go. Many authors put a lot of effort into creating software libraries and shared it with us. So, most undoubtedly, a lot of knowledge, work, testing and time has already gone into it.&lt;/p&gt;
&lt;p&gt;Therefore, there is a high chance that rewriting that library from scratch is the least favorable option.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;So, what should we do?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Worst case scenario: We don’t do anything and leave it be. But this way it won’t get fixed, the authors won’t be aware of it, and others will encounter the same bug and spend unnecessary time on it.&lt;/p&gt;
&lt;p&gt;Best case scenario: We track down the bug, propose a solution to the authors and hope they will acknowledge and accept it. But sometimes we don’t have the means, options or time to fix the bug. Consequently, the second best way is telling the authors about the bug you found. But wait, before we file a bug we should ask ourselves the following question&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Are we running the latest version of the library?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;writing-good-bug-reports-helps-yourself-andothers&quot;&gt;&lt;strong&gt;Writing good Bug Reports helps Yourself and Others&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;We at &lt;a href=&quot;https://img.ly/&quot;&gt;IMG.LY&lt;/a&gt; provide a software library for photo editing. Thus, we are both library authors as well as users.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I would like to say that we don’t ever make mistakes, but truth be told, everyone does.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As you can imagine, providing photo editing capabilities results in a lot of code for rendering, UI, or other business logic. Although all the usual quality checks are in place, mistakes or unthought-of use-cases manifest in bugs, no matter what.&lt;/p&gt;
&lt;p&gt;Consequently, we get bug reports. Now, unfortunately, an awful lot of said bug reports only contain a single line that literally says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“XYZ does not work.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;While, this is far better than not reporting it at all, it doesn’t help much in hunting down the bug.&lt;/p&gt;
&lt;p&gt;With bug reports like this, we spend a lot of our time on trying to reproduce the bug or asking for details on how to reproduce it. That time would be better spent on improving the libraries or helping other users. However, with just a little help we’d be able to find bugs faster and be more effective. So, what should a proper bug report look like? From our point of view, bug reports should be comprised out of the following things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One bug at a time,&lt;/li&gt;
&lt;li&gt;the context of the bug,&lt;/li&gt;
&lt;li&gt;a minimal runnable example, and&lt;/li&gt;
&lt;li&gt;the steps to reproduce the bug.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;one-bug-at-atime&quot;&gt;&lt;strong&gt;One bug at a time&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;In reality, one may encounter multiple bugs at the same time, and might wish to drop them at the library authors all at once. However, it is far better not to combine multiple problems even if they seem to be alike. So, one should always report each bug individually.&lt;/p&gt;
&lt;h2 id=&quot;describing-thecontext&quot;&gt;&lt;strong&gt;Describing the context&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Often forgotten when reporting bugs is to describe the context the bug occurs in. For us, a good bug report contains at least the following specifications:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A description,&lt;/li&gt;
&lt;li&gt;the environment&lt;/li&gt;
&lt;li&gt;the actual and desired output, and&lt;/li&gt;
&lt;li&gt;attachments (e.g. Screenshots).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;description&quot;&gt;Description&lt;/h3&gt;
&lt;p&gt;First thing we need to know is what the bug is about. This includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A short meaningful &lt;em&gt;title&lt;/em&gt; of the bug (e.g. Exporting image after crop and rotate corrupts output), and&lt;/li&gt;
&lt;li&gt;a &lt;em&gt;description&lt;/em&gt; of the bug which explains the error in an understandable manner.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;environment&quot;&gt;Environment&lt;/h3&gt;
&lt;p&gt;Due to the nature of web and app development, software libraries can be used in many different environments. All of which have their own little differences and quirks. Thus, it is very helpful to include information about the environment, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the used &lt;em&gt;operating system’s&lt;/em&gt; version (e.g. iOS 10.1),&lt;/li&gt;
&lt;li&gt;the &lt;em&gt;device&lt;/em&gt; it is running on (e.g. iPhone 7 32GB),&lt;/li&gt;
&lt;li&gt;the &lt;em&gt;used browser or runtime environment&lt;/em&gt; and its version (e.g. Chrome 65.0.3325.181 (64-Bit) or Node.js 8.11.1 ), and not to forget&lt;/li&gt;
&lt;li&gt;the &lt;em&gt;name of the library&lt;/em&gt; and its version/variant (e.g. pesdk-html5 4.1.3).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;actual-output-and-expectedoutput&quot;&gt;Actual Output and Expected Output&lt;/h3&gt;
&lt;p&gt;Often, an experienced developer can classify the bug on the basis of the resulting error or error output only. Therefore, a useful bug report should provide:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the &lt;em&gt;actual output&lt;/em&gt; that is is observed, and&lt;/li&gt;
&lt;li&gt;the &lt;em&gt;desired output&lt;/em&gt; that should be generated&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;attachments&quot;&gt;Attachments&lt;/h3&gt;
&lt;p&gt;Additionally, attachments are very helpful to pinpoint the bug. Helpful attachments can be but are not limited to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;error output or logs&lt;/em&gt; generated by the compiler and build system, console output, and stack trace, and whenever the bug results in something that is visual recognizable, and&lt;/li&gt;
&lt;li&gt;&lt;em&gt;screenshots&lt;/em&gt; showing the issue.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;reproducibility-iskey&quot;&gt;&lt;strong&gt;&lt;em&gt;Reproducibility&lt;/em&gt;&lt;/strong&gt; &lt;strong&gt;is key&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;While all aforementioned greatly assists to narrow down the context in which the bug appears there is one thing that helps even more:&lt;/p&gt;
&lt;p&gt;Even if it seems trivial to reproduce, a good bug report should come with a &lt;em&gt;minimal runnable example&lt;/em&gt; that produces the bug in question and a description of how to trigger it.&lt;/p&gt;
&lt;h3 id=&quot;providing-a-minimal-runningexample&quot;&gt;Providing a minimal running Example&lt;/h3&gt;
&lt;p&gt;So, one should strip away everything from the current code that isn’t necessary and keep it simple. The faster we and other library maintainers can track down an error, the sooner it’s going to be fixed.&lt;/p&gt;
&lt;p&gt;Also, probably it was already necessary to narrow down the issue so stripping it out into a minimal example is not too much work. If possible, the Gist should be provided via a GitHub repository or any other similar sharing system.&lt;/p&gt;
&lt;h3 id=&quot;keep-it-simple-to-trigger-the-bug-and-be-specific-aboutit&quot;&gt;&lt;strong&gt;Keep it simple to trigger the Bug and be specific about it&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;While having a minimal example is already lovely, sometimes it needs a bit more than just code to trigger the bug. Writing down precise instructions on how to trigger it is not always easy but being specific dramatically helps to get to it.&lt;/p&gt;
&lt;p&gt;That is why one should summarize the problem in brevity and with utmost precision.&lt;/p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;From our point of view these are the most important things one needs to consider when reporting a bug. Most certainly, the requirements change and need to be adapted for different types of software. We’d really like your feedback on this. So, if you have any comments and additions please let us know.&lt;/p&gt;
&lt;p&gt;*&lt;strong&gt;*Thanks for reading! To stay in the loop, subscribe to our&lt;/strong&gt; &lt;a href=&quot;https://photoeditorsdk.us13.list-manage.com/subscribe?u=dc9f652839dbb620d14d6d28d&amp;#x26;id=04a306e4b2&quot;&gt;&lt;strong&gt;Newsletter&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;.**&lt;/strong&gt;&lt;/p&gt;</content:encoded><dc:creator>Daniel</dc:creator><media:content url="https://blog.img.ly/2020/04/image-35.png" medium="image"/><category>Software Development</category><category>Bug Report</category><category>Support</category><category>Code</category><category>Software</category><category>Learning</category></item></channel></rss>