drawImage outputs grainy image when context is scaled with scale 0.33 or less




Canvas: 2D
6 years ago
6 years ago


(Reporter: yury, Unassigned)


15 Branch

Firefox Tracking Flags

(Not tracked)



(1 attachment)



6 years ago
Created attachment 627767 [details]
Sample of the image and its scaling

Too many details of the original image lost if the context is scaled with scale 0.5 or less. Per MDN ( https://developer.mozilla.org/en/Canvas_tutorial/Using_images#drawImage_example_2 ):

"Images can become blurry when scaling up or grainy if they're scaled down too much. Scaling is probably best not done if you've got some text in it which needs to remain legible."

Is this behavior normal? If yes, is it described in the canvas 2d context specification?

Comment 1

6 years ago
correction: with scale 0.33 or less
OS: Windows 7 → All
Summary: drawImage outputs grainy image when context is scaled more than 2 times → drawImage outputs grainy image when context is scaled with scale 0.33 or less
The canvas 2d spec does not define scaling behavior at all.

But in general, downscaling line art of the sort you have there will be very lossy, yes: computer screens can't draw fractional pixels.  I doubt that has anything to do with canvas.

I just tested three other canvas implementations (Chrome, Safari, Opera), and they all behave similarly, unsurprisingly.
All browsers have switched to bilinear scaling for canvas images for performance. This means each destination pixel is constructed from an interpolation of the 4 nearest source pixels and thus when the scale is such that pixels are skipped the quality suffers.

If you need to work around this I'd suggest constructing a mipmap tree for the image, by essentially recursively scaling down in half. Then when you go to draw the image you can choose the mipmap level that is closest to the desired scale. This should give you quality closer to what you expect.
You can turn it off by setting ctx.mozImageSmoothingEnabled = false;
That would just drop you to nearest neighbour which would be even worse, no?

The mipmap approach that jeff suggested is likely the best if you need performance; alternatively, you could implement your own image scaling using get/putImageData that uses higher quality interpolation.
Last Resolved: 6 years ago
Resolution: --- → WONTFIX
You need to log in before you can comment on or make changes to this bug.