<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Image Manipulation – IMG.LY Blog</title><description>Posts tagged Image Manipulation on the IMG.LY blog.</description><link>https://img.ly/blog/tag/image-manipulation/</link><language>en-us</language><image><url>https://img.ly/apple-touch-icon.png</url><title>Image Manipulation – IMG.LY Blog</title><link>https://img.ly/blog/tag/image-manipulation/</link></image><atom:link href="https://img.ly/blog/tag/image-manipulation/rss.xml" rel="self" type="application/rss+xml"/><generator>Astro</generator><lastBuildDate>Wed, 14 Oct 2026 14:42:51 GMT</lastBuildDate><ttl>60</ttl><item><title>Comparing the Top 5 Open Source JavaScript Image Manipulation Libraries</title><link>https://img.ly/blog/the-top-5-open-source-javascript-image-manipulation-libraries/</link><guid isPermaLink="true">https://img.ly/blog/the-top-5-open-source-javascript-image-manipulation-libraries/</guid><description>Learn the difference between five major image manipulation libraries and choose the right one for you!</description><pubDate>Tue, 27 Sep 2022 13:29:03 GMT</pubDate><content:encoded>&lt;p&gt;Image Manipulation Libraries (IML) are used to perform various manipulation functions on images: you can increase the brightness of an image, add saturation or filters, crop and resize, and more valuable features that will help you to do almost everything and turn your web browser into an Adobe Lightroom!&lt;br&gt;
We have included libraries for every significant image manipulation task, from simple, low-level operations such as filters, brightness, and saturation to single-purpose libraries for cropping or image composition. To finish up, we wandered into the realm of testing images, since no image manipulation application is complete without a reliable way to test results.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Updated September 2026.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;quick-comparison&quot;&gt;Quick comparison&lt;/h2&gt;
&lt;p&gt;Here’s how the five libraries compare at a glance.&lt;/p&gt;





















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Library&lt;/th&gt;&lt;th&gt;Runs in&lt;/th&gt;&lt;th&gt;Best for&lt;/th&gt;&lt;th&gt;Native dependencies&lt;/th&gt;&lt;th&gt;License&lt;/th&gt;&lt;th&gt;Latest release&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Sharp&lt;/td&gt;&lt;td&gt;Node.js, Deno, Bun&lt;/td&gt;&lt;td&gt;Fast resizing and format conversion&lt;/td&gt;&lt;td&gt;libvips (prebuilt for most systems)&lt;/td&gt;&lt;td&gt;Apache 2.0&lt;/td&gt;&lt;td&gt;0.35.4, August 2026&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Cropper.js&lt;/td&gt;&lt;td&gt;Browser&lt;/td&gt;&lt;td&gt;Cropping UI&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;td&gt;MIT&lt;/td&gt;&lt;td&gt;2.2.0, August 2026&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Merge Images&lt;/td&gt;&lt;td&gt;Browser, Node.js with node-canvas&lt;/td&gt;&lt;td&gt;Combining images&lt;/td&gt;&lt;td&gt;node-canvas in Node.js&lt;/td&gt;&lt;td&gt;MIT&lt;/td&gt;&lt;td&gt;2.0.0, March 2020&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;LooksSame&lt;/td&gt;&lt;td&gt;Node.js&lt;/td&gt;&lt;td&gt;Comparing images in tests&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;td&gt;MIT&lt;/td&gt;&lt;td&gt;10.0.1, August 2025&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Jimp&lt;/td&gt;&lt;td&gt;Browser, Node.js&lt;/td&gt;&lt;td&gt;Resizing, filters, and text&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;td&gt;MIT&lt;/td&gt;&lt;td&gt;1.6.1, April 2026&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;sharp&quot;&gt;Sharp&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://sharp.pixelplumbing.com/&quot;&gt;Sharp&lt;/a&gt; is a high-performance Node.js image processing library to resize different image formats such as JPEG, PNG, WebP, GIF, AVIF, SVG, and TIFF. The typical use case for this high-speed Node.js module is to convert large images in standard formats to smaller, web-friendly images. It works with Node.js (version 20.9.0 or later), Deno, and Bun.&lt;/p&gt;
&lt;p&gt;Sharp earns its place on large files or batches, and on compositing, extraction, color management and Pango-backed text. For resizing a single small image, ordinary HTML and vanilla JavaScript will be more beneficial. Sharp is built on libvips, which makes resizing typically 4x-5x faster than the quickest ImageMagick and GraphicsMagick settings, allowing you to resize and compress your images much more quickly.&lt;/p&gt;
&lt;h3 id=&quot;use-cases&quot;&gt;Use cases&lt;/h3&gt;
&lt;p&gt;I used it to resize a whole NFT Collection with a size of over 80Gb, which after compression came out at circa 10Gb. So again, if you would like to use it for resizing several large images, then it’s a strong choice. You’ll do it faster than the quickest ImageMagick and GraphicsMagick settings.&lt;/p&gt;
&lt;h3 id=&quot;example&quot;&gt;Example&lt;/h3&gt;
&lt;p&gt;You can install this library by using the command below:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;span&gt; sharp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is how you would resize an image using sharp:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; sharp&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; require&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;sharp&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sharp&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;yellow.png&apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  .&lt;/span&gt;&lt;span&gt;resize&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;200&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  .&lt;/span&gt;&lt;span&gt;toFile&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;yellow-200.png&apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  .&lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;info&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(info);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  .&lt;/span&gt;&lt;span&gt;catch&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;err&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(err);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  });&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;cropperjs&quot;&gt;Cropper.js&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/fengyuanchen/cropperjs&quot;&gt;Cropper.js&lt;/a&gt; is another popular JavaScript library for image manipulation. You can use it to crop your images in all possible ways, change aspect ratio, rotate, zoom and work with canvas data. &lt;a href=&quot;https://github.com/fengyuanchen/cropperjs&quot;&gt;Cropper.js&lt;/a&gt; is the right choice for cropping without any extra features. Version 2.0 rebuilt it as a set of web components, so code written for version 1 needs updating, although version 1 is still maintained.&lt;/p&gt;
&lt;h3 id=&quot;use-cases-1&quot;&gt;Use cases&lt;/h3&gt;
&lt;p&gt;You can use its flexible API to create a custom image cropping UI in your web app allowing your users to adjust photos to the correct size and aspect ratio. It will be more efficient because it requires almost nothing, doesn’t have any useless features, and is very optimized for cropping!&lt;/p&gt;
&lt;h3 id=&quot;example-1&quot;&gt;Example&lt;/h3&gt;
&lt;p&gt;This library can be installed with the following command:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;span&gt; cropperjs&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; Cropper &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;cropperjs&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; cropper&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; Cropper&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;#image&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; selection&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; cropper.&lt;/span&gt;&lt;span&gt;getCropperSelection&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;// cropper-canvas defaults to a 200px min-width and 100px min-height, so give it a real size&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cropper.&lt;/span&gt;&lt;span&gt;getCropperCanvas&lt;/span&gt;&lt;span&gt;().style.height &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;500px&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;selection.aspectRatio &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 16&lt;/span&gt;&lt;span&gt; /&lt;/span&gt;&lt;span&gt; 9&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;selection.&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;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;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(event.detail.x);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(event.detail.y);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(event.detail.width);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  console.&lt;/span&gt;&lt;span&gt;log&lt;/span&gt;&lt;span&gt;(event.detail.height);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check out the Cropper.js &lt;a href=&quot;https://fengyuanchen.github.io/cropperjs/playground.html&quot;&gt;playground&lt;/a&gt; to try it in your browser and see the result instantly.&lt;/p&gt;
&lt;p&gt;For an in-depth guide on how to add image cropping to your React app, check out our &lt;a href=&quot;blog/how-to-crop-an-image-in-react-with-react-image-crop/&quot;&gt;guide on using&lt;/a&gt; &lt;a href=&quot;blog/how-to-crop-an-image-in-react-with-react-image-crop/&quot;&gt;&lt;code&gt;react-image-crop&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;merge-images&quot;&gt;Merge Images&lt;/h2&gt;
&lt;p&gt;Working with the canvas can be slightly tedious, especially when you need the canvas context to do relatively simple things like merging a few images. &lt;a href=&quot;https://github.com/lukechilds/merge-images&quot;&gt;Merge Images&lt;/a&gt; abstracts all repetitive tasks into simple function calls. It’s a wrapper around the Canvas API, abstracting its low-level functions, which makes this specific task a lot easier. You can also create parameters like positioning, opacity, and several more. You can find them in the docs on &lt;a href=&quot;https://github.com/lukechilds/merge-images&quot;&gt;GitHub&lt;/a&gt;. It works in the browser and in Node.js (with node-canvas), though it hasn’t had a new release since version 2.0.0 in March 2020.&lt;/p&gt;
&lt;h3 id=&quot;use-cases-2&quot;&gt;Use cases&lt;/h3&gt;
&lt;p&gt;It’s a valuable library that can help with several tasks. For example, you can generate an NFT Collection where you can merge all components to have a complete set of variations. Or you can find this library helpful for personal use, for example, combining a few different images to generate a collage.&lt;/p&gt;
&lt;h3 id=&quot;example-2&quot;&gt;Example&lt;/h3&gt;
&lt;p&gt;Install the library itself:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;span&gt; --save&lt;/span&gt;&lt;span&gt; merge-images&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then you can use this code to generate a simple image:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;//write this inside of your javascript file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; mergeImages &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;merge-images&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;mergeImages&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;&apos;/body.png&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;/eyes.png&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;/mouth.png&apos;&lt;/span&gt;&lt;span&gt;]).&lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  (&lt;/span&gt;&lt;span&gt;b64&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; (document.&lt;/span&gt;&lt;span&gt;querySelector&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;img&apos;&lt;/span&gt;&lt;span&gt;).src &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; b64)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;//And that would update the img element to show this image:&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, I used it to merge several components to create a final variation (here I used Background, Character, Horns, Emotion, and Accessories).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Merge components for a new variation. I have used Background, Character, Horns, Emotion, and Accessories.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 4000px) 4000px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;4000&quot; height=&quot;5000&quot; src=&quot;https://img.ly/_astro/Cark--0454--1-_ZvLqbB.webp&quot; srcset=&quot;/_astro/Cark--0454--1-_Z1wxTcy.webp 640w, /_astro/Cark--0454--1-_14UP8b.webp 750w, /_astro/Cark--0454--1-_g6a9V.webp 828w, /_astro/Cark--0454--1-_ZhBA4t.webp 1080w, /_astro/Cark--0454--1-_15E14A.webp 1280w, /_astro/Cark--0454--1-_Z1e6wTF.webp 1668w, /_astro/Cark--0454--1-_1zXXWg.webp 2048w, /_astro/Cark--0454--1-_Z2sbDqJ.webp 2560w, /_astro/Cark--0454--1-_ZvLqbB.webp 4000w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;lookssame&quot;&gt;LooksSame&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/gemini-testing/looks-same&quot;&gt;LooksSame&lt;/a&gt; is a Node.js library for comparing images, built for visual regression testing. If the two images you uploaded are duplicates, the library will let you know. All you have to do is provide the file paths (or buffers) of the pictures you would like compared. LooksSame is not strictly an image manipulation library, but is helpful for testing purposes. It has had no release and no commit on its default branch since August 2025.&lt;/p&gt;
&lt;h3 id=&quot;use-cases-3&quot;&gt;Use cases&lt;/h3&gt;
&lt;p&gt;You can use this library and write code for automation and loop cycles that search a directory and compare each pair of your images for duplicates. Additionally, you can delete these duplicates and automate this process as well. It is a splendid library if you’re constantly working with ML algorithms that include large numbers of images.&lt;/p&gt;
&lt;h3 id=&quot;example-3&quot;&gt;Example&lt;/h3&gt;
&lt;p&gt;To start comparing images, you need just to install it by using this command:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span&gt; looks-same&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; i&lt;/span&gt;&lt;span&gt; -D&lt;/span&gt;&lt;span&gt; jest&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, you can see how to test this library with &lt;a href=&quot;https://jestjs.io/docs/getting-started&quot;&gt;Jest&lt;/a&gt;. The test compares two files you put next to it, &lt;code&gt;image1.png&lt;/code&gt; and &lt;code&gt;image2.png&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; looksSame&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; require&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;looks-same&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;//Parameters can be paths to files or buffer with compressed png image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;test&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;image1 and image2 are the same&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; () &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;equal&lt;/span&gt;&lt;span&gt; } &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; looksSame&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;image1.png&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;image2.png&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  expect&lt;/span&gt;&lt;span&gt;(equal).&lt;/span&gt;&lt;span&gt;toBe&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;//The test passes if the two images look the same&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;LooksSame loads its image decoder with a dynamic import, which Jest only allows with an extra Node flag. Run the test with &lt;code&gt;NODE_OPTIONS=--experimental-vm-modules npx jest&lt;/code&gt;, otherwise the suite fails before the test starts.&lt;/p&gt;
&lt;h2 id=&quot;jimp&quot;&gt;Jimp&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jimp-dev/jimp&quot;&gt;Jimp&lt;/a&gt; stands for JavaScript Image Manipulation Program, that allows you to edit your image in almost every possible way. With it, you can invert your image, add some text, resize, use pixelation, clone images, blur them, invert colors, and several other cool features which will increase the image manipulation capabilities of your app. It’s written entirely in JavaScript with zero native dependencies, so it runs both in the browser and in Node.js. Version 1.0 moved to named imports and options objects, so older code examples need small changes. Development has been quiet since the 1.6.1 release in April 2026.&lt;/p&gt;
&lt;h3 id=&quot;use-cases-4&quot;&gt;Use cases&lt;/h3&gt;
&lt;p&gt;With &lt;a href=&quot;https://github.com/jimp-dev/jimp&quot;&gt;Jimp&lt;/a&gt;, you can build your web application where you’ll be able to edit and manipulate images in almost any possible way. Crop, resize, rotate, and filter features let you create your own photo editor and add an interface on top of it. To streamline this process, you can try IMG.LY’s &lt;a href=&quot;products/photo-sdk/&quot;&gt;&lt;strong&gt;Photo Editor SDK&lt;/strong&gt;&lt;/a&gt;. It will provide you with a polished user interface and photo editing features, so you can focus on the application you are building instead.&lt;/p&gt;
&lt;h3 id=&quot;example-4&quot;&gt;Example&lt;/h3&gt;
&lt;p&gt;Here’s the JavaScript code to try this excellent library. There’s an async function in which you can see many types of properties that you can easily change. Such as &lt;em&gt;Add Text&lt;/em&gt;, &lt;em&gt;Resize Image&lt;/em&gt;, &lt;em&gt;Blur the Image&lt;/em&gt;, etc. To use at least one of them, you’ll need to uncomment only part that you need, and your program is ready to run! The example uses &lt;code&gt;import&lt;/code&gt; and writes files to disk, so save it as an &lt;code&gt;.mjs&lt;/code&gt; file and run it with Node.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// Import dependencies&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { Jimp, loadFont } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;jimp&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; { SANS_16_WHITE } &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &apos;jimp/fonts&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; function&lt;/span&gt;&lt;span&gt; () {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // Read the image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; image&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; Jimp.&lt;/span&gt;&lt;span&gt;read&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;images/shapes.png&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // // Add text&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  const font = await loadFont(SANS_16_WHITE); // bitmap fonts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  image.print({ font, x: 0, y: 0, text: &apos;Hello world!&apos; });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  // Resize the image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  // Resize the image to 250 x 250&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  image.resize({ w: 250, h: 250 });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  // Resize the height to 250 and scale the width accordingly&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  image.resize({ h: 250 });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  // Resize the width to 250 and scale the height accordingly&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  image.resize({ w: 250 });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  // Add a sepia wash to the image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  image.sepia();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  // Pixelation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  image.pixelate(5);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  // Clone&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  const image2 = image.clone();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  // Blur the image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  image.gaussian(1);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  image.blur(1);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  // Inverts the image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  image.invert();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  // Set the brightness&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  image.brightness(0.5);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  // Resize the image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  image.resize({ w: 256, h: 256 });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  // Convert to grayscale&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  image.greyscale();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // Save the image&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  await&lt;/span&gt;&lt;span&gt; image.&lt;/span&gt;&lt;span&gt;write&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;images/edited-shapes.png&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  // Or save it as a JPEG with a set quality&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  //  await image.write(&apos;images/edited-shapes.jpg&apos;, { quality: 100 });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;})();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;PS: Don’t forget to uncomment the effects which you want to use and save the file after. :)&lt;/p&gt;
&lt;p&gt;As you can see here, I blurred everything and inverted the colors for the previous image that I showed you, getting the following result:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The shapes image after Jimp blurred it and inverted its colors.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; sizes=&quot;(min-width: 2000px) 2000px, 100vw&quot; data-astro-image=&quot;constrained&quot; data-astro-image-pos=&quot;center&quot; width=&quot;2000&quot; height=&quot;2500&quot; src=&quot;https://img.ly/_astro/edited-shapes--1-_ZNQdOU.webp&quot; srcset=&quot;/_astro/edited-shapes--1-_Z1sqhGl.webp 640w, /_astro/edited-shapes--1-_1zUk2V.webp 750w, /_astro/edited-shapes--1-_1VHvQg.webp 828w, /_astro/edited-shapes--1-_ZDagoU.webp 1080w, /_astro/edited-shapes--1-_Z1hzfoz.webp 1280w, /_astro/edited-shapes--1-_ZeiJHv.webp 1668w, /_astro/edited-shapes--1-_ZNQdOU.webp 2000w&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;other-libraries-worth-a-look&quot;&gt;Other libraries worth a look&lt;/h2&gt;
&lt;p&gt;A few more open-source libraries come up often and might fit your project better. &lt;a href=&quot;https://github.com/nodeca/pica&quot;&gt;Pica&lt;/a&gt; resizes images in the browser with high quality, picking the best technology available, such as web workers or WebAssembly. &lt;a href=&quot;https://github.com/fabricjs/fabric.js&quot;&gt;Fabric.js&lt;/a&gt; is an HTML5 canvas library with built-in image filters and interactions like scale, move, and rotate. &lt;a href=&quot;https://github.com/scaleflex/filerobot-image-editor&quot;&gt;Filerobot Image Editor&lt;/a&gt; gives your users a ready-made editor for cropping, resizing, filters, and annotations, though installing it today pulls a 5.0 beta while its README still documents the 4.x API. And &lt;a href=&quot;https://github.com/image-js/image-js&quot;&gt;image-js&lt;/a&gt; is an image processing and manipulation library maintained by Zakodium. All four are MIT-licensed.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;That’s it! Now you know the differences between five of the most popular image manipulation libraries for JavaScript. Some of them are useful for only one task, such as resizing images, while others can do multiple tasks at once and help you with more processes. You have also met IMG.LY’s &lt;a href=&quot;products/photo-sdk/&quot;&gt;Photo Editor SDK&lt;/a&gt; to work smarter and save time building photo editing solutions, and focus on building your great product instead.&lt;/p&gt;
&lt;p&gt;These libraries all solve the processing half of the problem. If what you actually need is an editor your users work in, the calculation changes, and an open-source library is not always the cheaper path once you count the UI. We wrote an &lt;a href=&quot;blog/open-source-photo-editing-sdks-vs-img-ly-ce-sdk-an-honest-comparison-for-developers/&quot;&gt;honest comparison of the open-source photo editing SDKs against CE.SDK&lt;/a&gt; that lays out where each one stops.&lt;/p&gt;
&lt;h2 id=&quot;faq&quot;&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Should I use Sharp or Jimp?&lt;/strong&gt;
Use Sharp when speed matters, for example when you process large images or many of them on a server. It’s built on libvips and runs natively. Use Jimp when you want zero native dependencies or need the same code to run in the browser, and you can accept slower processing. Jimp has been quiet since its 1.6.1 release in April 2026.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Does Sharp work in the browser?&lt;/strong&gt;
No. Sharp runs on Node.js, Deno, and Bun, and its documentation lists browser use as unsupported for the WebAssembly build. For resizing images in the browser, Jimp and Pica are the options from this guide.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What changed in Cropper.js 2.0?&lt;/strong&gt;
Cropper.js 2.0 is a rewrite built from web components such as cropper-canvas, cropper-image, and cropper-selection. Options like aspectRatio moved onto those elements, so code written for version 1 needs updating. The docs list version 1’s status as Maintaining against version 2’s Active, so it remains an option if you aren’t ready to migrate.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Is Merge Images still maintained?&lt;/strong&gt;
It still works, but it hasn’t had a new release since version 2.0.0 in March 2020. In Node.js, it needs node-canvas to run.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How do I compare two images in automated tests?&lt;/strong&gt;
LooksSame compares two images, given as file paths or buffers, and tells you whether they look the same. By default, it ignores differences a person wouldn’t notice, such as antialiasing, and you can switch to strict mode to catch every difference.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Which library should I use for a photo editor UI?&lt;/strong&gt;
None of the five are complete editors on their own. Cropper.js gives you a cropping UI, and Filerobot Image Editor is an open-source editor you can embed. If you need a complete, customizable photo editor, IMG.LY’s Photo Editor SDK provides the interface and editing features.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Are these libraries free for commercial use?&lt;/strong&gt;
Yes. Sharp’s own code uses the Apache 2.0 license, and Cropper.js, Merge Images, LooksSame, and Jimp use the MIT license. The prebuilt libvips binaries that an install of Sharp pulls in are published under LGPL-3.0-or-later. All three licenses allow commercial use.&lt;/p&gt;
</content:encoded><dc:creator>Mark</dc:creator><media:content url="https://blog.img.ly/2022/09/image-manipulation-libraries-javascript-1.png" medium="image"/><category>How-To</category><category>Image Manipulation</category><category>Image Editing</category><category>Insights</category></item></channel></rss>