FabricJS Setting background image size and position - javascript

I'm using FabricJS for a project in which I need to be able to set the background image of the canvas. The canvas can be any size and can be resized at any time. Lastly, the image should always fill the canvas regardless of its size, but never be distorted in any way.
So for example, if I have an 800x600 (WxH) canvas and a 1200x700 background image, the image should be scaled down to 1029x600 so that it covers the entire canvas without being distorted.
I've written a function that is supposed to calculate the dimensions of the canvas and image and set the size and position of the image accordingly, but I'm having trouble getting it to work correctly. It works most of the time, but is not "bullet proof". Sometimes the image gets distorted and other times it doesn't fill the entire canvas.
What I would like help with is refactoring this into a bullet-proof solution that will always meet my sizing criteria no matter what size the canvas or image is.
I've created a fiddle with the code. the fiddle loads an 800x600 canvas and then sets first a landscape background image to demonstrate how the code isn't sizing the image to cover the canvas, and then a portrait image to show how it sometimes distorts images.
Here is the code itself:
var canvas = window._canvas = new fabric.Canvas('c'),
canvasOriginalWidth = 800,
canvasOriginalHeight = 600,
canvasWidth = 800,
canvasHeight = 600,
canvasScale = .5,
photoUrlLandscape = 'https://images8.alphacoders.com/292/292379.jpg',
photoUrlPortrait = 'https://presspack.rte.ie/wp-content/blogs.dir/2/files/2015/04/AMC_TWD_Maggie_Portraits_4817_V1.jpg';
setCanvasSize({height: canvasHeight, width: canvasWidth});
setTimeout(function() {
setCanvasBackgroundImageUrl(photoUrlLandscape, 0, 0, 1)
}, 50)
setTimeout(function() {
setCanvasBackgroundImageUrl(photoUrlPortrait, 0, 0, 1)
}, 4000)
function setCanvasSize(canvasSizeObject) {
canvas.setWidth(canvasSizeObject.width);
canvas.setHeight(canvasSizeObject.height);
setZoom();
}
function setZoom() {
setCanvasZoom();
canvas.renderAll();
}
function setCanvasZoom() {
var width = canvasOriginalWidth;
var height = canvasOriginalHeight;
var tempWidth = width * canvasScale;
var tempHeight = height * canvasScale;
canvas.setWidth(tempWidth);
canvas.setHeight(tempHeight);
}
function setCanvasBackgroundImageUrl(url, top, left, opacity) {
if(url && url.length > 0) {
fabric.Image.fromURL(url, function(img) {
var aspect, scale;
if(parseInt(canvasWidth) > parseInt(canvasHeight)) {
if(img.width >= img.height) {
// Landscape canvas, landscape source photo
aspect = img.width / img.height;
if(img.width >= parseInt(canvasWidth)) {
scale = img.width / parseInt(canvasWidth);
} else {
scale = parseInt(canvasWidth) / img.width;
}
img.width = parseInt(canvasWidth)
img.height = img.height / scale;
} else {
// Landscape canvas, portrait source photo
aspect = img.height / img.width;
if(img.width >= parseInt(canvasWidth)) {
scale = img.width / parseInt(canvasWidth);
} else {
scale = parseInt(canvasWidth) / img.width;
}
img.width = parseInt(canvasWidth);
img.height = img.height * scale;
}
} else {
if(img.width >= img.height) {
// Portrait canvas, landscape source photo
aspect = img.width / img.height;
if(img.height >= parseInt(canvasHeight)) {
scale = img.width / parseInt(canvasHeight);
} else {
scale = parseInt(canvasHeight) / img.height;
}
img.width = img.width * scale;
img.height = parseInt(canvasHeight)
} else {
// Portrait canvas, portrait source photo
aspect = img.height / img.width;
if(img.height >= parseInt(canvasHeight)) {
scale = img.height / parseInt(canvasHeight);
} else {
scale = parseInt(canvasHeight) / img.height;
}
img.width = img.width * scale;
img.height = parseInt(canvasHeight);
}
}
canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas), {
top: parseInt(top) || 0,
left: parseInt(left) || 0,
originX: 'left',
originY: 'top',
opacity: opacity ? opacity : 1,
scaleX: canvasScale,
scaleY: canvasScale
});
canvas.renderAll();
setZoom();
});
} else {
canvas.backgroundImage = 0;
canvas.setBackgroundImage('', canvas.renderAll.bind(canvas));
canvas.renderAll();
setZoom();
}
};

