How to compress .png images when exporting from Canvas using toDataURL()? - javascript

Need to generate .png images that are about ~20k in size using HTML5 canvas. Unfortunately, when creating .pngs using the toDataURL() method, you cannot specify quality like you can with jpegs.
Any ideas for a workaround? toDataURL seems to be the only way to generate images from Canvas and canvas seems to be the best tool for image processing without server interaction. Appreciate any suggestions.

There IS a way to have compression for PNG images using lossless zlib deflate process http://www.w3.org/TR/PNG-Compression.html . There is a library (https://github.com/ShyykoSerhiy/canvas-png-compression) that provides shim for HTMLCanvasElement.toDataURL() when image type is 'image/png' and enables ability to provide 'quality' as second parameter to HTMLCanvasElement.toDataURL() for png.
NOTE that it provides better results(smaller size) only in Chrome. Firefox sometimes has better compression than canvas-png-compression(as for 0.0.3 version).

You can do something by scaling it down and then scaling it up again.
Scale down by drawing it on a smaller canvas, then get the data url.
Create an image object set the data url as its source.
Draw on the original canvas with this img object (obviously inside the onload event callback)
Find the size ratio of the canvases to give you optimum result by experimenting a bit.

Related

Is it possible to resize an image that is stored in a Uint8Array without using the browser's built-in canvas implementation?

I need to compress and rotate the image in the browser. Image sources can be drag'n'drop from a local user or the image can be downloaded from an URL with the same domain as the page with this script. But asking for permission to use HTML5 canvas doesn't fit into the design specification in any way.
The image can be in JPEG, PNG or HEIC format and in the current implementation is stored in Uint8Array. Is it possible to generate a thumbnail or change image orientation without using canvas?
No browser that I know of will ask for permission to use a canvas. Using a canvas is the quickest solution to do this (it's very simple indeed), and HEIC support is easy too: https://alexcorvi.github.io/heic2any/

Compressing and Resizing Images for the Web

So I'm currently building a website using a php backend and polymer frontend. The client wants to be able to have a news feature for their own events. For this I want to convert all the images to webp and create a few different sizes so I can serve them quickly to different browsers (Mobile, Tablet, Desktop etc). However I haven't been able to find a good way of doing this in PHP or JS. Squoosh is great for static assets but not user generated content. Any help appreciated thanks!
PHP has functions for manipulating webp images. Try this.
<?php
$im = imagecreatefromstring(file_get_contents('path/to/image.jpg')); // Create image identifier
imagewebp($im, 'path/to/image.webp'); // Generate webp image and save to location
imagedestroy($im); // Free up image identifier
?>
The resizing must be necessarily done server side. The thing that you can do is to use the srcset and sizes attributes of the image tag to optimize the version to use:
<img srcset="elva-fairy-320w.jpg 320w,
elva-fairy-480w.jpg 480w,
elva-fairy-800w.jpg 800w"
sizes="(max-width: 320px) 280px,
(max-width: 480px) 440px,
800px"
src="elva-fairy-800w.jpg" alt="Elva dressed as a fairy" />
(directly from Mozilla documentation)
I would highly recommend using Adobe Photoshop. With this you can manually compress/resize images or submit them in batch.
I don't know if you have access to the server, but one way could be to call ImageMagick from PHP.
It would require for PHP to interact with the server, which can be dangerous, so please keep that in mind.
ImageMagick although don't support webm, to my knowledge, but Im sure you get the idea behind the though.
If you don't want PHP to interact with the server itself, you could also scan for non-converted / Resized images, and then convert them.
On linux it could be: find ./ -name "*.jpg" -exec CONVERT_FUNCTION{} \;
For resizing and compressing the image, you would need an image library installed with your PHP, like ImageMagick or GD
You can write your own resizing function as shown in https://stackoverflow.com/a/14649689, but you have to be careful with the image-types, as they may have their own function per type.
A maybe more easy way to resize is using the image intervention package. https://image.intervention.io/v2/api/resize (this also requires either GD or IamgeMagick to be installed):
// resize image to fixed size
$img->resize(300, 200);
// resize only the width of the image
$img->resize(300, null);
// resize only the height of the image
$img->resize(null, 200);
// resize the image to a width of 300 and constrain aspect ratio (auto height)
$img->resize(300, null, function ($constraint) {
$constraint->aspectRatio();
});
Using this library, you may also compress the image using encode or save function:
https://image.intervention.io/v2/api/encode
https://image.intervention.io/v2/api/save
// open and resize an image file
$img = Image::make('public/foo.jpg')->resize(300, 200);
// save file as jpg with medium quality
$img->save('public/bar.jpg', 60);
You may alsouse tinypng API's to compress your images: https://tinypng.com/developers, it compresses jpg, png and WebP and is free if you scale 500 images per month

How to draw a bitmap file on a canvas in html?

How to draw a .bmp file using a canvas tag in html. i found ways to draw a png and jpeg but not bmp files. Can someone suggest me the approaches and also does every browser and platform support bmp files? Please help.
Drawing .bmp file is not limited by the canvas but infact by the browser. Here is a link to the browser image file support list. Besides that if you are new to canvas I am going to point you here to a bunch of fantastic resources on using canvas specifically the section of images about half way down the page. Out of curiosity why are you drawing and image to canvas instead of using an img tag?

Gradual Rendering of Progressive Images in HTML5 Canvas

Is there a way to draw partially loaded progressive Image objects (PNG, JPG) into canvas?
Most browsers support progressive loading in the tag, but I can't find how it can be controlled in within canvas.
The answer is no, as per the specification's orders.
If a browser does happen to do this, it is against the spec, which states:
If the image isn't yet fully decoded, then nothing is drawn.
When an img element is in the completely available state and the user agent can decode the media data without errors, then the img element is said to be fully decodable.
You can take a look at streamingtextures js lib
which use custom decoding of progressive JPEG images (via Emscripten version of libjpeg) and return image content as an array of bytes.
This method is used with WebGL but could be also used for 2D canvas and extended to support also GIF, PNG and WebP

Upload canvas element to webserver/database?

I'm searching for a good method to upload a canvas element from Firefox to a webserver or database to have the ability to reload it later.
My ideas:
1. my first idea was to use getImageData() and save the canvas as an ImageData object to the database, but this might not a good solution because these objets can get quite large.
2. second idea is to use a Flash/Javascript method to upload the canvas as an PNG to the webserver.
Do you have any comments on these methods or maybe have another good solution?
Canvas elements have a toDataURL function that serializes the image on the canvas as a PNG, encoded into a data URL. You could either post the image with a form (by setting a hidden input element's value to the data URL) or in the background using AJAX.
You should be aware that toDataURL (or any other method of getting the pixel data) will throw a security exception if the canvas is not "origin-clean". For example, if you ever call drawImage with an image from a different domain, you can no longer use the toDataURL or getImageData functions.
I'm not too sure I would be worried about size unless images are typically > 10 mb in size. Is that really an issue?
If not, using getImageData() would be the most practical and simplest method IMO.

Categories