PDFBox - PDDocument 与 byte 数组、PDF 加密

一、PDDocument 与 byte 数组

1、由 byte 数组创建 PDDocument
(1)基本介绍
  • 调用 PDDocument 的 load 静态方法,由 byte 数组创建 PDDocument
java 复制代码
public static PDDocument load(byte[] input) throws IOException {
    return load(input, "");
}
(2)演示
java 复制代码
File pdfFile = new File("pdf/image_example.pdf");

InputStream pdfInputStream;
try {
    pdfInputStream = new FileInputStream(pdfFile);
} catch (FileNotFoundException e) {
    e.printStackTrace();
    System.out.println("PDF 文件不存在");
    return;
}

ByteArrayOutputStream pdfBuffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[1024];
try {
    while ((nRead = pdfInputStream.read(data, 0, data.length)) != -1) {
        pdfBuffer.write(data, 0, nRead);
    }
} catch (IOException e) {
    e.printStackTrace();
    System.out.println("PDF 读取文件失败");
    return;
}

byte[] pdfBytes = pdfBuffer.toByteArray();

try (PDDocument document = PDDocument.load(pdfBytes)) {
    PDPage page = new PDPage();
    document.addPage(page);

    File imgFile = new File("pdf/dzs.jpeg");

    InputStream imgInputStream;
    try {
        imgInputStream = new FileInputStream(imgFile);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
        System.out.println("图片不存在");
        return;
    }

    ByteArrayOutputStream imgBuffer = new ByteArrayOutputStream();
    int nReadImg;
    byte[] dataImg = new byte[1024];
    try {
        while ((nReadImg = imgInputStream.read(dataImg, 0, dataImg.length)) != -1) {
            imgBuffer.write(dataImg, 0, nReadImg);
        }
    } catch (IOException e) {
        e.printStackTrace();
        System.out.println("图片读取失败");
        return;
    }

    byte[] imgBytes = imgBuffer.toByteArray();

    PDImageXObject pdImage = PDImageXObject.createFromByteArray(document, imgBytes, "dzs.jpeg");

    try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
        contentStream.drawImage(pdImage, 100, 600, pdImage.getWidth() * 0.25f, pdImage.getHeight() * 0.25f);
    } catch (IOException e) {
        e.printStackTrace();
    }

    document.save("pdf/image_example.pdf");
} catch (IOException e) {
    e.printStackTrace();
}
2、由 PDDocument 得到 byte 数组
(1)基本介绍
  • 调用 PDDocument 的 save 方法,使用 ByteArrayOutputStream 来捕获输出,由 PDDocument 得到 byte 数组
java 复制代码
public void save(OutputStream output) throws IOException {
    if (this.document.isClosed()) {
        throw new IOException("Cannot save a document which has been closed");
    } else {
        Iterator var2 = this.fontsToSubset.iterator();

        while(var2.hasNext()) {
            PDFont font = (PDFont)var2.next();
            font.subset();
        }

        this.fontsToSubset.clear();
        COSWriter writer = new COSWriter(output);

        try {
            writer.write(this);
        } finally {
            writer.close();
        }

    }
}
(2)演示
java 复制代码
File pdfFile = new File("pdf/image_example.pdf");

InputStream pdfInputStream;
try {
    pdfInputStream = new FileInputStream(pdfFile);
} catch (FileNotFoundException e) {
    e.printStackTrace();
    System.out.println("PDF 文件不存在");
    return;
}

ByteArrayOutputStream pdfBuffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[1024];
try {
    while ((nRead = pdfInputStream.read(data, 0, data.length)) != -1) {
        pdfBuffer.write(data, 0, nRead);
    }
} catch (IOException e) {
    e.printStackTrace();
    System.out.println("PDF 读取文件失败");
    return;
}

byte[] pdfBytes = pdfBuffer.toByteArray();

