PDFbox基本操作

详细内容见:https://iowiki.com/pdfbox/pdfbox_index.html

目录

PDFBox - 概述:

什么是PDFBox :

PDFBox的组件:

PDFBox的基本操作

1、创建一个空的pdf文件

2、给pdf文件添加一页

3、加载一个文件来创建一个pdf

4、删除一页

5、使用PDDocumentInformation 如何向PDF文档添加“ Author, Title, Date, and Subject等属性。

6、使用指定的字体和位置,在文件中写入指定的内容(一行内容)

6.1 中文的写入

7、添加多行

8、从pdf文档中提取全部文本

9、插入图像

10、使用StandardProtectionPolicy和AccessPermission classes提供的方法加密PDF文档。

11、PDF文档的拆分:Splitter的类将给定的PDF文档拆分为多个PDF文档,有几页就分成几个文档

12、使用PDFMergerUtility类的类将多个PDF文档合并到一个PDF文档中

13、将pdf转换成图片

14、pdf中添加矩形

15、添加矩形的基础上高亮标注(高亮的部分要是透明的,不能遮挡原有的文字)

 

 


PDFBox - 概述:

每个PDF文件都包含固定布局平面文档的描述,包括现实和它所包含的文本、字体、图形和其他信息。

有几个库可用于程序创建和操作PDF文档,例如:

  • Adobe PDF Library - 该库提供C ++,.NET和Java等语言的API,使用它可以编辑,查看打印和从PDF文档中提取文本。

  • Formatting Objects Processor - 由XSL格式化对象和输出独立格式化程序驱动的开源打印格式化程序。 主要输出目标是PDF。

  • iText - 该库提供Java,C#和其他.NET语言等语言的API,使用该库我们可以创建和操作PDF,RTF和HTML文档。

  • JasperReports - 这是一个Java报告工具,可以生成PDF文档的报告,包括Microsoft Excel,RTF,ODT,逗号分隔值和XML文件。

什么是PDFBox :

Apache PDFBox是一个开源的Java库,支持PDF文档的开发和转换。使用此库,可以开发用于创建、转换和操作pDF文档的java程序。除此之外,PDFBox还包括一个命令行使用程序,用于使用可用的Jar文件对PDF执行各种操作。

PDFBox的组件:

以下是PDFBox的四个主要组成部分 -

  • PDFBox - 这是PDFBox的主要部分。 它包含与内容提取和操作相关的类和接口。

  • FontBox - 它包含与font相关的类和接口,使用这些类我们可以修改PDF文档的文本字体。

  • XmpBox - 包含处理XMP元数据的类和接口。

  • Preflight - 此组件用于根据PDF/A-1b标准验证PDF文件。

 

PDFBox环境,maven项目中需要添加的依赖:

  
       
         org.apache.pdfbox 
         pdfbox 
         2.0.1 
         
       
         org.apache.pdfbox 
         fontbox 
         2.0.0 
      
        
         org.apache.pdfbox 
         jempbox 
         1.8.11 
       
      
         org.apache.pdfbox 
         xmpbox 
         2.0.0 
       
       
         org.apache.pdfbox 
         preflight 
         2.0.0 
       
       
         org.apache.pdfbox 
         pdfbox-tools 
         2.0.0 
      
   

 

PDFBox的基本操作

 

1、创建一个空的pdf文件

