Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

canvas drawImage quality

Here is a .png image (on the right), and the canvas element which I drew the image on (on the left). Can you notice the quality difference? Canvas renders the image with noticeable quality loss. What can we do?

I observed this result on Chrome and IE9. Others will probably do the same thing. How I render the image is quite usual: In the script I create a new Image() object, after it's loaded I call
context.drawImage(myimage, x, y);

Right: What I want, Left: What I get

EDIT:

This is the initial image i observed on the canvas:
In more detail: What I got first

And here's what the canvas renders after I wrote:
context.drawImage(myimage,parseInt(x),parseInt(y));
In more detail: What I get with rounded coordinates

What can I say, great answer man. Sharpshooting at its best. The hat is off to you.

EDIT2:

I tried context.drawImage(myimage, parseInt(x) + 0.5, parseInt(y)+ 0.5);, here's the result:

In more detail: Worst case

I think it's worse than the first one. I observed this on chrome, on IE9 it's somewhat same as bad.

like image 263
Halo Avatar asked Oct 18 '12 03:10

Halo


People also ask

Why is my canvas blurry?

If you've uploaded images into Canva and used them in your design, check if they're high resolution. Using low quality images can result in blurry or pixelated designs. Where possible, upload only high quality photos in 300 DPI.

Which is the method used to draw image on a canvas?

The drawImage() method draws an image, canvas, or video onto the canvas. The drawImage() method can also draw parts of an image, and/or increase/reduce the image size. Note: You cannot call the drawImage() method before the image has loaded.

How do I change the height and width of an image in canvas?

To set the height and width canvas HTML5 has two attributes: Height: With the help of Height attribute we can set the height. Width: With the help of Width attribute we can set the width.


2 Answers

I just created an overlay of both images so that they neutralise each other. It didn't work, I had difficulties with edges.

overlayed image

Please check if your coordinates x, y are integers. Using floating point number here might blur your image as some implementations try to render it "between the pixels"

context.drawImage(myimage, parseInt(x), parseInt(y));

If this doesn't work either, try to use the integer value + 0.5
I know that for OpenGL implementations, you have to use coordinates with 0.5 in order to hit the center of a pixel.

context.drawImage(myimage, parseInt(x)+0.5, parseInt(y)+0.5);


EDIT:

Check out this page on Html5Rocks!

like image 199
Nippey Avatar answered Sep 18 '22 13:09

Nippey


I know this has already been answered, but I want to give more information to talk about what's going on here and what can be done.


This is because of image smoothing, which defaults to smooth algorithms like bilinear/trilieaner/bicubic on canvas by default, whereas what you want is known as nearest-neighbor.

The specification has recently added a property called imageSmoothingEnabled, which defaults to true and determines if images drawn on non-integer coordinates or drawn scaled will use a smoother algorithm. If it is set to false then nearest-neighbor is used, producing a less smooth image and instead just making larger looking pixels.

Image smoothing has only recently been added to the canvas specification and isn’t supported by all browsers, but some browsers have implemented vendor-prefixed versions of this property. On the context there exists mozImageSmoothingEnabled in Firefox and webkitImageSmoothingEnabled in Chrome and Safari, and setting these to false will stop anti-aliasing from occurring. Unfortunately, at the time of writing, IE9 and Opera have not implemented this property, vendor prefixed or otherwise.

In general you simply need to follow two rules:

  1. If you are scaling the canvas, you need to disable image smoothing or scale it by using nearest-neighbor interpolation. There are a few algorithms to do this manually right now and this is what the above options are doing.
  2. If you are not drawing on integer coordinates you'll get the same problem and it has the same solution. If the above options do not exist on your browser you'll need to revert to integer coordinates (x | 0, y | 0)

Where x | 0 floors x quickly, however will not work with numbers larger than 2,147,483,647: The largest 32 bit signed integer.

Hopefully your coordinates are not larger than that!

like image 39
Simon Sarris Avatar answered Sep 18 '22 13:09

Simon Sarris