PDFBox:将pdf页面转换为图像时出现问题

10

我的任务非常简单:将PDF文件的每一页转换为图像。我尝试使用开源版本的icepdf生成图像,但它们不能生成正确字体的图像。因此,我开始使用PDFBox代替。代码如下:

PDDocument document = PDDocument.load(new File("testing.pdf"));             
List<PDPage> pages = document.getDocumentCatalog().getAllPages();
for (int i = 0; i < pages.size(); i++) {
 PDPage singlePage = pages.get(i);
 BufferedImage buffImage = convertToImage(singlePage, 8, 12);
 ImageIO.write(buffImage, "png", new File(PdfUtil.DATA_OUTPUT_DIR+(count++)+".png"));
}

字体看起来不错,但pdf文件中的图片看起来有些模糊(见附件)。我查看了源代码,但仍然不知道如何修复它。你们有什么想法吗?请帮忙,谢谢!


亲爱的用户552910,你的convertToImage方法是什么样子的?为了完整起见,你能否把它发布出来呢?这将对我非常有帮助... - Atmocreations
我看不到任何附件。除非我漏掉了什么(我不知道在这里可以放附件),请在PDFBox JIRA上提交问题或将PDF文件发送给我,如果它不是机密的话。 - Tilman Hausherr
你也可以使用PDFBox的主干版本,它在字体方面非常出色,不像1.8.x版本那样。但是你需要了解svn和maven。 - Tilman Hausherr
我也遇到了同样的问题... 有更新吗? - Don Cheadle
不,但我们正在努力尽快发布。 - Tilman Hausherr
显示剩余2条评论
3个回答

2

使用pdfbox将PDF文件04-Request-Headers.pdf转换为图像。

下载此文件并将其粘贴到文档文件夹中。

示例:

package com.pdf.pdfbox.test;

import java.awt.HeadlessException;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.List;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.util.PDFImageWriter;

public class ConvertPDFPageToImageWithoutText {
    public static void main(String[] args) {
        try {
            String oldPath = "C:/Documents/04-Request-Headers.pdf";
            File oldFile = new File(oldPath);
            if (oldFile.exists()) {
            PDDocument document = PDDocument.load(oldPath);
            @SuppressWarnings("unchecked")
            List<PDPage> list = document.getDocumentCatalog().getAllPages();

            String fileName = oldFile.getName().replace(".pdf", "");
            String imageFormat = "png";
            String password = "";
            int startPage = 1;
            int endPage = list.size();
            String outputPrefix = "C:/Documents/PDFCopy/";//converted images saved here
            File file = new File(outputPrefix);
            if (!file.exists()) {
                file.mkdirs();
            }
            int imageType = 24;
            String color = "rgb";
            int resolution;

            try {
                resolution = Toolkit.getDefaultToolkit().getScreenResolution();
            } catch (HeadlessException e) {
                resolution = 96;
            }

            if ("bilevel".equalsIgnoreCase(color)) {
                imageType = BufferedImage.TYPE_BYTE_BINARY;
            } else if ("indexed".equalsIgnoreCase(color)) {
                imageType = BufferedImage.TYPE_BYTE_INDEXED;
            } else if ("gray".equalsIgnoreCase(color)) {
                imageType = BufferedImage.TYPE_BYTE_GRAY;
            } else if ("rgb".equalsIgnoreCase(color)) {
                imageType = BufferedImage.TYPE_INT_RGB;
            } else if ("rgba".equalsIgnoreCase(color)) {
                imageType = BufferedImage.TYPE_INT_ARGB;
            } else {
                System.err.println("Error: the number of bits per pixel must be 1, 8 or 24.");
            }

            PDFImageWriter pdfImageWriter = new PDFImageWriter();
            boolean imageWriter = pdfImageWriter.writeImage(document, imageFormat, password, startPage, endPage, outputPrefix + fileName, imageType, resolution);
            if (!imageWriter) {
                throw new Exception("No writer found for format '" + imageFormat + "'");
            }
            document.close();

        } else {
            System.err.println(oldPath +" File Can't be found");
        }

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

}

或者

尝试以下解决方案将PDF文件转换为图像格式。

如何使用PDF Renderer在Java中将PDF转换为带分辨率的图像


这是否解决了 OP 的问题,即源 PDF 中的图像“变淡”了? - Don Cheadle
我尝试了您提供的PDF解决方案,但我收到了“INFO:ColorSpace模式未提供非描边颜色,使用白色代替!”的消息,并且图像(在这种情况下是QR码)未被复制... 它只是空白的白色。 - Don Cheadle
我在 http://stackoverflow.com/questions/28589477/pdfbox-pdf-to-image-losing-qr-code-colorspace-pattern-doesnt-provide-a-non-str 上有一个带附加文档的问题。 - Don Cheadle
@mmcrae 我尝试使用附加的PDF文档,但在转换时条形码被消除了。如果您使用PDFRenderer-0.9.0 jar文件,则可以将pdf页面与条形码一起转换。 - UdayKiran Pulipati
谢谢你的提示!我用了它,它起作用了:)。你知道这个有什么限制吗?我很惊讶为什么没有更多的人使用它...他们使用付费服务或GhostScript,而这个却没有限制。为什么呢? - Don Cheadle
@mmcrae,它有一些限制,请参阅Visualforce PDF渲染注意事项和限制 - UdayKiran Pulipati

1
请使用以下代码进行转换,它能够正常工作!
  import java.awt.HeadlessException;
         import java.awt.Toolkit;
         import java.awt.image.BufferedImage;

