2015-11-29 109 views
2

有一个Canvas。画一些东西(在我的情况下,几条红线)。如何将一个画布的内容复制到另一个画布?

enter image description here

我想这个画布内容毫不夸张地复制到另一个。这是我做的:

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

这是你的第二画布得到什么:

enter image description here

它是模糊的。我猜测它是反锯齿的。

我想这可能是因为我使用的是Macbook Pro,Retina Display。

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

回答

4

下面是示例代码,它允许您在右侧绘制运行时的左侧画布和画布。

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()中。

enter image description here

测试使用JavaFX 8u40,Win7的。虽然抗锯齿功能不如激烈,但副本不是1:1副本。如果删除

params.setFill(Color.TRANSPARENT); 

,你会得到一个1

enter image description here

:1复制:

如果您在像素级比较2条线,你会得到这个

enter image description here

所以它似乎与SnapshotParameters中的透明填充颜色有关。

+0

右侧看起来比左侧厚。你甚至可以在你的图像中看到它。 – Voldemort

+0

你是对的,我没有注意到,它不像你的模糊。您可以在放大的像素级别看到它。我修改了答案。看起来问题是SnapshotParameters中的透明填充颜色。如果你不使用它,它会在你的系统上正确复制吗? – Roland

+0

这是对的,它现在起作用。虽然这是一种遗憾,因为在某些情况下我确实需要透明填充颜色。无论如何,我改变了项目方法,所以我不再需要这个了。谢谢。 – Voldemort

相关问题