2014-09-07 19 views
5

ho trovato le immagini che raffigurano qual è il mio problema:Ritagliare l'immagine in forma irregolare e si estendono

enter image description here

enter image description here

utente sarà in grado di scegliere quattro punti su tela per ritagliare la parte di immagine e poi allungarla.

Come farlo in HTML5? La funzione drawImage (come so) funziona solo con i rettangoli (prende i valori x, y, larghezza e altezza), quindi non posso usare la forma irregolare. La soluzione deve funzionare in ogni browser moderno, quindi non voglio le cose basate su webgl o qualcosa del genere.

MODIFICA: Altre informazioni: questa sarà l'app per la modifica delle immagini. Voglio consentire all'utente di tagliare parte di un'immagine più grande e modificarlo. Sarà simile a Paint, quindi è necessario il canvas per modificare i pixel.

+1

Sto pensando la risposta migliore sarebbe quella di utilizzare WebGL che fornisce funzionalità 3D sulla tela, ma se non voglio provare che si potrebbe anche sguardi nella manipolazione delle immagini – Canvas

+0

Can voi usare qualcosa di diverso dalla tela es css3 trasformare? – soktinpk

+0

Vuoi fornire l'immagine modificata al tuo utente? – GameAlchemist

risposta

0

Quindi, ecco un trucco uccisione: È possibile utilizzare la drawImage regolare del context2d per disegnare una texture all'interno di un triangolo.
Il vincolo è che le coordinate della trama devono essere allineate all'asse.

Per disegnare un triangolo con texture è necessario:
• Calcola da solo la trasformazione richiesta per disegnare l'immagine.
• Agganciare a un triangolo, poiché drawImage disegnerebbe un quad.
• drawImage con la trasformazione corretta.

Quindi l'idea è di dividere il quad in due triangoli e renderli entrambi.

Ma c'è un altro trucco: quando si disegna il triangolo in basso a destra, la lettura della trama dovrebbe iniziare dalla parte in basso a destra della trama, quindi spostarsi verso l'alto e verso sinistra. Questo non può essere fatto in Firefox, che accetta solo argomenti positivi per disegnareImmagine. Quindi computo lo "specchio" del primo punto rispetto agli altri due, e posso ancora disegnare nella direzione normale: il ritaglio garantirà che venga disegnata solo la parte destra.

violino è qui:

http://jsfiddle.net/gamealchemist/zch3gdrx/

enter image description here

function rasterizeTriangle(v1, v2, v3, mirror) { 
    var fv1 = { 
     x: 0, 
     y: 0, 
     u: 0, 
     v: 0 
    }; 
    fv1.x = v1.x; 
    fv1.y = v1.y; 
    fv1.u = v1.u; 
    fv1.v = v1.v; 
    ctx.save(); 
    // Clip to draw only the triangle 
    ctx.beginPath(); 
    ctx.moveTo(v1.x, v1.y); 
    ctx.lineTo(v2.x, v2.y); 
    ctx.lineTo(v3.x, v3.y); 
    ctx.clip(); 
    // compute mirror point and flip texture coordinates for lower-right triangle 
    if (mirror) { 
     fv1.x = fv1.x + (v3.x - v1.x) + (v2.x - v1.x); 
     fv1.y = fv1.y + (v3.y - v1.y) + (v2.y - v1.y); 
     fv1.u = v3.u; 
     fv1.v = v2.v; 
    } 
    // 
    var angleX = Math.atan2(v2.y - fv1.y, v2.x - fv1.x); 
    var angleY = Math.atan2(v3.y - fv1.y, v3.x - fv1.x); 
    var scaleX = lengthP(fv1, v2); 
    var scaleY = lengthP(fv1, v3); 
    var cos = Math.cos, 
     sin = Math.sin; 
    // ---------------------------------------- 
    //  Transforms 
    // ---------------------------------------- 
    // projection matrix (world relative to center => screen) 
    var transfMatrix = []; 
    transfMatrix[0] = cos(angleX) * scaleX; 
    transfMatrix[1] = sin(angleX) * scaleX; 
    transfMatrix[2] = cos(angleY) * scaleY; 
    transfMatrix[3] = sin(angleY) * scaleY; 
    transfMatrix[4] = fv1.x; 
    transfMatrix[5] = fv1.y; 
    ctx.setTransform.apply(ctx, transfMatrix); 
    // !! draw !! 
    ctx.drawImage(bunny, fv1.u, fv1.v, v2.u - fv1.u, v3.v - fv1.v, 
    0, 0, 1, 1); 
    // 
    ctx.restore(); 
}; 