         import javax.imageio.ImageIO;

         import org.apache.pdfbox.exceptions.InvalidPasswordException;
         import org.apache.pdfbox.pdmodel.PDDocument;
         import org.apache.pdfbox.util.PDFImageWriter;

         /**
          * Convert a PDF document to an image.
          *
          * @author <a href="ben@benlitchfield.com">Ben Litchfield</a>
          * @version $Revision: 1.6 $
          */
         public class PDFToImage
         {

             private static final String PASSWORD = "-password";
             private static final String START_PAGE = "-startPage";
             private static final String END_PAGE = "-endPage";
             private static final String IMAGE_FORMAT = "-imageType";
             private static final String OUTPUT_PREFIX = "-outputPrefix";
             private static final String COLOR = "-color";
             private static final String RESOLUTION = "-resolution";

             /**
              * private constructor.
             */
             private PDFToImage()
             {
                 //static class
             }

             /**
              * Infamous main method.
              *
              * @param args Command line arguments, should be one and a reference to a file.
              *
              * @throws Exception If there is an error parsing the document.
              */
             public static void main( String[] args ) throws Exception
             {
                 String password = "";
                 String pdfFile = "D:/docoverview.pdf";
                 String outputPrefix = "D:/printdata/pdfimages/";
                 String imageFormat = "jpg";
                 int startPage = 1;
                 int endPage = Integer.MAX_VALUE;
                 String color = "rgb";
                 int resolution;
                 try
                 {
                     resolution = Toolkit.getDefaultToolkit().getScreenResolution();
                 }
                 catch( HeadlessException e )
                 {
                     resolution = 96;
                 }
                 for( int i = 0; i < args.length; i++ )
                 {
                     if( args[i].equals( PASSWORD ) )
                     {
                         i++;
                         if( i >= args.length )
                         {
                             usage();
                         }
                         password = args[i];
                     }
                     else if( args[i].equals( START_PAGE ) )
                     {
                         i++;
                         if( i >= args.length )
                         {
                             usage();
                         }
                         startPage = Integer.parseInt( args[i] );
                     }
                     else if( args[i].equals( END_PAGE ) )
                     {
                         i++;
                         if( i >= args.length )
                         {
                             usage();
                         }
                         endPage = Integer.parseInt( args[i] );
                     }
                     else if( args[i].equals( IMAGE_FORMAT ) )
                     {
                         i++;
                         imageFormat = args[i];
                     }
                     else if( args[i].equals( OUTPUT_PREFIX ) )
                     {
                         i++;
                         outputPrefix = args[i];
                     }
                     else if( args[i].equals( COLOR ) )
                     {
                         i++;
                         color = args[i];
                     }
                     else if( args[i].equals( RESOLUTION ) )
                     {
                         i++;
                         resolution = Integer.parseInt(args[i]);
                     }
                     else
                     {
                         if( pdfFile == null )
                         {
                             pdfFile = args[i];
                         }
                     }
                 }
                 if( pdfFile == null )
                 {
                     usage();
                 }
                 else
                 {
                     if(outputPrefix == null)
                     {
                         outputPrefix = pdfFile.substring( 0, pdfFile.lastIndexOf( '.' ));
                     }

                     PDDocument document = null;
                     try
                     {
                         document = PDDocument.load( pdfFile );     
                         //document.print();

                         if( document.isEncrypted() )
                         {
                             try
                             {
                                 document.decrypt( password );
                             }
                             catch( InvalidPasswordException e )
                             {
                                 if( args.length == 4 )//they supplied the wrong password
                                 {
                                     System.err.println( "Error: The supplied password is incorrect." );
                                     System.exit( 2 );
                                 }
                                 else
                                 {
                                     //they didn't supply a password and the default of "" was wrong.
                                     System.err.println( "Error: The document is encrypted." );
                                     usage();
                                 }
                             }
                         }
                         int imageType = 24;
                         if ("bilevel".equalsIgnoreCase(color))
                         {
                             imageType = BufferedImage.TYPE_BYTE_BINARY;
                         }
                         else if ("indexed".equalsIgnoreCase(color))
                         {
                             imageType = BufferedImage.TYPE_BYTE_INDEXED;
                         }
                         else if ("gray".equalsIgnoreCase(color))
                         {
                             imageType = BufferedImage.TYPE_BYTE_GRAY;
                         }
                         else if ("rgb".equalsIgnoreCase(color))
                         {
                             imageType = BufferedImage.TYPE_INT_RGB;
                         }
                         else if ("rgba".equalsIgnoreCase(color))
                         {
                             imageType = BufferedImage.TYPE_INT_ARGB;
                         }
                         else
                         {
                             System.err.println( "Error: the number of bits per pixel must be 1, 8 or 24." );
                             System.exit( 2 );
                         }

                         //Make the call
                         PDFImageWriter imageWriter = new PDFImageWriter();
                         boolean success = imageWriter.writeImage(document, imageFormat, password,
                                 startPage, endPage, outputPrefix, imageType, resolution);
                         if (!success)
                         {
                             System.err.println( "Error: no writer found for image format '"
                                     + imageFormat + "'" );
                             System.exit(1);
                         }
                     }
                     catch (Exception e)
                     {
                         System.err.println(e);
                     }
                     finally
                     {
                         if( document != null )
                         {
                             document.close();
                         }
                     }
                 }
             }

