How can I use html5 canvas to straighten & crop an image? [closed] - html

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
How can I use html5 canvas to rotate imageas shown below?
From before:
To after:

Normally I wouldn't answer a "request to write code", but I had the code you need laying around.
I offer it here without further explanation or annotation:
var canvas1a=document.createElement("canvas");
var ctx1a=canvas1a.getContext("2d");
var canvas2=document.getElementById("canvas2");
var ctx2=canvas2.getContext("2d");
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
function reOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
window.onresize=function(e){ reOffset(); }
var canvas1=document.getElementById("canvas1");
var ctx1=canvas1.getContext("2d");
function reOffset1(){
var BB=canvas1.getBoundingClientRect();
offsetX1=BB.left;
offsetY1=BB.top;
}
var offsetX1,offsetY1;
reOffset1();
window.onscroll=function(e){ reOffset1(); }
window.onresize=function(e){ reOffset1(); }
var topLeft,topRight,bottomRight,bottomLeft;
var startX,startY,mouseX,mouseY;
var isDown=false;
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/tilted.jpg";
function start(){
canvas.width=img.width;
canvas.height=img.height;
ctx.drawImage(img,0,0);
//
$("#canvas").on('mousedown',handleMouseDown);
}
function handleMouseDown(e){
e.preventDefault();
e.stopPropagation();
//
mX=parseInt(e.clientX-offsetX);
mY=parseInt(e.clientY-offsetY);
//
if(!topLeft){
topLeft={x:mX,y:mY};
drawMarker(topLeft);
}else if(!topRight){
topRight={x:mX,y:mY};
drawMarker(topRight);
}else{
$("#canvas").off('mousedown',handleMouseDown);
//
bottomRight={x:mX,y:mY};
drawMarker(bottomRight);
//
var dx=topRight.x-topLeft.x;
var dy=topRight.y-topLeft.y;
var angle=Math.atan2(dy,dx);
var width=Math.sqrt(dx*dx+dy*dy);
dx=bottomRight.x-topRight.x;
dy=bottomRight.y-topRight.y;
var height=Math.sqrt(dx*dx+dy*dy);
//
canvas1a.width=canvas1.width=width;
canvas1a.height=canvas1.height=height;
ctx1a.rotate(-angle);
ctx1a.drawImage(img,-topLeft.x,-topLeft.y);
ctx1.strokeStyle='red';
ctx1.drawImage(canvas1a,0,0);
//
$("#canvas1").mousedown(function(e){handleMouseDown1(e);});
$("#canvas1").mousemove(function(e){handleMouseMove1(e);});
$("#canvas1").mouseup(function(e){handleMouseUpOut1(e);});
$("#canvas1").mouseout(function(e){handleMouseUpOut1(e);});
}
}
function handleMouseDown1(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
//
startX=parseInt(e.clientX-offsetX1);
startY=parseInt(e.clientY-offsetY1);
// set drag flag
isDown=true;
}
function handleMouseUpOut1(e){
if(!isDown){return;}
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
//
mouseX=parseInt(e.clientX-offsetX1);
mouseY=parseInt(e.clientY-offsetY1);
// clear drag flag
isDown=false;
//
var w=mouseX-startX;
var h=mouseY-startY;
canvas2.width=w;
canvas2.height=h;
ctx2.drawImage(canvas1a,startX,startY,w,h,0,0,w,h);
}
function handleMouseMove1(e){
if(!isDown){return;}
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
mouseX=parseInt(e.clientX-offsetX1);
mouseY=parseInt(e.clientY-offsetY1);
ctx1.drawImage(canvas1a,0,0);
ctx1.strokeRect(startX,startY,mouseX-startX,mouseY-startY);
}
function drawMarker(pt){
ctx.beginPath();
ctx.arc(pt.x,pt.y,3,0,Math.PI*2);
ctx.closePath();
ctx.fillStyle='red';
ctx.fill();
}
body {
background-color: ivory;
}
canvas {
border: 1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>First the topLeft corner<br>then click topRight corner<br>then click bottomRight corner</h4>
<canvas id="canvas" width=300 height=300></canvas><br>
<h4>Drag to clip a part of the image</h4>
<canvas id="canvas1" width=300 height=300></canvas>
<h4>Straightened & clipped image</h4>
<canvas id="canvas2" width=300 height=300></canvas>

Related

Enable and disable mouse events for canvas using Fabric.js

I am using Fabric.js to draw rectangles on a canvas. After drawing a rectangle, I want to disable all events on that object. I have tried to do it using canvas.__eventListeners["mouse:down"] = []; but then after the object selection is cleared, the canvas can't apply any events.
<html lang="en" >
<head>
<meta charset="utf-8" />
<title>HTML5 canvas - Image color picker | Script Tutorials</title>
<link href="index.css" rel="stylesheet" type="text/css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.1.0/fabric.all.min.js" ></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
</head>
<body>
<div class="container">
<div class="column1">
<canvas id="panel" width="700" height="350"></canvas>
</div>
<div style="clear:both;"></div>
<div id="log"></div>
</div>
</body>
<script>
(function() {
var canvas = new fabric.Canvas('panel');
var clicks=0;
var x1=0;var y1=0;
var rect;
canvas.on('mouse:down', function(e){
//check if you clicked on an object that exists canvas
if(e.target == undefined){
if (clicks == 0) {
var pointer=canvas.getPointer(event.e);
console.log(pointer);
x1 = pointer.x;
y1 =pointer.y;
console.log("Start Pointer " +x1 ,y1);
clicks++;
}
else
{
var endpointer=canvas.getPointer();
console.log(endpointer);
var endx=endpointer.x;
var endy=endpointer.y;
console.log("Endpointer " +endx ,endy);
console.log("x and y"+x1,y1);
var newwidth=endpointer.x- x1;
var newheight=endpointer.y - y1;
rect=new fabric.Rect({
left:x1,
top: y1,
originX :'left',
originY :'top',
width:newwidth,
height:newheight,
selectable: true,
evented:false,
fill:'red',
opacity :0.3
});
canvas.add(rect);
//console.log(rect.setWidth(pointer2.x- x1 ));
//console.log(rect.setHeight( pointer2.y - y1));
canvas.renderAll();
clicks=0;
}
}
else
{
//canvas.getActiveObject().remove();
canvas.__eventListeners["mouse:down"] = [];
}
});
canvas.on('object:moving',function(){
var bound=rect.getBoundingRect();
console.log(bound.left,bound.top,bound.width,bound.height);
});
canvas.on('object:scaling',function(){
var bound=rect.getBoundingRect();
console.log(bound.left,bound.top,bound.width,bound.height);
});
canvas.on('object:selected',function(e){
document.onkeydown = function(e) {
if (e.keyCode === 27||e.button==3) {
e.preventDefault();
canvas.getActiveObject().remove();
}
}
});
fabric.Image.fromURL('fedex.jpg', function (img) {
canvas.add(img.set({
width: 700,
height:350,
left: 350,
top: 175,
selectable: false,
}));
});
})();
</script>
With the method canvas.off('mouse:down', eventHandler) event handlers registered using canvas.on('mouse:down', eventHandler) can be removed. Be sure to pass the same function into both calls (e.g. by assigning the handler to a variable).
This method is available on all Observables in fabric (see API doc: http://fabricjs.com/docs/fabric.Observable.html#off)
What is the final answer? We're basing our decision to mousedown on or mousedown off, based on the event - if it has a target. I came up with this solution (a 2nd mousedown handler), but it didn't work.
canvas.on('mouse:down', function (e) {
// canvas click, not object click; so create the obj
if (e.target === undefined) {
canvas.on('mouse:down', eventHandler);
}
else {
// an object was clicked, so don't create the obj again
canvas.off('mouse:down', eventHandler);
}
});
Where eventHandler is the function that handles object creation.

How to execute a function on mouse click on rectangle HTML5 Canvas

I'm looking for a simple way to execute a function when someone clicks on a rectangle inside an HTML5 Canvas. I would like to do it in a way that doesn't require any special libraries. Any suggestions?
Here's a no-library way which involves:
Listening for mousedown events:
var canvas=document.getElementById("canvas");
canvas.onmousedown=handleMousedown;
Testing if the clicked mouse position is inside the rectangle:
var rect={x:100,y:100,w:75,h:40};
// mx & my are the mouse coordinates
if(mx>=rect.x && mx<=rect.x+rect.w && my>=rect.y && my<=rect.y+rect.h){
alert("clicked in rect");
}
Here's example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var BB,BBoffsetX,BBoffsetY;
setBB();
var rect={x:100,y:100,w:75,h:40};
ctx.fillRect(rect.x,rect.y,rect.w,rect.h);
canvas.onmousedown=handleMousedown;
function handleMousedown(e){
e.preventDefault();
e.stopPropagation();
var mx=e.clientX-BBoffsetX;
var my=e.clientY-BBoffsetY;
if(mx>=rect.x && mx<=rect.x+rect.w && my>=rect.y && my<=rect.y+rect.h){
alert("clicked in rect");
}
}
function setBB(){
BB=canvas.getBoundingClientRect();
BBoffsetX=BB.left;
BBoffsetY=BB.top;
}
body{ background-color: ivory; }
canvas{border:1px solid red;}
<h4>Click in the rect for an alert</h4>
<canvas id="canvas" width=300 height=300></canvas>

move multiple images from one canvas to other canvas

There is an example given at http://www.rgraph.net/blog/2013/january/an-example-of-html5-canvas-drag-n-drop.html
I am not able to add multiple images into canvas 1 and move those added images to canvas 2. Also I should be able to drag(move the added image within canvas 2) those added images in second canvas.
function dragDrop(e, ui) {
// get the drop point (be sure to adjust for border)
var x = parseInt(ui.offset.left - offsetX) - 1;
var y = parseInt(ui.offset.top - offsetY);
// get the drop payload (here the payload is the $tools index)
var theIndex = ui.draggable.data("toolsIndex");
// drawImage at the drop point using the dropped image
ctx.drawImage($tools[theIndex], x, y, 32, 32);
}
http://jsfiddle.net/cyur7/
This jsfiddle link is working fine.
This solution uses the KineticJS library to accomplish your need.
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/bSpBF/
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.5.1.min.js"></script>
<style>
body{ background-color: ivory; padding:10px;}
#container1,#container2{
border:solid 1px #ccc;
margin-top: 10px;
width:300px;
height:100px;
}
#container2{
height:300px;
}
</style>
<script>
$(function(){
var highlightWidth=8;
var stage = new Kinetic.Stage({
container: 'container1',
width: 300,
height: 100
});
var layer = new Kinetic.Layer();
stage.add(layer);
var dropzone = new Kinetic.Stage({
container: 'container2',
width: 300,
height: 300
});
var dropLayer = new Kinetic.Layer();
dropzone.add(dropLayer);
// these must go after the creation of stages & layers
addBackground(stage,layer,dropLayer);
layer.draw();
addBackground(dropzone,dropLayer,layer);
dropLayer.draw();
// get images & then trigger start()
var images={};
var URLs = {
house1: 'https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-3.jpg',
house2: 'https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-4.jpg',
house3: 'https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-1.jpg'
};
loadImages(URLs,start);
function start(){
var house1=kImage(images.house1,10,10,50,50,layer);
var house2=kImage(images.house2,75,10,50,50,layer);
var house3=kImage(images.house3,140,10,50,50,layer);
layer.draw();
}
function swapStagesIfSelected(sourceLayer,destinationLayer,startX,startY){
// get all elements on the source layer
var elements=sourceLayer.get("Image");
// don't let dropped elements fall off the stage
var totalWidth=0;
var maxHeight=-999;
var layerWidth=destinationLayer.getStage().getWidth();
var layerHeight=destinationLayer.getStage().getHeight();
for(var i=0;i<elements.length;i++){
if(elements[i].isSelected){
totalWidth+=elements[i].getWidth();
maxHeight=Math.max(elements[i].getHeight(),maxHeight);
}
}
if(startX+totalWidth>layerWidth){
startX=layerWidth-totalWidth-15;
}
if(startY+maxHeight>layerHeight){
startY=layerHeight-maxHeight-15;
}
// move all selected images
// to the clicked x/y of the destination layer
for(var i=0;i<elements.length;i++){
var element=elements[i];
if(element.isSelected){
var img=element.getImage();
kImage(img,startX,startY,element.getWidth(),element.getHeight(),destinationLayer);
startX+=element.getWidth()+10;
element.remove();
}
}
sourceLayer.draw();
destinationLayer.draw();
}
// build the specified KineticJS Image and add it to the specified layer
function kImage(image,x,y,width,height,theLayer){
var image=new Kinetic.Image({
image:image,
x:x,
y:y,
width:width,
height:height,
strokeWidth:0.1,
stroke:"green",
draggable:true
});
image.myLayer=theLayer;
image.isSelected=false;
image.on("click",function(){
highlight(this);
this.myLayer.draw();
});
image.myLayer.add(image);
return(image);
}
// build a background image and add it to the specified stage
function addBackground(theStage,theLayer,otherLayer){
var background = new Kinetic.Rect({
x: 0,
y: 0,
width: theStage.getWidth(),
height: theStage.getHeight(),
fill: "white",
stroke: "green",
strokeWidth: 1
});
background.on("click",function(){
var pos=theStage.getMousePosition();
var mouseX=parseInt(pos.x);
var mouseY=parseInt(pos.y);
swapStagesIfSelected(otherLayer,theLayer,mouseX,mouseY);
});
theLayer.add(background);
}
///////////// Image loader
function loadImages(URLs, callback) {
var loaded = 0;
var needed = 0;
for(var url in URLs) { needed++; console.log(url); }
for(var url in URLs) {
images[url] = new Image();
images[url].onload = function() {
if(++loaded >= needed) {
callback(images);
}
};
images[url].src = URLs[url];
}
}
///////////// Toggle Highlighting
function highlight(element,setStrokeWidth){
if(setStrokeWidth){
element.setStrokeWidth(setStrokeWidth);
}else{
if(element.getStrokeWidth()>5){
element.setStrokeWidth(0.1);
element.isSelected=false;
}else{
element.setStrokeWidth(highlightWidth);
element.isSelected=true;
}
}
}
}); // end $(function(){});
</script>
</head>
<body>
<p>Click on image(s) to toggle selection</p>
<p>Then click in the other canvas to drop</p>
<div id="container1"></div>
<div id="container2"></div>
<button id="clear">Clear Hightlights</button>
<button id="swap">Swap Selected</button>
</body>
</html>

