【问题标题】:Java : PDF page preview error, expected xrefJava:PDF 页面预览错误,预期外部参照
【发布时间】:2017-11-21 09:16:34
【问题描述】:

我正在尝试为由 Ballasamic Mockups 创建的 PDF 文件创建预览。大约 50% 的时间,我没有得到预览并且得到外部参照缺失错误。我做错了什么?

错误日志:

com.sun.pdfview.PDFParseException: Expected 'xref' at start of table
at com.sun.pdfview.PDFFile.readTrailer(PDFFile.java:974)
at com.sun.pdfview.PDFFile.parseFile(PDFFile.java:1175)
at com.sun.pdfview.PDFFile.<init>(PDFFile.java:126)
at com.sun.pdfview.PDFFile.<init>(PDFFile.java:102)

代码:

private byte[] onlyCreatePdfPreview(String path, int attachId) {
    try {
        File file = new File(path);
        RandomAccessFile raf = new RandomAccessFile(file, "r");
        FileChannel channel = raf.getChannel();
        ByteBuffer buf = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());

        PDFFile pdffile = new com.sun.pdfview.PDFFile(buf);
        PDFPage page = pdffile.getPage(0);
        Rectangle rect = new Rectangle(0, 0,
            (int) page.getBBox().getWidth(),
            (int) page.getBBox().getHeight());
        java.awt.Image img = page.getImage(
            rect.width, rect.height, //width & height
            rect, // clip rect
            null, // null for the ImageObserver
            true, // fill background with white
            true  // block until drawing is done
        );

        BufferedImage buffered = toBufferedImage(img);
        buffered = Scalr.resize(buffered, Scalr.Method.ULTRA_QUALITY, 400, 250);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(buffered, "png", baos);
        baos.flush();
        return baos.toByteArray();

    } catch (Exception e) {
        e.printStackTrace();
    }
}

我做错了什么?谢谢你。

最终工作代码

      try {
            String pdfPath = zipLocation + String.valueOf(new BigInteger(130, random).toString(32));
            PdfReader reader = new PdfReader(path);
            PdfStamper pdfStamper = new PdfStamper(reader,new FileOutputStream(pdfPath));
            pdfStamper.getWriter().setPdfVersion(PdfWriter.PDF_VERSION_1_4);
            pdfStamper.close();
            reader.close();
     RandomAccessFile raf = new RandomAccessFile(pdfPath, "r");
            FileChannel channel = raf.getChannel();
            ByteBuffer buf = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
             PDFFile pdffile = new com.sun.pdfview.PDFFile(buf);
                PDFPage page = pdffile.getPage(0);
                Rectangle rect = new Rectangle(0, 0,
                        (int) page.getBBox().getWidth(),
                        (int) page.getBBox().getHeight());
                java.awt.Image img = page.getImage(
                        rect.width, rect.height, //width & height
                        rect, // clip rect
                        null, // null for the ImageObserver
                        true, // fill background with white
                        true  // block until drawing is done
                );

                BufferedImage buffered = toBufferedImage(img);
                buffered = Scalr.resize(buffered, Scalr.Method.ULTRA_QUALITY, 400, 250);
            ByteArrayOutputStream  baos = new ByteArrayOutputStream();
                ImageIO.write(buffered, "png", baos);
                baos.flush();
         return baos.toByteArray();
}//catch block

【问题讨论】:

  • 显然com.sun.pdfview.PDFFile 期望与 xref 的交叉引用。但是这种期望只对遵循 2001 年 11 月发布的修订版 3(版本 1.4)的 PDF 参考的 PDF 有意义;后续参考甚至 ISO 32000 标准(第 1 部分或第 2 部分)的 PDF 可以选择使用交叉引用流(以对象编号开头)而不是交叉引用表(以 xref 开头)。因此,您应该改用遵循比 15 年以上旧版本更新的规范的软件。
  • @mkl 这是在 Windows 10 上运行的软件的最新版本。知道如何手动设置此元素吗?谢谢。
  • 您必须对 PDF 进行预处理,方法是加载并保存 PDF 版本 1.4 兼容性。您可以手动(例如使用 Adob​​e Acrobat)或自动执行(例如使用 iText)。
  • 我上面的 cmets,顺便说一下,假设 由 Ballasamic Mockups 创建的 PDF 文件 是有效的。但我假设你已经检查过了。毕竟,如果它们无效,com.sun.pdfview.PDFFile 的异常将是最正确的反应......
  • @mkl :我将检查如何使用 Itext 执行此操作,但问题是它随机发生。

标签: java pdf file-conversion


【解决方案1】:

(此答案从 cmets 收集有关最终导致解决方案的问题的信息。)

显然com.sun.pdfview.PDFFile 期望交叉引用以 xref 开头。但是这种期望只对遵循 2001 年 11 月发布的 PDF 参考版本 3(版本 1.4)之后的 PDF 有意义;遵循后续参考甚至 ISO 32000 标准(第 1 部分或第 2 部分)的 PDF 可以选择使用交叉引用流(以对象编号开头)而不是交叉引用表(以 xref 开头)。

因此,人们应该改用遵循更新规范的软件,而不是使用超过 15 年的旧版本,或者必须转换自己的 PDF 以遵循旧规范,至少在表面上是这样。

可以手动转换(例如使用 Adob​​e Acrobat)或自动转换(例如使用 iText)。 (这些示例软件产品实际上只是示例,其他产品也可以用于此任务。)

如果使用当前的 iText 5 版本,转换如下所示:

PdfReader reader = new PdfReader(SOURCE);
PdfStamper stamper = new PdfStamper(reader, DEST);
stamper.getWriter().setPdfVersion(PdfWriter.PDF_VERSION_1_4);
stamper.close();
reader.close();

并且必须注意,如果SOURCE 是文件名或随机访问文件,则DEST 不能是同一文件的文件输出流。否则,原始文件在PdfStamper 有机会将其全部复制到其输出之前被截断。

【讨论】:

    猜你喜欢
    • 2021-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多