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
相关推荐
林恒smileZAZ2 小时前
Vue<前端页面版本检测>
前端·javascript·vue.js
ulias2124 小时前
Linux系统中的权限问题
linux·运维·服务器
码事漫谈5 小时前
当AI开始“思考”:我们是否真的准备好了?
前端·后端
青花瓷5 小时前
Ubuntu下OpenClaw的安装(豆包火山API版)
运维·服务器·ubuntu
许杰小刀5 小时前
ctfshow-web文件包含(web78-web86)
android·前端·android studio
014-code5 小时前
订单超时取消与库存回滚的完整实现(延迟任务 + 状态机)
java·开发语言
北顾笙9806 小时前
LLM学习-day02
学习
我是Superman丶6 小时前
Element UI 表格某行突出悬浮效果
前端·javascript·vue.js
恋猫de小郭6 小时前
你的代理归我了:AI 大模型恶意中间人攻击,钱包都被转走了
前端·人工智能·ai编程
Dream of maid6 小时前
Linux(下)
linux·运维·服务器