In my fabricjs I am making a canvas and adding an image to it and setting the image as background. and then I am clipping the cavas to some width and height.
After I clip the canvas I want a new canvas or same canvas with clipped area as background all covering the canvas with its width and height or can make new canvas with clipped area's height and width
Currently I am doing this..
function crop(url, name, left, top, width, height, callback) {
var c = document.createElement('canvas')
var id = "canvas_" + name
c.id = id
var canvas = new fabric.Canvas(id)
fabric.Image.fromURL(url, function(oImg) {
oImg.set({
selectable:false,
})
canvas.setDimensions({width:oImg.width, height:oImg.height})
canvas.add(oImg)
canvas.clipTo = function (ctx) {
ctx.rect(left, top, width, height)
console.log(ctx)
};
canvas.centerObject(oImg)
canvas.renderAll()
var img = canvas.toDataURL('image/png')
console.log(img)
callback(img)
}, {crossOrigin: "Anonymous"})
}
Here I can easyly clip the canvas with my given left, top, width and height but I am getting the same canvas with clipped clipped part and removed part with another color. But after clipping I want the clipped part to paint over canvas or set clipped part as background.
How can I do that ??
Actually you cropped the rendering of the canvas.
To save the cropped area you must use Canvas.toDataURL() method, as you can see there is parameters top, left, width, height just use the same as you put into ctx.rect(left, top, width, height) and it will returns you a string representing the cropped area (base64 encoded).
Then use this string as your canvas new background image with Canvas.setBackgrounsImage
Your code should look like:
function crop(url, name, left, top, width, height, callback) {
var c = document.createElement('canvas')
var id = "canvas_" + name
c.id = id
var canvas = new fabric.Canvas(id)
fabric.Image.fromURL(url, function(oImg) {
oImg.set({
selectable:false,
})
canvas.setDimensions({width:oImg.width, height:oImg.height})
canvas.add(oImg)
canvas.centerObject(oImg)
canvas.renderAll()
var img = canvas.toDataURL({
format: 'image/png',
left: left,
right: right,
width: width,
height: height
})
console.log(img)
canvas.setBackgroundImage(img)
callback(img)
}, {crossOrigin: "Anonymous"})
}
Related
I'm trying to scale an image so that it fits into the available canvas when using the scaleToHeight method the image is being cropped. So for example:
The FabricJS canvas is 1024x768, and the image resolution is 4149x2761. I cannot for the life of me figure out why the image is being cropped. Here is the code:
_currentImage = new Image();
_currentImage.src = "images/7.jpg";
_currentImage.onload = function () {
var img = new fabric.Image(_currentImage, {
selectable: false,
top: 0,
left: 0
});
//img.scaleToWidth(1024);
img.scaleToHeight(768);
//img.width = _fabricCanvas.width;
_fabricCanvas.add(img);
};
If I scale to the canvas width only, the image is not cropped, but obviously fails to fill the canvas correctly.
this is perfectly normal as you are asking for a scale factor to keep the original ratio of your image. If the destination container don't have the same ratio as the image, then the image in the container will be cropped.
as you can see in this short snippet image and canvas ratio are not the same:
console.log("canvas ratio:" + 1024/768 + " image ratio: " + 4149/2761);
use:
img.scaleX = canvasWidth / img.width
img.scaleY = canvasHeight / img.height
or
img.set({
scaleX: canvasWidth / img.width,
scaleY: canvasHeight / img.height
})
Warning you will loose the original ratio of your image.
I have the following in html:
<img id="MarkingImage"></img>
<canvas id="MarkingCanvas"></canvas>
And on css:
#MarkingCanvas { width: 100%; background-color: #7986CB; height: 96%; }
#MarkingImage { position: absolute; }
And on js:
function LoadImage()
{
var markingImage = new Image();
markingImage.addEventListener('load', function()
{
m_imageWidth = this.naturalWidth;
m_imageHeight = this.naturalHeight;
m_markingCanvasContext.drawImage(markingImage, 0, 0, m_imageWidth, m_imageHeight);
});
markingImage.src = 'PICT0001.JPG';
}
The thing is that this output stretches the image and it's quality gets really poor (see attached "Original" and "Result").
When I debug, I can see that the sizes if my canvas are:
width - 1410
height - 775
The sizes if my image are:
width - 551
height - 335
So my question is: why isn't the image placed in it's original size? I mean, there's enough space on the canvas. Also, why does the image gets stretched, and as a result gets in pretty low quality. Appears like it stretches beyond the size of the canvas.
What am I missing here?
You need to set the canvas width and height dynamically according to the browser window's width and height. also, there is no need to use the image's naturalWidth / naturalHeight.
var m_markingCanvas = document.getElementById('MarkingCanvas');
var m_markingCanvasContext = m_markingCanvas.getContext('2d');
// setting canvas width and height dynamically
m_markingCanvas.width = window.innerWidth;
m_markingCanvas.height = window.innerHeight;
function LoadImage() {
var markingImage = new Image();
markingImage.addEventListener('load', function() {
m_markingCanvasContext.drawImage(this, 0, 0);
});
markingImage.src = 'https://i.stack.imgur.com/a3Wpy.jpg';
}
LoadImage();
<canvas id="MarkingCanvas"></canvas>
I am using cropper JS to crop my image. I am able to get width and height of my canvas, however, need to know co-ordinates (X and Y) of cropped image.
Here is my code-
(function () {
//getting ratio
function getImageRatio(sourceCanvas) {
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
var width = sourceCanvas.width;
var height = sourceCanvas.height;
canvas.width = width;
canvas.height = height;
context.beginPath();
context.arc(width / 2, height / 2, Math.min(width, height) / 2, 0, 2 * Math.PI);
context.strokeStyle = 'rgba(0,0,0,0)';
context.stroke();
context.clip();
context.drawImage(sourceCanvas, 0, 0, width, height);
return canvas;
}
window.addEventListener('DOMContentLoaded', function () {
var image = document.getElementById('image');
var button = document.getElementById('button');
var result = document.getElementById('result');
var croppable = false;
var cropper = new Cropper(image, {
aspectRatio: 1,
viewMode: 1,
built: function () {
croppable = true;
}
});
button.onclick = function () {
var croppedCanvas;
var roundedCanvas;
var roundedImage;
if (!croppable) {
return;
}
// Crop
croppedCanvas = cropper.getCroppedCanvas();
console.log(getImageRatio(croppedCanvas));
};
});
})();
Any idea, how to get coordinate of cropped image, so that I can crop this image by PHP.
So, if i understand properly, you are looking for the method getData.
It will return these properties as the documentation says:
x: the offset left of the cropped area
y: the offset top of the cropped area
width: the width of the cropped area
height: the height of the cropped area
rotate: the rotated degrees of the image
scaleX: the scaling factor to apply on the abscissa of the image
scaleY: the scaling factor to apply on the ordinate of the image
Although, i suggest taking a look at this section of the doc:
https://github.com/fengyuanchen/cropper#getcroppedcanvasoptions
Specifically at this part:
After then, you can display the canvas as an image directly, or use HTMLCanvasElement.toDataURL to get a Data URL, or use HTMLCanvasElement.toBlob to get a blob and upload it to server with FormData if the browser supports these APIs.
If you cannot use the toBlob method because some browser limitation (you can always add a polyfill), you can get the image using toDataUrl over the canvas (IE9+). And send it to the backend service already cropped. For this you are going to need to do something like this:
var formData = new FormData();
formData.append('image', canvas.toDataURL());
You can check the formData browser support in caniuse
Hope you find it helpful!
I have this example of a canvas as a div background (I forked it from another example, don't remember where I found it):
http://jsfiddle.net/sevku/6jace59t/18/
var canvas = document.getElementsByTagName('canvas')[0];
var ctx = canvas.getContext('2d');
var divHeight = document.getElementById('canvas').clientHeight;
var divWidth = document.getElementById('canvas').clientWidth;
function assignToDiv(){ // this kind of function you are looking for
dataUrl = canvas.toDataURL();
document.getElementsByTagName('div')[0].style.background='url('+dataUrl+')'
}
function draw() { // replace with your logic
ctx.fillStyle = "rgb(100, 250, 100)";
ctx.fillRect (10, 10, divWidth-20, divHeight-20);
}
draw()
assignToDiv()
My problem; If I put the dimensions of the div 300 x 150, the canvas does what it is supposed to do. But if I change the dimensions, the canvas is supposed to adapt to the div dimensions. What did I do wrong that this doesn't happen?
PS: I'm a beginner, so please forgive me stupid questions.
It's because if you don't give canvas width and height, it's default to 300x150, so after you get the width and height from div, you should use them to set your canvas' dimensions as well.
Another point worth notice is that you use div.style.background property to set the background image, however, as there's many background related properties (e.g: background-repeat in your jsfiddle, background-position, background-size...), the background can set all of them at once.
When you use div.style.background='url('+dataUrl+')';. It overrides all other background-related properties to initial.
If you want to preserve those properties, you may either reset them after you set style.background, or you can use div.style.backgroundImage to change the background image without affect other background related properties.
jsfiddle
var canvas = document.getElementsByTagName('canvas')[0];
var ctx = canvas.getContext('2d');
var divHeight = document.getElementById('canvas').clientHeight;
var divWidth = document.getElementById('canvas').clientWidth;
// VVVV After you get WxH, set the canvas's dimension too.
canvas.width = divWidth;
canvas.height = divWidth;
var div1 = document.getElementById('canvas');
var div2 = document.getElementById('canvas2');
function assignToDiv(div){ // this kind of function you are looking for
var dataUrl = canvas.toDataURL();
div.style.background='url('+dataUrl+')'; // This line will overwrite your background settings.
div.style.backgroundRepeat = 'repeat-x'; // Use this to set background related properties after above.
}
function assignToDivAlt(div){ // this kind of function you are looking for
var dataUrl = canvas.toDataURL();
div.style.backgroundImage = 'url('+dataUrl+')'; // Only set the background-image would have same effect.
}
function draw() { // replace with your logic
ctx.fillStyle = "rgb(100, 250, 100)";
// If you don't set WH, then the canvas would be 300x150, and those
// you drawed but out of boundary are clipped.
ctx.fillRect (10, 10, divWidth-20, divHeight-20);
}
draw()
assignToDiv(div1);
assignToDiv(div2);
canvas {display:none;}
div {
width:600px;
height:550px;
border:1px solid grey;
background-repeat:repeat-x;
}
<canvas></canvas>
<div id="canvas"></div>
<div id="canvas2"></div>
If the source svg is in a responsive environment, how do I use drawImage() to draw a to a given canvas size?
Example: How do I get the svg drawn to a 412.5 x 487.5 canvas, if the original svg is 550 x 650 and it is being viewed on a mobile device (so obviously the svg will be seen smaller than the original size)?
Fiddle
svgToImage(svg2, function(img2){
ctx2.drawImage(img2, 0, 0);
});
function svgToImage(svg2, callback) {
var nurl = "data:image/svg+xml;utf8," + encodeURIComponent(svg2),
img2 = new Image;
img2.onload = function() {
callback(img2);
}
img2.src = nurl;
}
When you SVG has loaded, simply set the canvas size, then draw in the image using the width and height arguments of drawImage.
Note that a bitmap can only take integer values so your canvas has to be either 413x488 or 412x487. If you don't set the canvas size it will default to 300x150 and then stretch to the size you use for style/CSS:
svgToImage(svg2, function(img2){
ctx2.canvas.width = 413; // set canvas size
ctx2.canvas.height = 488;
ctx2.drawImage(img2, 0, 0, 413, 488); // draw SVG/image at same size
});
Updated fiddle