macos - 剪裁时打印像素化

标签 macos javafx printing

在运行 JDK 17 和 JavaFX 18 的 macOS Big Sur 上,当您有不规则的裁剪区域时,裁剪图像在打印时会严重像素化。

像素化既发生在实际纸张上(在我的爱普生打印机上),也发生在保存为 PDF 时(使用 macOS 固有的“保存为 PDF”功能)。

如果您有一个带有矩形的剪辑区域,则没有像素化,一切看起来都平滑而清晰。

注意,必须是Rectangle,矩形Polygon也有问题。

这是实际屏幕渲染的屏幕截图: enter image description here

接下来是查看生成的 PDF 的屏幕截图。

enter image description here

您可以看到圆圈内的文本和线条都是像素化的。

在我看来,它将节点渲染为“PDF 分辨率”,即 72 DPI(不是实际的打印机分辨率),然后使用位图操作屏蔽该区域,而不是将内容实际剪切到不规则边框。但它是特殊情况下的矩形和剪辑。

有什么办法可以解决这个问题吗?

下面是一个演示这一点的示例。

package pkg;

import javafx.application.Application;
import javafx.print.PrinterJob;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class App extends Application {

    Pane printPane;

    @Override
    public void start(Stage stage) {
        var scene = new Scene(getView(), 640, 480);
        stage.setScene(scene);
        stage.show();
    }

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

    private Pane getView() {
        var flowPane = new FlowPane(getCirclePane(), getRectPane());
        var b = new Button("Print");
        printPane = flowPane;
        b.setOnAction((t) -> {
            var job = PrinterJob.createPrinterJob();

            if (job != null && job.showPrintDialog(null)) {
                if (job.printPage(printPane)) {
                    job.endJob();
                }
            }

        });
        var bp = new BorderPane();
        bp.setCenter(flowPane);
        bp.setBottom(b);

        return bp;
    }

    private Pane getCirclePane() {
        var pane = new Pane();
        var circle = new Circle(100, 100, 45);
        pane.setClip(circle);
        var text = new Text(75, 100, "Circle");
        pane.getChildren().add(text);
        for (int i = 0; i < 10; i++) {
            double ox = i * 25;
            pane.getChildren().add(new Line(ox, 200, ox + 25, 0));
            pane.getChildren().add(new Line(ox, 0, ox + 25, 200));
        }

        return pane;
    }

    private Pane getRectPane() {
        var pane = new Pane();
        var rect = new Rectangle(50, 50, 200, 125);
        pane.setClip(rect);
        var text = new Text(125, 100, "Rectangle");
        pane.getChildren().add(text);
        for (int i = 0; i < 10; i++) {
            double ox = i * 25;
            pane.getChildren().add(new Line(ox, 200, ox + 25, 0));
            pane.getChildren().add(new Line(ox, 0, ox + 25, 200));
        }

        return pane;
    }

}

更新:

我想出了这个作为解决方法。

简单地说,我不能剪辑的东西,我可以涂上。

我创建了一个与整个场景大小相同的新矩形,然后使用 Shape.subtract(...) 以我的剪辑区域的形状在其中打洞。我用我的背景颜色填充这个新形状。然后我把它放在一个新 Pane 中,并使用 Stack Pane 将它分层放在我的母版之上。它不完美,而且有点繁琐,而且不得不这样做很烦人。但它有效且易于解释。

所以,以圆为例:

private Pane getCirclePane() {
    var pane = new Pane();
    var circle = new Circle(100, 100, 45);
    var text = new Text(75, 100, "Circle");
    pane.getChildren().add(text);
    for (int i = 0; i < 10; i++) {
        double ox = i * 25;
        pane.getChildren().add(new Line(ox, 200, ox + 25, 0));
        pane.getChildren().add(new Line(ox, 0, ox + 25, 200));
    }
    Rectangle rect = new Rectangle(0, 0, 250, 200);
    Shape overlay = Shape.subtract(rect, circle);
    overlay.setFill(Color.WHITE);
    Pane overlayPane = new Pane();
    overlayPane.getChildren().add(overlay);
    pane = new StackPane(pane, overlayPane);
    
    return pane;
}

最佳答案

作为一种临时解决方法,您可以采用所见的方法 here ;它使用 Shape.subtract()创建一个合适的 mask ,其功能类似于相应的剪辑

var c = new Circle(100, 100, 80);
var r = new Rectangle(250, 200);
Shape matte = Shape.subtract(r, c);
matte.setFill(Color.WHITE);
pane.getChildren().add(matte);

打印出来的:

As printed

经测试:

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.print.PrinterJob;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class App extends Application {

    @Override
    public void start(Stage stage) {
        var scene = new Scene(getView());
        stage.setScene(scene);
        stage.show();
    }

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

    private Pane getView() {
        final var printBox = new HBox(8, getCirclePane(), getRectPane());
        var b = new Button("Print");
        b.setOnAction((t) -> {
            var job = PrinterJob.createPrinterJob();
            if (job != null && job.showPrintDialog(null)) {
                if (job.printPage(printBox)) {
                    job.endJob();
                }
            }
        });
        var bp = new BorderPane();
        bp.setCenter(printBox);
        bp.setBottom(b);
        BorderPane.setAlignment(b, Pos.BOTTOM_CENTER);
        return bp;
    }

    private Pane getCirclePane() {
        var pane = new Pane();
        var text = new Text(80, 100, "Circle");
        pane.getChildren().add(text);
        addPattern(pane);
        var c = new Circle(100, 100, 80);
        var r = new Rectangle(250, 200);
        Shape matte = Shape.subtract(r, c);
        matte.setFill(Color.WHITE);
        pane.getChildren().add(matte);
        return pane;
    }

    private Pane getRectPane() {
        var pane = new Pane();
        var rect = new Rectangle(50, 50, 200, 125);
        pane.setClip(rect);
        var text = new Text(125, 100, "Rectangle");
        pane.getChildren().add(text);
        addPattern(pane);
        return pane;
    }

    private void addPattern(Pane pane) {
        for (int i = 0; i < 10; i++) {
            double ox = i * 25;
            pane.getChildren().add(new Line(ox, 200, ox + 25, 0));
            pane.getChildren().add(new Line(ox, 0, ox + 25, 200));
        }
    }
}

关于macos - 剪裁时打印像素化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72723418/

相关文章:

java - KeychainStore 不向 Mac OS X 上的 Java 提供证书

objective-c - .[NSOpenPanel目录URL]给出错误: No visible @interface for 'NSOpenPanel' declares the selector 'directoryURL:'

java - 使用 JavaFX 显示 OpenCV Mat

python 2.7 : Print a dictionary without brackets and quotation marks

java - 程序将 *.csv 文件读取到数组中并打印内容。需要打印索引号

java - 将缓冲图像打印到打印机

Mac 上的 Silverlight - 如何调试内存泄漏?

objective-c - 注册显示重新配置回调

JavaFX 8 如何从左侧而不是右侧设置标签省略号?

java - JavaFX 中的绑定(bind)标签 textProperty