Question

I am doing an image zooming/croping in canvas and I ran in a problem. If the image I try to generate from doesn't fit perfectly, then:

  • in chrome (2nd image) all is Ok
  • Opera generates the image, but incorrect (3rd)
  • Firefox and IE give error. IndexSizeError: Index or size is negative or greater than the allowed amount

I need to generate the image correctly, keep ratio, if the image doesn't fit perfectly then gray area should be transparent.

Image dimensions are 259x194. In the example variables have values: sx = 0, sy = 0, sw = 259, sh = 259, x = 0, y = 0, width = 119, height = 119. Problem is that I try to get pixels from image that have vertical position more than 194px (<= 259). If I change sy to image height then the image generates, but proportions are wrong. How to keep them?

ctx.drawImage(resizableBgImage, sx, sy, sw, sh, x, y, width, height);
  1. Image

  2. Chrome

  3. Opera

Was it helpful?

Solution

You can use context transforms (scaling) to scale your original image with transparent background.

  • save the unscaled context state.
  • translate to the center of the canvas
  • draw the scaled image offset by half the image width and height
  • restore the unscaled context state.

Here's example code and a Demo: http://jsfiddle.net/m1erickson/765Jt/

function drawScaled(img,scaleFactor,canvas,ctx){
    var cw=canvas.width;
    var ch=canvas.height;
    var scaledIW=img.width*scaleFactor;
    var scaledIH=img.height*scaleFactor;

    // save the unscaled context state
    ctx.save();

    // translate to the center of the canvas
    // Note: the 0,0 coordinate is now center-canvas
    ctx.translate(cw/2,ch/2);

    // draw the image using the extended drawImage scaling ability
    // be sure to offset your canvas drawing by half the image size
    // since the 0,0 coordinate is now center-canvas

    ctx.drawImage(img,
        0,0,img.width,img.height,
        -scaledIW/2,-scaledIH/2,scaledIW,scaledIH
    );   
    ctx.restore();

}

enter image description here

OTHER TIPS

I had the same problem, here is what I use:

function patchedDrawImage(source, destination, sx, sy, sw, sh, dx, dy, dw, dh) {
var scaled = dw !== undefined;
if (scaled) {
    var wRatio = dw / sw;
    var hRatio = dh / sh;
}
if (sx < 0) {
    dx -= sx;
    sx = 0;
    if (scaled) {
        dw += wRatio * sx;
        sw += sx;   // or sw -= (-sx), same for dw, sh, dh
    }
}
if (sy < 0) {
    dy -= sy;
    sy = 0;
    if (scaled) {
        dh += hRatio * sy;
        sh += sy;
    }
}
if (scaled) {
    if (sx + sw > source.width) {
        dw -= wRatio * (sx + sw - source.width);
        sw -= (sx + sw - source.width);
    }
    if (sy + sh > source.height) {
        dh -= hRatio * (sy + sh - source.height);
        sh -= (sy + sh - source.height);
    }
}
destination.getContext("2d").drawImage(source, sx, sy, sw, sh, dx, dy, dw, dh);   }

Note that this function changes the arguments, I (and you :)) should change that.

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