2016-10-05 102 views
0

我有這樣一個正方形圖片:拉伸圖像以適合多邊形HTML5畫布

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拉伸到新的位置。無論如何,這可以實現嗎?

+1

使用帆布,未必是理想的控制。 SVG在做這類事情方面很出色。 – Keith

+0

@Keith你能指出一個我能得到一個快速創意的來源嗎? –

+1

http://stackoverflow.com/questions/20660085/how-to-stretch-an-image-in-a-svg-shape-to-fill-its-bounds – Keith

回答

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(); 
+0

驚人的,也許我錯了,但這個代碼不工作,一旦你改變任何其他圖像 –

+0

我試過這個圖片http://ielts-results.weebly.com/uploads/4/0/6/6/40661105 /1113084_orig.jpg,它適用於我,但是您必須修改腳本中的屏幕尺寸。 –

2

的2D畫布被稱爲2D的一個很好的理由。你不能改變一個正方形,使得它的任何一側的收斂(不平行),因此2D

但是,在有需要總是有辦法..

您可以通過切割圖像爲做到這一點切片,然後繪製每個切片比最後一個略小。

我們人類在收斂時不喜歡看到圖像扭曲,所以您需要添加我們期望的扭曲,透視。物體越遠,點之間的距離越小。

所以下面的函數繪製的圖像與頂部和底部邊緣融合..

這不是真正的3D,但它確實使圖像出現失真的強制收斂的頂部和底部沒有降低是第三步。動畫引入了一些錯覺。第二個渲染縮短圖像,使其看起來不那麼假。

請參閱關於如何使用該功能的代碼。

/** 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();