Edit: ho aggiunto il relativo commento di @szym, con il suo esempio d'immagine:

questo solo tipo di sembra giusto. Se ci sono linee rette nell'immagine originale vedrai che ogni triangolo è deformato in modo diverso (2 diverse trasformazioni affini piuttosto che una trasformazione prospettiva).

enter image description here

+0

Questo tipo di aspetto è giusto. Se ci sono linee rette nell'immagine originale vedrai che ogni triangolo è deformato in modo diverso (2 diverse trasformazioni affini piuttosto che una trasformazione prospettica). Vedi: http://imgur.com/OpLlGlC – szym

-1
  1. È necessario disporre di un contenitore con la prospettiva e la prospettiva-origine di
  2. È necessario utilizzare RotateY, skewY e modificare le altezze e la larghezza sul tuo immagine

C'è probabilmente un sacco di matematica dietro questo - personalmente ho solo giocherellare con esso nel mio browser per farlo sembrare abbastanza vicino a quello che mi serve

ecco un violino:

http://jsfiddle.net/6egdevwe/1/

#container { 
margin: 50px; 
perspective: 166px; perspective-origin: 50% 0px; } 

#testimage { 
transform: rotateY(93.4deg) skewY(34deg); 
width: 207px; 
height: 195px; } 
+0

Non desidero ridimensionare solo alcuni oggetti. Il mio programma ridurrà parte dell'immagine più grande e consentirà all'utente di modificare questa parte tagliata. – Piotrek

3

L'effetto si sta andando per è "prospettiva orditura".

Il contesto 2D di Canvas non può essere "pronto all'uso" perché non può trasformare un rettangolo in un trapezoide. Canvas 2D può eseguire solo trasformazioni affini che possono formare solo parallelogrammi.

Come dice @Canvas, Canvas 3D (webgl) può fare le trasformazioni che stai cercando.

Ho fatto questo tempo indietro. Usa Canvas 2d e ridisegna un'immagine usando sezioni verticali larghe 1 pixel che vengono allungate per "falsificare" una distorsione prospettiva. Siete invitati a usarlo come punto di partenza per il vostro progetto.

enter image description here enter image description here

codice di esempio e una demo: http://jsfiddle.net/m1erickson/y4kst2pk/

<!doctype html> 
<html> 
<head> 
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css --> 
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script> 
<style> 
    body{ background-color: ivory; } 
    #canvas{border:1px solid red;} 
