2

I'm trying to simulate the background-size: cover property in canvas. I got it working, but the quality is bad.

Here is a fiddle. You can compare the two images(zoom out so you can see both image next to each other):

My code looks like:

function drawImageProp(ctx, img, x, y, w, h, offsetY) {
    var iw = img.width,
        ih = img.height,
        r = Math.min(w / iw, h / ih),
        newW = iw * r,
        newH = ih * r,
        cx, cy, cw, ch, ar = 1;

    if (newW < w) ar = w / newW;
    if (newH < h) ar = h / newH;
    newW *= ar;
    newH *= ar;

    cw = iw / (newW / w);
    ch = ih / (newH / h);

    cy = -parseInt(offsetY) * ih / newH;

    ctx.patternQuality = 'best';
    ctx.antialias = 'default';
    ctx.filter = 'default';

    ctx.drawImage(img, 0, cy, cw, ch, x, y, w, h);

I've tried adding

ctx.patternQuality = 'best';
ctx.antialias = 'default';
ctx.filter = 'default';

in order to improve quality, but I'm still no getting enough good quality. Is it possible to use the original quality image in canvas.

Also parseInt(x) and parseInt(x) + 0.5 to the cordinates, didn't fixed the problem.

*This question is tagged with nodejs because I'm using this code in nodejs with the node-canvas module.

Deepsy
  • 3,769
  • 7
  • 39
  • 71
  • Some good info here - http://stackoverflow.com/questions/12946608/canvas-drawimage-quality – Rob Sedgwick Mar 09 '14 at 15:47
  • Tried with both parseInt and parseInt + 0.5, still not getting nice quality: http://jsfiddle.net/Kwd5L/5/ – Deepsy Mar 09 '14 at 20:48
  • I suspect that there are some rounding inaccuracies in your math which cause the blur. – Philipp Mar 09 '14 at 23:27
  • 4
    Canvas typically uses bi-linear interpolation when resizing images while image elements typically use bicubic which produce better results. Try to add a sharpener convolution to the result to sharpen it up (see f.ex. this: http://stackoverflow.com/a/19235791/1693593). Ps. code from SO must be attributed.. –  Mar 12 '14 at 07:28

1 Answers1

2

Try setting imageSmoothingEnabled property to false on the context:

ctx.imageSmoothingEnabled = false;

By default canvas using bilinear filter when scaling. It is blurry. You may need nearest-neighbor filtering, which is a mere pixel repetition.

Vitalhead
  • 21
  • 1