论坛首页 移动开发技术论坛

用PDFBox转PDF文件为图片备忘

浏览 8671 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-07-20   最后修改:2010-08-02

PDFBox自我手中有的0.8版本就有了转图片的功能,在其java org.apache.pdfbox.ExtractImages类中有具体的代码,但是没有很好的封装,似乎是用来做命令行的.

 

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.pdfbox;

import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.encryption.AccessPermission;
import org.apache.pdfbox.pdmodel.encryption.StandardDecryptionMaterial;
import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectImage;

/**
 * This will read a read pdf and extract images. <br/><br/>
 *
 * usage: java org.apache.pdfbox.ExtractImages &lt;pdffile&gt; &lt;password&gt; [imageprefix]
 *
 * @author  <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
 * @version $Revision: 1.7 $
 */
public class ExtractImages
{
    private int imageCounter = 1;

    private static final String PASSWORD = "-password";
    private static final String PREFIX = "-prefix";

    private ExtractImages()
    {
    }

    /**
     * This is the entry point for the application.
     *
     * @param args The command-line arguments.
     *
     * @throws Exception If there is an error decrypting the document.
     */
    public static void main( String[] args ) throws Exception
    {
        ExtractImages extractor = new ExtractImages();
        extractor.extractImages( args );
    }

    private void extractImages( String[] args ) throws Exception
    {
        if( args.length < 1 || args.length > 3 )
        {
            usage();
        }
        else
        {
            String pdfFile = null;
            String password = "";
            String prefix = null;
            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( PREFIX ) )
                {
                    i++;
                    if( i >= args.length )
                    {
                        usage();
                    }
                    prefix = args[i];
                }
                else
                {
                    if( pdfFile == null )
                    {
                        pdfFile = args[i];
                    }
                }
            }
            if(pdfFile == null)
            {
                usage();
            }
            else
            {
                if( prefix == null && pdfFile.length() >4 )
                {
                    prefix = pdfFile.substring( 0, pdfFile.length() -4 );
                }

                PDDocument document = null;

                try
                {
                    document = PDDocument.load( pdfFile );

                    if( document.isEncrypted() )
                    {

                        StandardDecryptionMaterial spm = new StandardDecryptionMaterial(password);
                        document.openProtection(spm);
                        AccessPermission ap = document.getCurrentAccessPermission();


                        if( ! ap.canExtractContent() )
                        {
                            throw new IOException(
                                "Error: You do not have permission to extract images." );
                        }
                    }

                    List pages = document.getDocumentCatalog().getAllPages();
                    Iterator iter = pages.iterator();
                    while( iter.hasNext() )
                    {
                        PDPage page = (PDPage)iter.next();
                        PDResources resources = page.getResources();
                        Map images = resources.getImages();
                        if( images != null )
                        {
                            Iterator imageIter = images.keySet().iterator();
                            while( imageIter.hasNext() )
                            {
                                String key = (String)imageIter.next();
                                PDXObjectImage image = (PDXObjectImage)images.get( key );
                                String name = getUniqueFileName( key, image.getSuffix() );
                                System.out.println( "Writing image:" + name );
                                image.write2file( name );
                            }
                        }
                    }
                }
                finally
                {
                    if( document != null )
                    {
                        document.close();
                    }
                }
            }
        }
    }

    private String getUniqueFileName( String prefix, String suffix )
    {
        String uniqueName = null;
        File f = null;
        while( f == null || f.exists() )
        {
            uniqueName = prefix + "-" + imageCounter;
            f = new File( uniqueName + "." + suffix );
            imageCounter++;
        }
        return uniqueName;
    }

    /**
     * This will print the usage requirements and exit.
     */
    private static void usage()
    {
        System.err.println( "Usage: java org.apache.pdfbox.ExtractImages [OPTIONS] <PDF file>\n" +
            "  -password  <password>        Password to decrypt document\n" +
            "  -prefix  <image-prefix>      Image prefix(default to pdf name)\n" +
            "  <PDF file>                   The PDF document to use\n"
            );
        System.exit( 1 );
    }

}

 例子很简单,可以运行,但是对于中文PDF就有问题了,如果用了中文字体,会报告Can't find the specified basefont的错误,原因是读取中文字体出错,其实是读取编码格式错误,导致读到的字体是乱码.解决上述问题后,还会出现会自动把英文字体的数字翻译为英语单词,空格翻译为space的问题.追了一天,发现可能是encoding的问题,反正解析的都是中文,于是去掉英文的默认encoding,终于可以输出比较正常的图片的.

