PDFBox - abrir e salvar um pdf assinado invalida minha assinatura
Estou tentando aprender a usar o pdfBox do Apache para lidar com documentos assinados digitalmente para o trabalho. Durante o teste, criei um documento pdf completamente vazio.
Então, assinei o documento através do Adobe Reader usando a função assinar com certificado.
Tentei abrir, salvar e fechar o arquivo assinado com o pdfBox sem nenhuma modificação. No entanto, uma vez que abro o arquivo no Adobe, os arquivos não são mais válidos.
A Adobe me diz: "Existem erros na formatação ou nas informações contidas nesta assinatura (informações de suporte: dados ilegais do SigDict / Contents)"
Como não modifiquei o conteúdo do arquivo, intuitivamente não deveria ter havido problemas e a assinatura ainda deve ser válida, no entanto, esse não é o caso e não sei quais são as soluções (o Google não produziu resultados).
Como eu crio o documento:
@Test
public void createEmptyPDF() throws IOException {
String path = "path to file";
PDDocument document = new PDDocument();
PDPage page = new PDPage();
document.addPage(page);
document.save(path);
document.close();
}
Eu assino com o Adobe e passo por:
@Test
public void copySignedDocument() throws IOException {
String path = "path to file";
File file = new File(path);
PDDocument document = PDDocument.load(file);
document.save(file);
document.close();
//just opening and saving the file invalidates the signatures
}
Estou realmente sem saber por que isso não funciona. Qualquer ajuda seria ótimo!
EDITAR:
Então, eu fiz algumas investigações e parece que a atualização de um documento assinado existente (adicionando anotações ou preenchendo formulários) ainda não foi implementada no PDFBox 2.0.1 e está programada para ocorrer nas versões 2.1 (no entanto, nenhuma data de lançamento foi especificada). Mais Informaçõesaqui eaqui.
No entanto, parece possível adicionar anotações em documentos assinados com o IText sem invalidar a assinatura usando o PDFStamper,desta pergunta
EDIÇÃO 2: Código para adicionar um carimbo a um documento e salvá-lo gradualmente:
@Test
public void stampSignedDocument() throws IOException {
File file = new File("path to file");
PDDocument document = PDDocument.load(file);
File image = new File("path to image to be added to annotation");
PDPage page = document.getPage(0);
List<PDAnnotation> annotations = page.getAnnotations();
PDImageXObject ximage = PDImageXObject.createFromFileByContent(image, document);
//stamp
PDAnnotationRubberStamp stamp = new PDAnnotationRubberStamp();
stamp.setName("testing rubber stamp");
stamp.setContents("this is a test");
stamp.setLocked(true);
stamp.setReadOnly(true);
stamp.setPrinted(true);
PDRectangle rectangle = createRectangle(100, 100, 100, 100, 100, 100);
PDFormXObject form = new PDFormXObject(document);
form.setResources(new PDResources());
form.setBBox(rectangle);
form.setFormType(1);
form.getResources().add(ximage);
PDAppearanceStream appearanceStream = new PDAppearanceStream(form.getCOSObject());
PDAppearanceDictionary appearance = new PDAppearanceDictionary(new COSDictionary());
appearance.setNormalAppearance(appearanceStream);
stamp.setAppearance(appearance);
stamp.setRectangle(rectangle);
PDPageContentStream stream = new PDPageContentStream(document, appearanceStream);
Matrix matrix = new Matrix(100, 0, 0, 100, 100, 100);
stream.drawImage(ximage, matrix);
stream.close();
//close and save
annotations.add(stamp);
page.getCOSObject().setNeedToBeUpdated(true);
OutputStream os = new FileOutputStream(file);
document.saveIncremental(os);
document.close();
os.close();
}
O código acima não invalida minha assinatura, mas não salva a anotação que adicionei.
Conforme sugerido, configurei o sinalizador NeedToBeUpdated como true para a lista de anotações, página e anotações adicionada (espero que eu tenha feito o último corretamente):
stamp.getCOSObject().setNeedToBeUpdated(true);
COSArrayList<PDAnnotation> list = (COSArrayList<PDAnnotation>) annotations;
COSArrayList.converterToCOSArray(list).setNeedToBeUpdated(true);
page.getCOSObject().setNeedToBeUpdated(true);
document.getDocumentCatalog().getCOSObject().setNeedToBeUpdated(true);
A anotação ainda não foi salva, então estou obviamente perdendo alguma coisa.
EDIT 3:
Este é o meu método atual para adicionar uma anotação:
@Test
public void stampSignedDocument() throws IOException {
File file = new File(
"E:/projects/eSign/g2digitalsignature/G2DigitalSignatureParent/G2DigitalSignatureTest/src/test/resources/pdfBoxTest/empty.pdf");
PDDocument document = PDDocument.load(file);
File image = new File(
"E:/projects/eSign/g2digitalsignature/G2DigitalSignatureParent/G2DigitalSignatureTest/src/test/resources/pdfBoxTest/digitalSign.png");
PDPage page = document.getPage(0);
List<PDAnnotation> annotations = page.getAnnotations();
PDImageXObject ximage = PDImageXObject.createFromFileByContent(image, document);
//stamp
PDAnnotationRubberStamp stamp = new PDAnnotationRubberStamp();
stamp.setName("testing rubber stamp");
stamp.setContents("this is a test");
stamp.setLocked(true);
stamp.setReadOnly(true);
stamp.setPrinted(true);
PDRectangle rectangle = createRectangle(100, 100, 100, 100, 100, 100);
PDFormXObject form = new PDFormXObject(document);
form.setResources(new PDResources());
form.setBBox(rectangle);
form.setFormType(1);
form.getResources().getCOSObject().setNeedToBeUpdated(true);
form.getResources().add(ximage);
PDAppearanceStream appearanceStream = new PDAppearanceStream(form.getCOSObject());
PDAppearanceDictionary appearance = new PDAppearanceDictionary(new COSDictionary());
appearance.setNormalAppearance(appearanceStream);
stamp.setAppearance(appearance);
stamp.setRectangle(rectangle);
PDPageContentStream stream = new PDPageContentStream(document, appearanceStream);
Matrix matrix = new Matrix(100, 0, 0, 100, 100, 100);
stream.drawImage(ximage, matrix);
stream.close();
//close and save
annotations.add(stamp);
appearanceStream.getCOSObject().setNeedToBeUpdated(true);
appearance.getCOSObject().setNeedToBeUpdated(true);
rectangle.getCOSArray().setNeedToBeUpdated(true);
stamp.getCOSObject().setNeedToBeUpdated(true);
form.getCOSObject().setNeedToBeUpdated(true);
COSArrayList<PDAnnotation> list = (COSArrayList<PDAnnotation>) annotations;
COSArrayList.converterToCOSArray(list).setNeedToBeUpdated(true);
document.getPages().getCOSObject().setNeedToBeUpdated(true);
page.getCOSObject().setNeedToBeUpdated(true);
document.getDocumentCatalog().getCOSObject().setNeedToBeUpdated(true);
OutputStream os = new FileOutputStream(file);
document.saveIncremental(os);
document.close();
os.close();
}
Quando adiciono uma anotação usando-a em um documento não assinado, a anotação é adicionada e fica visível. No entanto, ao usá-lo em um documento assinado, a anotação não aparece.
Abri o arquivo pdf no bloco de notas ++ e descobri que a anotação parece ter sido adicionada desde que o encontrei, assim como o restante do código referente à anotação:
<<
/Type /Annot
/Subtype /Stamp
/Name /testing#20rubber#20stamp
/Contents (this is a test)
/F 196
/AP 29 0 R
/Rect [100.0 100.0 200.0 200.0]
>>
No entanto, ele não aparece quando abro o documento no Adobe Reader. Talvez isso tenha mais a ver com os fluxos de aparência do que com a própria anotação?