当前位置:   article > 正文

使用Apache PDFBox实现拆分、合并PDF_pdfbox官方文档

pdfbox官方文档

使用Apache PDFBox实现拆分、合并PDF

问题背景

  • 如何拆分PDF?
  • 如何合并PDF?
  • 如何拆分合并PDF实现去除PDF的某些页?

Apache PDFBox介绍

Apache PDFBox 1.8.10官方文档

Apache PDFBox 库是一个开源的 Java 工具,用于处理 PDF 文件。该项目允许创建新的PDF文档,操作 现有文档以及从文档中提取内容的能力。 PDFBox还包括几个命令行实用程序。PDFBox 发布 在 Apache 许可证下,版本 2.0。

也就是说,我们可以使用PDFBox实现拆分合并PDF。

在maven项目中添加依赖:

        <!--PDF操作-->
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox-app</artifactId>
            <version>1.8.10</version>
        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

拆分PDF

我们需实现WPS这种按照范围拆分的拆分规则:
拆分规则

  1. 参考样例

以下是wiki教程中找到的样例,可以实现按照每页拆分成pdf。

public static void main(String[] args) throws IOException {
      //Loading an existing PDF document
      File file = new File("C:/PdfBox_Examples/sample.pdf");
      PDDocument document = PDDocument.load(file); 
      //Instantiating Splitter class
      Splitter splitter = new Splitter();
      //splitting the pages of a PDF document
      List<PDDocument> Pages = splitter.split(document);
      //Creating an iterator 
      Iterator<PDDocument> iterator = Pages.listIterator();
      //Saving each page as an individual document
      int i = 1;
      while(iterator.hasNext()) {
         PDDocument pd = iterator.next();
         pd.save("C:/PdfBox_Examples/sample"+ i++ +".pdf");
      }
      System.out.println("Multiple PDF’s created");
      document.close();
   }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  1. org.apache.pdfbox.util.Splitter

Splitter 类有三个拆分相关的参数

    private int splitAtPage = 1;
    private int startPage = -2147483648;
    private int endPage = 2147483647;
  • 1
  • 2
  • 3

分别代表拆分的页数范围,开始拆分的页数,结束拆分的页数。

也就是说,我们可以通过实现设置splitter的相关参数(如splitter.setStartPage(12)等)来实现按照范围拆分的功能。

  1. 匹配拆分规则

建立SplitterDTO

/**
 * Splitter类的配置
 */
@Data
class SplitterDTO {
    private int splitAtPage;
    private int startPage;
    private int endPage;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

使用正则表达式校验按照范围拆分的拆分规则,将其参数保存在List<SplitterDTO>中:

    // m-n 例如 3-5,拆分第三到第五页的pdf
    private static final String ruleOne = "^[1-9]\\d*-[1-9]\\d*$";
    // m 例如 7,拆分第七页的pdf
    private static final String ruleTwo = "^[1-9]\\d*$";
    /**
     * 正则校验匹配  拆分规则
     * @param splitRule 拆分规则
     * @return
     */
    private List<SplitterDTO> matchByRegex(String splitRule) {
        List<SplitterDTO> result = new ArrayList<>();
        String[] splits = splitRule.split(",");
        for (String split : splits) {
            SplitterDTO dto = new SplitterDTO();
            if (split.matches(ruleOne)) {
                String[] nums = split.split("-");
                dto.setStartPage(Integer.parseInt(nums[0]));
                dto.setEndPage(Integer.parseInt(nums[1]));
                // 拆分的长度
                dto.setSplitAtPage(dto.getEndPage() - dto.getStartPage() + 1);
                result.add(dto);
            } else if (split.matches(ruleTwo)) {
                dto.setStartPage(Integer.parseInt(split));
                dto.setEndPage(Integer.parseInt(split));
                dto.setSplitAtPage(1);
                result.add(dto);
            } else {
                System.out.println("错误的规则:" + split);
            }
        }
        return result;
    }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  1. 拆分PDF

根据拆分规则开始拆分PDF并保存为pdf。

