当前位置: 首页 > 知识库问答 >
问题:

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

牟正真
2023-03-14

我已经设法使用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无法正确显示页面。当我使用上面代码中注释掉的BuffereImage类时,文档很简单,没有创建,我不知道为什么。

笔记

这是在JavaFX2.2中拍摄场景或部分场景的屏幕截图的后续问题,但特定于pdf创建部分,而不是节点快照部分。

共有2个答案

梁渊
2023-03-14

通过将图像转换为PNG并首先将其写入Outputstream,然后将转换后的PNG从Outputstream读取到BuffereImage,我将快照转换为PDF格式。

最终的BufferedImage在PDJpeg中渲染良好,没有任何问题。

这是我的密码。

public static BufferedImage generate_png_from_container(Node node) {
        SnapshotParameters param = new SnapshotParameters();
        param.setDepthBuffer(true);
        WritableImage snapshot = node.snapshot(param, null);
        BufferedImage tempImg = SwingFXUtils.fromFXImage(snapshot, null);
        BufferedImage img = null;
        byte[] imageInByte;
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(tempImg, "png", baos);
            baos.flush();
            imageInByte = baos.toByteArray();
            baos.close();
            InputStream in = new ByteArrayInputStream(imageInByte);
            img = ImageIO.read(in);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
       //the final image sent to the PDJpeg
       return img;
}
季阳朔
2023-03-14

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

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

我尝试的两种方法是:

>

这种方法不起作用,因为SwingFXUtils创建的BuffereImage是使用SampleModel编码的,该SampleModel与pdfbox api所需的不兼容。

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

这种方法不起作用。失败的原因可能是ImageIO从SwingFXUtils创建的BuffereImage创建了粉色(即编码错误的)JPEG。这可能是ImageIO中的一个错误。此外,我使用pdfbox将结果图像添加到jpeg中的方式可能存在缺陷。

正式建议

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

可执行示例代码

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); }
}
 类似资料:
  • 我正在使用iText生成Pdf。但当我试图在pdf中添加图像时, 我mage.get实例(新的URL(timetableResource.getImageUrl()));document.add(学校标志); 但我得到的错误是 HTTP状态500-服务器为URL返回了HTTP响应代码400:http://139.59.72.150:8080/sms/attachments/23/42/school

  • 有人能给我举个例子,说明如何使用ApachePDFBox转换不同图像中的PDF文件(PDF的每一页对应一个图像)?

  • 问题内容: 我正在尝试做一些非常简单的事情。我想在表中特定行的列中放置一个图标。如果是文件夹,则显示文件夹图标。如果是文件,则显示文件图标。 有人知道如何在JavaFX 2中执行此操作吗? 我已经尝试了很多事情,这似乎应该很简单,或者至少是某个地方的例子。 问题答案: 好吧,我有一个巨大的假时刻。原来我的图片网址路径错误。 我确实找到了一个网站,该网站提供了为表添加元素的绝佳示例。这帮助我了解了一

  • 问题内容: 我想将PDF文档转换为图像。我正在使用Ghost4j。 问题: Ghost4J需要gsdll32.dll文件在运行时,我也 并不 想使用的DLL文件。 问题1: 在ghost4j中,有没有办法在没有dll的情况下转换图像? 问题2: 我在PDFBox API中找到了解决方案。convertToImage()将PDF页面转换为图像格式。 PDF文档上只有文本。运行此代码时出现该异常: 问

  • 我想把PDF文档转换成图像。我用的是Ghost4j。 问题:Ghost4J需要gsdll32。dll文件,我不想使用dll文件。 问题1:是否有任何方法,在ghost4j转换图像没有dll? 问题2:我在PDFBox API中找到了解决方案<代码>组织。阿帕奇。pdfbox。pdmodel。PDPagep具有将PDF页面转换为图像格式的方法convertToImage()。 我只有PDF文档上的文

  • 问题内容: 如何将图像放在特定位置的现有PDF文件上。pdf表示一张图纸页。图像将被缩放。我正在检查ReportLab,但找不到答案。谢谢。 问题答案: http://pybrary.net/pyPdf/: 我觉得就像,请参阅手册以获取更好的主意