Question

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.

Was it helpful?

Solution

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!

OTHER TIPS

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!

I think this link will be help full. I did the same but in my case I give the canvas weight and height dynamically using javascript. Then I gave the height and width to canvas when I declare it. That solve the problem.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top