I recently discovered the HTML5 Canvas, it's lovely, like the good old days of using $A000:0000!
However, when drawing an image to the canvas it kept coming out all blurry. As it turns out, there are actually quite a few possible reasons for this to happen... here's a short checklist of what I discovered on my quest to fix it.
Most articles I came across mentioned that you should always explicitly specify the dimensions of a canvas, either when creating the element in bland HTML e.g.,
or via JavaScript e.g,
The above is actually not enough though, you also need to set the CSS dimensions, changing the above JavaScript to SOMETHING like:
Testing my code out on my retina iPad, I discovered that
Turns out there's a variable called
...sort of. See the "Drawing Pixels is hard" link below for a much clearer explanation.
Turns out there's ALSO a CSS variable you can change to affect how things are handled internally, it's called
You can use it something like this:
Finally getting to what actually fixed it for me, a silly mistake to make.
I wanted to draw my image centered on the canvas, so ended up doing something like: x = canvas.width / 2 - image.naturalWidth / 2, doing the same thing for y.
This leads to floating point co-ordinates, perhaps starting in the middle of a pixel. Being a JavaScript dunce I simply used
Oddly enough though, I've seen many mentions of always drawing to x+0.5,y+0.5, but I have no idea why you'd do that... unless you always happened to start at 0.5 in the first place.
Drawing pixels is hard
About the image-rendering setting
However, when drawing an image to the canvas it kept coming out all blurry. As it turns out, there are actually quite a few possible reasons for this to happen... here's a short checklist of what I discovered on my quest to fix it.
Setting Canvas dimensions
Most articles I came across mentioned that you should always explicitly specify the dimensions of a canvas, either when creating the element in bland HTML e.g.,
<canvas id="drawable" width="100px" height="100px"></canvas>
or via JavaScript e.g,
canvas = document.getElementById("drawable");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
Setting Canvas style dimensions
The above is actually not enough though, you also need to set the CSS dimensions, changing the above JavaScript to SOMETHING like:
canvas = document.getElementById("drawable");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.style.width = canvas.width.toString() + "px";
canvas.style.height = canvas.height.toString() + "px";
Catering for different pixel ratios
Testing my code out on my retina iPad, I discovered that
window.innerWidth
and window.innerHeight
were returning half of what they should have.Turns out there's a variable called
window.devicePixelRatio
that is present on retina devices, and contains the scale you should use when dealing with dimensions......sort of. See the "Drawing Pixels is hard" link below for a much clearer explanation.
CSS image rendering settings
Turns out there's ALSO a CSS variable you can change to affect how things are handled internally, it's called
image-rendering
You can use it something like this:
/* applies to GIF and PNG images; avoids blurry edges */
img[src$=".gif"], img[src$=".png"] {
image-rendering: -moz-crisp-edges; /* Firefox */
image-rendering: -o-crisp-edges; /* Opera */
image-rendering: -webkit-optimize-contrast;/* Webkit (non-standard naming) */
image-rendering: crisp-edges;
-ms-interpolation-mode: nearest-neighbor; /* IE (non-standard property) */
}
Pixel offsets
Finally getting to what actually fixed it for me, a silly mistake to make.
I wanted to draw my image centered on the canvas, so ended up doing something like: x = canvas.width / 2 - image.naturalWidth / 2, doing the same thing for y.
This leads to floating point co-ordinates, perhaps starting in the middle of a pixel. Being a JavaScript dunce I simply used
parseInt(x)
to draw the image, and that seemed to cure it for me.Oddly enough though, I've seen many mentions of always drawing to x+0.5,y+0.5, but I have no idea why you'd do that... unless you always happened to start at 0.5 in the first place.
References
Drawing pixels is hard
About the image-rendering setting