JavaFX-在高dpi的Canvas上使用rect绘制时避免模糊

问题描述 投票:0回答:1

我想使用JavaFX Canvas。画布的坐标是由双精度值提供的,但是我知道为了“捕捉”到像素网格,我需要整数以避免在像素之间绘制“中间”,这会导致边缘模糊/平滑。

考虑这个最小的例子:

public class App extends Application {

    @Override
    public void start(Stage stage) {

        var vbox = new VBox();
        var canvas = new Canvas(600, 400);
        var gc = canvas.getGraphicsContext2D();

        // draw a background
        gc.beginPath();
        gc.setFill(Color.rgb(200,200,200));
        gc.rect(0, 0, 600, 400);
        gc.fill();

        // draw a smaller square
        gc.beginPath();
        gc.setFill(Color.rgb(100,100,100));
        gc.rect(9.0, 9.0, 50, 50);  // snap to grid
        gc.fill();

        vbox.getChildren().addAll(canvas);

        var scene = new Scene(vbox, 640, 480);
        stage.setScene(scene);
        stage.show();
    }

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

}

此方法将产生清晰的边缘,请考虑以下图像:

enter image description here

现在假定已启用HighDPI,即考虑是否将Windows 10中的图形缩放到125%。这将导致比例因子为1.25(我们可以通过getOutputScaleX / Y获得它)。

然而,整个画布以此比例缩放,我们得到了模糊效果。查看附带的图像(但是您必须缩放,并且可能在图形程序中而不是在浏览器中查看它们)。

enter image description here

然后,我认为我们可以调整原始坐标,以便缩放后的坐标将产生整数。例如,要确保在缩放后的图像上命中偏移量为9 * 1.25 = 11.25的整数,让我们尝试以11.0为目标,即更改此行

gc.rect(9.0, 9.0, 50, 50); 

gc.rect(11.0/1.25, 11.0/1.25, 50, 50); 

但是此静止导致边缘模糊。

我们如何解决这个问题?理想情况下,我想完全关闭画布的dpi缩放比例,并进行自己的(像素完美)计算。这可能还是有其他解决方案?

对于drawImage,有一个参数setSmoothing,但是当直接绘制形状时(如rect)没有任何东西。

java javafx canvas blur highdpi
1个回答
1
投票

我不知道这是否是您想要的,但似乎DPI和Java存在一些问题。

好像Java报告自己是DPI感知的,因此操作系统无法扩展它,但是它本身不能正确地扩展。您可以使用以下类似的jvm属性来关闭此行为并强制系统缩放Java GUI:

-Dsun.java2d.dpiaware=false

我在SuperUser论坛上找到了一个有趣的讨论,您可能会找到有用的东西,请take a look

© www.soinside.com 2019 - 2024. All rights reserved.