1. 程式人生 > >Java使用PDFBox操作PDF檔案

Java使用PDFBox操作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;
            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<String,PDXObjectImage> imgs = resource.getImages();                    
                     for(Map.Entry<String,PDXObjectImage> 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<String,PDXObjectImage> imgs = resource.getImages();                    
                        for(Map.Entry<String,PDXObjectImage> 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;
    }
    /ul>

—–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:遺憾的是,我沒有處理好,替換文字或者是插入文字時,中文亂碼問題,有處理好的同學記得和博主說一下,大家共同進步