【问题标题】:How to copy contents of one canvas to another?如何将一个画布的内容复制到另一个画布?
【发布时间】:2016-03-03 11:57:27
【问题描述】:

有一个Canvas。画一些东西(在我的例子中,是几条红线)。

我想将这个画布的内容完全复制到另一个画布上。我就是这样做的:

SnapshotParameters params = new SnapshotParameters();
params.setFill(Color.TRANSPARENT);         
WritableImage image = firstCanvas.snapshot(params, null);
secondCanvas.getGraphicsContext2D().drawImage(image, 0, 0);

这就是你在第二个画布中得到的:

它是模糊的。我猜它是抗锯齿的。

我想这可能是因为我使用的是 Macbook Pro,视网膜显示屏。

如何才能将一个画布的内容正确复制到另一个画布?

【问题讨论】:

    标签: java image canvas javafx pixels


    【解决方案1】:

    这是一个示例代码,可让您在左侧进行绘制,并在运行时在右侧镜像画布。

    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);
        }
    }
    

    您的代码在 copyCanvas() 中。

    使用 JavaFX 8u40、Win7 测试。虽然抗锯齿没有那么强烈,但副本不是 1:1 副本。如果你在像素级别上比较 2 行,你会得到:

    如果你删除了

    params.setFill(Color.TRANSPARENT);  
    

    您将获得 1:1 副本:

    所以看来和 SnapshotParameters 中的透明填充颜色有关。

    【讨论】:

    • 右侧看起来比左侧厚。您甚至可以在图像中看到它。
    • 你说得对,我没有注意到,它没有你的那么模糊。您可以在放大的像素级别看到它。我修改了答案。看起来问题出在 SnapshotParameters 中的透明填充颜色。如果你不使用它,它会在你的系统上正确复制吗?
    • 没错,现在可以了。虽然很遗憾,因为在某些情况下我确实需要透明填充颜色。无论如何,我改变了项目方法,所以我不再需要这个了。谢谢。
    猜你喜欢
    • 2011-05-23
    • 1970-01-01
    • 2013-01-22
    • 2014-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多