I found images that depict what is my problem:
User will able to choose four points on canvas to crop the part of image and than stretch it.
How to do that in HTML5? drawImage function (as I know) works only with rectangles (takes x, y, width and height values) so I can't use irregular shape. The solution have to work in every modern browser, so I don't want things based on webgl or something.
EDIT: More info: this will be app for editing pictures. I want to let user cut some part of bigger picture and edit that. It will be similar to Paint, so canvas is required to edit pixels.
The effect you're going for is "perspective warping".
Canvas's 2D context cannot do this "out-of-the-box" because it can't turn a rectangle into a trapezoid. Canvas 2D can only do affine transforms which can only form parallelograms.
As user @Canvas says, Canvas 3D (webgl) can do the transforms you're going for.
I did this a while back. It uses Canvas 2d and it redraws an image using 1 pixel wide vertical slices which are stretched to "fake" a perspective warp. You are welcome to use it as a starting point for your project.
Example code and a 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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With