要转换的文档和出问题的截图如下:

  

 

    之后又出现tiff图像无法导出的问题,日志中出现"getRGBImage returned NULL"的warning,查看代码发现作者这样描述:

 

    /**
     * Returns an image of the CCITT Fax, or null if TIFFs are not supported. (Requires additional JAI Image filters )
     *
     * {@inheritDoc}
     */
    public BufferedImage getRGBImage() throws IOException

    在对应警告的地方也写了TODO标签,说明是待完善的,主要是ImageIO-lib的授权所限,所以Appach不提供直接tiff支持.

    摘录两段官网上的留言

 

Andreas Lehmkühler added a comment - 15/Apr/10 01:49 PM

The ImageIO-lib provides the missing tiff-support PDFBox needs to render such images. But unfortunately the license isn't suitable, so that we can not distribute it in combination with pdfbox. I hope sooner or later sanselan [1] will support the missing tiff support. 

[1] http://commons.apache.org/sanselan/

 

Andreas Lehmkühler added a comment - 16/Apr/10 03:42 AM

I've found another source for a possible ImageIO replacement. I've found an older posting from Jeremias. He mentioned a TIFF-decompressor within Apache XMLGraphics. That should work as builtin support for T.4 and T.6 decoded XObjects. 

[1] http://www.mail-archive.com/pdfbox-dev@incubator.apache.org/msg00932.html

    JAI Image确实有效,加入后还可以把图片格式导出为tiff,但是会导致导出图片的效率很低,在开发机上大约3-5秒导出一副tiff图片,还算可以接受的范围.

//***************************************************

又发现两个问题:

1 如果图片是旋转的,会导致图片无法显示。解决方法,修改源码,处理图片时有两个地方处理了旋转图片,方法不同,但是都有问题。

2 嵌入字体时,导出为图片显示乱码,以前是导出为文字时Identity-H乱码,但是嵌入字体还OK,1.1.0后解决了,但是导出图片又出现问题,真是麻烦啊,看看到处的TODO,让人头皮发麻,这就是开源项目的无奈啊。解决,中文嵌入式字体加载存在问题。

//***************************************************

再次发现一个问题

嵌入文字中的图片位置不对(补漏洞补得好辛苦啊)。解决,是修改旋转图片代码时改错的,注意PDF的坐标系是第一象限,而不是一搬图形坐标系的第四象限。

另外发现旋转图片后老是蒙上一层粉色,很郁闷。

//***************************************************

部署到64位的2007服务器上面发现读取的字体居然和32位xp的不一样,而且仿宋体居然无法读取,只好换为宋体。

  • 大小: 4.8 KB
  • 大小: 2.9 KB
   发表时间:2010-07-22  
做过一个类似的功能
将PDF文档第一页生产一张缩略图
使用了pdf-renderer
https://pdf-renderer.dev.java.net/
比较好用 但是有时会报错 生成的图片只有上面一半
0 请登录后投票
   发表时间:2010-07-26  
pdftoimage绝对无敌。
0 请登录后投票
   发表时间:2010-07-28  
如果是php的话,用FPDF就能非常方便的导出pdf!
0 请登录后投票
   发表时间:2010-07-29  
PDF是开源,但是问题确实相当的多
0 请登录后投票
论坛首页 移动开发技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics