Simple resize image in browser

Tram Ho

Do you know that you can resize images right in your browser without using any tools or libraries?

Use canvas

Canvas API allows us to draw 2D graphics as we want in the browser. This means that we can completely redraw an image of the desired size. In other words, resize it . Let’s take a look at the method used to redraw an image on the canvas drawImage . drawImage can have up to 9 parameters:

Inside:

  • sx , sy : is the top left position of the original image that we want to redraw.
  • sWidth , sHeight : is the size of the image we want to redraw from the original image.
  • dx , dy : is the position on the canvas that we want to redraw the original image.
  • dWidth , dHeight : is the size on the canvas that we want to redraw the original image.

So just set dWidth and dHeight to the size we want to resize and we will resize the image. Try it out. For example, I have this picture.

mashu.png

The original image size is 1207 x 1800 . Now I will resize it to 301 x 450 . Our code is like this:

This is the result.

mashu-rsz.png

Hmm, it doesn’t look so good . The image is quite sharp compared to the original image. This is because this API is not designed to resize images with good algorithms such as image editing tools or server-side libraries for performance reasons. So resizing with too much difference size will make the image look like this. To limit this, we will resize it little by little to avoid resizing too much. Resizing multiple times may cause a loss of quality, but it will avoid such aliasing. I modified the code a little like this, each time I will resize to half, gradually to the size I want.

Here is the result:

mashu-multirsz.png

It looks much better.

There is also an experimental feature currently available on Chrome that can customize resize quality as the imageSmoothingQuality option of 2D canvas context. I tried it and got the result like this:

mashu-hqrsz.png

It’s not much different from the above, I think the top is even more beautiful .

Use createImageBitmap

Still the Canvas API but this time we have another method, still only support on chrome (Firefox has support but is cropped instead of resize. createImageBitmap allows creating ImageBitmap to save image data from the original image (image or canvas). During the creation process also supports resize feature. And especially it returns a Promise so we don’t have to worry it will cause browser lag when rendering. Resizing an image still doesn’t see any difference, but you’ll see the difference in the paragraph after we resize multiple images at once. Probably thanks to that so it allows the use of better resize algorithms.

Now let’s try it out, the code is like this:

Here is the result:

mashu-cib.png

This is a picture I tried to resize with a good photo editing tool to see the quality is not much different.

mashu-pdn

Here is the code of all the above ways for you to compare. You open the full example to compare for ease. Results may vary depending on the browser you use.

Link codepen: https://codepen.io/thphuong/pen/qBOeMRb

Resize GIF

If you try the above way with GIF images will not work. For example, I resize this image

yutathrowheart.gif

Will only be the first frame.

yutathrow-first-frame.png

You probably already know that gif images are made up of frames. The day before, I also wrote a gif making article here . So if we can split the gif into frames, then resize each frame, then merge it back to the same place as the resized gif .

I will use gif-frames to split gif into frame and gif.js to merge frames into gif .

No more explaining how the library is used to save you time, code separates gif file into frame like this.

And this one to merge frames into gif

Function resize as before, then join and run, I will get the result like this.

yuta-throw-rsz-1.gif

Hmm, it’s got a black border again. As you can see, the original gif has a transparent background. With png, to have a transparent background we will give the transparent pixels the value alpha channel = 0 (a in rgba). At the edge of the border so the transition from colored to transparent will be smooth, not jagged, there will be a lot of px with reduced transparency, like this.

png-edge.png

As you can see, it is resize canvas, because it renders the png image, it is convenient to render the pixels in the border instead of being the same as the original image. Gifs do not have an alpha channel like png (RGB only), each pixel can only have color or no color, no blurry see-through type like png. The border is almost the same as png.

gif-edge.png

When we merge the frames, because there is no alpha channel, the transparent pixels which are rgba(0, 0, 0, 0) color rgba(0, 0, 0, 0) will be converted to rgb(0, 0, 0) (black). As you can see above, we need the transparent: 'rgba(0, 0, 0, 0)' option transparent: 'rgba(0, 0, 0, 0)' to know which pixels should be converted to transparent. In addition, the pixels near the border are rgb(0, 0, 0) and a close to 0, so it will still turn black. That’s why we have less black borders like the picture above.

So now we have 2 options. Fill the background with no more transparent borders. Or we fix it by fixing pixels with alpha channel to be not transparent as required by gif.

To edit the data of the image in the canvas, we use canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height).data . The image data will be an array of 8-bit integers (0-255). Each 4 numbers will be 1 pixel, representing 4 values ​​in rgba . So now I loop in the pile of array pixels and see that any color with a value less than 255 will set it to 255. Also, if pixels have alpha channel too small (<127), I also set = 0 always to prevent jaggies. Further code you see the fixEdgeSmoothing function in the demo.

The results are much better. Compared to resize with a good library like Imagemagick, I feel no less.

yuta-throw-rsz.gif

Code and demo here, guys.

Codesandbox: https://codesandbox.io/s/gif-resize-zn6bnl

Demo: https://zn6bn.csb.app

If you noticed, I used createImageBitmap when possible. When running on a browser that does not support createImageBitmap like Firefox, pressing the resize button will cause a delay in the browser due to the time-consuming resize.

Share the news now

Source : Viblo