拉伸图像以适合多边形html5画布

时间:2016-10-05 10:38:45

标签: javascript html css html5 canvas

我有一个像这样的方形图像:

enter image description here

我试图将这个图像拉伸成这样的多边形:

enter image description here

到目前为止,我已经能够使用以下javascript在画布上创建一个多边形作为上面的图像:

function drawCanvas() {
        var c2 = document.getElementById('myCanvas6').getContext('2d');
        var img = document.getElementById("scream");
        c2.fillStyle = '#000';
        c2.beginPath();
        c2.moveTo(20, 20);
        c2.lineTo(320, 50);
        c2.lineTo(320, 170);
        c2.lineTo(20, 200);
        //c2.drawImage(img, 150, 10, img.width, img.height);
        c2.closePath();
        c2.fill();

    }

我尝试使用drawImage()方法,但它没有将A,B,C,D点拉伸到新位置。无论如何这可以实现吗?

2 个答案:

答案 0 :(得分:2)

2D画布被称为2D,这是一个很好的理由。你不能变换一个正方形使得它的任何一侧会聚(不平行)因此2D

但是在有需要的地方总有办法......

您可以通过将图像切割成切片,然后绘制每个切片略小于最后一个切片来实现。

我们人类不喜欢看到图像在会聚时扭曲,所以你需要添加我们期望的扭曲,透视。物体越远,点之间的距离就越小。

因此下面的函数绘制一个顶部和底部边缘会聚的图像。

这不是真正的3D,但它确实使图像看起来像jus会聚顶部和底部而不会减少y步骤一样扭曲。动画引入了一点视错觉。第二个渲染会缩短图像,使其看起来不那么假。

请参阅有关如何使用该功能的代码。

/** CreateImage.js begin **/
// creates a blank image with 2d context
var createImage=function(w,h){var i=document.createElement("canvas");i.width=w;i.height=h;i.ctx=i.getContext("2d");return i;}

/** CreateImage.js end **/

var can = createImage(512,512);
document.body.appendChild(can);
var ctx = can.ctx;
const textToDisplay = "Perspective"
const textSize = 80;
ctx.font = textSize+"px arial";
var w = ctx.measureText(textToDisplay).width + 8;
var text = createImage(w + 64,textSize + 32);
text.ctx.fillStyle = "#08F";
text.ctx.strokeStyle = "black";
text.ctx.lineWidth = 16;
text.ctx.fillRect(0,0,text.width,text.height);
text.ctx.strokeRect(0,0,text.width,text.height);
text.ctx.font = textSize+"px arial";
text.ctx.fillStyle = "#F80";
text.ctx.strokeStyle = "Black";
text.ctx.lineWidth = 4;
text.ctx.strokeText(textToDisplay,38,textSize + 8);
text.ctx.fillText(textToDisplay,38,textSize + 8);






// Not quite 3D
// ctx is the context to draw to
// image is the image to draw
// x1,x2 left and right edges of the image
// zz1,zz2 top offset for left and right
// image top edge has a slops from zz1 to zz2
// yy if the position to draw top. This is where the top would be if z = 0
function drawPerspective(ctx, image, x1, zz1, x2, zz2, yy){
    var x, w, h, h2,slop, topLeft, botLeft, zDistR, zDistL, lines, ty;
    w    = image.width;                   // image size
    h    = image.height;
    h2   = h /2;                          // half height
    slop = (zz2 - zz1) / (x2 - x1);       // Slope of top edge
    z1   = h2 - zz1;                      // Distance (z) to first line
    z2   = (z1 / (h2 - zz2)) * z1 - z1;   // distance (z) between first and last line
    if(z2 === 0){ // if no differance in z then is square to camera
        topLeft = - x1 * slop + zz1;      // get scan line top left edge
        ctx.drawImage(image,0, 0, w, h,x1, topLeft + yy ,x2-x1, h - topLeft * 2)  // render to desination 
        return;
    }
    // render each display line getting all pixels that will be on that line
    for (x = x1; x < x2; x++) {                 // for each line horizontal line
        topLeft = (x - x1) * slop + zz1;        // get scan line top left edge
        botLeft = ((x + 1) - x1) * slop + zz1;  // get scan line bottom left edge
        zDistL  = (z1 / (h2 - topLeft)) * z1;   // get Z distance to Left of this line
        zDistR  = (z1 / (h2 - botLeft)) * z1;   // get Z distance to right of this line
        ty      = ((zDistL - z1) / z2) * w;     // get y bitmap coord
        lines   = ((zDistR - z1) / z2) * w - ty;// get number of lines to copy
        ctx.drawImage(image,
            ty % w, 0, lines, h,                // get the source location of pixel
            x, topLeft + yy,1 , h - topLeft * 2 // render to desination 
        );
    }
}


var animTick = 0;
var animRate = 0.01;
var pos = 0;
var short = 0;
function update1(){
    animTick += animRate;
    pos =  Math.sin(animTick) * 20 + 20;
    short =  Math.cos((pos / 40) * Math.PI) * text.width * 0.12 -  text.width * 0.12;
    ctx.clearRect(0,0,can.width,can.height)

    drawPerspective(ctx,text,0,0,text.width,pos,20)

    drawPerspective(ctx,text,0,0,text.width+short,pos,textSize + 32 + 30)


    requestAnimationFrame(update1);
}
update1();

答案 1 :(得分:1)

我认为这是一个很好的解决方案:http://jsfiddle.net/fQk4h/ 这是魔术:

for (i = 0; i < w; i++) {
dy = (leftTop * (w - i)) / w;
dh = (leftBot * (w - i) + h * i) / w;
ctx.drawImage(tmpCtx.canvas,
    i, 0, 1, h,
    i, dy, 1, dh);
}

ctx.restore();