HTML5 Canvas - Context Sensitive Menu

I'm drawing a number of rectangles on an HTML5 canvas and want to be able to right click on the boxes and get a context sensitive menu displayed. The menu should be specific to the type of box being clicked on and be totally user specified, i.e. it should not include Reload, Save As, Print etc...
Can any one give me any pointers?
Thanks,
Paul
You can addEventListener for context menu to handle right-mouse requests:
// listen for contextmenu requests
canvas.addEventListener('contextmenu', handleContextmenu, false);
Then in the handler, you check each of your rects for hits:
function handleContextmenu(e){
// get mouse position relative to the canvas
var x=parseInt(e.clientX-offsetX);
var y=parseInt(e.clientY-offsetY);
// check each rect for hits
for(var i=0;i<rects.length;i++){
var rect=rects[i];
var rectRight=rect.x+rect.width;
var rectBottom=rect.y+rect.height;
// if this rect is hit, display an alert
if(x>=rect.x && x<=rectRight && y>=rect.y && y<=rectBottom ){
alert("Context menu request on the "+rect.color+" rectangle.");
}
}
// prevents the usual context from popping up
e.preventDefault()
return(false);
}
Here is working code (no jsFiddle because no right-clicking in X-Domain iframes):
<!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 canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var rects=[];
rects.push({x:50,y:50,width:50,height:50,color:"red"});
rects.push({x:150,y:100,width:75,height:75,color:"blue"});
ctx.clearRect(0,0,canvas.width,canvas.height);
for(var i=0;i<rects.length;i++){
var rect=rects[i];
ctx.beginPath();
ctx.fillStyle=rect.color;
ctx.rect(rect.x,rect.y,rect.width,rect.height);
ctx.fill();
}
// listen for contextmenu requests
canvas.addEventListener('contextmenu', handleMouseDown, false);
function handleMouseDown(e){
// get mouse position relative to the canvas
var x=parseInt(e.clientX-offsetX);
var y=parseInt(e.clientY-offsetY);
// check each rect for hits
for(var i=0;i<rects.length;i++){
var rect=rects[i];
var rectRight=rect.x+rect.width;
var rectBottom=rect.y+rect.height;
// check each rect for hits
if(x>=rect.x && x<=rectRight && y>=rect.y && y<=rectBottom ){
alert("Context menu request on the "+rect.color+" rectangle.");
}
}
// prevents the usual context from popping up
e.preventDefault()
return(false);
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

How to print a canvas element?

I have a canvas element on my page. I draw an image over it and some data that the user entered. On a press of a button I want to send the canvas to printer, to print it on paper. I tried to use this plug-in: jQuery.printElement, like that:
the button code:
PRINT
'print_voucher()' function:
function print_voucher()
{
$("#canvas_voucher").printElement();
}
canvas_voucher is the ID of my canvas element. It printed the page, but didn't print the canvas. I tried to use it like that as well:
$("#canvas_voucher img").printElement();
But that didn't even start the printer.
So how can I do that? How can I print the content of the canvas?
**EDIT**
Here's the code that creates my canvas and tries to create an image with it:
function create_voucher(visitor_name, visitor_identity_num, unique_number)
{
var canvas = $("#canvas_voucher")[0];
if (canvas.getContext)
{
var ctx = canvas.getContext('2d');
// Draw image
var img = new Image();
img.src = 'https://someurl.com/image.jpg';
img.onload = function(){
ctx.drawImage(img,0,0);
ctx.fillStyle="#CCC";
ctx.font="bold 20px Arial";
ctx.fillText(visitor_name, 750, 270);
ctx.fillText(visitor_identity_num, 750, 295);
ctx.font="bold 25px Arial";
ctx.fillText(unique_number, 620, 325);
}
var voucher = canvas.toDataURL("image/png");
$("#voucher_img").attr("src", voucher);
} else {
alert('You need Safari or Firefox 1.5+ to see this.');
}
}
This will convert the canvas to a .png image URL and open it in a new browser window
The Print Dialog is triggered to let the user print the page.
function print_voucher(){
var win=window.open();
win.document.write("<br><img src='"+canvas.toDataURL()+"'/>");
win.print();
win.location.reload();
}
Here is example code:
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
ctx.fillStyle="gold";
ctx.strokeStyle="blue";
ctx.lineWidth=5;
ctx.rect(50,50,100,100);
ctx.fill();
ctx.stroke();
function print_voucher(){
var win=window.open();
win.document.write("<br><img src='"+canvas.toDataURL()+"'/>");
win.print();
win.location.reload();
}
$("#printVoucher").click(function(){ print_voucher(); });
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas><br>
<button id="printVoucher">Print</button>
</body>
</html>
Found the problem and fixed it.
Apparently it was a security issue at this line:
img.src = 'https://someurl.com/image.jpg';
Once it was pointing out to a server, it was considered as a potential security threat. So I changed it to:
img.src = 'images/image.jpg';
After that I created a function to make an image from the canvas and called it within the 'img.onload' part:
...
img.onload = function(){
ctx.drawImage(img,0,0);
ctx.fillStyle="#CCC";
ctx.font="bold 20px Arial";
ctx.fillText(visitor_name, 750, 270);
ctx.fillText(visitor_identity_num, 750, 295);
ctx.font="bold 25px Arial";
ctx.fillText(unique_number, 620, 325);
draw_voucher_img();
...
function draw_voucher_img()
{
var canvas = $("#canvas_voucher")[0];
var voucher = canvas.toDataURL();
$("#voucher_img").attr("src", voucher);
}
Now it worked!