Here is a fiddle that does what (I think) you want to achieve:
https://jsfiddle.net/whippet71/7s5obuk2/
The code for scaling the image is fairly straightforward:
function scaleAndPositionImage() {
setCanvasZoom();
var canvasAspect = canvasWidth / canvasHeight;
var imgAspect = bgImage.width / bgImage.height;
var left, top, scaleFactor;
if (canvasAspect >= imgAspect) {
var scaleFactor = canvasWidth / bgImage.width;
left = 0;
top = -((bgImage.height * scaleFactor) - canvasHeight) / 2;
} else {
var scaleFactor = canvasHeight / bgImage.height;
top = 0;
left = -((bgImage.width * scaleFactor) - canvasWidth) / 2;
}
canvas.setBackgroundImage(bgImage, canvas.renderAll.bind(canvas), {
top: top,
left: left,
originX: 'left',
originY: 'top',
scaleX: scaleFactor,
scaleY: scaleFactor
});
canvas.renderAll();
}
Basically you just want to know if the aspect ratio of the image is greater or less than that of the canvas. Once you know that you can work out the scale factor, the final step is to work out how to offset the image such that it's centered on the canvas.

fabric.Image.fromURL("image.jpg", function (img) {
canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas), {
scaleX: canvas.width / img.width,
scaleY: canvas.height / img.height
});
});
It set image to full canvas

Related

fabric.js canvas background image won't load until an object is clicked

I'm trying to set an image as a background for a canvas but the image won't load until until an object(rectangle) is clicked on the canvas.
Did someone has the same problem?
var canvas = new fabric.Canvas('image_canvas');
canvas.setWidth(window.innerWidth * factor);
canvas.setHeight(window.innerWidth / 2 * factor);
var canvasHeight = canvas.height;
var canvasWidth = canvas.width;
//Just a debug statement console.log(canvasWidth, canvasHeight);
var bgImg = new fabric.Image();
bgImg.setSrc('<?= $image_src ?>', function () {
bgImg.set({
top: 0,
left: 0,
scaleX: canvasWidth / bgImg.width,
scaleY: canvasHeight / bgImg.height,
});
});
canvas.setBackgroundImage(bgImg, canvas.renderAll.bind(canvas));
canvas.renderAll();

setTransform and Scale to fit Canvas for the given image