try (PDDocument document = PDDocument.load(pdfBytes)) {
    PDPage page = new PDPage();
    document.addPage(page);

    File imgFile = new File("pdf/dzs.jpeg");

    InputStream imgInputStream;
    try {
        imgInputStream = new FileInputStream(imgFile);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
        System.out.println("图片不存在");
        return;
    }

    ByteArrayOutputStream imgBuffer = new ByteArrayOutputStream();
    int nReadImg;
    byte[] dataImg = new byte[1024];
    try {
        while ((nReadImg = imgInputStream.read(dataImg, 0, dataImg.length)) != -1) {
            imgBuffer.write(dataImg, 0, nReadImg);
        }
    } catch (IOException e) {
        e.printStackTrace();
        System.out.println("图片读取失败");
        return;
    }

    byte[] imgBytes = imgBuffer.toByteArray();

    PDImageXObject pdImage = PDImageXObject.createFromByteArray(document, imgBytes, "dzs.jpeg");

    try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
        contentStream.drawImage(pdImage, 100, 600, pdImage.getWidth() * 0.25f, pdImage.getHeight() * 0.25f);
    } catch (IOException e) {
        e.printStackTrace();
    }

    ByteArrayOutputStream output = new ByteArrayOutputStream();
    document.save(output);
    byte[] bytes = output.toByteArray();
    System.out.println("PDF 字节数:" + bytes.length);
} catch (IOException e) {
    e.printStackTrace();
}
复制代码
# 输出结果

PDF 字节数:86736

二、PDF 加密

1、基本介绍
(1)用户密码
  1. 用户密码(User Password / Open Password)用于打开 PDF 文件,也叫打开密码或文档密码

  2. 如果设置了用户密码,任何人在打开该 PDF 时都必须输入这个密码,否则无法查看内容

(2)所有者密码
  1. 所有者密码(Owner Password / Permissions Password)用于解除权限限制

  2. 所有者密码用于禁止某些操作,例如,打印、复制、编辑

  3. 只有拥有所有者密码的用户,才能移除这些限制,普通用户即使能打开 PDF,也无法绕过这些限制

2、创建加密的 PDF
java 复制代码
try (PDDocument document = new PDDocument()) {
    PDPage page = new PDPage();
    document.addPage(page);

    try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
        contentStream.beginText();
        contentStream.setFont(PDType1Font.HELVETICA_BOLD, 12);
        contentStream.newLineAtOffset(100, 700);
        contentStream.showText("Hello PDFBox");
        contentStream.endText();
    } catch (IOException e) {
        e.printStackTrace();
    }

    // 设置权限
    AccessPermission accessPermission = new AccessPermission();
    accessPermission.setReadOnly();

    // 设置保护策略
    StandardProtectionPolicy policy = new StandardProtectionPolicy("12345", "12345", accessPermission);
    document.protect(policy);

    document.save("pdf/test.pdf");
} catch (IOException e) {
    e.printStackTrace();
}
3、读取加密的 PDF
  1. 读取时未设置密码或设置了错误的密码
java 复制代码
try (PDDocument document = PDDocument.load(new File("pdf/test.pdf"), "abc")) {
    PDFTextStripper stripper = new PDFTextStripper();
    String text = stripper.getText(document);
    System.out.println(text);
} catch (Exception e) {
    e.printStackTrace();
}
复制代码
# 输出结果

org.apache.pdfbox.pdmodel.encryption.InvalidPasswordException: Cannot decrypt PDF, the password is incorrect
  1. 读取时设置了正确的密码
java 复制代码
try (PDDocument document = PDDocument.load(new File("pdf/test.pdf"), "12345")) {
    PDFTextStripper stripper = new PDFTextStripper();
    String text = stripper.getText(document);
    System.out.println(text);
} catch (Exception e) {
    e.printStackTrace();
}
复制代码
# 输出结果

Hello PDFBox
相关推荐
坚持就完事了6 分钟前
数据结构之树(Java实现)
java·算法
Monly219 分钟前
Java:修改打包配置文件
java·开发语言
roman_日积跬步-终至千里9 分钟前
【架构设计与实现】动态数据源切换:核心代码实现手册
java
毕设源码_廖学姐16 分钟前
计算机毕业设计springboot招聘系统网站 基于SpringBoot的在线人才对接平台 SpringBoot驱动的智能求职与招聘服务网
spring boot·后端·课程设计
XiaoFan01218 分钟前
免密批量抓取日志并集中输出
java·linux·服务器
●VON22 分钟前
React Native for OpenHarmony:2048 小游戏的开发与跨平台适配实践
javascript·学习·react native·react.js·von
souyuanzhanvip23 分钟前
ServerBox v1.0.1316 跨平台 Linux 服务器管理工具
linux·运维·服务器
顾北1224 分钟前
MCP服务端开发:图片搜索助力旅游计划
java·spring boot·dubbo
我命由我1234531 分钟前
Android 广播 - 静态注册与动态注册对广播接收器实例创建的影响
android·java·开发语言·java-ee·android studio·android-studio·android runtime
ZH154558913131 分钟前
Flutter for OpenHarmony Python学习助手实战:自动化脚本开发的实现
python·学习·flutter