{"id":26716461,"url":"https://github.com/ytiurin/downscale","last_synced_at":"2025-04-07T17:08:46.289Z","repository":{"id":25696386,"uuid":"102403754","full_name":"ytiurin/downscale","owner":"ytiurin","description":"Better image downscale with canvas.","archived":false,"fork":false,"pushed_at":"2023-01-06T01:34:06.000Z","size":36624,"stargazers_count":100,"open_issues_count":20,"forks_count":17,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-27T15:32:08.094Z","etag":null,"topics":["canvas","crop","downsample","downscale","fast","image","javascript","jpeg","linear","performance","photo","pica","png","processing","resample","resize","scale","sharp","thumbnails","upload"],"latest_commit_sha":null,"homepage":"https://ytiurin.github.io/downscale/demo/multiselect.html","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ytiurin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-09-04T21:23:32.000Z","updated_at":"2025-01-22T12:11:22.000Z","dependencies_parsed_at":"2023-01-14T07:00:50.565Z","dependency_job_id":null,"html_url":"https://github.com/ytiurin/downscale","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ytiurin%2Fdownscale","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ytiurin%2Fdownscale/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ytiurin%2Fdownscale/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ytiurin%2Fdownscale/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ytiurin","download_url":"https://codeload.github.com/ytiurin/downscale/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247694876,"owners_count":20980733,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["canvas","crop","downsample","downscale","fast","image","javascript","jpeg","linear","performance","photo","pica","png","processing","resample","resize","scale","sharp","thumbnails","upload"],"created_at":"2025-03-27T15:27:35.868Z","updated_at":"2025-04-07T17:08:46.267Z","avatar_url":"https://github.com/ytiurin.png","language":"JavaScript","readme":"\nBetter image downscale with canvas ([demo](https://ytiurin.github.io/downscale/demo/multiselect.html \"Quick demo\"))\n===================================\nThis function downscales images in the browser, producing a better quality result, than the traditional [`CanvasRenderingContext2D.scale()`](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/scale \"The CanvasRenderingContext2D.scale() method of the Canvas 2D API adds a scaling transformation to the canvas units by x horizontally and by y vertically.\") method. It neutralises the \"fuzzy\" look caused by the native canvas downsampling, when processing relatively large images like photos taken with a smartphone. Check the [demo page](https://ytiurin.github.io/downscale/demo/multiselect.html \"Quick demo\").\n\n![Better image downscale demo](https://github.com/ytiurin/downscale/raw/master/public/demo.jpg)\n\nMotivation\n----------\nWhile other image resizing libraries are based on complex interpolation algorithms such as [Lanczos resampling](https://en.wikipedia.org/wiki/Lanczos_resampling \"Lanczos resampling and Lanczos filtering are two applications of a mathematical formula. It can be used as a low-pass filter or used to smoothly interpolate the value of a digital signal between its samples.\"), image downscaling usually doesn't require that complexity, because there is no interpolation happening (in other words we don't create new pixels).\n\nOn the other hand, browsers implement very fast [`HTMLCanvasElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement \"The HTMLCanvasElement interface provides properties and methods for manipulating the layout and presentation of canvas elements.\") downsampling, when the pixel from source position is directly transfered to the destination position, loosing all the neighbouring pixels information. The resulting image may often look very noisy.\n\nTo resolve this problem, the proposed function does a simple area-average downsampling, producing preferable results with relatively small processing time.\n\nPerformance\n-----------\nThis function uses the technique, proposed by [Paul Rouget](http://paulrouget.com/) in his [article](https://hacks.mozilla.org/2011/12/faster-canvas-pixel-manipulation-with-typed-arrays/ \"Faster Canvas Pixel Manipulation with Typed Arrays\") about pixel manipulation with [Typed Arrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays \"JavaScript typed arrays are array-like objects and provide a mechanism for accessing raw binary data.\"). His method reduces the number of read/write operations to the [`ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer \"The ArrayBuffer object is used to represent a generic, fixed-length raw binary data buffer. You cannot directly manipulate the contents of an ArrayBuffer; instead, you create one of the typed array objects or a DataView object which represents the buffer in a specific format, and use that to read and write the contents of the buffer.\") of the [`ImageData`](https://developer.mozilla.org/en-US/docs/Web/API/ImageData \"The ImageData interface represents the underlying pixel data of an area of a \u003ccanvas\u003e element. It is created using the ImageData() constructor or creator methods on the CanvasRenderingContext2D object associated with a canvas: createImageData() and getImageData(). It can also be used to set a part of the canvas by using putImageData().\") returned by the [`CanvasRenderingContext2D.getImageData()`](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/getImageData \"The CanvasRenderingContext2D.getImageData() method of the Canvas 2D API returns an ImageData object representing the underlying pixel data for the area of the canvas denoted by the rectangle which starts at (sx, sy) and has an sw width and sh height. This method is not affected by the canvas transformation matrix.\") method. This saves overall processing time when you want to iterate through every pixel of the source image.\n\nAlso, the usage of [`Math.round()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round \"The Math.round() function returns the value of a number rounded to the nearest integer.\") method is avoided in favour of [Bitwise operators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators \"Bitwise operators treat their operands as a sequence of 32 bits (zeroes and ones), rather than as decimal, hexadecimal, or octal numbers. For example, the decimal number nine has a binary representation of 1001. Bitwise operators perform their operations on such binary representations, but they return standard JavaScript numerical values.\"), giving a significant boost in performance in some browsers.\n\nImage cropping\n--------------\nImage cropping is very often used in pair with resizing, but both can be very naturally combined. As we don't need to iterate through pixels in cropped areas, the function does both downscaling and cropping in range of the same processing loop. This saves some memory and processing time.\n\nBy default, the source image is cropped in the way, that the center of the source image is transfered to the resulting image.\n\nRollback to `canvas` resizing\n--------\nThe function also uses basic `canvas` resizing method when the scale factor of the resulting image is greater than 0.5x. So the better downscaling happen only when the resulting image is at least 2 times smaller than the initial image. In other cases basic `canvas` resizing gives better image quality result.\n\nInstall\n-------\n```\nnpm install downscale\n```\n\nSyntax\n------\n```javascript\nPromise\u003cDOMString\u003e downscale(source, width, height[, options]);\n```\n\n### Parameters\n\u003cdl\u003e\n  \u003cdt\u003esource\u003c/dt\u003e\n  \u003cdd\u003e\n    Defines the source of the image data to downscale. This can either be:\n    \u003cul\u003e\n      \u003cli\u003e\n        A \u003ca href=\"https://developer.mozilla.org/en-US/docs/Web/API/File\" title=\"The File interface provides information about files and allows JavaScript in a web page to access their content.\"\u003e\u003ccode\u003eFile\u003c/code\u003e\u003c/a\u003e object, contained by the \u003ca href=\"https://developer.mozilla.org/en-US/docs/Web/API/FileList\" title=\"An object of this type is returned by the files property of the HTML \u003cinput\u003e element; this lets you access the list of files selected with the \u003cinput type=\u0026quot;file\u0026quot;\u003e element. It's also used for a list of files dropped into web content when using the drag and drop API; see the DataTransfer object for details on this usage.\"\u003e\u003ccode\u003eFileList\u003c/code\u003e\u003c/a\u003e, returned by the \u003ccode\u003e\u003ca href=\"https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement#files_prop\" title=\"The HTMLInputElement interface provides special properties and methods for manipulating the layout and presentation of input elements.\"\u003eHTMLInputElement.files\u003c/a\u003e\u003c/code\u003e property.\n      \u003c/li\u003e\n      \u003cli\u003e\n        A \u003ccode\u003e\u003ca title=\"The HTMLVideoElement interface provides special properties and methods for manipulating video objects. It also inherits properties and methods of HTMLMediaElement and HTMLElement.\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement\"\u003eHTMLImageElement\u003c/a\u003e\u003c/code\u003e with the \u003ccode\u003e\u003ca title=\"The image URL. This attribute is mandatory for the \u003cimg\u003e element.\" href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-src\"\u003esrc\u003c/a\u003e\u003c/code\u003e HTML attribute, containing the full URL to the source image.\n      \u003c/li\u003e\n      \u003cli\u003e\n        A \u003ca title=\"The HTMLVideoElement interface provides special properties and methods for manipulating video objects. It also inherits properties and methods of HTMLMediaElement and HTMLElement.\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement\"\u003e\u003ccode\u003eHTMLVideoElement\u003c/code\u003e\u003c/a\u003e in any state.\n      \u003c/li\u003e\n      \u003cli\u003e\n        A \u003ca title=\"DOMString is a UTF-16 String. As JavaScript already uses such strings, DOMString is mapped directly to a String.\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/DOMString\"\u003e\u003ccode\u003eDOMString\u003c/code\u003e\u003c/a\u003e representing the URL to the source image.\n      \u003c/li\u003e\n    \u003c/ul\u003e\n  \u003c/dd\u003e\n\n  \u003cdt\u003ewidth\u003c/dt\u003e\n  \u003cdd\u003eA \u003ca href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number\" title=\"The Number JavaScript object is a wrapper object allowing you to work with numerical values. A Number object is created using the Number() constructor.\"\u003e\u003ccode\u003eNumber\u003c/code\u003e\u003c/a\u003e indicating width of the resulting image. If the value is \u003ccode\u003e0\u003c/code\u003e, the width is adapted to keep the same aspect ratio as in the source image.\u003c/dd\u003e\n\n  \u003cdt\u003eheight\u003c/dt\u003e\n  \u003cdd\u003eA \u003ca href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number\" title=\"The Number JavaScript object is a wrapper object allowing you to work with numerical values. A Number object is created using the Number() constructor.\"\u003e\u003ccode\u003eNumber\u003c/code\u003e\u003c/a\u003e indicating height of the resulting image. If the value is \u003ccode\u003e0\u003c/code\u003e, the height is adapted to keep the same aspect ratio as in the source image.\u003c/dd\u003e\n\n  \u003cdt\u003eoptions \u003csup\u003e(optional)\u003c/sup\u003e\u003c/dt\u003e\n  \u003cdd\u003e\n    An object with properties representing optional function parameters:\n    \u003cul\u003e\n      \u003cli\u003e\n        \u003cdl\u003e\n          \u003cdt\u003eimageType\u003c/dt\u003e\n          \u003cdd\u003eA \u003ca title=\"DOMString is a UTF-16 String. As JavaScript already uses such strings, DOMString is mapped directly to a String.\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/DOMString\"\u003e\u003ccode\u003eDOMString\u003c/code\u003e\u003c/a\u003e indicating image format. Possible values are \u003ccode\u003ejpeg\u003c/code\u003e, \u003ccode\u003epng\u003c/code\u003e, \u003ccode\u003ewebp\u003c/code\u003e. The default format type is \u003ccode\u003ejpeg\u003c/code\u003e.\u003c/dd\u003e\n        \u003c/dl\u003e\n      \u003c/li\u003e\n      \u003cli\u003e\n        \u003cdl\u003e\n          \u003cdt\u003equality\u003c/dt\u003e\n          \u003cdd\u003eA \u003ca href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number\" title=\"The Number JavaScript object is a wrapper object allowing you to work with numerical values. A Number object is created using the Number() constructor.\"\u003e\u003ccode\u003eNumber\u003c/code\u003e\u003c/a\u003e between \u003ccode\u003e0\u003c/code\u003e and \u003ccode\u003e1\u003c/code\u003e indicating image quality if the requested \u003ccode\u003eimageType\u003c/code\u003e is \u003ccode\u003ejpeg\u003c/code\u003e or \u003ccode\u003ewebp\u003c/code\u003e. The default value is \u003ccode\u003e0.85\u003c/code\u003e.\u003c/dd\u003e\n        \u003c/dl\u003e\n      \u003c/li\u003e\n      \u003cli\u003e\n        \u003cdl\u003e\n          \u003cdt\u003ereturnBlob\u003c/dt\u003e\n          \u003cdd\u003eA \u003ca title=\"The Boolean object is an object wrapper for a boolean value.\" href=\"/en-US/docs/Web/API/Boolean\"\u003e\u003ccode\u003eBoolean\u003c/code\u003e\u003c/a\u003e indicating if the returned \u003ca href=\"https://developer.mozilla.org/en-US/docs/Web/API/Promise\" title=\"The Promise interface represents a proxy for a value not necessarily known at its creation time. It allows you to associate handlers to an asynchronous action's eventual success or failure. This lets asynchronous methods return values like synchronous methods: instead of the final value, the asynchronous method returns a promise of having a value at some point in the future.\"\u003e\u003ccode\u003ePromise\u003c/code\u003e\u003c/a\u003e should resolve with \u003ca href=\"https://developer.mozilla.org/en-US/docs/Web/API/Blob\" title=\"A Blob object represents a file-like object of immutable, raw data. Blobs represent data that isn't necessarily in a JavaScript-native format. The File interface is based on Blob, inheriting blob functionality and expanding it to support files on the user's system.\"\u003e\u003ccode\u003eBlob\u003c/code\u003e\u003c/a\u003e object representing the resulting image. The default value is \u003ccode\u003efalse\u003c/code\u003e.\u003c/dd\u003e\n        \u003c/dl\u003e\n      \u003c/li\u003e\n      \u003cli\u003e\n        \u003cdl\u003e\n          \u003cdt\u003ereturnCanvas\u003c/dt\u003e\n          \u003cdd\u003eA \u003ca title=\"The Boolean object is an object wrapper for a boolean value.\" href=\"/en-US/docs/Web/API/Boolean\"\u003e\u003ccode\u003eBoolean\u003c/code\u003e\u003c/a\u003e indicating if the returned \u003ca href=\"https://developer.mozilla.org/en-US/docs/Web/API/Promise\" title=\"The Promise interface represents a proxy for a value not necessarily known at its creation time. It allows you to associate handlers to an asynchronous action's eventual success or failure. This lets asynchronous methods return values like synchronous methods: instead of the final value, the asynchronous method returns a promise of having a value at some point in the future.\"\u003e\u003ccode\u003ePromise\u003c/code\u003e\u003c/a\u003e should resolve with \u003ca title=\"The HTMLCanvasElement interface provides properties and methods for manipulating the layout and presentation of canvas elements. The HTMLCanvasElement interface also inherits the properties and methods of the HTMLElement interface.\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement\"\u003e\u003ccode\u003eHTMLCanvasElement\u003c/code\u003e\u003c/a\u003e containing the resulting image. The default value is \u003ccode\u003efalse\u003c/code\u003e.\u003c/dd\u003e\n        \u003c/dl\u003e\n      \u003c/li\u003e\n      \u003cli\u003e\n        \u003cdl\u003e\n          \u003cdt\u003esourceX\u003c/dt\u003e\n          \u003cdd\u003eA \u003ca href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number\" title=\"The Number JavaScript object is a wrapper object allowing you to work with numerical values. A Number object is created using the Number() constructor.\"\u003e\u003ccode\u003eNumber\u003c/code\u003e\u003c/a\u003e indicating distance from the left side of the source image to draw into the destination context. This allows to crop the source image from the left side. The default value is calculated to centralize the destination rectangle relatively to the source canvas.\u003c/dd\u003e\n        \u003c/dl\u003e\n      \u003c/li\u003e\n      \u003cli\u003e\n        \u003cdl\u003e\n          \u003cdt\u003esourceY\u003c/dt\u003e\n          \u003cdd\u003eA \u003ca href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number\" title=\"The Number JavaScript object is a wrapper object allowing you to work with numerical values. A Number object is created using the Number() constructor.\"\u003e\u003ccode\u003eNumber\u003c/code\u003e\u003c/a\u003e indicating distance from the top side of the source image to draw into the destination context. This allows to crop the source image from the top side. The default value is calculated to centralize the destination rectangle relatively to the source canvas.\u003c/dd\u003e\n        \u003c/dl\u003e\n      \u003c/li\u003e\n    \u003c/ul\u003e\n  \u003c/dd\u003e\n\u003c/dl\u003e\n\n### Return value\nA [`Promise`](https://developer.mozilla.org/en-US/docs/Web/API/Promise \"The Promise interface represents a proxy for a value not necessarily known at its creation time. It allows you to associate handlers to an asynchronous action's eventual success or failure. This lets asynchronous methods return values like synchronous methods: instead of the final value, the asynchronous method returns a promise of having a value at some point in the future.\") that resolves to a [`DOMString`](https://developer.mozilla.org/en-US/docs/Web/API/DOMString \"DOMString is a UTF-16 String. As JavaScript already uses such strings, DOMString is mapped directly to a String.\") containing the resulting image in [data URI](https://developer.mozilla.org/en-US/docs/Web/HTTP/data_URIs \"URLs prefixed with the data: scheme, allow content creators to embed small files inline in documents.\") format.\n\nExamples\n--------\n### Send image data with `\u003cform\u003e`\nThis is just a simple code snippet which uses the form file input as a source of the image data.\n#### HTML\n```html\n\u003cinput type=\"file\" accept=\"image/*\" onchange=\"filesChanged(this.files)\" multiple /\u003e\n\u003cform method=\"post\"\u003e\u003cinput type=\"submit\"/\u003e\u003c/form\u003e\n```\n#### Javascript\n```javascript\nfunction filesChanged(files)\n{\n  for (var i = 0; i \u003c files.length; i++) {\n    downscale(files[i], 400, 400).\n    then(function(dataURL) {\n      var destInput = document.createElement(\"input\");\n      destInput.type = \"hidden\";\n      destInput.name = \"image[]\";\n      destInput.value = dataURL;\n      // Append image to form as hidden input\n      document.forms[0].appendChild(destInput);\n      // Preview image\n      var destImg = document.createElement(\"img\");\n      destImg.src = dataURL;\n      document.body.appendChild(destImg);\n    })\n  }\n}\n```\n\n### Send image data with `FormData`\nYou can use even cleaner [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData \"The FormData interface provides a way to easily construct a set of key/value pairs representing form fields and their values, which can then be easily sent using the XMLHttpRequest.send() method. It uses the same format a form would use if the encoding type were set to \\\"multipart/form-data\\\".\") interface to send pure `blob` data to the server.\n#### HTML\n```html\n\u003cinput type=\"file\" accept=\"image/*\" onchange=\"filesChanged(this.files)\" multiple /\u003e\n\u003cbutton onclick=\"submitForm()\"\u003eSubmit form data\u003c/button\u003e\n\n\u003cdiv id=\"previews\"\u003e\u003c/div\u003e\n```\n#### Javascript\n```javascript\nvar formData = new FormData();\nvar URL = window.URL || window.webkitURL;\n\nfunction filesChanged(files)\n{\n  for (let i = 0; i \u003c files.length; i++) {\n    downscale(files[i], 400, 400, {returnBlob: 1}).\n    then(function(blob) {\n      // Append image to form as a blob data\n      formData.append(\"userpic[]\", blob, files[i].name);\n      // Preview image\n      var destImg = document.createElement(\"img\");\n      destImg.src = URL.createObjectURL(blob);\n      document.body.appendChild(destImg);\n    })\n  }\n}\n\nfunction submitForm()\n{\n  var request = new XMLHttpRequest();\n  request.open(\"POST\", \"http://foo.com/submitform.php\");\n  request.send(formData);\n}\n```\n\n### Resize `\u003cimg\u003e` element\nProcessing an `\u003cimg\u003e` element is quite simple. The function will wait for image load, so you don't have to worry about it.\n#### HTML\n```html\n\u003cimg id=\"source\" src=\"../public/1.jpg\" /\u003e\n```\n#### Javascript\n```javascript\nvar sourceImg = document.getElementById('source');\n\ndownscale(sourceImg, 400, 400).\nthen(function(dataURL) {\n  var destImg = document.createElement('img');\n  destImg.src = dataURL;\n  document.body.appendChild(destImg);\n})\n```\n\n### Load image from URL\nThe function can upload the source image from the given URL with no extra code needed. Keep in mind that the image should share [origin](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin \"The Origin request header indicates where a fetch originates from. It doesn't include any path information, but only the server name. It is sent with CORS requests, as well as with POST requests. It is similar to the Referer header, but, unlike this header, it doesn't disclose the whole path.\") with the code file.\n```javascript\nvar imageURL = \"/public/1.jpg\";\n\ndownscale(imageURL, 400, 400).\nthen(function(dataURL) {\n  var destImg = document.createElement('img');\n  destImg.src = dataURL;\n  document.body.appendChild(destImg);\n})\n```\n\nOther libraries\n---------------\nCheck out other great in-browser image resizing libraries:\n- [pica](https://github.com/nodeca/pica \"Resize image in browser with high quality and high speed.\") is great image resizing tool with support of [WebWorkers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API \"Web Workers makes it possible to run a script operation in background thread separate from the main execution thread of a web application. The advantage of this is that laborious processing can be performed in a separate thread, allowing the main (usually the UI) thread to run without being blocked/slowed down.\") and [WebAssembly](https://developer.mozilla.org/en-US/docs/WebAssembly \"WebAssembly is a new type of code that can be run in modern web browsers — it is a low-level assembly-like language with a compact binary format that runs with near-native performance and provides languages such as C/C++ with a compilation target so that they can run on the web. It is also designed to run alongside JavaScript, allowing both to work together.\") from the box\n- [Hermite-resize](https://github.com/viliusle/Hermite-resize \"Canvas image resize/resample using Hermite filter with JavaScript.\") does image resize/resample using Hermite filter and [WebWorkers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API \"Web Workers makes it possible to run a script operation in background thread separate from the main execution thread of a web application. The advantage of this is that laborious processing can be performed in a separate thread, allowing the main (usually the UI) thread to run without being blocked/slowed down.\")\n\nLicense\n-------\nMIT\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fytiurin%2Fdownscale","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fytiurin%2Fdownscale","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fytiurin%2Fdownscale/lists"}