gpt4 book ai didi

java - 使用 JavaFX 将图像放置在 PDF 文件上

转载 作者:行者123 更新时间:2023-11-29 07:55:30 25 4
gpt4 key购买 nike

我已经使用 Apache 的 Javafx 和 PDFbox 将文本放入 pdf 文件中。现在我正在尝试将拍摄场景屏幕截图的图像放置到 pdf 文档中。

    WritableImage snapshot = quotes.getScene().snapshot(null);
PDDocument doc = null;
PDPage page = null;
PDXObjectImage ximg = null;
BufferedImage bufferedImg = SwingFXUtils.fromFXImage(snapshot, null);

try{
doc = new PDDocument();
page = new PDPage();


doc.addPage(page);
PDPageContentStream content = new PDPageContentStream(doc, page);


/* ByteArrayOutputStream out = new ByteArrayOutputStream();
InputStream in = new ByteArrayInputStream(out.toByteArray());*/

ximg = new PDJpeg(doc, bufferedImg);
//ximg = new PDJpeg(doc, in);
content.drawImage(ximg, 100, 100);

content.close();
doc.save("PDFWithText.pdf");
doc.close();
} catch (Exception e){
System.out.println(e);
}

当我使用 InputStream 和 OutputStream 类时,文档已创建,但当我打开它时,Adobe 和其他程序给我一个错误,指出 Acrobat 无法正确显示页面。当我使用上面代码中注释掉的 BufferedImage 类时,文档很简单,没有创建,我不知道为什么。

注意

这是 Taking a screenshot of a scene or a portion of a scene in JavaFx 2.2 的后续问题,但特定于 pdf 创建部分而不是节点快照部分。

最佳答案

这不是实际的解决方案(因为提供的代码不起作用),而是我尝试解决问题的文档

我花了一些时间试图解决这个问题,但没能成功。我已经包含了我的解决方案的示例代码,因为它提供了一个 SSCCE 和方法,可以帮助其他人尝试解决这个问题。

我尝试的两种方法是:

  1. 通过 JavaFX 方法 SwingFXUtils.fromFXImage 获取 BufferedImage 输出并将其用作 pdfbox api 的输入。

    这种方法不起作用,因为 SwingFXUtils 创建的 BufferedImage 编码的 SampleModel 与 pdfbox api 要求的不兼容。

  2. 通过 JavaFX 方法 SwingFXUtils.fromFXImage 从 BufferedImage 输出创建 Jpeg 流(使用 ImageIO),并将其用作 pdfbox api 的输入。

    这种方法行不通。失败的原因可能是 ImageIO 从 SwingFXUtils 创建的 BufferedImage 创建了粉红色(即编码不正确)的 jpeg。这可能是 ImageIO 中的错误。此外,我使用 pdfbox 将结果图像添加到 jpeg 的方式可能存在错误。

推荐

还有许多其他 API 可用于从 JavaFX 创建 PDF 文件。我建议尝试使用任何其他 API 来执行创建 pdf 文件的任务,而不是继续解决 JavaFX 输出的图像与 pdfbox 的集成问题(谷歌搜索会显示它们)。

可执行示例代码

import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import org.apache.pdfbox.exceptions.COSVisitorException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.edit.PDPageContentStream;
import org.apache.pdfbox.pdmodel.graphics.xobject.PDJpeg;
import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectImage;

import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import java.awt.image.*;
import java.io.*;
import java.nio.file.Paths;
import java.util.Arrays;

// #### THIS CODE CURRENTLY DOES NOT FUNCTION CORRECTLY - SEE INLINE COMMENTS IN THE CODE TO UNDERSTAND WHY ####
//
// Demonstrates converting a JavaFX SceneGraph to a pdf (just as a bitmapped image, not as vector graphics).
// 1. creating a snapshot of a JavaFX node.
// 2. creating a pdf from the snapshot (using apache pdfbox http://pdfbox.apache.org/).
// 3. saving the pdf to a file.
// 4. opening the saved pdf in a web browser so the web browser can trigger showing
// the pdf in an appropriate pdf viewer (if the user has such a viewer installed).
public class PdfWithImageCreator extends Application {
// icon courtesy of http://www.aha-soft.com/ not for commercial use (free for non-commercial use).
private static final String imageURL =
"http://icons.iconarchive.com/icons/aha-soft/free-global-security/512/Global-Network-icon.png";

private static final String PDF_PATH =
Paths.get("exported.pdf").toAbsolutePath().toString();

@Override public void start(Stage stage) {
VBox layout = new VBox(20);

ImageView imageView = new ImageView(
new Image(imageURL)
);

Button export = new Button("Export");
export.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
exportToPDF(layout, PDF_PATH);
}
});

layout.setStyle("-fx-font-size: 20px;");
layout.setAlignment(Pos.CENTER);
layout.setPadding(new Insets(20));
layout.getChildren().setAll(
export,
imageView
);