I have an image on Canvas.
After rendering an image, I rotate the canvas to 90 degrees clockwise and then have to scale to fit the canvas.
Scaling an image to fit on canvas
Resize image and rotate canvas 90 degrees
there is so many solutions available but unfortunately none of them worked for me yet
This is what I have right now.
width = 300; // after rotation
height = 400; // after rotation
var scale = width / img.height; // how much to scale the image to fit
console.log(scale);
canvas.width = width;
canvas.height = height;
ctx.setTransform(
0, scale, // x axis down the screen
-scale, 0, // y axis across the screen from right to left
width, // x origin is on the right side of the canvas
0 // y origin is at the top
);
ctx.drawImage(img, 0, 0);
ctx.setTransform(1, 0, 0, 1, 0, 0); // restore default
Currently, canvas is rotating fine but image is not fitting or scaling properly according to canvas width and height.
Original image is large, I want to scale it to fit 300x400 on canvas.
Original Image -
Actual result image looks like this which is not scaling full image -
To fit an image to a display area, use the min scale to fit height or fit width.
// size of canvas
const width = 100;
const height = 298;
// image is assumed loaded and ready to be drawn
// Get min scale to fit
var scale = Math.min(width / image.width , height / image.height);
// you can also scale to fill using max
// var scale = Math.max(width / image.width , height / image.height);
canvas.width = width;
canvas.height = height;
// // draw image from top left corner
ctx.setTransform(scale, 0, 0, scale, 0, 0);
ctx.drawImage(image, 0, 0);
ctx.setTransform(1, 0, 0, 1, 0, 0); // restore default
Update
Re comment
As you are having trouble, and I am still not sure what you what the image to do, here is a general purpose function to rotate image in 90 deg steps, and scales to fit, fill, and natural. (Demo version in bottom snippet a little less verbose)
// img image to draw
// rot 1 unit = 90 deg. scaleType fit or fill
function drawRotatedImage(img, rot = 1, scaleType = "fit") {
const w = img.naturalWidth;
const h = img.naturalHeight;
// direction of xAxis
var xAxisX = Math.cos(rot * Math.PI / 2);
var xAxisY = Math.sin(rot * Math.PI / 2);
// modified transform image width and height to match the xAxis
const tw = Math.abs(w * xAxisX - h * xAxisY);
const th = Math.abs(w * xAxisY + h * xAxisX);
var scale = 1;
if (scaleType === "fit") {
scale = Math.min(canvas.width / tw, canvas.height / th);
} else if (scaleType === "fill") {
scale = Math.max(canvas.width / tw, canvas.height / th);
}
xAxisX *= scale;
xAxisY *= scale;
// Rotate scale to match scaleType . Center on canvas
ctx.setTransform(xAxisX, xAxisY, -xAxisY, xAxisX, canvas.width / 2, canvas.height / 2);
// Image drawn offset so center is at canvas center
ctx.drawImage(img, -w / 2, -h / 2, w, h);
}
And to make sure the following is a tested runing example using your image.
const canWidth = 300;
const canHeight = 400;
const rot = 1;
const scaleType = "fit";
const PI90 = Math.PI / 2;
function drawRotatedImage(img, rot, scale) {
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
const w = img.naturalWidth, h = img.naturalHeight;
var xAX = Math.cos(rot *= PI90 ), xAY = Math.sin(rot);
const tw = Math.abs(w * xAX - h * xAY);
const th = Math.abs(w * xAY + h * xAX);
scale = Math[scale === "fit" ? "min" : "max" ](canvas.width / tw, canvas.height / th);
xAX *= scale;
xAY *= scale;
ctx.setTransform(xAX, xAY, -xAY, xAX, canvas.width / 2, canvas.height / 2);
ctx.drawImage(img, -w / 2, -h / 2, w, h);
}
// Stuff for demo and test. unrelated to answer.
const ctx = canvas.getContext("2d");
// size canvas
canvas.width = canWidth;
canvas.height = canHeight;
const img = new Image;
const tests = [[0,"fit"], [1,"fit"], [2,"fit"], [3,"fit"],[0,"fill"], [1,"fill"], [2,"fill"], [3,"fill"]];
tests.clicker = 0;
img.src = "https://i.stack.imgur.com/SQmuv.jpg";
img.addEventListener("load", () => {
info.textContent = ((rot % 4) * 90) + "deg CW scaled to " + scaleType.toUpperCase() + " click canvas to rotate and switch scales";
drawRotatedImage(img, rot, scaleType)
});
canvas.addEventListener("click",() => {
const test = tests[tests.clicker++ % tests.length];
info.textContent = ((test[0] % 4) * 90) + "deg CW scaled to " + test[1].toUpperCase();
drawRotatedImage(img, ...test)
});
body {
font-family: "arial black";
}
canvas {
border: 1px solid black;
position: absolute;
top: 30px;
left: 10px;
}
#info {
position: absolute;
top: 2px;
left: 10px;
}
<canvas id="canvas"></canvas>
<div id="info"></div>

Reduce the dimension of base64 image maintaining aspect ratio in javascript

