java操作pdf>>>pdfBox使用体验

pdfBox对中文非常不友好,如果各位同学最进要对pdf进行插入文字操作的话,建议你们使用itext,如果你操作的pdf没有中文,或者只是对pdf文件插入图片,删除页面等操作,那么请继续看下去~~~~

前言:

前段时间在完成公司安排的任务同时,利用空余时间做了一个使用java操作pdf的功能
刚开始没什么头绪,直到在网上找到了pdfBox,
pdfBox是apach提供的免费,开源的pdf操作工具,使用起来也挺方便,github可下载
我也上传了一份, [ pdfbox-1.8.9.zip ]

1首先,导入jar

我是maven方式导入
PS:
这个jar里面囊括了所有的pdfbox操作工具类,导入这一个就够了
(我在找工具类的时候,看到别的博主导了pdfbox的很多类,然后一股脑也导了进去,结果jar包冲突,原来只导入一个,那就是官方已经整合好的那个,就够了)

        <dependency>
            <groupId>org.apache.pdfboxgroupId>
            <artifactId>pdfbox-appartifactId>
            <version>1.8.10version>
        dependency>

2.在你的项目中创建一个工具类

2.1这个类的取名:随意,
我是取的pdfUtil

2.2当然,如果你想将操作记录入录到数据库的话,你也可以创建一个pdf的实体类
这个实体类创不创建大家随意,我贴一下我的实体类的属性,供参考

    //实体类的名称:pdfDomainVO

    private Integer id;//id

    private Date time;//操作时间

    private String filename;//文件名

    private String filesize;//文件大小

    private String filetype;//文件类型

    private String details;//操作详情

    private String content;//pdf中内容

    private String outputfile;//输出路径(保存路径)

    private String inputfile;//要操作的pdf路径

    private String strtofind;//需要替换的文本

    private String message;//替换的文本

    private String imagefile;//图片路径

    private String imagelist;//图片集合

    private Integer pageno;//指定页码

    private Integer pages;//总页数

    private Integer rid;//...

    private Integer pageoperation;//操作页数

    private Integer pagestart;//开始页

    private Integer pageend;//结束页

    private String position;//位置:X,Y

    private String fileSizeAfter;//操作后文件大小

    private Integer status;//状态

    private Integer afterPages;//操作后页码

    private Integer imgSize;//图片大小

3.在pdfUtil写代码

PS:我下面会有用到pdfDomainVO实体类的时候,大家参考下上面贴的属性

大家可以在pdfbox-1.8.9.zip文件夹中,找到examples文件夹
里面有很多事例,比如:
1创建一个pdf文件
2读取pdf中,全部文字信息(可用String接收)
3替换pdf中字符(中文我还没有解决好,不好意思啊)
4在pdf中插入图片
等等操作……
PS:我现在贴一下我的代码

—–1创建1到多个空白页面

/***
     * 创建1到多个空白页面
     * @param file
     * @throws IOException
     * @throws COSVisitorException
     */
    public static void createBlank( String outputFile ) throws IOException, COSVisitorException
    {
        //首先创建pdf文档类
        PDDocument document = null;
        try
        {
            document = new PDDocument();
            //实例化pdf页对象
            PDPage blankPage = new PDPage();
            PDPage blankPage1 = new PDPage();
            PDPage blankPage2 = new PDPage();
            //插入文档类
            document.addPage( blankPage );
            document.addPage( blankPage1 );
            document.addPage( blankPage2 );
            //记得一定要写保存路径,如"H:\\text.pdf"
            document.save( outputFile );
            System.out.println("over");
        }
        finally
        {
            if( document != null )
            {
                document.close();
            }
        }
    }

—–2读取pdf中文字信息(全部)

    /**
     * 读取pdf中文字信息(全部)
     */
    public static void READPDF(String inputFile){
        //创建文档对象
        PDDocument doc =null;
        String content="";
        try {
            //加载一个pdf对象
            doc =PDDocument.load(new File(inputFile));
            //获取一个PDFTextStripper文本剥离对象  
            PDFTextStripper textStripper =new PDFTextStripper("GBK");
            content=textStripper.getText(doc);
            vo.setContent(content);
            System.out.println("内容:"+content);
            System.out.println("全部页数"+doc.getNumberOfPages());  
            //关闭文档
            doc.close();
        } catch (Exception e) {
            // TODO: handle exception
        }
    }