stage.setScene(
new Scene(
new Group(
layout
)
)
);

stage.show();
}

/**
* Snapshots the provided node.
* Encodes the snapshot in a pdf.
* Saves the pdf to the provided file path.
* Opens the pdf in the default system web browser.
*
* @param node the node for which the snapshot is to be taken.
* @param filePath the path where the pdf is to be saved.
*/
private void exportToPDF(Node node, String filePath){
PDDocument doc = null;
PDPage page = null;
PDPageContentStream content = null;
PDXObjectImage ximage = null;

try {
// snapshot the node and convert it to an awt buffered image.
Image fxImage = node.snapshot(null, null);
BufferedImage bufferedImage = SwingFXUtils.fromFXImage(fxImage, null);

// create a pdf containing the snapshot image.
doc = new PDDocument();
page = new PDPage();
doc.addPage(page);

content = new PDPageContentStream(doc, page);

// alternate path A => try to create a PDJpeg from a jpegInputStream.
ximage = createPDJpegFromJpegStream(doc, bufferedImage);

// alternate path B => try to create a PDJpeg from directly from a BufferedImage directly.
// ximage = createPDJpegFromBufferedImage(doc, bufferedImage);

content.drawImage(ximage, 0, 0);
content.close();

// save the created image to disk.
doc.save(filePath);

System.out.println("Exported PDF to: " + filePath);

// show the generated pdf in a web browser.
// (if the browser is pdf enabled, this will display the pdf in the web browser).
getHostServices().showDocument(filePath);
} catch(IOException | COSVisitorException ie) {
ie.printStackTrace();
} finally {
try {
if (content != null) { content.close(); }
if (doc != null) { doc.close(); }
} catch (IOException e) {
e.printStackTrace();
}
}
}

// #### THIS METHOD DOES NOT FUNCTION AS EXPECTED
// alternate path => try to create a PDJpeg from a jpegInputStream.
// when using a jpeg stream this doesn't work, the created pdf is not well formed and
// you end up with adobe pdf reader running out of memory trying to read the resultant pdf.
// Also outputs a weird message that I currently don't understand =>
// INFO: About to return NULL from unhandled branch. filter = COSName{DCTDecode}
private PDXObjectImage createPDJpegFromJpegStream(PDDocument doc, BufferedImage bufferedImage) throws IOException {
// provide the buffered image data as input to a jpeg input stream.
ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
ImageOutputStream jpegImageOutputStream = ImageIO.createImageOutputStream(jpegOutputStream);
ImageIO.write(bufferedImage, "jpeg", jpegImageOutputStream);
InputStream jpegInputStream = new ByteArrayInputStream(
Arrays.copyOf(jpegOutputStream.toByteArray(), jpegOutputStream.size())
);

// output created jpg file for debugging purposes
// => when you view it is pink due to (I believe) an ImageIO bug.
// you can see how the resultant image is pink by opening the image file named in system.out in any image viewer.
// this improper encoding of the jpeg data may be why the subsequent use of it to generate a pdf
// will generate a an invalid pdf.
File file = new File("output.jpg");
FileOutputStream fos = new FileOutputStream(file);
fos.write(Arrays.copyOf(jpegOutputStream.toByteArray(), jpegOutputStream.size()));
System.out.println(file.getAbsolutePath());

return new PDJpeg(doc, jpegInputStream);
}

// #### THIS METHOD DOES NOT FUNCTION AS EXPECTED
// alternate path => try to create a PDJpeg from directly from a BufferedImage directly, get the following exception:
// Exception in thread "JavaFX Application Thread" java.lang.IllegalArgumentException: Raster IntegerInterleavedRaster: width = 552 height = 616 #Bands = 1 xOff = 0 yOff = 0 dataOffset[0] 0 is incompatible with ColorModel ColorModel: #pixelBits = 8 numComponents = 1 color space = java.awt.color.ICC_ColorSpace@125fe1b6 transparency = 1 has alpha = false isAlphaPre = false
// at java.awt.image.BufferedImage.<init>(BufferedImage.java:630)
// Browsing the awt PDJpeg and awt code it appears that the BufferedImage returned by JavaFX uses a
// SinglePixelPackedSampleModel, but PDJpeg required the buffered image to use a ComponentColorModel
// and the two are incompatible. So the bufferedimage needs to be re-encoded to a compatible
// raster format that utilizes a SampleModel (i.e. a ComponentColorModel) that is acceptable by PDJpeg.
//
private PDXObjectImage createPDJpegFromBufferedImage(PDDocument doc, BufferedImage bufferedImage) throws IOException {
return new PDJpeg(doc, bufferedImage);
}

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

关于java - 使用 JavaFX 将图像放置在 PDF 文件上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18038797/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com