I have a base64 string for an image, which i have to display as an icon. If the dimension of an image are bigger i have to display icon maintaining aspect ratio.
I have written a logic to identify if the image is landscape or portrait based on which height and width will be settled for canvas. But seems height and width of icons are not proper as i have hard coded it.
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
var height, width;
if (this.height>this.width) {
height = 50;
width = 30;
} else if (this.height<this.width) {
height = 30;
width = 50;
}
canvas.width = width;
canvas.height = height;
ctx.drawImage(image,
0, 0, this.width, this.height,
0, 0, canvas.width, canvas.height
);
var scaledImage = new Image();
scaledImage.src = canvas.toDataURL();
Is there any way we can calculate it dynamically or any other way to preserve aspect ratio for icons.
Working Example can be found on https://codepen.io/imjaydeep/pen/ewBZRK
It will be fine if some space will be left on x-y axis.
You just need to calculate the scale or ratio and multiply both dimensions by that. Here's an example function, and here's your edited codepen.
Creates trimmed, scaled image:
function scaleDataURL(dataURL, maxWidth, maxHeight){
return new Promise(done=>{
var img = new Image;
img.onload = ()=>{
var scale, newWidth, newHeight, canvas, ctx;
if(img.width < maxWidth){
scale = maxWidth / img.width;
}else{
scale = maxHeight / img.height;
}
newWidth = img.width * scale;
newHeight = img.height * scale;
canvas = document.createElement('canvas');
canvas.height = newHeight;
canvas.width = newWidth;
ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, newWidth, newHeight);
done(canvas.toDataURL());
};
img.src = dataURL;
});
}
Or, if you want the image to always be the provided dimensions with empty surrounding area, you can use this: (codepen)
Creates scaled image of exact provided dimensions:
function scaleDataURL(dataURL, maxWidth, maxHeight){
return new Promise(done=>{
var img = new Image;
img.onload = ()=>{
var scale, newWidth, newHeight, canvas, ctx, dx, dy;
if(img.width < maxWidth){
scale = maxWidth / img.width;
}else{
scale = maxHeight / img.height;
}
newWidth = img.width * scale;
newHeight = img.height * scale;
canvas = document.createElement('canvas');
canvas.height = maxWidth;
canvas.width = maxHeight;
ctx = canvas.getContext('2d');
dx = (maxWidth - newWidth) / 2;
dy = (maxHeight - newHeight) / 2;
console.log(dx, dy);
ctx.drawImage(img, 0, 0, img.width, img.height, dx, dy, newWidth, newHeight);
done(canvas.toDataURL());
};
img.src = dataURL;
});
}
For someone who search for a solution when the image is bigger that you need.
function scaleDataURL(dataURL: string, maxWidth: number, maxHeight: number) {
return new Promise((done) => {
var img = new Image()
img.onload = () => {
var scale, newWidth, newHeight, canvas, ctx
if (img.width > maxWidth) {
scale = maxWidth / img.width
} else if (img.height > maxHeight) {
scale = maxHeight / img.height
} else {
scale = 1
}
newWidth = img.width * scale
newHeight = img.height * scale
canvas = document.createElement('canvas')
canvas.height = newHeight
canvas.width = newWidth
ctx = canvas.getContext('2d')
console.log('img', 'scale', scale, 0, 0, img.width, img.height, 0, 0, newWidth, newHeight)
ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, newWidth, newHeight)
done(canvas.toDataURL())
}
img.src = dataURL
})
}
Usage:
scaleDataURL(base64data, 600, 200)
.then((newBase64data) => {
console.log(newBase64data)
})
.catch((err) => console.log(err))

Want to optimize code for captured image resize and rotate using canvas of html5, which now giving low memory warning on mobile

