【问题标题】:Override path with transparent color in javafx Canvas/GraphicsContext在 javafx Canvas/GraphicsContext 中用透明颜色覆盖路径
【发布时间】:2015-03-04 02:48:16
【问题描述】:

我想知道 JavaFX 中 Canvas 的 GraphicsContext 中是否有任何方法可以覆盖路径中的所有像素,从而使它们再次变得透明。与 clearRect 函数类似,但适用于任何路径。

我查看了不同的 BlendModes 和 Effects,但似乎没有办法真正覆盖可以通过例如实现的 alpha 值

  • 使用 Porter/Duff Src 运算符渲染透明颜色
  • 在 HTML5 中使用 globalCompositeOperation 目的地输出呈现非透明颜色

如果有人知道一种无需细分路径和使用多个 clearRect 调用即可实现此目的的方法,我将非常高兴。谢谢。

http://docs.oracle.com/javase/8/javafx/api/javafx/scene/canvas/GraphicsContext.html


对第一条评论的补充: 我没有使用 Path 节点,而是使用 Canvas 节点使用 GraphicsContext 执行渲染,因此无法修改先前渲染路径的颜色。 我正在尝试做类似的事情

Canvas canvas = …;
final GraphicsContext context = canvas.getGraphicsContext();
context.setFill(Color.BLUE);
context.fillRect(0,0,100,100);
…
…

稍后我想将路径中的像素重置为透明

context.setStroke(Color.TRANSPARENT);
context.beginPath();
context.moveTo(0, 0);
context.lineTo(10,10);
…
context.stroke();

但是,由于应用了混合,这不起作用。在其他渲染库中,可以使用例如上面提到的混合/合成方法之一来实现这一点,但直到现在我无法在 javafx 中识别出这样的功能。

【问题讨论】:

  • 您想要实现什么,它在图像示例中的外观如何?要么你有路径节点并设置不透明度,要么你没有,你用背景颜色重绘路径。
  • 我已经用更多细节编辑了这个问题,试图让问题更清晰
  • 但是当你在画布上用透明颜色作画时,你会期待什么?它不会有任何影响。只需将其涂上背景颜色即可。我怀疑你想要的是不同的层次。这不是单个 Canvas 的含义。
  • 请看关于How to work with Canvas的文章。
  • 画布只是层次结构中的一个节点,我想将一些像素设置回透明,以使该区域中的较低层可见。由于这是其他 Canvas 实现中的常见操作,我很好奇 javafx 中是否没有办法实现这一点。例如HTML5 Canvas 例如Android Canvas

标签: javafx javafx-8 graphicscontext


【解决方案1】:

我还没有找到根据路径清除画布的机制。但您可以手动执行以下操作:

  • 创建用于绘制路径的蒙版
  • 手动混合图像和蒙版

带有路径蒙版的蓝色矩形示例:

public class ManualBlendWithMask extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {

        Group root = new Group();

        // create canvas
        Canvas canvas = new Canvas(200, 200);
        canvas.setTranslateX(100);
        canvas.setTranslateY(100);

        // create canvas with blue rectangle
        GraphicsContext canvasGC = canvas.getGraphicsContext2D();
        canvasGC.setFill(Color.BLUE);
        canvasGC.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());

        // create mask
        Canvas mask = new Canvas( canvas.getWidth(), canvas.getHeight());
        GraphicsContext maskGC = mask.getGraphicsContext2D();
        maskGC.setFill(Color.WHITE);
        maskGC.fillRect(0, 0, mask.getWidth(), mask.getHeight());

        // draw path
        maskGC.setStroke(Color.BLACK);
        maskGC.setLineWidth(20);
        maskGC.beginPath();
        maskGC.moveTo(0, 0);
        maskGC.lineTo(400, 400);
        maskGC.stroke();

        // get image from canvas
        WritableImage srcImage = new WritableImage((int) canvas.getWidth(), (int) canvas.getHeight());
        srcImage = canvas.snapshot(null, srcImage);

        // get image from mask
        WritableImage srcMask = new WritableImage((int) mask.getWidth(), (int) mask.getHeight());
        srcMask = mask.snapshot(null, srcMask);

        PixelReader maskReader = srcMask.getPixelReader();
        PixelReader imageReader = srcImage.getPixelReader();

        int width = (int) srcMask.getWidth();
        int height = (int) srcMask.getHeight();

        // create dest image
        WritableImage dest = new WritableImage(width, height);
        PixelWriter writer = dest.getPixelWriter();

        // blend image and mask
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {

                Color maskColor = maskReader.getColor(x, y);
                Color imageColor = imageReader.getColor(x, y);

                if (maskColor.equals(Color.WHITE)) {
                    writer.setColor(x, y, imageColor);
                }

            }
        }

        // clear canvas and fill it with the blended image
        canvasGC = canvas.getGraphicsContext2D();
        canvasGC.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
        canvasGC.drawImage(dest, 0, 0);

        // draw background with gradient
        Rectangle rect = new Rectangle(400, 400);
        rect.setFill(new LinearGradient(0, 0, 1, 1, true, CycleMethod.REFLECT, new Stop(0, Color.RED), new Stop(1, Color.YELLOW)));

        // show nodes
        root.getChildren().addAll(rect, canvas);

        primaryStage.setScene(new Scene(root, 400, 400));
        primaryStage.show();

    }

}

当然,如果有人能想出一个使用 BlendModes 的例子就更好了。

【讨论】:

  • 感谢您的详细解答。由于您的回答显示了解决问题的不同方法,因此我将接受您的回答,因为似乎没有人知道使用 BlendModes 或类似技术来实现这一点的方法,这肯定需要更少的资源。谢谢。
【解决方案2】:

在看到 2015 年的几篇类似的帖子之后,我发现这仍然没有添加到 javaFX,这让我感到惊讶。据我所知,AWT 中有一个“DST-OUT”混合选项,那么为什么不在javaFX 中呢?!

无论如何.. 我在找到自己的解决方案后回到这里,所以我可以分享我的解决方案,并希望能帮助下一个来这里寻找答案的不安分的灵魂。

我的具体需要是在基于SVGPath 的区域中使画布透明。所以这是我的解决方案:

private void clearPath(GraphicsContext gc, SVGPath path) {
    int xstart = (int) path.getLayoutX();
    int xend = (int) (xstart + path.getLayoutBounds().getMaxX());
    int ystart = (int) path.getLayoutY();
    int yend = (int) (ystart + path.getLayoutBounds().getMaxY());

    PixelWriter pw = gc.getPixelWriter();
    for (int x = xstart; x <= xend; x++) {
        for (int y = ystart; y <= yend; y++) {
            if(path.contains(new Point2D(x, y))) {
                pw.setColor(x, y, Color.TRANSPARENT);
            }
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-07
    • 1970-01-01
    • 2014-02-06
    • 2012-11-05
    • 2016-12-10
    • 1970-01-01
    相关资源
    最近更新 更多