2014-09-07 11 views
5

fand ich Bilder, die zeigen, was mein Problem ist:das Bild zuschneiden in unregelmäßiger Form und dehnt es

enter image description here

enter image description here

Benutzer werden in der Lage vier Punkte auf Leinwand zu wählen, um den Teil des zuzuschneiden Bild und dann dehnen.

Wie geht das in HTML5? Die Funktion drawImage funktioniert (wie ich weiß) nur mit Rechtecken (nimmt Werte für x, y, Breite und Höhe an), so dass ich keine unregelmäßige Form verwenden kann. Die Lösung muss in jedem modernen Browser funktionieren, also möchte ich nicht, dass Dinge auf webgl basieren oder so.

EDIT: Weitere Informationen: Dies wird App zum Bearbeiten von Bildern sein. Ich möchte, dass der Benutzer einen Teil des größeren Bildes ausschneiden und bearbeiten kann. Es wird ähnlich wie Paint sein, also wird Canvas benötigt, um Pixel zu bearbeiten.

+1

ich die beste Antwort zu denken wäre WebGL zu verwenden, die 3D-Funktionalität auf der Leinwand sieht, aber wenn Sie nicht wollen, um zu versuchen, dass Sie auch Bildmanipulation könnte in – Canvas

+0

Können Sie sieht Verwenden Sie etwas anderes als Leinwand z CSS3 transformieren? – soktinpk

+0

Möchten Sie das geänderte Bild Ihrem Benutzer zur Verfügung stellen? – GameAlchemist

Antwort

0

hier ist also eine Tötungs Trick: Sie haben die regelmäßigen drawImage des context2d können in einem Dreieck eine Textur zu zeichnen.
Die Einschränkung besteht darin, dass die Texturkoordinaten achsversetzt sein müssen.

Um ein texturiertes Dreieck zu zeichnen, müssen Sie:
• Berechnen Sie selbst die erforderliche Transformation, um das Bild zu zeichnen.
• Clip auf ein Dreieck, da drawImage ein Quad zeichnen würde.
• drawImage mit der richtigen Transformation.

Die Idee besteht also darin, Ihr Quad in zwei Dreiecke aufzuteilen und beides zu rendern.

Aber es gibt noch einen weiteren Trick: Wenn Sie das untere rechte Dreieck zeichnen, sollte die Texturablesung am unteren rechten Teil der Textur beginnen und dann nach oben und links gehen. Dies ist in Firefox nicht möglich, da nur positive Argumente für drawImage akzeptiert werden. Also berechne ich den "Spiegel" des ersten Punktes gegen die beiden anderen, und ich kann wieder in die normale Richtung zeichnen - der Ausschnitt sorgt dafür, dass nur der rechte Teil gezeichnet wird.

Geige ist hier:

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: i den entsprechenden Kommentar von @szym hinzugefügt, mit seinem Beispiel Bild:

nur diese Art sieht gut aus. Wenn im Originalbild gerade Linien vorhanden sind, sehen Sie, dass jedes Dreieck anders verzerrt ist (2 verschiedene affine Transformationen als eine perspektivische Transformation).

enter image description here

+0

Das sieht nur irgendwie richtig aus. Wenn im Originalbild gerade Linien vorhanden sind, sehen Sie, dass jedes Dreieck anders verzerrt ist (2 verschiedene affine Transformationen als eine perspektivische Transformation). Siehe: http://imgur.com/OpLlGlC – szym

-1
  1. Sie benötigen einen Behälter haben, mit Perspektive und Perspektive-Ursprung gesetzt
  2. Sie benötigen rotateY, skewY zu verwenden und deine Höhen und Breite ändern auf Bild

es ist wahrscheinlich eine Menge Mathematik dahinter - persönlich mit ihm ich in meinem Browser nur Geige, um es ziemlich nah aussehen zu lassen, was ich brauche

So, hier ist eine Geige:

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

Ich möchte nicht nur einige Objekte in der Größe ändern. Mein Programm wird einen Teil des größeren Bildes ausschneiden und den Benutzer diesen geschnittenen Teil bearbeiten lassen. – Piotrek

3

Der Effekt, den Sie für fahren ist "Perspektive Warping".

Der 2D-Kontext von Canvas kann dies nicht "out-of-the-box" tun, da ein Rechteck nicht in ein Trapez verwandelt werden kann. Canvas 2D kann nur affine Transformationen durchführen, die nur Parallelogramme bilden können.

Wie Benutzer @ Canvas sagt, kann Canvas 3D (webgl) die Transformationen ausführen, für die Sie arbeiten.

Ich habe dies eine Weile zurück. Es verwendet Canvas 2d und zeichnet ein Bild mit 1 Pixel breiten vertikalen Slices, die gestreckt werden, um eine perspektivische Verzerrung "vorzutäuschen". Sie können es gerne als Ausgangspunkt für Ihr Projekt verwenden.

enter image description here enter image description here

Beispielcode und eine 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

Dies ist eine sehr kreative Lösung.Das hat meine Frage nicht direkt beantwortet, aber dank dir habe ich eine Idee: D – Piotrek

Verwandte Themen