How to save Zoomed and Panned Canvas to dataUrl in Javascript - javascript

I build a canvas Element in which you can zoom and pan a background image and by click you can add Icons on it. It is built on fabric js.
So once I added icons and zoomed and panned, I would like to save the image to dataurl. If I just use canvas.toDataURL, I can only see the currently shown area. Does anybody have an Idea, how I can save the entire area of the background image with all elements on the canvas? I therefore need a function, which resets the zoom and the pan and adjusts the size of the canvas to the size of the background image.
I included an example of how initialized my canvas below.
// New Fabric Canvas
var canvas = new fabric.Canvas('c'); //render image to this canvas
window.addEventListener('resize', resizeCanvas, false);
function resizeCanvas() {
canvas.setHeight(window.innerHeight);
canvas.setWidth(window.innerWidth);
canvas.renderAll();
}
// resize on init
resizeCanvas();
// Load image
var image = new Image();
image.onload = function() {
loadImage(image, canvas);
canvas.height = image.height;
canvas.width = image.width;
}
function loadImage(image, canv) {
var img = new fabric.Image(image, {
selectable: false,
lockUniScaling: true,
centeredScaling: true,
alignX: "mid",
alignY: "mid",
});
canv.add(img);
canv.centerObject(img);
}
image.src = 'http://placehold.it/350x150';
<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.1.0/fabric.all.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="canvasarea" style="background: #000;">
<canvas id='c' onclick="return false;"></canvas>
</div>

If you just want to generate an image and not change the zoom level of canvas, you can pass multiplier parameter to toDataUrl function.
var dataURL = canvas.toDataURL({
format: 'png',
multiplier: 2
});
This will generate an image after zooming in 200%.
You can even specify the part of the canvas, you want to generate an image of by using:
var dataURL = canvas.toDataURL({
format: 'png',
left: 100,
top: 100,
width: 200,
height: 200
});
Check the details here, toDataUrl function:
http://fabricjs.com/docs/fabric.Canvas.html

Related

Set background image for Fabric Canvas dynamically

