Better image downscale with canvas.
npm install downscale
Better image downscale with canvas (demo)
===================================
This function downscales images in the browser, producing a better quality result, than the traditional 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.
Motivation
----------
While other image resizing libraries are based on complex interpolation algorithms such as Lanczos resampling, image downscaling usually doesn't require that complexity, because there is no interpolation happening (in other words we don't create new pixels).
On the other hand, browsers implement very fast HTMLCanvasElement 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.
To resolve this problem, the proposed function does a simple area-average downsampling, producing preferable results with relatively small processing time.
Performance
-----------
This function uses the technique, proposed by Paul Rouget in his article about pixel manipulation with Typed Arrays. His method reduces the number of read/write operations to the ArrayBuffer of the element. It is created using the ImageData(" class="text-primary hover:underline" target="_blank" rel="noopener noreferrer">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() 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.
Also, the usage of Math.round() function returns the value of a number rounded to the nearest integer.") method is avoided in favour of Bitwise operators, 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.
Image cropping
--------------
Image 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.
By default, the source image is cropped in the way, that the center of the source image is transfered to the resulting image.
Rollback to canvas resizing
--------
The 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.
Install
-------
```
npm install downscale
Syntax
------
`javascript`
Promise
File object, contained by the FileList, returned by the HTMLInputElement.files property.HTMLImageElement with the src HTML attribute, containing the full URL to the source image.HTMLVideoElement in any state.DOMString representing the URL to the source image.
Number indicating width of the resulting image. If the value is 0, the width is adapted to keep the same aspect ratio as in the source image.
Number indicating height of the resulting image. If the value is 0, the height is adapted to keep the same aspect ratio as in the source image.
DOMString indicating image format. Possible values are jpeg, png, webp. The default format type is jpeg.Number between 0 and 1 indicating image quality if the requested imageType is jpeg or webp. The default value is 0.85.Boolean indicating if the returned Promise should resolve with Blob object representing the resulting image. The default value is false.Boolean indicating if the returned Promise should resolve with HTMLCanvasElement containing the resulting image. The default value is false.Number 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.Number 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. that resolves to a DOMString containing the resulting image in data URI format.Examples
--------
html
`
#### Javascript
`javascript
function filesChanged(files)
{
for (var i = 0; i < files.length; i++) {
downscale(files[i], 400, 400).
then(function(dataURL) {
var destInput = document.createElement("input");
destInput.type = "hidden";
destInput.name = "image[]";
destInput.value = dataURL;
// Append image to form as hidden input
document.forms[0].appendChild(destInput);
// Preview image
var destImg = document.createElement("img");
destImg.src = dataURL;
document.body.appendChild(destImg);
})
}
}
`$3
You can use even cleaner FormData 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.
#### HTML
`html
`
#### Javascript
`javascript
var formData = new FormData();
var URL = window.URL || window.webkitURL;function filesChanged(files)
{
for (let i = 0; i < files.length; i++) {
downscale(files[i], 400, 400, {returnBlob: 1}).
then(function(blob) {
// Append image to form as a blob data
formData.append("userpic[]", blob, files[i].name);
// Preview image
var destImg = document.createElement("img");
destImg.src = URL.createObjectURL(blob);
document.body.appendChild(destImg);
})
}
}
function submitForm()
{
var request = new XMLHttpRequest();
request.open("POST", "http://foo.com/submitform.php");
request.send(formData);
}
`$3
Processing an element is quite simple. The function will wait for image load, so you don't have to worry about it.
#### HTML
`html

`
#### Javascript
`javascript
var sourceImg = document.getElementById('source');downscale(sourceImg, 400, 400).
then(function(dataURL) {
var destImg = document.createElement('img');
destImg.src = dataURL;
document.body.appendChild(destImg);
})
`$3
The function can upload the source image from the given URL with no extra code needed. Keep in mind that the image should share origin with the code file.
`javascript
var imageURL = "/public/1.jpg";downscale(imageURL, 400, 400).
then(function(dataURL) {
var destImg = document.createElement('img');
destImg.src = dataURL;
document.body.appendChild(destImg);
})
``Other libraries
---------------
Check out other great in-browser image resizing libraries:
- pica is great image resizing tool with support of WebWorkers thread to run without being blocked/slowed down.") and WebAssembly from the box
- Hermite-resize does image resize/resample using Hermite filter and WebWorkers thread to run without being blocked/slowed down.")
License
-------
MIT