I have written code which will capture photo using camera and show it as snapshot. But before showing it as snapshot I am resizing image and rotate (if captured image is horizontal). This re-sized image is binary content which is less in size so uploading it on server becomes quick. Now I want to optimize code so that it will work better with low memory.
Problem facing:
On mobile device, sometimes chrome browser showing "unable to complete previous operation due to low memory".
Could be possible solution (i think but with question):
Processing image in chunks, will make think work better?
Thanks in advance for your help.
You may see working code here
or
Working sample code
<style>
#yourimage {
width:100%;
}
.imgWeightHght {
height: 290px !important;
width: 220px !important;
}
.captureInsuPanel img {
height: auto;
width: auto;
}
.newLoaderMask {
display: none;
background: #E5E5E5;
position: fixed;
left: 0;
top: 0;
z-index: 10;
width: 100%;
height: 100%;
opacity: 0.8;
z-index: 999;
}
</style>
<div id="mask" class="newLoaderMask">
<img src="http://jimpunk.net/Loading/wp-content/uploads/loading1.gif" width="200" id="loader" />
</div>
<input type="file" accept="image/*" capture="camera" id="takePictureField" />
<div class="captureInsuPanel">
<img id="yourimage" class="imgWeightHght" width="500" />
</div>
<script>
$(document).ready(function () {
$("#takePictureField").on("change", gotPic);
});
var max_width = 1000;
var max_height = 1000;
function gotPic(event) {
if (event.target.files.length == 1 && event.target.files[0].type.indexOf("image/") == 0) {
var image = event.target.files[0];
processCapturedImage(image, 90, max_width, max_height, $("#yourimage"));
}
}
function processCapturedImage(image, angle, max_width, max_height, thumbNailImage) {
$('#mask').show();
//create a hidden canvas object we can use to create new rotated image
var canvas = document.createElement('canvas');
canvas.id = "hidden_canvas_old";
canvas.style.display = "none";
document.body.appendChild(canvas);
//create a hidden canvas object we can use to create the new cropped &/or resized image data
var canvas_new = document.createElement('canvas');
canvas_new.id = "hidden_canvas_new";
canvas_new.style.display = "none";
document.body.appendChild(canvas_new);
var fileLoader = new FileReader(),
imageObj = new Image();
if (image.type.indexOf("image/") == 0) {
fileLoader.readAsDataURL(image);
} else {
alert('File is not an image');
}
fileLoader.onload = function () {
var data = this.result;
imageObj.src = data;
};
fileLoader.onabort = function () {
alert("The upload was aborted.");
};
fileLoader.onerror = function () {
alert("An error occured while reading the file.");
};
// set up the images onload function which clears the hidden canvas context,
// draws the new image then gets the blob data from it
imageObj.onload = function () {
var imgWidth = this.width;
var imgHeight = this.height;
if (imgWidth > imgHeight) {
//Rotate horizontal image to vertical and resizing is needed
rotateAndResize(this, imgWidth, imgHeight, angle, max_width, max_height, thumbNailImage);
} else {
//no need to rotate only resizing is needed
resize(this, imgWidth, imgHeight, max_width, max_height, thumbNailImage);
}
};
imageObj.onabort = function () {
alert("Image load was aborted.");
};
imageObj.onerror = function () {
alert("An error occured while loading image.");
};
}
function rotateAndResize(image, imgWidth, imgHeight, angle, max_width, max_height, thumbNailImage) {
var canvas = document.getElementById("hidden_canvas_old"),
ctx = canvas.getContext("2d");
var widthHalf = imgWidth / 2,
heightHalf = imgHeight / 2;
canvas.width = imgWidth;
canvas.height = imgWidth;
//clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
//set coordinate to rotate canvas
ctx.translate(canvas.width / 2, canvas.height / 2);
//rotate canvas with given angle
ctx.rotate(angle * Math.PI / 180);
//draw image on rotated canvas with given coordinate
ctx.drawImage(image, -widthHalf, -widthHalf);
ctx.restore();
var tempCanvas = document.getElementById("hidden_canvas_new"),
tCtx = tempCanvas.getContext("2d");
tempCanvas.width = imgHeight;
tempCanvas.height = imgWidth;
/*
* Crop rotated image from old canvas to remove white space
* So that canvas will have only image content without extra padding
*/
tCtx.drawImage(canvas, canvas.width - imgHeight, 0, imgHeight, imgWidth, 0, 0, imgHeight, imgWidth);
tCtx.restore();
//Delete unwanted canvas to reduce page size
canvas.remove();
/**
* Resizing Rotated image
*/
// calculate the width and height, constraining the proportions
if (imgWidth > imgHeight) {
if (imgWidth > max_width) {
imgHeight = Math.round(imgHeight *= max_width / imgWidth);
imgWidth = max_width;
}
} else {
if (imgWidth > max_height) {
imgWidth = Math.round(imgWidth *= max_height / imgHeight);
imgHeight = max_height;
}
}
var tempCanvasTemp = tempCanvas;
tempCanvas.remove();
var tempCanvas1 = document.createElement("canvas"),
tCtx1 = tempCanvas1.getContext("2d");
tempCanvas1.id = 'hidden_canvas_new';
tempCanvas1.style.display = 'none';
tempCanvas1.width = imgHeight;
tempCanvas1.height = imgWidth;
tCtx1.drawImage(tempCanvasTemp, 0, 0, imgHeight, imgWidth);
tCtx1.restore();
document.body.appendChild(tempCanvas1);
thumbNailImage.attr("src", tempCanvas1.toDataURL('image/jpeg'));
$('#mask').hide();
}
function resize(image, imgWidth, imgHeight, max_width, max_height, thumbNailImage) {
/**
* Resizing image
*/
// calculate the width and height, constraining the proportions
if (imgWidth > imgHeight) {
if (imgWidth > max_width) {
//height *= max_width / width;
imgHeight = Math.round(imgHeight *= max_width / imgWidth);
imgWidth = max_width;
}
} else {
if (imgWidth > max_height) {
//width *= max_height / height;
imgWidth = Math.round(imgWidth *= max_height / imgHeight);
imgHeight = max_height;
}
}
var tempCanvas = document.getElementById("hidden_canvas_new"),
tCtx = tempCanvas.getContext("2d");
tempCanvas.width = imgWidth;
tempCanvas.height = imgHeight;
tCtx.drawImage(image, 0, 0, imgWidth, imgHeight);
thumbNailImage.attr("src", tempCanvas.toDataURL('image/jpeg'));
$('#mask').hide();
}
</script>
Try using MediaDevices.getUserMedia() (documentation) for browsers which support it, you don't need to resize the photo as you can request the size of the photo.
Several examples:
http://www.html5rocks.com/en/tutorials/getusermedia/intro/
https://github.com/addyosmani/getUserMedia.js
as far as I know getUserMedia() supports the maximum resolution of the video
So if you have a 12M camera, but video is maximum 720p then you can set image quality to maximum 720p

