Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/355.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaFX-使用高DPI在画布上使用rect绘制时避免模糊_Java_Javafx_Canvas_Blur_Highdpi - Fatal编程技术网

JavaFX-使用高DPI在画布上使用rect绘制时避免模糊

JavaFX-使用高DPI在画布上使用rect绘制时避免模糊,java,javafx,canvas,blur,highdpi,Java,Javafx,Canvas,Blur,Highdpi,我想在JavaFX画布上画画。画布的坐标由双值提供,但我知道为了捕捉到像素网格,我需要整数来避免在像素之间绘制,这将导致边缘模糊/平滑 考虑这个最小的例子: public class App extends Application { @Override public void start(Stage stage) { var vbox = new VBox(); var canvas = new Canvas(600, 400);

我想在JavaFX画布上画画。画布的坐标由双值提供,但我知道为了捕捉到像素网格,我需要整数来避免在像素之间绘制,这将导致边缘模糊/平滑

考虑这个最小的例子:

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

}
<>这将导致一个清晰的边缘,考虑这个图像:

现在假设HydPI被启用,即考虑在Windows 10到125%中缩放图形。这将导致比例因子为1.25,我们可以通过getOutputScaleX/Y获得

然而,然后整个画布都用这个因子缩放,我们得到了一个模糊。查看附加的图像,但您必须缩放,并且可能在图形程序中而不是在浏览器中查看它们

然后我想我们可以调整原始坐标,这样缩放坐标就会得到整数。例如,为了确保在缩放图像上找到偏移量为9*1.25=11.25的整数,让我们尝试以11.0为目标,即更改此行

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

但这仍然会导致边缘模糊

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


对于drawImage,有一个参数setSmoothing,但在像rect这样直接绘制形状时没有任何参数。

您可以通过消除将画布缩放到较小尺寸所使用的缩放来解决此问题。下面是一个示例说明,在JavaFX中,像素之间画有直线,因此要使它们清晰,需要添加0.5

此示例还将在缩放的画布周围放置一个组。这需要在进行布局时考虑比例,但也会对渲染产生一些影响。该示例在100%、125%和150%下进行测试

import javafx.application.Application;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class CanvasTest extends Application {

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

  @Override
  public void start(Stage stage) throws Exception {
    HBox hbox = new HBox();

    Canvas canvas = new Canvas(100,100);

    GraphicsContext g2d = canvas.getGraphicsContext2D();

    g2d.fillRect(15, 15, 60, 10);
    g2d.fillRect(15.5, 30, 60, 10);  // supposed to be blurry
    g2d.fillRect(16, 45, 60, 10);
    g2d.fillRect(16.5, 60, 60, 10);  // supposed to be blurry

    g2d.setStroke(Color.RED);
    g2d.strokeLine(13.5, 13.5, 13.5, 93.5);
    g2d.strokeLine(13.5, 13.5, 93.5, 93.5);
    hbox.getChildren().add(new Group(canvas));

    Scene scene = new Scene(hbox);

    stage.setScene(scene);
    stage.show();

    canvas.scaleXProperty().bind(new SimpleDoubleProperty(1.0).divide(scene.getWindow().outputScaleXProperty()));
    canvas.scaleYProperty().bind(new SimpleDoubleProperty(1.0).divide(scene.getWindow().outputScaleYProperty()));
  }
}
下面是它在150%监视器上的外观左侧放大了5倍,因此您可以看到没有模糊:

下面是更新后的示例中125%的情况:


您可以通过消除将画布缩放到较小尺寸所使用的缩放来解决此问题。下面是一个示例说明,在JavaFX中,像素之间画有直线,因此要使它们清晰,需要添加0.5

此示例还将在缩放的画布周围放置一个组。这需要在进行布局时考虑比例,但也会对渲染产生一些影响。该示例在100%、125%和150%下进行测试

import javafx.application.Application;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class CanvasTest extends Application {

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

  @Override
  public void start(Stage stage) throws Exception {
    HBox hbox = new HBox();

    Canvas canvas = new Canvas(100,100);

    GraphicsContext g2d = canvas.getGraphicsContext2D();

    g2d.fillRect(15, 15, 60, 10);
    g2d.fillRect(15.5, 30, 60, 10);  // supposed to be blurry
    g2d.fillRect(16, 45, 60, 10);
    g2d.fillRect(16.5, 60, 60, 10);  // supposed to be blurry

    g2d.setStroke(Color.RED);
    g2d.strokeLine(13.5, 13.5, 13.5, 93.5);
    g2d.strokeLine(13.5, 13.5, 93.5, 93.5);
    hbox.getChildren().add(new Group(canvas));

    Scene scene = new Scene(hbox);

    stage.setScene(scene);
    stage.show();

    canvas.scaleXProperty().bind(new SimpleDoubleProperty(1.0).divide(scene.getWindow().outputScaleXProperty()));
    canvas.scaleYProperty().bind(new SimpleDoubleProperty(1.0).divide(scene.getWindow().outputScaleYProperty()));
  }
}
下面是它在150%监视器上的外观左侧放大了5倍,因此您可以看到没有模糊:

下面是更新后的示例中125%的情况:


与getOutputScaleX/Y相比,getRenderScaleX/Y方法在您的情况下返回什么值。您所说的HighDPI选项是什么?您是否调整了windows为可执行文件提供的任何选项,如高DPI设置或兼容模式?因为JavaFX不需要这样做,所以它具有高dpi感知能力。Windows设置应用程序->系统->显示->缩放和布局部分->更改文本、应用程序和其他图标的大小。这实际上改变了Windows中的dpi设置。与getOutputScaleX/Y相比,getRenderScaleX/Y方法在您的案例中返回了哪些值。您所说的HighDPI选项是什么?您是否调整了windows为可执行文件提供的任何选项,如高DPI设置或兼容模式?因为JavaFX不需要这样做,所以它具有高dpi感知能力。Windows设置应用程序->系统->显示->缩放和布局部分->更改文本、应用程序和其他图标的大小。这实际上改变了WindowsI中的dpi设置,因为它的屏幕为1920*1080。如果我以150%的比例运行您的示例,则不会出现模糊。然而,在125%时,黑色矩形周围有一个像素线的灰色模糊。嗯,什么版本的JavaFX?我用的是11.0.1。对我来说,上面的例子完美无瑕,即使当我将窗口从100%屏幕拖动到150%屏幕时,它也会立即被重新绘制。如果没有OutputScale侦听器,我会得到模糊的结果。也许您可以打印OutputScaleX/Y的值,看看它们是否改变。对于4k屏幕3840x2160,我在150%时得到2560x1440的输出比例。奇怪的是,在125%时,在+0.5像素偏移处绘制矩形,填充矩形15.5、15.5、60、60完全消除了这种模糊。这听起来确实像一个bug。在+0.5的画布上添加一个translate也可以解决125%的问题。现在,让这些调整按比例因子配置可能是一个令人满意的解决方案。我发现这个问题与125%的比例有类似的问题。这不完全相同,但可能是一个类似的问题,Math.round和Math.ceil之间的差异很重要,但使用了错误的。我快速浏览了JFX代码库,但找不到任何明显的OutputScale相关内容,这可能会导致我们在这里看到的结果。可能值得一试
我有一个1920*1080的屏幕。如果我以150%的比例运行您的示例,则不会出现模糊。然而,在125%时,黑色矩形周围有一个像素线的灰色模糊。嗯,什么版本的JavaFX?我用的是11.0.1。对我来说,上面的例子完美无瑕,即使当我将窗口从100%屏幕拖动到150%屏幕时,它也会立即被重新绘制。如果没有OutputScale侦听器,我会得到模糊的结果。也许您可以打印OutputScaleX/Y的值,看看它们是否改变。对于4k屏幕3840x2160,我在150%时得到2560x1440的输出比例。奇怪的是,在125%时,在+0.5像素偏移处绘制矩形,填充矩形15.5、15.5、60、60完全消除了这种模糊。这听起来确实像一个bug。在+0.5的画布上添加一个translate也可以解决125%的问题。现在,让这些调整按比例因子配置可能是一个令人满意的解决方案。我发现这个问题与125%的比例有类似的问题。这不完全相同,但可能是一个类似的问题,Math.round和Math.ceil之间的差异很重要,但使用了错误的。我快速浏览了JFX代码库,但找不到任何明显的OutputScale相关内容,这可能会导致我们在这里看到的结果。也许值得提出一个问题。