public class Document_Creation {
    public static void main(String[] args) {
        PDDocument document = new PDDocument();
        try {
            document.save("./my_doc.pdf");
            System.out.println("PDF created");
            document.close();
            // 这时候直接打开创建的文件会发现打不开
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

这时候直接打开创建的文件会发现打不开,打开时报错:

PDFbox基本操作_第1张图片

 

2、给pdf文件添加一页

public static void main(String[] args) {
    PDDocument document = new PDDocument();
    try {
        System.out.println("PDF created");
        PDPage blankPage = new PDPage();
        document.addPage(blankPage);
        document.save("./my_doc.pdf");
        document.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

这个时候创建的文档就可以打开了。注意save语句要写在addPage的后面

3、加载一个文件来创建一个pdf

public static void main(String[] args) {
//        File file = new File("/Users/qinwenjing/Documents/Projects/Test/src/main/java/com/pdfbox/Document_Creation"
//                + ".java");
       // File file = new File("/Users/qinwenjing/Documents/en_test.pdf");
        File file = new File("/Users/qinwenjing/Documents/en_test_scan.pdf");
        try {
            PDDocument pdDocument = PDDocument.load(file);
            System.out.println("PDF loaded");
            pdDocument.addPage(new PDPage());
            pdDocument.save("./sample.pdf");
            pdDocument.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

注意:

1)加载的pdf文件是原文件或者扫描件都可以,写的结果和原文一样

2)重新执行这个程序的时候,指定的sample.pdf文件的内容会被覆盖

3)加载的文件必须是个pdf, 如果不是报错:java.io.IOException: Error: End-of-File, expected line

or java.io.IOException: Error: Header doesn't contain versioninfo 等

 

4、删除一页

public static void main(String[] args) {
    File file = new File("./sample.pdf");
    try {
        PDDocument document = PDDocument.load(file);
        System.out.println(document.getNumberOfPages());
        document.removePage(1);
        document.save("./sample.pdf");
        System.out.println(document.getNumberOfPages());
        document.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

注意:

1)删除并并保存后在打印文件的页数发现已经少了一

2)设置删除的页为1, 实际上删除的是第2页,这个值是从0开始

3)删除不存在的页,会报错:java.lang.IndexOutOfBoundsException: Index out of bounds: 6

 

5、使用PDDocumentInformation 如何向PDF文档添加“ Author, Title, Date, and Subject等属性。

public class AddingDocumentAttributes {
    public static void main(String[] args) {
        PDDocument document = new PDDocument();
        document.addPage(new PDPage());
        PDDocumentInformation pdd = document.getDocumentInformation();
        pdd.setAuthor("qinwenjing");
        pdd.setTitle("sample document");
        pdd.setCreator("pdf examples");
        pdd.setSubject("example document");
        Calendar date = new GregorianCalendar();
        date.set(2020, 4, 8);
        pdd.setCreationDate(date);
        pdd.setKeywords("sample, first example, my pdf");
        try {
            document.save("./doc_attributes.pdf");
            document.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

找到对应的文件,右键->显示简介, 看到如下信息:

PDFbox基本操作_第2张图片

6、使用指定的字体和位置,在文件中写入指定的内容(一行内容)

public class AddingContent {
    public static void main(String[] args) {
        File file = new File("./doc_attributes.pdf");
        try {
            PDDocument document = PDDocument.load(file);
            PDPage page = document.getPage(0);
            PDPageContentStream contentStream = new PDPageContentStream(document, page);
            contentStream.beginText();
            contentStream.setFont(PDType1Font.TIMES_ROMAN, 12);
            // 设置这一行起点的位置,25是距离左侧的长度,600是距离页面底端的长度
            contentStream.newLineAtOffset(25, 600);
            String text = "This is the sample document and we are adding content to it.";
            contentStream.showText(text);
            contentStream.endText();
//            String text2 = "This is the sample document and we are adding content to it2222.";
//            contentStream.showText(text2);
            System.out.println("Content added");
            contentStream.close();
            document.save("./doc_attributes.pdf");
            document.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

注意:

1) 如果换一个写入的位置,重新执行一遍,原先的文件内容会被完全覆盖掉

2)此程序,您只能添加适合单行的文本。 如果您尝试添加更多内容,则不会显示超出行间距的所有文本(超出一行的内容不会被显示)。

  • 如果添加的内容text超出了一行的长度,则超出的部分不会被显示

  • 如果多次调用showText()方法,会发现所有的文本内容都会被添加在一行(即不会自动换行),而且超出一行长度的部分不会被显示

3)这里默认的字体是PDType1Font.TIMES_ROMAN, 但是PDType1Font是对英文的字体才使用,如果写入的内容是中文,则报错java.lang.IllegalArgumentException: U+6211 ('.notdef') is not available in this font's encoding: WinAnsiEncoding

那么如何写入中文呢?见6.1

6.1 中文的写入

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType0Font;

import com.itextpdf.io.font.otf.OpenTypeScript;

public class WritePdfText {
    public static void main(String[] args) {
        File file = new File("./writetest.pdf");
        try {
            PDDocument document = PDDocument.load(file);
            PDPageContentStream contentStream = new PDPageContentStream(document, document.getPage(0), PDPageContentStream.AppendMode.APPEND, false);
            contentStream.beginText();
            contentStream.newLineAtOffset(10, 200);
            PDFont pdFont = getDefaultFont(document);
            contentStream.setFont(pdFont, 12);
            contentStream.showText("大家好");
            contentStream.endText();
            contentStream.close();
            System.out.println("写入汉字");
            document.save("./writetest.pdf");
            document.close();

            // 这时候直接打开创建的文件会发现打不开
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private static PDFont getDefaultFont(PDDocument doc) {
        String path = "/unicode.ttf";
        PDFont font = null;
        try (InputStream input = OpenTypeScript.class.getResourceAsStream(path)) {
            font = PDType0Font.load(doc, input);
        } catch (IOException e) {
           e.printStackTrace();
        }
        return font;
    }
}

注意:

写中文用的字体是PDType0Font, 要中文字体得用外部的 ttf 文件来load 一个 type0的字体,这里的unicode.ttf文件是。。。(额,没有找到如何添加文件)。其中unicode.ttf文件放在对应的resource文件夹下。

 

7、添加多行

public static void main(String[] args) {
    File file = new File("./doc_attributes.pdf");
    try {
        PDDocument document = PDDocument.load(file);
        PDPage page = document.getPage(0);
        PDPageContentStream contentStream = new PDPageContentStream(document, page);
        contentStream.beginText();
        contentStream.setFont(PDType1Font.TIMES_ROMAN, 12);
        // 设置文本前导
        contentStream.setLeading(14.5f);
        contentStream.newLineAtOffset(25, 725);
        String text1 = "This is an example of adding text to a page in the pdf document. we can add as many lines";
        String text2 = "as we want like this using the ShowText()  method of the ContentStream class";
        contentStream.showText(text1);
        contentStream.newLine();
        contentStream.showText(text2);
        System.out.println("Content added");
        contentStream.close();
        document.save("./doc_attributes.pdf");
        document.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

注意:

1) 如果不设置setLeading(), 发现两段内容在同一行重叠了

2)加了newLine();两段内容是分行的

 

8、从pdf文档中提取全部文本

public static void main(String[] args) {
    File file = new File("./doc_attributes.pdf");
    try {
        PDDocument document = PDDocument.load(file);
        PDFTextStripper pdfTextStripper = new PDFTextStripper();
        String text = pdfTextStripper.getText(document);
        System.out.println(text);
        document.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

9、插入图像

public static void main(String[] args) {
    File file = new File("./new.pdf");
    try {
        PDDocument doc = PDDocument.load(file);
        PDImageXObject pdImage = PDImageXObject.createFromFile("./00.png", doc);

        PDPage page = doc.getPage(0);
        PDPageContentStream contentStream = new PDPageContentStream(doc, page);
        contentStream.drawImage(pdImage, 70, 250);
        contentStream.close();
        doc.save("./new.pdf");
        doc.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

注意:

开始用的图片是 jpg的格式,报错javax.imageio.IIOException: Not a JPEG file: starts with 0x4d 0x4d

直接改成png就可以了

 

10、使用StandardProtectionPolicy和AccessPermission classes提供的方法加密PDF文档。

public static void main(String[] args) {
    File file = new File("./new.pdf");
    try {
        PDDocument document = PDDocument.load(file);
        AccessPermission ap = new AccessPermission();
        StandardProtectionPolicy spp = new StandardProtectionPolicy("1234", "1234", ap);
        spp.setEncryptionKeyLength(128);
        spp.setPermissions(ap);
        document.protect(spp);
        System.out.println("Document encrypted");
        document.save(file);
        document.close();

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

11、PDF文档的拆分:Splitter的类将给定的PDF文档拆分为多个PDF文档,有几页就分成几个文档

import java.util.ListIterator;
import org.apache.pdfbox.multipdf.Splitter;
import org.apache.pdfbox.pdmodel.PDDocument;
public static void main(String[] args) {
    File file = new File("./sample.pdf");
    try {
        PDDocument document = PDDocument.load(file);
        Splitter spitter = new Splitter();
        List pages = spitter.split(document);
        ListIterator iterator = pages.listIterator();
        int i = 1;
        while (iterator.hasNext()) {
            PDDocument pd = iterator.next();
            pd.save("./sample" + i++ + ".pdf");
            pd.close();
        }
        System.out.println("Multiple PDF’s created");
        document.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

 

12、使用PDFMergerUtility类的类将多个PDF文档合并到一个PDF文档中

import org.apache.pdfbox.io.MemoryUsageSetting;
import org.apache.pdfbox.multipdf.PDFMergerUtility;
import org.apache.pdfbox.pdmodel.PDDocument;

public class MergePDFs {
    public static void main(String[] args) {
        File file1 = new File("./sample1.pdf");
        File file2 = new File("./sample2.pdf");
        File file3 = new File("./sample3.pdf");
        try {
            PDDocument doc1 = PDDocument.load(file1);
            PDDocument doc2 = PDDocument.load(file2);
            PDDocument doc3 = PDDocument.load(file3);
            PDFMergerUtility pdfMergerUtility = new PDFMergerUtility();
            pdfMergerUtility.setDestinationFileName("./mergesample.pdf");
            pdfMergerUtility.addSource(file1);
            pdfMergerUtility.addSource(file2);
            //pdfMergerUtility.addSource(file3);
            pdfMergerUtility.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly());
            System.out.println("Documents merged");

            doc1.close();
            doc2.close();
            doc3.close();

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

注意:

1) file3是包含一个空页的文件,如果使用了pdfMergerUtility.addSource(file3);,则会报错:IllegalArgumentException: resourceDictionary is null

2)Pdfbox Merge Document with 1.8.xx as like mergePdf.mergeDocuments() it working fine .now pdfbox version 2.0.0 contain some argument like org.apache.pdfbox.multipdf.PDFMergerUtility.mergeDocuments(MemoryUsageSetting arg0)

那么如何设置参数呢?可以设置为null或者MemoryUsageSetting.setupMainMemoryOnly()

 

13、将pdf转换成图片

import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;

public class PdfToImage {
    public static void main(String[] args) {
        File file = new File("./sample.pdf");
        try {
            PDDocument document = PDDocument.load(file);
            // 名为PDFRenderer的类将PDF文档呈现为AWT BufferedImage 。
            PDFRenderer renderer = new PDFRenderer(document);
            BufferedImage image = renderer.renderImage(0);
            ImageIO.write(image, "JPEG",new File("./immm.jpg"));
            System.out.println("Image created");
            //Closing the document
            document.close();

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

14、pdf中添加矩形

import java.awt.Color;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;

public class ShowColorBoxes {
    public static void main(String[] args) {
        File file = new File("./sample.pdf");
        try {
            PDDocument document = PDDocument.load(file);
            PDPage page = document.getPage(0);
            PDPageContentStream contentStream = new PDPageContentStream(document, page);
            contentStream.setNonStrokingColor(Color.DARK_GRAY);
            contentStream.addRect(200, 650, 100, 100);
            contentStream.fill();
            System.out.println("rectangle added");
            //Closing the ContentStream object
            contentStream.close();
            document.save(file);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

注意:

1)像前面写文件一样,这个地方添加了个矩形,会把当前页面的内容也会给覆盖掉,执行完成后,发现第一页只有个矩形,原来的内容都没有了。

2)注意PDPageContentStream contentStream = new PDPageContentStream(document, page);

默认的是这个方式:this(document, sourcePage, AppendMode.OVERWRITE, true, false); 可以指定AppendMode的值

/**
     * Create a new PDPage content stream.
     *
     * @param document The document the page is part of.
     * @param sourcePage The page to write the contents to.
     * @param appendContent Indicates whether content will be overwritten, appended or prepended.
     * @param compress Tell if the content stream should compress the page contents.
     * @param resetContext Tell if the graphic context should be reset. This is only relevant when
     * the appendContent parameter is set to {@link AppendMode#APPEND}. You should use this when
     * appending to an existing stream, because the existing stream may have changed graphic
     * properties (e.g. scaling, rotation).
     * @throws IOException If there is an error writing to the page contents.
     */
    public PDPageContentStream(PDDocument document, PDPage sourcePage, AppendMode appendContent,
                               boolean compress, boolean resetContext) throws IOException
    {
。。。。
}

 

15、添加矩形的基础上高亮标注(高亮的部分要是透明的,不能遮挡原有的文字)

import java.awt.Color;
import java.io.File;
import java.io.IOException;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;

public class ShowColorBoxes {
    public static void main(String[] args) {
        File file = new File("./en_test.pdf");
        try {
            PDDocument document = PDDocument.load(file);
            PDPage page = document.getPage(0);
            PDPageContentStream contentStream = new PDPageContentStream(document, page,
                    PDPageContentStream.AppendMode.APPEND, true, true);

            PDExtendedGraphicsState graphicsState = new PDExtendedGraphicsState();
            // 设置透明度
            graphicsState.setNonStrokingAlphaConstant(0.2f);
            graphicsState.setAlphaSourceFlag(true);

            contentStream.setGraphicsStateParameters(graphicsState);
            contentStream.addRect(200, 650, 10, 10);
            // 设置不划线颜色
            contentStream.setNonStrokingColor(Color.GREEN);

            contentStream.fill();
            System.out.println("rectangle added");
            //Closing the ContentStream object
            contentStream.close();
            document.save(file);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

注意:

1)new PDPageContentStream的倒数第二个参数如果是false,则无法进行透明的高亮标注

2)利用PDExtendedGraphicsState进行高亮标注

 

16、pdf中画线

import java.io.File;
import java.io.IOException;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPageContentStream;

public class WriteLinePdfText {
    public static void main(String[] args) {
        File file = new File("./writetest.pdf");
        try {
            PDDocument document = PDDocument.load(file);
            PDPageContentStream contentStream = new PDPageContentStream(document, document.getPage(0));
            contentStream.setStrokingColor(66, 177, 230);
            contentStream.moveTo(10, 20);
            contentStream.lineTo(200, 200);
            // 使用该方法画出线
            contentStream.stroke();
         /*   contentStream.setStrokingColor(66, 177, 230);
            contentStream.drawLine(100, 100, 200, 100);*/
            contentStream.close();
            document.save(file);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

注意:

1)没有contentStream.stroke();和document.save(file);是保存不了画的线的。

2)/**/中的方式也可以实现画线,不过属于过时的方法。

你可能感兴趣的:(基础知识)