Loader image not showing up when canvas rotating and resizing operation is going on selected file

I have created sample code here http://jsfiddle.net/kamlesh_bhure/YpejU/ where i am rotating image and resizing it as per max height and width.
Before starting this process I am showing mask with loading image and hiding it after completing it. But I am not able to see this loader on mobile device or on desktop browser even though I used large image.
Also I want to show loading image till browser complete its rendering of processed image.
Thanks in advance.
<!-- HTML Code -->
<div id="mask" class="newLoaderMask">
<img src="http://jimpunk.net/Loading/wp-content/uploads/loading1.gif" width="200" id="loader" />
</div>
<input type="file" accept="image/*" id="takePictureField" />
<div class="captureInsuPanel">
<img id="yourimage" class="imgWeightHght" width="500" />
</div>
<canvas id="hidden_canvas_old"></canvas>
<canvas id="hidden_canvas_new"></canvas>
<style>
#yourimage {
width:100%;
}
.imgWeightHght {
height: 290px !important;
width: 220px !important;
}
.captureInsuPanel img {
height: auto;
width: auto;
}
.newLoaderMask {
display: none;
background: #E5E5E5;
position: fixed;
left: 0;
top: 0;
z-index: 10;
width: 100%;
height: 100%;
opacity: 0.8;
z-index: 999;
}
</style>
<script>
//Js Code
$(document).ready(function () {
$("#takePictureField").on("change", gotPic);
});
function gotPic(event) {
if (event.target.files.length == 1 && event.target.files[0].type.indexOf("image/") == 0) {
var image = event.target.files[0];
$("#yourimage").attr("src", URL.createObjectURL(image));
drawRotatedImage(image, 90, 800, 1000);
}
}
function drawRotatedImage(image, angle, max_width, max_height) {
//show loading mask
$('#mask').show();
var fileLoader = new FileReader(),
imageObj = new Image();
if (image.type.indexOf("image/") == 0) {
fileLoader.readAsDataURL(image);
} else {
alert('File is not an image');
}
fileLoader.onload = function () {
var data = this.result;
imageObj.src = data;
};
fileLoader.onabort = function () {
alert("The upload was aborted.");
};
fileLoader.onerror = function () {
alert("An error occured while reading the file.");
};
// set up the images onload function which clears the hidden canvas context,
// draws the new image then gets the blob data from it
imageObj.onload = function () {
var imgWidth = this.width;
var imgHeight = this.height;
rotateAndResize(this, imgWidth, imgHeight);
};
function rotateAndResize(image, imgWidth, imgHeight) {
var canvas = document.getElementById("hidden_canvas_old"),
ctx = canvas.getContext("2d");
var widthHalf = imgWidth / 2,
heightHalf = imgHeight / 2;
canvas.width = imgWidth;
canvas.height = imgWidth;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.rotate(angle * Math.PI / 180);
ctx.drawImage(image, -widthHalf, -widthHalf);
ctx.restore();
var tempCanvas = document.getElementById("hidden_canvas_new"),
tCtx = tempCanvas.getContext("2d");
tempCanvas.width = imgHeight;
tempCanvas.height = imgWidth;
/*
* Crop rotated image from old canvas to remove white space
* So that canvas will have only image content without extra padding
*/
tCtx.drawImage(canvas, canvas.width - imgHeight, 0, imgHeight, imgWidth, 0, 0, imgHeight, imgWidth);
tCtx.restore();
/**
* Resizing Rotated image
*/
// calculate the width and height, constraining the proportions
if (imgWidth > imgHeight) {
if (imgWidth > max_width) {
imgHeight = Math.round(imgHeight *= max_width / imgWidth);
imgWidth = max_width;
}
} else {
if (imgWidth > max_height) {
imgWidth = Math.round(imgWidth *= max_height / imgHeight);
imgHeight = max_height;
}
}
var tempCanvasTemp = tempCanvas;
tempCanvas.remove();
canvas.remove();
var tempCanvas1 = document.createElement("canvas"),
tCtx1 = tempCanvas1.getContext("2d");
tempCanvas1.id = 'hidden_canvas_new';
//tempCanvas1.style.display = 'none';
tempCanvas1.width = imgHeight;
tempCanvas1.height = imgWidth;
tCtx1.drawImage(tempCanvasTemp, 0, 0, imgHeight, imgWidth);
tCtx1.restore();
document.body.appendChild(tempCanvas1);
$("#yourimage").attr("src", tempCanvas1.toDataURL('image/jpeg'));
}
//hide loading mask
$('#mask').hide();
}
</script>
You are hiding your loading div #mask in drawRotatedImage function but you should hide it in rotateAndResize function where you are drawing your picture to canvas.
CODE:
$(document).ready(function () {
$("#takePictureField").on("change", gotPic);
});
function gotPic(event) {
if (event.target.files.length == 1 && event.target.files[0].type.indexOf("image/") == 0) {
var image = event.target.files[0];
$("#yourimage").attr("src", URL.createObjectURL(image));
drawRotatedImage(image, 90, 800, 1000);
}
}
function drawRotatedImage(image, angle, max_width, max_height) {
$('#mask').show();
var fileLoader = new FileReader(),
imageObj = new Image();
if (image.type.indexOf("image/") == 0) {
fileLoader.readAsDataURL(image);
} else {
alert('File is not an image');
}
fileLoader.onload = function () {
var data = this.result;
imageObj.src = data;
};
fileLoader.onabort = function () {
alert("The upload was aborted.");
};
fileLoader.onerror = function () {
alert("An error occured while reading the file.");
};
// set up the images onload function which clears the hidden canvas context,
// draws the new image then gets the blob data from it
imageObj.onload = function () {
var imgWidth = this.width;
var imgHeight = this.height;
rotateAndResize(this, imgWidth, imgHeight);
};
function rotateAndResize(image, imgWidth, imgHeight) {
var canvas = document.getElementById("hidden_canvas_old"),
ctx = canvas.getContext("2d");
var widthHalf = imgWidth / 2,
heightHalf = imgHeight / 2;
canvas.width = imgWidth;
canvas.height = imgWidth;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.rotate(angle * Math.PI / 180);
ctx.drawImage(image, -widthHalf, -widthHalf);
ctx.restore();
var tempCanvas = document.getElementById("hidden_canvas_new"),
tCtx = tempCanvas.getContext("2d");
tempCanvas.width = imgHeight;
tempCanvas.height = imgWidth;
/*
* Crop rotated image from old canvas to remove white space
* So that canvas will have only image content without extra padding
*/
tCtx.drawImage(canvas, canvas.width - imgHeight, 0, imgHeight, imgWidth, 0, 0, imgHeight, imgWidth);
tCtx.restore();
/**
* Resizing Rotated image
*/
// calculate the width and height, constraining the proportions
if (imgWidth > imgHeight) {
if (imgWidth > max_width) {
imgHeight = Math.round(imgHeight *= max_width / imgWidth);
imgWidth = max_width;
}
} else {
if (imgWidth > max_height) {
imgWidth = Math.round(imgWidth *= max_height / imgHeight);
imgHeight = max_height;
}
}
var tempCanvasTemp = tempCanvas;
tempCanvas.remove();
canvas.remove();
var tempCanvas1 = document.createElement("canvas"),
tCtx1 = tempCanvas1.getContext("2d");
tempCanvas1.id = 'hidden_canvas_new';
//tempCanvas1.style.display = 'none';
tempCanvas1.width = imgHeight;
tempCanvas1.height = imgWidth;
tCtx1.drawImage(tempCanvasTemp, 0, 0, imgHeight, imgWidth);
tCtx1.restore();
document.body.appendChild(tempCanvas1);
$("#yourimage").attr("src", tempCanvas1.toDataURL('image/jpeg'));
$('#mask').hide();
}
}
DEMO FIDDLE
NOTE: While testing fiddle found out one more issue, if we try to upload image second time second canvas in not updating with new image. Hope you need to work on this.

Categories