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
相关推荐
一个尚在学习的计算机小白17 小时前
java集合
java·开发语言
欢喜躲在眉梢里17 小时前
CANN 异构计算架构实操指南:从环境部署到 AI 任务加速全流程
运维·服务器·人工智能·ai·架构·计算
小女孩真可爱17 小时前
大模型学习记录(五)-------调用大模型API接口
pytorch·深度学习·学习
hd51cc17 小时前
C++ 学习笔记 名称
笔记·学习
IUGEI17 小时前
synchronized的工作机制是怎样的?深入解析synchronized底层原理
java·开发语言·后端·c#
用户479492835691517 小时前
React 渲染两次:是 Bug 还是 Feature?聊聊严格模式的“良苦用心”
前端·react.js·前端框架
q***136117 小时前
Windows操作系统部署Tomcat详细讲解
java·windows·tomcat
z***I39417 小时前
Java桌面应用案例
java·开发语言
间彧18 小时前
GraalVM Native Image:跨平台能力与编译模式深度解析
后端
间彧18 小时前
GraalVM Native Image 与传统 JVM 内存管理:云原生时代的技术选型指南
后端