当前位置 博文首页 > 小下和的博客:java操作pdf>>>pdfBox使用体验

    小下和的博客:java操作pdf>>>pdfBox使用体验

    作者:[db:作者] 时间:2021-08-01 20:58

    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.pdfbox</groupId>
                <artifactId>pdfbox-app</artifactId>
                <version>1.8.10</version>
            </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;