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
相关推荐
layman052811 分钟前
webpack5 css-loader:从基础到原理
前端·css·webpack
半桔13 分钟前
【前端小站】CSS 样式美学:从基础语法到界面精筑的实战宝典
前端·css·html
AI老李13 分钟前
PostCSS完全指南:功能/配置/插件/SourceMap/AST/插件开发/自定义语法
前端·javascript·postcss
_OP_CHEN15 分钟前
【前端开发之CSS】(一)初识 CSS:网页化妆术的终极指南,新手也能轻松拿捏页面美化!
前端·css·html·网页开发·样式表·界面美化
啊哈一半醒17 分钟前
CSS 主流布局
前端·css·css布局·标准流 浮动 定位·flex grid 响应式布局
PHP武器库20 分钟前
ULUI:不止于按钮和菜单,一个专注于“业务组件”的纯 CSS 框架
前端·css
Fᴏʀ ʏ꯭ᴏ꯭ᴜ꯭.23 分钟前
Keepalived VIP迁移邮件告警配置指南
运维·服务器·笔记
电商API_1800790524728 分钟前
第三方淘宝商品详情 API 全维度调用指南:从技术对接到生产落地
java·大数据·前端·数据库·人工智能·网络爬虫
晓晓莺歌30 分钟前
vue3某一个路由切换,导致所有路由页面均变成空白页
前端·vue.js
Genie cloud41 分钟前
1Panel SSL证书申请完整教程
服务器·网络协议·云计算·ssl