I want to add draw shapes on a Image, so decided to use Fabric JS. I am able to get all shapes and objects working well. Now How do I background set exactly to Image. The Image is dynamic, I want to draw on top of that image, and basically store the annotations of objects for backend processing.
Existing solution using Canvas
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d");
canvas.width = 903;
canvas.height = 657;
var background = new Image();
background.src = "http://www.samskirrow.com/background.png";
// Make sure the image is loaded first otherwise nothing will draw.
background.onload = function(){
ctx.drawImage(background,0,0);
}
Reference - https://stackoverflow.com/a/14013068/2094670
I like this solution.
Live Demo
My Current Fabric JS Code
// Initialize a simple canvas
var canvas = new fabric.Canvas("c", {
hoverCursor: 'pointer',
selection: true,
selectionBorderColor: 'green',
backgroundColor: null
});
// Define the URL where your background image is located
var imageUrl = "../dog.jpg";
// Define
canvas.setBackgroundImage(imageUrl, canvas.renderAll.bind(canvas), {
// Optionally add an opacity lvl to the image
backgroundImageOpacity: 0.5,
// should the image be resized to fit the container?
backgroundImageStretch: false
});
Html
<canvas id="c"></canvas>
Problem.
The image of dog is full hd image, however I see only portion of it. How to do render the background image to its actual height and width using Fabric Canvas ? Since Images are comming dynamically, I might not know exact height and width to hardcode it.
Here's the way to set canvas size base on image size via fabric.js.
It's done initiating the Fabric canvas inside the onload callback, that way we are able to get the image width and height, then set them into the setDimesions method.
img.onload = function () {
...
canvas.setDimensions({ width: img.width, height: img.height });
};
var imageUrl = "http://i.imgur.com/yf6d9SX.jpg";
var background = new Image();
background.src = imageUrl;
// wait for the image to load, then set Fabric Canvas on the callback that runs after image finishes loading
background.onload = function () {
var canvas = new fabric.Canvas("c", {
hoverCursor: "pointer",
selection: true,
selectionBorderColor: "green",
backgroundColor: null,
});
// set canvas width and height based on image size
canvas.setDimensions({ width: background.width, height: background.height });
canvas.setBackgroundImage(imageUrl, canvas.renderAll.bind(canvas), {
// Optionally add an opacity lvl to the image
backgroundImageOpacity: 0.5,
// should the image be resized to fit the container?
backgroundImageStretch: false,
});
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.1.0/fabric.min.js"></script>
<canvas id="c"></canvas>

not able to draw rect on existing <canvas> which rendered PDF using pdfjs

Task
Have a canvas in your page
<canvas id="pdfCanvas">
create a fabric canvas for existing canvas
new fabric.Canvas("pdfCanvas");
have mouse.down, mouse.up, mouse.move methods to enable drawing rectangles
render pdf in the above canvas "pdfCanvas" using PDF.js
browser now shows the rendered PDF
now draw rectangles on the pdf, it hides the rendered canvas but it does draw objects
Problem
Here is the fiddle to see the issue:
- run the above https://jsfiddle.net/hiitskiran/wgz8qore/2/
- you can see the fabric rectangle is hiding behind the rendered pdf
- click on the pdf canvas area to see the fabric objects
What I see from your fiddle is that you don't wait the result of page.render method, which is asyncronous, then, unfortunately, if you wait the page.render, the fabric.canvas instance will clean your previously filled canvas, and we can't do nothing for this.
So I tried another approach: First of all, I wait the pdf.js page.render method, then I invoke the .toDataURL of your previously filled canvas so that I can have a copy of the old content, then I set your previously filled canvas as background of your new fabric.canvas and finish to draw your rectangle.
var url = 'http://www.africau.edu/images/default/sample.pdf';
var canvas = document.getElementById('pdfcanvas');
var context = canvas.getContext('2d');
PDFJS.disableWorker = true;
PDFJS.getDocument(url).then(function(pdf) {
pdf.getPage(1).then(function(page) {
var scale = 1.5;
var viewport = page.getViewport(scale);
canvas.height = viewport.height;
canvas.width = viewport.width;
page.render({
canvasContext: context,
viewport: viewport
}).then(function() {
var bg = canvas.toDataURL("image/png");
var fcanvas = new fabric.Canvas("pdfcanvas", {
selection: false
});
fcanvas.setBackgroundImage(bg,fcanvas.renderAll.bind(fcanvas));
fcanvas.setWidth(300);
fcanvas.setHeight(300);
var rect = new fabric.Rect({
left: 100,
top: 100,
width: 50,
height: 50,
fill: '#FF454F',
opacity: 0.5,
transparentCorners: true,
borderColor: "gray",
cornerColor: "gray",
cornerSize: 5
});
fcanvas.add(rect);
fcanvas.renderAll();
});
});
});
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.js"></script>
<script src="https://seikichi.github.io/tmp/PDFJS.0.8.715/pdf.min.js"></script>
<canvas id="pdfcanvas" style="border:1px solid black"></canvas>

Pixel manipulation with FabricJS

I'm using FabricJS v1.5.0 and have a problem when manipulated pixel by pixel on the canvas.
this.canvas = new this.fabric.Canvas('canvas');
let imageData = this.canvas.contextContainer.getImageData(0, 0, this.canvas.getWidth(), this.canvas.getHeight());
//here a changed imageData
this.canvas.contextContainer.putImageData(imageData, 0, 0);
//data seted in canvas.
let imageAdd = new this.fabric.Image(image, {
left: 100,
top: 100,
width: 100,
height: 100
});
this.canvas.add(imageAdd).setActiveObject(imageAdd);
//in this moment, the canvas don't have more the imageData setted
Why add image clear imageData? I need to transform imageData in FabricJS Object to add in canvas?
Yes, I think you do need to turn your image data into a fabricjs image. When you need to save the state of the canvas you can do this:
var dataUrl;
....
// Save canvas state
dataUrl = canvas.toDataURL()
// Make changes to the canvas
Then when you need to restore the canvas from it's saved state:
var img = fabric.Image.fromURL(dataUrl, function (i) {
canvas.clear();
canvas.add(i);
canvas.renderAll();
});
You should then be able to add other images as before.
What you need to find out is if your image is actually an image object, because fabric.Image() needs your image object.
If it's a URL or Blob format of your image ( which I guess it is ), you need to use fabric.Image.fromURL() and provide the src of the image not the whole image object.
Here is an example on how to create an instance of fabric.Image from a URL string
fabric.Image.fromURL(link, function(img) {
img.set({
id : 'someId',
width : canvas.width / 2,
height : canvas.height / 2
});
canvas.add(img).renderAll().setActiveObject(img);
});

Image animate function not working in fabric js?

I am using fabric js for canvas animation and I am created canvas with id 'canvas' then put image in it and set left position to zero. It's working fine but animate function is not working.
Please help me.
My code:
HTML:
<canvas id="canvas" width="990" height="285">
This text is displayed if your browser
does not support HTML5 Canvas.
</canvas>
javascript:
var canvas = new fabric.Canvas('canvas');
var image = new Image();
image.src = 'images/body.png';
var bugBody = fabric.Image.fromURL(image.src, function (oImg) {
canvas.add(oImg);
oImg.set('left',0)
});
bugBody.animate('left', 200, {
onChange: canvas.renderAll.bind(canvas)
});
Thanking You.
I think that this happen because your image is not complete loaded.
So, you can put your animation code inside your callback function.
Check this jsfiddle: http://jsfiddle.net/9x9Qc/
Like this:
var srcImg = "http://fabricjs.com/lib/pug.jpg";
// canvas
var canvas = new fabric.Canvas('c');
fabric.Image.fromURL(srcImg, function (oImg) {
canvas.add(oImg);
oImg.set('left',0);
oImg.set('top', 100);
oImg.scale(.25);
canvas.renderAll();
// and then, we can animate the image
oImg.animate('left', 200, {
onChange: canvas.renderAll.bind(canvas)
});
});

Creating a repeating image during zooming for kineticJS?

I'm using KineticJS and trying to get proper zoom functionality. I have a layer to which I have appended a background image at the original dimensions I want.
However when I zoom in (via layer.setScale()), my image shrinks when zooming in along with everything else (leaving exposed white areas).
So how can I make my image repeat even when this happens? Here is the code I used to add my image:
var imageObj = new Image();
imageObj.onload = function() {
var image = new Kinetic.Image({
image: imageObj,
width: width,
height: height
});
// add the shape to the layer
main_layer.add(image);
// add the layer to the stage
stage.add(main_layer);
};
imageObj.src = 'images/blueprint_background.png';
Try to create rectangle and then fill it with the image.
var rect = new Kinetic.Rect({
x: 0,
y: 0,
width: 2 * imageObj.width,
height: imageObj.height,
fillPatternImage: imageObj,
fillPatternRepeat: 'repeat-x'
});
This rectangle will repeat your image twice by Ox.
You can try to create long rectangle then when you will scale layer or you can dynamically resize rectangle as scale changes.

Categories

Resources