在运行 JDK 17 和 JavaFX 18 的 macOS Big Sur 上,当您有不规则的裁剪区域时,裁剪图像在打印时会严重像素化。
像素化既发生在实际纸张上(在我的爱普生打印机上),也发生在保存为 PDF 时(使用 macOS 固有的“保存为 PDF”功能)。
如果您有一个带有矩形的剪辑区域,则没有像素化,一切看起来都平滑而清晰。
注意,必须是Rectangle,矩形Polygon也有问题。
接下来是查看生成的 PDF 的屏幕截图。
您可以看到圆圈内的文本和线条都是像素化的。
在我看来,它将节点渲染为“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);
打印出来的:
经测试:
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/