—–3读取pdf中文字信息(指定页面)

    /**
     * 读取pdf中文字信息(指定从第几页开始)
     */
    public static pdfDomainVO readPageNO(pdfDomainVO vo){   
        String content="";        
        try{
            PDDocument document = PDDocument.load(vo.getInputfile());
            // 获取页码
            int pages = document.getNumberOfPages();
             // 读文本内容
             PDFTextStripper stripper=new PDFTextStripper();
             // 设置按顺序输出
             stripper.setSortByPosition(true);
             stripper.setStartPage(vo.getPageno());
             stripper.setEndPage(vo.getPageno());
             //获取内容
             content = stripper.getText(document);
             vo.setContent(content);
             System.out.println("function : readPageNO over");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return vo;
    }

—–4替换指定pdf文件的文字内容(这个比较复杂,当时看api看了好久,然后一个一个的吧注释添了上去)

/**
     * 替换指定pdf文件的文字内容
     * @param args
     */
    public static pdfDomainVO replaceContent(pdfDomainVO vo)
    throws IOException,COSVisitorException{
        //创建一个文档对象
        PDDocument doc =null;
        try {
            //加载文件
            doc =PDDocument.load(vo.getInputfile());
            //获取全部页数
            List pages= doc.getDocumentCatalog().getAllPages();
            //获取与i对应的页面
            PDPage page = (PDPage)pages.get( vo.getPageno() );
            //流对象来接收当前page的内容
            PDStream contents = page.getContents();
            //PDF流对象剖析器(这将解析一个PDF字节流并提取操作数,等等)
            PDFStreamParser parser =new PDFStreamParser(contents.getStream());
            //这将分析流中的标记
            parser.parse();
            //用list存流中的所有标记
            List tokens =parser.getTokens();
            for (int j = 0; j < tokens.size(); j++) {
                //创建一个object对象去接收标记
                Object next = tokens.get( j );
                //instanceof判断其左边对象是否为其右边类的实例
                if(next  instanceof PDFOperator ) {
                    //pdf操作器对象
                    PDFOperator op =(PDFOperator)next;
                    //TJ和TJ是显示的两个操作符。 
                    //PDF中的字符串 
                    if(op.getOperation().equals("Tj")){
                        //COSString对象>>创建java字符串的一个新的文本字符串。
                        COSString previous = (COSString)tokens.get( j-1 );
                        //将此字符串的内容作为PDF文本字符串返回。 
                        String string=previous.getString();
                        //replaceFirst>>替换第一个字符
                        string = string.replaceFirst( vo.getStrtofind(), vo.getMessage() );
                        System.out.println(string);                           
                        System.out.println(string.getBytes("GBK"));
                        //重置COSString对象
                        previous.reset();
                        //设置字符编码格式
                        previous.append(string.getBytes("GBK") );
                    }else if(op.getOperation().equals("TJ")){
                        //COSArray是pdfbase对象数组,作为PDF文档的一部分
                        COSArray previous  =(COSArray)tokens.get( j-1 );
                        //循环previous
                        for (int k = 0; k < previous.size(); k++) {
                            //这将从数组中获取一个对象,这将取消引用该对象
                            //如果对象为cosnull,则返回null
                            Object arrElement = previous.getObject( k );
                            if( arrElement instanceof COSString ){
                                //COSString对象>>创建java字符串的一个新的文本字符串。
                                COSString cosString =(COSString)arrElement;
                                //将此字符串的内容作为PDF文本字符串返回。 
                                String string =cosString.getString();
                                //替换
                                string = string.replaceFirst(  vo.getStrtofind(), vo.getMessage());
                                //重置COSString对象
                                cosString.reset();
                                //设置字符编码格式
                                cosString.append(string.getBytes("GBK") );
                            }
                        }
                    }
                }
            }
             //创建一个PDStream 流对象
             PDStream updatedStream = new PDStream(doc);
             //创建一个输出流接收updatedStream
             OutputStream out =updatedStream.createOutputStream();
             //将接受一个列表并写出它们的流。 
             ContentStreamWriter tokenWriter  =new ContentStreamWriter(out);
             //写入一系列标记,后面跟着一行新行
             tokenWriter.writeTokens(tokens);
             //当前页设置新的内容
             page.setContents( updatedStream );
            //修改后保存的路径
            doc.save(vo.getOutputfile());
            //操作后的页数
            vo.setAfterPages(doc.getNumberOfPages());
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if( doc != null ){
                //关闭文档
                doc.close();
            }
        }
        return vo;
    }

—–5在pdf中插入图片(按指定页数插入)

/**
     * 在pdf中插入图片
     * @param inputFile
     * @param image
     * @param outputFile
     * @throws IOException
     * @throws COSVisitorException
     */
    public static pdfDomainVO  insertImage( pdfDomainVO vo ) 
              throws IOException, COSVisitorException{
        //偏移量设置
        String[] position =vo.getPosition().split(",");
        int x =Integer.valueOf(position[0]);
        int y =Integer.valueOf(position[position.length-1]);
        //创建一个文档对象
        PDDocument doc =null;
        try {
            //加载
            doc = PDDocument.load(vo.getInputfile());
            //获取加载进来的pdf文件的页面
            PDPage page = (PDPage)doc.getDocumentCatalog().getAllPages().get( vo.getPageno() );
            //pdfbox中图片对象类
            PDXObjectImage ximage = null;
            //判断是否是.jpg格式的图片
            if( vo.getImagefile().toLowerCase().endsWith( ".jpg" ) ){
                //传入一张图片
                 ximage = new PDJpeg(doc, new FileInputStream( vo.getImagefile() ) ); 
            }//如果是tif或tiff格式
            else if (vo.getImagefile().toLowerCase().endsWith(".tif") || vo.getImagefile().toLowerCase().endsWith(".tiff")){
                 ximage = new PDCcitt(doc, new RandomAccessFile(new File(vo.getImagefile()),"r"));
            }else{
                //Image和BufferedImage的主要作用就是将一副图片加载到内存中
                BufferedImage awtImage = ImageIO.read( new File( vo.getImagefile() ) );
                ximage = new PDPixelMap(doc, awtImage);
            }
            //这是选择如何处理流:覆盖、追加
            PDPageContentStream contentStream = new PDPageContentStream(doc, page, true, true);
            //控制图片的大小
            float scale = vo.getImgSize();
            scale = scale/10;//(这个值最好是0.1~1,0.5就已经很大了)

            //ximage.setHeight(ximage.getHeight()/5);
            //ximage.setWidth(ximage.getWidth()/5);
             System.out.println(ximage.getHeight());
             System.out.println(ximage.getWidth());
             //设置位移等参数
             contentStream.drawXObject(ximage, x, y, ximage.getWidth()*scale, ximage.getHeight()*scale);
             //关闭流对象
             contentStream.close();
             //保存路径
             doc.save( vo.getOutputfile() );
             //操作后的页数
             vo.setAfterPages(doc.getNumberOfPages());
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if( doc != null ){
                //关闭文档
                doc.close();
            }
        }   
        return vo;
     }

—–6指定页数的PDF文件转换为图片

/***
     * 指定页数的PDF文件转换为图片:
     * @param inputFile
     * @param outputFile 这里指定文件夹
     */
    public static pdfDomainVO toImage( pdfDomainVO vo ) {
        try {
            //加载
            PDDocument doc = PDDocument.load(vo.getInputfile());
            //
            //int pageCount = doc.getPageCount();
            ////获取全部页数
            //指定单页转pdf
            List pages = doc.getDocumentCatalog().getAllPages();
            if(vo.getPageno()!=null){
                String count=(int)(Math.random()*1000)+"-"+(int)(Math.random()*1000);
                //接收页面
                PDPage page = (PDPage) pages.get(vo.getPageno());
                //定义图片操作对象来设置图片
                BufferedImage image = page.convertToImage();
                //定义迭代器对象存储
                Iterator iter = ImageIO.getImageWritersBySuffix("jpg");
                //图片写入器对象写入图片
                ImageWriter writer = (ImageWriter) iter.next();
                //循环保存图片
                File outFile = new File(vo.getOutputfile()+vo.getFilename()+"-"+(vo.getPageno()+1)+".jpg");
                //创建文件输出流对象
                FileOutputStream out = new FileOutputStream(outFile);
                //ImageIO去实现ImageOutputStream获取当前图片
                ImageOutputStream outImage = ImageIO.createImageOutputStream(out);
                writer.setOutput(outImage);
                writer.write(new IIOImage(image, null, null));
            }else{
                //循环
                for (int i = 0; i < pages.size(); i++) {
                    //接收页面
                    PDPage page = (PDPage) pages.get(i);
                    //定义图片操作对象来设置图片
                    BufferedImage image = page.convertToImage();
                    //定义迭代器对象存储
                    Iterator iter = ImageIO.getImageWritersBySuffix("jpg");
                    //图片写入器对象写入图片
                    ImageWriter writer = (ImageWriter) iter.next();
                    //循环保存图片
                    File outFile = new File(vo.getOutputfile()+i+".jpg");
                    //创建文件输出流对象
                    FileOutputStream out = new FileOutputStream(outFile);
                    //ImageIO去实现ImageOutputStream获取当前图片
                    ImageOutputStream outImage = ImageIO.createImageOutputStream(out);
                    writer.setOutput(outImage);
                    writer.write(new IIOImage(image, null, null));
                }
            }
            //关文档
            doc.close();
            //操作后的页数
            vo.setAfterPages(doc.getNumberOfPages());
            System.out.println("over");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return vo;
    }

—–7指定页插入一段文字(大家可自调字体,插入文字的位置)

/***
     * 指定页插入一段文字
     * @param inputFile
     * @param message
     * @param outputFile
     * @throws IOException
     * @throws COSVisitorException
     */
    public static pdfDomainVO InsertPageContent (pdfDomainVO vo ) throws IOException, COSVisitorException
    { 
        // the document
        PDDocument doc = null;
        try
        {
            doc = PDDocument.load( vo.getInputfile() );
            List allPages = doc.getDocumentCatalog().getAllPages();
            PDFont font = PDType1Font.HELVETICA_BOLD;
            //字体大小
            float fontSize = 36.0f;
            PDPage page = (PDPage)allPages.get( vo.getPageno() );
            PDRectangle pageSize = page.findMediaBox();
            float stringWidth = font.getStringWidth( vo.getMessage() )*fontSize/1000f;
            // calculate to center of the page
            int rotation = page.findRotation(); 
            boolean rotate = rotation == 90 || rotation == 270;
            float pageWidth = rotate ? pageSize.getHeight() : pageSize.getWidth();
            float pageHeight = rotate ? pageSize.getWidth() : pageSize.getHeight();
            double centeredXPosition = rotate ? pageHeight/2f : (pageWidth - stringWidth)/2f;
            double centeredYPosition = rotate ? (pageWidth - stringWidth)/2f : pageHeight/2f;
            // append the content to the existing stream
            PDPageContentStream contentStream = new PDPageContentStream(doc, page, true, true,true);
            contentStream.beginText();
            // set font and font size
            contentStream.setFont( font, fontSize );
            // set text color to red
            contentStream.setNonStrokingColor(255, 0, 0);
            if (rotate)
            {
                // rotate the text according to the page rotation
                contentStream.setTextRotation(Math.PI/2, centeredXPosition, centeredYPosition);
            }
            else
            {
                contentStream.setTextTranslation(centeredXPosition, centeredYPosition);
            }
            contentStream.drawString( vo.getMessage() );
            contentStream.endText();
            contentStream.close();
            vo.setAfterPages(doc.getNumberOfPages());
            doc.save( vo.getOutputfile() );
            System.out.println("over");
        }
        finally
        {
            if( doc != null )
            {
                doc.close();
            }
        }
        return vo;
    }

—–8提取图片并保存

/**
     * 提取图片并保存
     * @param pdfDomainVO 
     * @throws IOException 
     * 
     */
    public static pdfDomainVO extractImage(pdfDomainVO vo ) throws IOException{
        //创建文档  
        PDDocument doc=null;
        try{
            //加载 pdf 文档,获取PDDocument文档对象
            doc=PDDocument.load(vo.getInputfile());           
            /** 文档页面信息 **/  
            //获取PDDocumentCatalog文档目录对象
            PDDocumentCatalog catalog = doc.getDocumentCatalog();
            //获取文档页面PDPage列表
            List pages = catalog.getAllPages();  
            int pageNum=pages.size();   //文档页数
            PDPage page = null;
            if(vo.getPageno()!=null){
                 page = ( PDPage ) pages.get( vo.getPageno() ); 
                 if( null != page ){  
                     PDResources resource = page.findResources();                      
                     //获取页面图片信息 
                     Map imgs = resource.getImages();                    
                     for(Map.Entry me: imgs.entrySet()){
                         //System.out.println(me.getKey());
                         PDXObjectImage img = me.getValue();  
                         //保存图片,会自动添加图片后缀类型
                         img.write2file( vo.getOutputfile() + vo.getFilename()+"-"+(vo.getPageno()+1) );     
                     }  
                 }  
            }else{
                //遍历每一页
                for( int i = 0; i < pageNum; i++ ){  
                    //取得第i页
                     page = ( PDPage ) pages.get( i ); 
                    if( null != page ){  
                        PDResources resource = page.findResources();                      
                        //获取页面图片信息 
                        Map imgs = resource.getImages();                    
                        for(Map.Entry me: imgs.entrySet()){
                            String count=(int)(Math.random()*1000)+"-"+(int)(Math.random()*1000);
                            //System.out.println(me.getKey());
                            PDXObjectImage img = me.getValue();  
                            //保存图片,会自动添加图片后缀类型
                            img.write2file( vo.getOutputfile() + count );  
                        }  
                    }  
                } 
            }
            //操作后的页数
            vo.setAfterPages(doc.getNumberOfPages());
            System.out.println("extractImage:over");
        }  finally
        {
            if( doc != null )
            {
                doc.close();
            }
        }
        return vo;
    }

—–9PDF文档中删除页面(不能删除最后一页!)

    /***
     * PDF文档中删除页面
     * 一个PDF文档必须至少有一页,且不能删除最后一页!
     * @param inputFile
     * @param outputFile
     * @throws Exception
     */
    public static pdfDomainVO removePage(pdfDomainVO vo) throws Exception
    {
        vo.setStatus(Details.FailStatus);
        PDDocument document = null;
        try
        {
            document = PDDocument.load(vo.getInputfile() );
            if( document.isEncrypted() )
            {
                throw new IOException( "Encrypted documents are not supported for this example" );
            }
            if( document.getNumberOfPages() <= 1 )
            {
                throw new IOException( "Error: A PDF document must have at least one page, " +
                                       "cannot remove the last page!");
            }
            document.removePage( vo.getPageno() );
            document.save(vo.getOutputfile() );
            //操作后的页数
            vo.setAfterPages(document.getNumberOfPages());
            //设置成功状态
            vo.setStatus(Details.SuccessStatus);
            System.out.println("over");
        }
        finally
        {
            if( document != null )
            {
                document.close();
            }
        }
        return vo;
    }

pdfbox很强大,最主要是开源,(就是TMD不支持中文)以上只是部分功能,大家如果还想拓展,可以参考官方的事例和api

PS:遗憾的是,我没有处理好,替换文字或者是插入文字时,中文乱码问题,有处理好的同学记得和博主说一下,大家共同进步

这有一篇文:http://blog.csdn.net/undergrowth/article/details/39136673是对于pdfbox各个方法,属性解析的比较好的文,大家可以去看下

你可能感兴趣的:(pdfBox)