             /**
              * This will print the usage requirements and exit.
              */
             private static void usage()
             {
                 System.err.println( "Usage: java org.apache.pdfbox.PDFToImage [OPTIONS] <PDF file>\n" +
                     "  -password  <password>          Password to decrypt document\n" +
                     "  -imageType <image type>        (" + getImageFormats() + ")\n" +
                     "  -outputPrefix <output prefix>  Filename prefix for image files\n" +
                     "  -startPage <number>            The first page to start extraction(1 based)\n" +
                     "  -endPage <number>              The last page to extract(inclusive)\n" +
                     "  -color <string>                The color depth (valid: bilevel, indexed, gray, rgb, rgba)\n" +
                     "  -resolution <number>           The bitmap resolution in dpi\n" +
                     "  <PDF file>                     The PDF document to use\n"
                     );
                 System.exit(1);
             }

             private static String getImageFormats()
             {
                 StringBuffer retval = new StringBuffer();
                 String[] formats = ImageIO.getReaderFormatNames();
                 for( int i = 0; i < formats.length; i++ )
                 {
                     retval.append( formats[i] );
                     if( i + 1 < formats.length )
                     {
                         retval.append( "," );
                     }
                 }
                 return retval.toString();
             }
         }

4
由于您正在使用Java编写,我建议您使用Java代码惯例:http://www.oracle.com/technetwork/java/javase/documentation/codeconvtoc-136057.html - Lilian A. Moraru
@MoraruLilian 但是我已经遵循了代码规范。你指的是哪一行代码? - Harinder
1
在Morau的链接7.2中,“左大括号应该放在开始复合语句的行的末尾;右大括号应该单独成行,并缩进到复合语句的开头。”将大括号放在单独的一行会使类变得比需要的更长!此外,if((带有空格)而不是if(,最后,for(int i = 0; i < formats.length; i ++)是老派的。使用增强型for循环for(int i:formats) - Steve Atkinson
1
答案中的代码来自PDFBox本身。我们使用不同的代码约定来提高可读性:https://pdfbox.apache.org/codingconventions.html - Tilman Hausherr
2
PDFImageWriter在2.0版本中已被移除。有关2.0的信息,请参见此处:https://dev59.com/a2Ag5IYBdhLWcg3wq8eU - Tilman Hausherr

0

我最终尝试了不同的PDF库。最好的解决方案是使用"JPedal",但你只能免费获得试用版。你也可以免费尝试icepdf,但它可能无法生成正确的字体。


还有一个开源版本的jpedal(https://github.com/Lonzak/JPedal)可供使用。 - Lonzak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接