Turning a canvas element into an image object - javascript

I have a primary canvas element which I perform drawing operations on using the context. I can successfully draw images, shapes, and also transform those objects using the context.
I now need my own textbox. I want to create another canvas, render the text to that canvas, then copy that data onto the primary canvas... the catch is I want to have it transformable, almost is if I was just calling the drawImage function.
There exists the getImageData and putImageData methods, but those do not work because it does not take into consideration the transformation.
I am looking for something like this...
var tempcanvas = document.createElement("canvas");
var ctx = tempcanvas.getContext('2d');
ctx.fillRect(0,0,5,5);
then on my primary canvas which I already have, I would like to draw that as if it were an image object.
context = maincanvas.getContext('2d');
context.translate(50,50);
context.rotate(180);
context.drawImage(tempcanvas)

Related

Using ImageData object in drawImage

Is it possible to use ImageData array object to get an Image() object. My eventual goal is to use drawImage instead of putImageData since putImageData is too slow (from stackoverflow similar qs and my own tests). All I have is ImageData array that I want to draw on top of an existing image on a canvas .
You can create an ImageBitmap from an ImageData and pass that to drawImage().
https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/createImageBitmap
Something like:
const imgdata = ...;
const ctx = ...;
createImageBitmap(imgdata).then(function(imgBitmap) {
ctx.drawImage(imgBitmap, ...remaining args);
});
I was able to do this to scale some ImageData I had, since putImageData does not have arguments for scaling. Unfortunately, it looks like IE, Edge, and Safari do not support createImageBitmap().
It's worth mentioning that for my case (resizing the ImageData), createImageBitmap() does have extra options for resizing the resulting ImageBitmap on its own.

Fabricjs copy part of canvas to another canvas

I am trying to copy part of a fabricjs canvas to another canvas.I am not sure if fabric has a method suitable for doing it (please let me know if that's the case) and after some searching I decided to do it without using fabric. But the canvas was already created using fabricjs. new fabric.Canvas(). Now when I try to copy a part of this canvas using context.drawImage(), I get a TypeError. I tried replacing the canvas with a img or a canvas created without using fabric and that works. So, I am guessing I may have to use the fabric canvas object a bit differently.
If you want to copy a rectangular zone from the canvas in order to export it as an image you could use the following:
canvas.deactivateAll();
canvas.renderAll();
var ctx = canvas.getContext("2d");
var myImageData = ctx.getImageData(box.x, box.y, box.w, box.h);
var buffer = document.createElement('canvas');
var bufferCtx = buffer.getContext("2d");
buffer.width = box.w;
buffer.height = box.h;
bufferCtx.putImageData(myImageData, 0, 0);
window.open(buffer.toDataURL('image/png'));

Mask for putImageData with HTML5 canvas?

I want to take an irregularly shaped section from an existing image and render it as a new image in Javascript using HTML5 canvases. So, only the data inside the polygon boundary will be copied. The approach I came up with involved:
Draw the polygon in a new canvas.
Create a mask using clip
Copy the data from the original canvas using getImageData (a rectangle)
Apply the data to the new canvas using putImageData
It didn't work, the entire rectangle (e.g. the stuff from the source outside the boundary) is still appearing. This question explains why:
"The spec says that putImageData will not be affected by clipping regions." Dang!
I also tried drawing the shape, setting context.globalCompositeOperation = "source-in", and then using putImageData. Same result: no mask applied. I suspect for a similar reason.
Any suggestions on how to accomplish this goal? Here's basic code for my work in progress, in case it's not clear what I'm trying to do. (Don't try too hard to debug this, it's cleaned up/extracted from code that uses a lot of functions that aren't here, just trying to show the logic).
// coords is the polygon data for the area I want
context = $('canvas')[0].getContext("2d");
context.save();
context.beginPath();
context.moveTo(coords[0], coords[1]);
for (i = 2; i < coords.length; i += 2) {
context.lineTo(coords[i], coords[i + 1]);
}
//context.closePath();
context.clip();
$img = $('#main_image');
copy_canvas = new_canvas($img); // just creates a new canvas matching dimensions of image
copy_ctx = copy.getContext("2d");
tempImage = new Image();
tempImage.src = $img.attr("src");
copy_ctx.drawImage(tempImage,0,0,tempImage.width,tempImage.height);
// returns array x,y,x,y with t/l and b/r corners for a polygon
corners = get_corners(coords)
var data = copy_ctx.getImageData(corners[0],corners[1],corners[2],corners[3]);
//context.globalCompositeOperation = "source-in";
context.putImageData(data,0,0);
context.restore();
dont use putImageData,
just make an extra in memory canvas with document.createElement to create the mask and apply that with a drawImage() and the globalCompositeOperation function (depending on the order you need to pick the right mode;
I do something similar here the code is here (mind the CasparKleijne.Canvas.GFX.Composite function)

Any way to clone HTML5 canvas element with its content?

Is there any way to create a deep copy of a canvas element with all drawn content?
Actually the correct way to copy the canvas data is to pass the old canvas to the new blank canvas. Try this function.
function cloneCanvas(oldCanvas) {
//create a new canvas
var newCanvas = document.createElement('canvas');
var context = newCanvas.getContext('2d');
//set dimensions
newCanvas.width = oldCanvas.width;
newCanvas.height = oldCanvas.height;
//apply the old canvas to the new one
context.drawImage(oldCanvas, 0, 0);
//return the new canvas
return newCanvas;
}
Using getImageData is for pixel data access, not for copying canvases. Copying with it is very slow and hard on the browser. It should be avoided.
You can call
context.getImageData(0, 0, context.canvas.width, context.canvas.height);
which will return an ImageData object. This has a property named data of type CanvasPixelArray which contains the rgb and transparency values of all the pixels. These values are not references to the canvas so can be changed without affecting the canvas.
If you also want a copy of the element, you could create a new canvas element and then copy all attributes to the new canvas element. After that you can use the
context.putImageData(imageData, 0, 0);
method to draw the ImageData object onto the new canvas element.
See this answer for more detail getPixel from HTML Canvas? on manipulating the pixels.
You might find this mozilla article useful as well https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Canvas_tutorial/Drawing_shapes

HTML Canvas: draw image without anti-aliasing

I want to do pixel-true rendering of some images on my Canvas. Right now, I obtain the images through Javascript, so my images are HTMLImageElement instances. I can draw these on the Canvas' rendering context with drawImage. However, this performs anti-aliasing on the image, which I don't want.
There appears to be a lower-level image manipulation method named putImageData, operating on ImageData objects. Does this method perform any anti-aliasing? If not, it's a fine candidate for what I'm looking for, but I haven't found out how I can convert or blit an HTMLImageElement to an ImageData instance.
Any advice would be welcome!
Edit: my original problem was solved, I accidentally had a coordinate that was fractional, which forces anti-aliasing. The conversion-to-image-data question still stands though.
The only way to convert an image into an ImageData object is to draw it to a canvas first, so you'll need to create a temporary canvas, draw the image on it, and get the image data from there.
function imageToImageData(image) {
var canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0);
return ctx.getImageData(0, 0, canvas.width, canvas.height);
}
Note though, that the same-origin policy prevents you from calling getImageData if you draw an image from a different domain to the canvas, so this will only work on images from the same domain as the document. If you need to draw images from other domains, your only option is to call drawImage on the context for you main canvas directly, making sure there are no transformations that will affect the accuracy.

Categories

Resources