如何用PDFBox编写移除PDF只读模式与数字签名的等效代码
移除PDF写保护/加密及数字签名的PDFBox实现
我们时常需要移除PDF文档的写保护/加密以及数字签名,以便对文档进行修改并重新签名,比如原文档丢失或被修改导致数字签名损坏的场景。
此前我们使用iText 8实现了该功能,但要注意展平AcroForm并非最优方案,会导致交互式表单失效等问题,原代码如下:
public static byte[] cleanUpPdfItext(byte[] originalPdfData) throws Exception { // Read the PDF document try ( ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); PdfReader pdfReader = new PdfReader(new ByteArrayInputStream(originalPdfData)).setUnethicalReading(true); PdfWriter pdfWriter = new PdfWriter(byteArrayOutputStream); PdfDocument pdfDocument = new PdfDocument(pdfReader, pdfWriter) ) { // Create the signature utils SignatureUtil signatureUtil = new SignatureUtil(pdfDocument); // Check if encrypted and/or contains signatures boolean isEncrypted = pdfReader.isEncrypted(); boolean hasSignatures = !signatureUtil.getSignatureNames().isEmpty(); // Handle all cases if (isEncrypted && hasSignatures) { // Encrypted and signatures // Remove the signatures PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDocument, true); form.flattenFields(); // Write the changes to the output stream, so we can read them pdfDocument.close(); // Get the manipulated document return byteArrayOutputStream.toByteArray(); } else if (isEncrypted) { // Encrypted but no signatures // Write the changes to the output stream, so we can read them pdfDocument.close(); // Get the manipulated document return byteArrayOutputStream.toByteArray(); } else { // Not encrypted/no signatures // Return the original document data return originalPdfData; } } }
现在需要编写等效的PDFBox代码,实现移除PDF的写保护/加密以及所有现有签名,使文档可编辑并重新签名。以下是补充完整后的代码:
public static byte[] cleanUpPdfbox(byte[] original) throws Exception { try ( ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); PDDocument pdDocument = Loader.loadPDF(original) ) { // Check if encrypted or read only AccessPermission accessPermission = pdDocument.getCurrentAccessPermission(); boolean isEncrypted = pdDocument.isEncrypted() || accessPermission.isReadOnly(); // Check if signatures exist boolean hasSignatures = !pdDocument.getSignatureDictionaries().isEmpty(); PDAcroForm pdAcroForm = pdDocument.getDocumentCatalog().getAcroForm(); // Remove all security if required if (isEncrypted) { pdDocument.setAllSecurityToBeRemoved(true); } // Remove all signatures if (hasSignatures) { // 移除签名字典 pdDocument.setSignatureDictionaries(null); if (pdAcroForm != null) { // 移除所有签名字段 List<PDField> fieldsToRemove = new ArrayList<>(); for (PDField field : pdAcroForm.getFields()) { if (field instanceof PDSignatureField) { fieldsToRemove.add(field); } } fieldsToRemove.forEach(field -> pdAcroForm.getFields().remove(field)); // 更新AcroForm字典,移除相关签名条目 pdAcroForm.getCOSObject().removeItem(COSName.DS); pdAcroForm.getCOSObject().removeItem(COSName.SIG_FLAGS); } // 移除文档中的签名引用(如DSS字典) pdDocument.getDocumentCatalog().getCOSObject().removeItem(COSName.DSS); } // Write the document pdDocument.save(byteArrayOutputStream); return byteArrayOutputStream.toByteArray(); } }
代码说明:
- 移除安全设置:通过
setAllSecurityToBeRemoved(true)移除PDF的加密和只读限制,确保文档可编辑。 - 移除签名字典:直接清空文档的签名字典集合,清除已有的签名记录。
- 清理签名字段:遍历AcroForm中的字段,移除所有
PDSignatureField类型的字段,并清理AcroForm字典中与签名相关的条目(如DS、SIG_FLAGS)。 - 移除DSS字典:如果文档存在文档安全存储(DSS)字典,也一并移除,避免残留签名相关数据。
内容的提问来源于stack exchange,提问作者swaechter
相关产品推荐
相关产品推荐

