How to Copy Contents of One Canvas to Another Canvas Locally
Actually you don't have to create an image at all. drawImage()
will accept a Canvas
as well as an Image
object.
//grab the context from your destination canvas
var destCtx = destinationCanvas.getContext('2d');
//call its drawImage() function passing it the source canvas directly
destCtx.drawImage(sourceCanvas, 0, 0);
Way faster than using an ImageData
object or Image
element.
Note that sourceCanvas
can be a HTMLImageElement, HTMLVideoElement, or a HTMLCanvasElement. As mentioned by Dave in a comment below this answer, you cannot use a canvas drawing context as your source. If you have a canvas drawing context instead of the canvas element it was created from, there is a reference to the original canvas element on the context under context.canvas
.
Here is a jsPerf to demonstrate why this is the only right way to clone a canvas: http://jsperf.com/copying-a-canvas-element
Copying and pasting one canvas inside another canvas's corner
The way you are drawing the first canvas on the second one is not correct. You can directly draw a canvas on another canvas using drawImage()
method.
var first = document.getElementById('first').getContext('2d');var sec = document.getElementById('second').getContext('2d');
// draw on first canvasfirst.fillStyle = '#07C';first.fillRect(0, 0, first.canvas.width, first.canvas.height);
// draw image on second canvasvar img = new Image();img.src = "http://lorempixel.com/300/300";img.onload = function() { sec.drawImage(img, 0, 0, sec.canvas.width, sec.canvas.height); sec.drawImage(first.canvas, 100, 100, 100, 100); // draw first canvas on a portion of second canvas};
body {display: flex}
<canvas id="first" width="200" height="200"></canvas><canvas id="second" width="200" height="200"></canvas>
Display canvas image from one canvas to another canvas using base64
You shouldn't use base64 to copy the canvas. You can pass the source canvas into the destination canvas' context method, drawImage.
Otherwise you will suffer a serious performance hit. See my jsperf test at http://jsperf.com/copying-a-canvas-element.
drawImage()
will accept a Canvas
as well as an Image
object.
Try this:
//grab the context from your destination canvas
var destCtx = destinationCanvas.getContext('2d');
//call its drawImage() function passing it the source canvas directly
destCtx.drawImage(sourceCanvas, 0, 0);
Can you copy only a specific area from one Canvas to another?
getImageData(sx, sy, sw, sh)
allows you to extract image data based on a X/Y coordinate and a width & height, and
putImageData(imageData, dx, dy)
allows you to place it at a X/Y coordinate.
Or use drawImage, that allows you to use the existing canvas as "input" directly, and you can specify X/Y and width/height for both the origin and the target:
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
How to copy contents of one canvas to another?
Here's example code which lets you paint on the left side and which mirrors the canvas at runtime on the right side.
import java.util.Random;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.Image;
import javafx.scene.image.WritableImage;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class Main extends Application {
private static double SCENE_WIDTH = 1280;
private static double SCENE_HEIGHT = 720;
static Random random = new Random();
Canvas canvas;
Canvas copyCanvas;
GraphicsContext graphicsContext;
GraphicsContext copyGraphicsContext;
AnimationTimer loop;
Point2D mouseLocation = new Point2D( 0, 0);
boolean mousePressed = false;
Point2D prevMouseLocation = new Point2D( 0, 0);
Scene scene;
Image brush = createBrush( 30.0, Color.CHOCOLATE);
double brushWidthHalf = brush.getWidth() / 2.0;
double brushHeightHalf = brush.getHeight() / 2.0;
@Override
public void start(Stage primaryStage) {
BorderPane root = new BorderPane();
canvas = new Canvas( SCENE_WIDTH / 2, SCENE_HEIGHT);
graphicsContext = canvas.getGraphicsContext2D();
copyCanvas = new Canvas( SCENE_WIDTH / 2, SCENE_HEIGHT);
copyGraphicsContext = canvas.getGraphicsContext2D();
HBox hBox = new HBox();
hBox.getChildren().addAll(canvas, copyCanvas);
root.setCenter(hBox);
scene = new Scene(root, SCENE_WIDTH, SCENE_HEIGHT);
primaryStage.setScene(scene);
primaryStage.show();
addListeners();
startAnimation();
}
private void startAnimation() {
loop = new AnimationTimer() {
@Override
public void handle(long now) {
if( mousePressed) {
// try this
// graphicsContext.drawImage( brush, mouseLocation.getX() - brushWidthHalf, mouseLocation.getY() - brushHeightHalf);
// then this
bresenhamLine( prevMouseLocation.getX(), prevMouseLocation.getY(), mouseLocation.getX(), mouseLocation.getY());
}
prevMouseLocation = new Point2D( mouseLocation.getX(), mouseLocation.getY());
copyCanvas();
}
};
loop.start();
}
private void copyCanvas() {
SnapshotParameters params = new SnapshotParameters();
params.setFill(Color.TRANSPARENT);
WritableImage image = canvas.snapshot(params, null);
copyCanvas.getGraphicsContext2D().drawImage(image, 0, 0);
}
// https://de.wikipedia.org/wiki/Bresenham-Algorithmus
private void bresenhamLine(double x0, double y0, double x1, double y1)
{
double dx = Math.abs(x1-x0), sx = x0<x1 ? 1. : -1.;
double dy = -Math.abs(y1-y0), sy = y0<y1 ? 1. : -1.;
double err = dx+dy, e2; /* error value e_xy */
while( true){
graphicsContext.drawImage( brush, x0 - brushWidthHalf, y0 - brushHeightHalf);
if (x0==x1 && y0==y1) break;
e2 = 2.*err;
if (e2 > dy) { err += dy; x0 += sx; } /* e_xy+e_x > 0 */
if (e2 < dx) { err += dx; y0 += sy; } /* e_xy+e_y < 0 */
}
}
private void addListeners() {
scene.addEventFilter(MouseEvent.ANY, e -> {
mouseLocation = new Point2D(e.getX(), e.getY());
mousePressed = e.isPrimaryButtonDown();
});
}
public static Image createImage(Node node) {
WritableImage wi;
SnapshotParameters parameters = new SnapshotParameters();
parameters.setFill(Color.TRANSPARENT);
int imageWidth = (int) node.getBoundsInLocal().getWidth();
int imageHeight = (int) node.getBoundsInLocal().getHeight();
wi = new WritableImage(imageWidth, imageHeight);
node.snapshot(parameters, wi);
return wi;
}
public static Image createBrush( double radius, Color color) {
// create gradient image with given color
Rectangle brush = new Rectangle(0,0,1,1);
brush.setStroke(Color.RED);
brush.setFill(Color.RED);
// create image
return createImage(brush);
}
public static void main(String[] args) {
launch(args);
}
}
Your code is in copyCanvas().
Tested with JavaFX 8u40, Win7. Although the antialiasing isn't as intense, the copy isn't a 1:1 copy. If you compare 2 lines on a pixel-level, you'll get this:
If you remove the
params.setFill(Color.TRANSPARENT);
you'll get a 1:1 copy:
So it seems to have something to do with the transparent fill color in the SnapshotParameters.
How to copy from one canvas to another
A Canvas is always used to draw either on screen or onto a Bitmap. The solution of using Bitmaps works perfectly well: create a Bitmap, create a Canvas to draw onto that Bitmap, then draw the Bitmap onto another Canvas. You also record all drawing commands in a Picture and replay them on a different Canvas.
Copy user selection from one canvas to another
The following guide might be helpful.
http://www.i-programmer.info/programming/graphics-and-imaging/2078-canvas-bitmap-operations-bitblt-in-javascript.html
It mentions you can draw a section of the image using
drawImage(image,sx,sy,sw,sh,dx,dy,dw,dh)
Where s is source, and d is destination.
From there you just have to determine the position of the click and drag to work out the co-ordinates and width/heights.
I've updated your fiddle just to demonstrate. It's very crude, so just click once somewhere in the top left of the image, then click again somewhere in the bottom right.
http://jsfiddle.net/treerock/1zpc8fz0/
Related Topics
Input Type="Submit" VS Button Tag Are They Interchangeable
What Does "For" Attribute Do in HTML ≪Label≫ Tag
How to Set the Margin or Padding as Percentage of Height of Parent Container
How to Ignore HTML Element from Tabindex
Is There an Equivalent to Background-Size: Cover and Contain For Image Elements
Html/Css: Making Two Floating Divs the Same Height
Do You Put Schema Microdata Meta Tags in the HTML Body
Remove White Space Above and Below Large Text in an Inline-Block Element
How to Trigger Autofill in Google Chrome
How to Make Div Elements Display Inline
Heights Rendering Differently in Chrome and Firefox
Css Cut Out Circle from a Rectangular Shape
Put Icon Inside Input Element in a Form
Show Youtube Video Source into Html5 Video Tag