    /**
     * 拆分pdf
     * @param sourcePdf 源pdf(路径+文件名+文件后缀)
     * @param splitPath 拆分后的文件路径
     * @param splitFileName 拆分后的文件名(不含后缀)
     * @param splitterDTOS 拆分规则
     * @return finalPdfs 最终拆分成的pdf
     */
    private List<String> spitPdf(String sourcePdf, String splitPath, String splitFileName, List<SplitterDTO> splitterDTOS) throws IOException, COSVisitorException {
        List<String> finalPdfs = new ArrayList<>();
        int j = 1;
        String splitPdf = splitPath + "\\" + splitFileName + "_";

        for (SplitterDTO splitterDTO : splitterDTOS) {
            // Loading an existing PDF document
            File file = new File(sourcePdf);
            PDDocument document = PDDocument.load(file);
            // Instantiating Splitter class
            Splitter splitter = new Splitter();
            splitter.setStartPage(splitterDTO.getStartPage());
            splitter.setSplitAtPage(splitterDTO.getSplitAtPage());
            splitter.setEndPage(splitterDTO.getEndPage());
            // splitting the pages of a PDF document
            List<PDDocument> Pages = splitter.split(document);
            // Creating an iterator
            Iterator<PDDocument> iterator = Pages.listIterator();
            // Saving each page as an individual document
            while(iterator.hasNext()) {
                PDDocument pd = iterator.next();
                String pdfName = splitPdf+ j++ +".pdf";
                pd.save(pdfName);
                finalPdfs.add(pdfName);
            }
//            System.out.println("Multiple PDF’s created");
            document.close();
        }

        return finalPdfs;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  1. 拆分测试
    public static void main(String[] args) throws Exception {

        // 拆分规则:如拆分成1-4,5,以及8三个pdf
        String splitRule = "1-4,5,8";
        String sourcePdf = "D:\\BaiduNetdiskDownload\\test\\测试用pdf.pdf";
        // 拆分后pdf所放的文件夹
        String splitPath = "D:\\BaiduNetdiskDownload\\test";
        // 拆分后的文件名
        String splitFileName = UUID.randomUUID().toString().replace("-", "");
        /**
         * 1、拆分
         */
        PdfUtils pdfUtils = new PdfUtils();
        List<SplitterDTO> splitterDTOS = pdfUtils.matchByRegex(splitRule);
        List<String> pdfList = pdfUtils.spitPdf(sourcePdf, splitPath, splitFileName, splitterDTOS);
        System.out.println("pdf文件拆分成功------------");
        pdfList.forEach(System.out::println);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

控制台输出结果:

pdf文件拆分成功------------
D:\BaiduNetdiskDownload\test\a5f1b001f2d64a75ac63e75bdb4809e6_1.pdf
D:\BaiduNetdiskDownload\test\a5f1b001f2d64a75ac63e75bdb4809e6_2.pdf
D:\BaiduNetdiskDownload\test\a5f1b001f2d64a75ac63e75bdb4809e6_3.pdf
  • 1
  • 2
  • 3
  • 4

对应文件夹生成三个pdf文件:
pdf拆分测试


合并PDF

  1. 代码
    /**
     * 合并PDF
     * @param inputStreams 需合并的pdf文件流
     * @param bothPath 合并后的pdf文件路径
     * @param destinationFileName 合并后的pdf文件名
     */
    public static void MergePdf(List<InputStream> inputStreams, String bothPath, String destinationFileName) throws Exception {
        // org.apache.pdfbox.util.PDFMergerUtility:pdf合并工具类
        PDFMergerUtility mergePdf = new PDFMergerUtility();
        File file = new File(bothPath);
        if (!file.exists()) {
            file.mkdirs();
        }
        mergePdf.addSources(inputStreams);
        // 设置合并生成pdf文件名称
        mergePdf.setDestinationFileName(bothPath + File.separator + destinationFileName);
        // 合并PDF
        mergePdf.mergeDocuments();
        for (InputStream in : inputStreams) {
            if (in != null) {
                in.close();
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  1. 合并测试
    public static void main(String[] args) throws Exception {

        /**
         * 合并
         */
        // 合并pdf生成的文件名
        String destinationFileName = DateUtils.format(new Date());
        // 需要合并的PDF文件
        List<InputStream> inputStreams = new ArrayList<>();
        inputStreams.add(new FileInputStream(new File("D:\\ToPDF\\pdf\\水印冲鸭.pdf")));
        inputStreams.add(new FileInputStream(new File("D:\\ToPDF\\pdf\\testtest.pdf")));
        // 合并后pdf存放路径
        String bothPath = "D:\\ToPDF\\pdf";
        MergePdf(inputStreams, bothPath, destinationFileName+"测试合并.pdf");
        System.out.println("pdf文件合并成功");
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

控制台输出结果:

pdf文件合并成功
  • 1

对应文件夹生成合并的pdf文件:
pdf合并测试


拆分 + 合并

  1. 测试代码
    public static void main(String[] args) throws Exception {

        // 拆分规则:如拆分成1-4,5,以及8三个pdf
        String splitRule = "1-4,5,8";
        String sourcePdf = "D:\\BaiduNetdiskDownload\\test\\测试用pdf.pdf";
        // 拆分后pdf所放的文件夹
        String splitPath = "D:\\BaiduNetdiskDownload\\test";
        // 拆分后的文件名
        String splitFileName = UUID.randomUUID().toString().replace("-", "");
        /**
         * 1、拆分
         */
        PdfUtils pdfUtils = new PdfUtils();
        List<SplitterDTO> splitterDTOS = pdfUtils.matchByRegex(splitRule);
        List<String> pdfList = pdfUtils.spitPdf(sourcePdf, splitPath, splitFileName, splitterDTOS);
        System.out.println("pdf文件拆分成功------------");
        pdfList.forEach(System.out::println);

        /**
         * 2、合并
         */
        // 合并pdf生成的文件名
        String destinationFileName = splitFileName;
        // 需要合并的PDF文件
        List<InputStream> inputStreams = new ArrayList<>();
        for (String pdf : pdfList) {
            inputStreams.add(new FileInputStream(new File(pdf)));
        }
        // 合并后pdf存放路径
        String bothPath = "D:\\BaiduNetdiskDownload\\test";
        MergePdf(inputStreams, bothPath, destinationFileName + "测试合并.pdf");
        System.out.println("pdf文件合并成功-----------");
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  1. 测试结果
    控制台输出结果:
pdf文件拆分成功------------
D:\BaiduNetdiskDownload\test\a5f1b001f2d64a75ac63e75bdb4809e6_1.pdf
D:\BaiduNetdiskDownload\test\a5f1b001f2d64a75ac63e75bdb4809e6_2.pdf
D:\BaiduNetdiskDownload\test\a5f1b001f2d64a75ac63e75bdb4809e6_3.pdf
pdf文件合并成功-----------
  • 1
  • 2
  • 3
  • 4
  • 5

对应文件夹生成拆分后以及合并的pdf文件:
pdf拆分+合并测试


完整代码

package com.example.demo.utils;

import lombok.Data;
import org.apache.pdfbox.exceptions.COSVisitorException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.util.PDFMergerUtility;
import org.apache.pdfbox.util.Splitter;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * @Author 似有风中泣
 * @Description 操作PDF类
 * @Data 2022/6/27 16:18
 * @Version 1.0
 */
public class PdfUtils {

    // m-n 例如 3-5,拆分第三到第五页的pdf
    private static final String ruleOne = "^[1-9]\\d*-[1-9]\\d*$";
    // m 例如 7,拆分第七页的pdf
    private static final String ruleTwo = "^[1-9]\\d*$";


    public static void main(String[] args) throws Exception {

        // 拆分规则:如拆分成1-4,5,以及8三个pdf
        String splitRule = "1-4,5,8";
        String sourcePdf = "D:\\BaiduNetdiskDownload\\test\\测试用pdf.pdf";
        // 拆分后pdf所放的文件夹
        String splitPath = "D:\\BaiduNetdiskDownload\\test";
        // 拆分后的文件名
        String splitFileName = UUID.randomUUID().toString().replace("-", "");
        /**
         * 1、拆分
         */
        PdfUtils pdfUtils = new PdfUtils();
        List<SplitterDTO> splitterDTOS = pdfUtils.matchByRegex(splitRule);
        List<String> pdfList = pdfUtils.spitPdf(sourcePdf, splitPath, splitFileName, splitterDTOS);
        System.out.println("pdf文件拆分成功------------");
        pdfList.forEach(System.out::println);

        /**
         * 2、合并
         */
        // 合并pdf生成的文件名
        String destinationFileName = splitFileName;
        // 需要合并的PDF文件
        List<InputStream> inputStreams = new ArrayList<>();
        for (String pdf : pdfList) {
            inputStreams.add(new FileInputStream(new File(pdf)));
        }
        // 合并后pdf存放路径
        String bothPath = "D:\\BaiduNetdiskDownload\\test";
        MergePdf(inputStreams, bothPath, destinationFileName + "测试合并.pdf");
        System.out.println("pdf文件合并成功-----------");
    }

    /**
     * 正则校验匹配  拆分规则
     * @param splitRule 拆分规则
     * @return
     */
    private List<SplitterDTO> matchByRegex(String splitRule) {
        List<SplitterDTO> result = new ArrayList<>();
        String[] splits = splitRule.split(",");
        for (String split : splits) {
            SplitterDTO dto = new SplitterDTO();
            if (split.matches(ruleOne)) {
                String[] nums = split.split("-");
                dto.setStartPage(Integer.parseInt(nums[0]));
                dto.setEndPage(Integer.parseInt(nums[1]));
                // 拆分的长度
                dto.setSplitAtPage(dto.getEndPage() - dto.getStartPage() + 1);
                result.add(dto);
            } else if (split.matches(ruleTwo)) {
                dto.setStartPage(Integer.parseInt(split));
                dto.setEndPage(Integer.parseInt(split));
                dto.setSplitAtPage(1);
                result.add(dto);
            } else {
                System.out.println("错误的规则:" + split);
            }
        }
        return result;
    }

    /**
     * 拆分pdf
     * @param sourcePdf 源pdf(路径+文件名+文件后缀)
     * @param splitPath 拆分后的文件路径
     * @param splitFileName 拆分后的文件名(不含后缀)
     * @param splitterDTOS 拆分规则
     * @return finalPdfs 最终拆分成的pdf
     */
    private List<String> spitPdf(String sourcePdf, String splitPath, String splitFileName, List<SplitterDTO> splitterDTOS) throws IOException, COSVisitorException {
        List<String> finalPdfs = new ArrayList<>();
        int j = 1;
        String splitPdf = splitPath + "\\" + splitFileName + "_";

        for (SplitterDTO splitterDTO : splitterDTOS) {
            // Loading an existing PDF document
            File file = new File(sourcePdf);
            PDDocument document = PDDocument.load(file);
            // Instantiating Splitter class
            Splitter splitter = new Splitter();
            splitter.setStartPage(splitterDTO.getStartPage());
            splitter.setSplitAtPage(splitterDTO.getSplitAtPage());
            splitter.setEndPage(splitterDTO.getEndPage());
            // splitting the pages of a PDF document
            List<PDDocument> Pages = splitter.split(document);
            // Creating an iterator
            Iterator<PDDocument> iterator = Pages.listIterator();
            // Saving each page as an individual document
            while(iterator.hasNext()) {
                PDDocument pd = iterator.next();
                String pdfName = splitPdf+ j++ +".pdf";
                pd.save(pdfName);
                finalPdfs.add(pdfName);
            }
//            System.out.println("Multiple PDF’s created");
            document.close();
        }

        return finalPdfs;
    }

    /**
     * 合并PDF
     * @param inputStreams 需合并的pdf文件流
     * @param bothPath 合并后的pdf文件路径
     * @param destinationFileName 合并后的pdf文件名
     */
    public static void MergePdf(List<InputStream> inputStreams, String bothPath, String destinationFileName) throws Exception {
        // pdf合并工具类
        PDFMergerUtility mergePdf = new PDFMergerUtility();
        File file = new File(bothPath);
        if (!file.exists()) {
            file.mkdirs();
        }
        mergePdf.addSources(inputStreams);
        // 设置合并生成pdf文件名称
        mergePdf.setDestinationFileName(bothPath + File.separator + destinationFileName);
        // 合并PDF
        mergePdf.mergeDocuments();
        for (InputStream in : inputStreams) {
            if (in != null) {
                in.close();
            }
        }
    }


}

/**
 * Splitter类的配置
 */
@Data
class SplitterDTO {
    private int splitAtPage;
    private int startPage;
    private int endPage;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169

参考:

https://iowiki.com/pdfbox/pdfbox_splitting_a_pdf_document.html
https://github.com/apache/pdfbox
https://javadoc.io/doc/org.apache.pdfbox/pdfbox/1.8.10/index.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/539037
推荐阅读
相关标签
  

闽ICP备14008679号