how to skew image like this

You cannot achieve this with a single 2D transform.

A 2D transform allows you to skew the image “upwards” or “downwards” by passing the tangent of the skew angle in the second argument to setTransform(), but you want to perform both in a symmetrical manner (resulting in a “nearwards” and/or “farwards” deformation). You need a 3D transform to do that.

However, you can emulate the same result by slicing the image into several horizontal “bands” and applying a different transform when rendering each band. Bands further from the half of the image will be applied stronger skew angles. Something like:

var width = image.width,
    height = image.height,
    context = $("canvas")[0].getContext("2d");
for (var i = 0; i <= height / 2; ++i) {
    context.setTransform(1, -0.4 * i / height, 0, 1, 0, 60);
    context.drawImage(image,
        0, height / 2 - i, width, 2,
        0, height / 2 - i, width, 2);
    context.setTransform(1, 0.4 * i / height, 0, 1, 0, 60);
    context.drawImage(image,
        0, height / 2 + i, width, 2,
        0, height / 2 + i, width, 2);
}

Note the bands are two pixels high instead of one to avoid a moire effect.

You can see the results in this fiddle.

Leave a Comment