</style> 
<script> 
$(function(){ 

    var canvas=document.getElementById("canvas"); 
    var ctx=canvas.getContext("2d"); 
    var $canvas=$("#canvas"); 
    var canvasOffset=$canvas.offset(); 
    var offsetX=canvasOffset.left; 
    var offsetY=canvasOffset.top; 
    var scrollX=$canvas.scrollLeft(); 
    var scrollY=$canvas.scrollTop(); 

    // 
    var isDown=false; 
    var PI2=Math.PI*2; 
    var selectedGuide=-1; 
    var guides=[]; 


    // 
    var marginLeft=50; 
    var marginTop=50; 
    var iw,ih,cw,ch; 
    var img=new Image(); 
    img.onload=start; 
    img.src='https://dl.dropboxusercontent.com/u/139992952/stack1/buildings1.jpg'; 
    function start(){ 

     iw=img.width; 
     ih=img.height; 
     canvas.width=iw+100; 
     canvas.height=ih+100; 
     cw=canvas.width; 
     ch=canvas.height; 
     ctx.strokeStyle="blue"; 
     ctx.fillStyle="blue"; 

     guides.push({x:0,y:0,r:10}); 
     guides.push({x:0,y:ih,r:10}); 
     guides.push({x:iw,y:0,r:10}); 
     guides.push({x:iw,y:ih,r:10}); 

     // 
     $("#canvas").mousedown(function(e){handleMouseDown(e);}); 
     $("#canvas").mousemove(function(e){handleMouseMove(e);}); 
     $("#canvas").mouseup(function(e){handleMouseUp(e);}); 
     $("#canvas").mouseout(function(e){handleMouseOut(e);}); 

     drawAll(); 
    } 

    function drawAll(){ 
     ctx.clearRect(0,0,cw,ch); 
     drawGuides(); 
     drawImage(); 
    } 

    function drawGuides(){ 
     for(var i=0;i<guides.length;i++){ 
      var guide=guides[i]; 
      ctx.beginPath(); 
      ctx.arc(guide.x+marginLeft,guide.y+marginTop,guide.r,0,PI2); 
      ctx.closePath(); 
      ctx.fill(); 
     } 
    } 

    function drawImage(){ 

     // TODO use guides 
     var x1=guides[0].x; 
     var y1=guides[0].y; 
     var x2=guides[2].x; 
     var y2=guides[2].y; 
     var x3=guides[1].x; 
     var y3=guides[1].y; 
     var x4=guides[3].x; 
     var y4=guides[3].y; 


     // calc line equations slope & b (m,b) 
     var m1=Math.tan(Math.atan2((y2-y1),(x2-x1))); 
     var b1=y2-m1*x2; 
     var m2=Math.tan(Math.atan2((y4-y3),(x4-x3))); 
     var b2=y4-m2*x4; 
     // draw vertical slices 
     for(var X=0;X<iw;X++){ 
      var yTop=m1*X+b1; 
      var yBottom=m2*X+b2; 
      ctx.drawImage(img,X,0,1,ih, 
       X+marginLeft,yTop+marginTop,1,yBottom-yTop); 
     } 

     // outline 
     ctx.save(); 
     ctx.translate(marginLeft,marginTop); 
     ctx.beginPath(); 
     ctx.moveTo(x1,y1); 
     ctx.lineTo(x2,y2); 
     ctx.lineTo(x4,y4); 
     ctx.lineTo(x3,y3); 
     ctx.closePath(); 
     ctx.strokeStyle="black"; 
     ctx.stroke(); 
     ctx.restore(); 
    } 



    function handleMouseDown(e){ 
     e.preventDefault(); 
     var mouseX=parseInt(e.clientX-offsetX); 
     var mouseY=parseInt(e.clientY-offsetY); 

     // Put your mousedown stuff here 
     selectedGuide=-1; 
     for(var i=0;i<guides.length;i++){ 
      var guide=guides[i]; 
      var dx=mouseX-(guide.x+marginLeft); 
      var dy=mouseY-(guide.y+marginTop); 
      if(dx*dx+dy*dy<=guide.r*guide.r){ 
       selectedGuide=i; 
       break; 
      } 
     } 
     isDown=(selectedGuide>=0); 
    } 

    function handleMouseUp(e){ 
     e.preventDefault(); 
     isDown=false; 
    } 

    function handleMouseOut(e){ 
     e.preventDefault(); 
     isDown=false; 
    } 

    function handleMouseMove(e){ 
     if(!isDown){return;} 
     e.preventDefault(); 
     var x=parseInt(e.clientX-offsetX)-marginLeft; 
     var y=parseInt(e.clientY-offsetY)-marginTop; 
     var guide=guides[selectedGuide]; 
     guides[selectedGuide].y=y; 
     if(selectedGuide==0 && y>guides[1].y){guide.y=guides[1].y;} 
     if(selectedGuide==1 && y<guides[0].y){guide.y=guides[0].y;} 
     if(selectedGuide==2 && y>guides[3].y){guide.y=guides[3].y;} 
     if(selectedGuide==3 && y<guides[2].y){guide.y=guides[2].y;} 
     drawAll(); 
    } 

}); // end $(function(){}); 
</script> 
</head> 
<body> 
    <h4>Perspective Warp by vertically dragging left or right blue guides.</h4> 
    <canvas id="canvas" width=300 height=300></canvas> 
</body> 
</html> 
+0

Questa è una soluzione molto creativa.Non ho risposto direttamente alla mia domanda, ma grazie a te, ho un'idea: D – Piotrek

Problemi correlati