我有一些C#代码从pdf文件中提取所有附件。它工作得很好,即使它是附加文档级别或文件注释。
但是,如果我对这些pdf文件进行数字签名(和时间戳),附件的类型会从注释(或文件附件)更改为“小部件”或其他内容。我不是pdf专家,如果pdf签名,我找不到任何提取附件的方法。
任何帮助表示赞赏!
[编辑]
没有签名的示例:samplepdf_notsigned.pdf
带签名的示例(使用SetaPDF-Signer API签名):samplepdf_signed.pdf
代码块如下:
/*
* annotations
*/
iTextSharp.text.pdf.PdfReader reader = new iTextSharp.text.pdf.PdfReader("samplepdf_annotations.pdf");
for (int i = 1; i <= reader.NumberOfPages; i++)
{
iTextSharp.text.pdf.PdfArray array = reader.GetPageN(i).GetAsArray(iTextSharp.text.pdf.PdfName.ANNOTS);
if (array == null) continue;
for (int j = 0; j < array.Size; j++)
{
iTextSharp.text.pdf.PdfDictionary annot = array.GetAsDict(j);
if (iTextSharp.text.pdf.PdfName.FILEATTACHMENT.Equals(annot.GetAsName(iTextSharp.text.pdf.PdfName.SUBTYPE)))
{
iTextSharp.text.pdf.PdfDictionary fs = annot.GetAsDict(iTextSharp.text.pdf.PdfName.FS);
iTextSharp.text.pdf.PdfDictionary refs = fs.GetAsDict(iTextSharp.text.pdf.PdfName.EF);
foreach (iTextSharp.text.pdf.PdfName name in refs.Keys)
{
// I CAN GET THE ATTACHMENT HERE
string filename = fs.GetAsString(name).ToString();
byte[] binary = iTextSharp.text.pdf.PdfReader.GetStreamBytes((iTextSharp.text.pdf.PRStream)refs.GetAsStream(name));
}
}
else
{
iTextSharp.text.pdf.PdfDictionary fs = annot.GetAsDict(iTextSharp.text.pdf.PdfName.FS);
iTextSharp.text.pdf.PdfDictionary refs = fs.GetAsDict(iTextSharp.text.pdf.PdfName.EF);
foreach (iTextSharp.text.pdf.PdfName name in refs.Keys)
{
// I CAN GET THE ATTACHMENT HERE
string filename = fs.GetAsString(name).ToString();
byte[] binary = iTextSharp.text.pdf.PdfReader.GetStreamBytes((iTextSharp.text.pdf.PRStream)refs.GetAsStream(name));
}
}
}
}
/*
* embedded level
*/
iTextSharp.text.pdf.PdfReader reader = new iTextSharp.text.pdf.PdfReader("samplepdf_embedded.pdf");
iTextSharp.text.pdf.PdfDictionary root = reader.Catalog;
iTextSharp.text.pdf.PdfDictionary documentnames = root.GetAsDict(iTextSharp.text.pdf.PdfName.NAMES);
iTextSharp.text.pdf.PdfDictionary embeddedfiles = documentnames.GetAsDict(iTextSharp.text.pdf.PdfName.EMBEDDEDFILES);
iTextSharp.text.pdf.PdfArray filespecs = embeddedfiles.GetAsArray(iTextSharp.text.pdf.PdfName.NAMES);
for (int i = 0; i < filespecs.Size; ) {
filespecs.GetAsString(i++);
iTextSharp.text.pdf.PdfDictionary filespec = filespecs.GetAsDict(i++);
iTextSharp.text.pdf.PdfDictionary refs = filespec.GetAsDict(iTextSharp.text.pdf.PdfName.EF);
foreach (iTextSharp.text.pdf.PdfName key in refs.Keys)
{
iTextSharp.text.pdf.PRStream stream = (iTextSharp.text.pdf.PRStream)iTextSharp.text.pdf.PdfReader.GetPdfObject(refs.GetAsIndirectObject(key));
// I CAN GET THE ATTACHMENT HERE
string filename = filespec.GetAsString(key).ToString();
byte[] binary = iTextSharp.text.pdf.PdfReader.GetStreamBytes(stream);
}
}
答案 0 :(得分:0)
我认为问题出在你的顶级代码块中,它试图找到文件附件注释。在其内部循环(检查每个注释)中,您有一个构造:
if (iTextSharp.text.pdf.PdfName.FILEATTACHMENT.Equals(annot.GetAsName(iTextSharp.text.pdf.PdfName.SUBTYPE)))
{
[...block 1...]
}
else
{
[...block 2...]
}
这里第1和第2块是相同的,即你在任何情况下执行代码,既用于 文件附件的注释,也用于不是的注释。< / p>
只要PDF中的唯一注释是文件附件,这无关紧要,但只要有另一个注释,该块中的代码就可以了
iTextSharp.text.pdf.PdfDictionary fs = annot.GetAsDict(iTextSharp.text.pdf.PdfName.FS);
iTextSharp.text.pdf.PdfDictionary refs = fs.GetAsDict(iTextSharp.text.pdf.PdfName.EF);
foreach (iTextSharp.text.pdf.PdfName name in refs.Keys)
{
// I CAN GET THE ATTACHMENT HERE
string filename = fs.GetAsString(name).ToString();
byte[] binary = iTextSharp.text.pdf.PdfReader.GetStreamBytes((iTextSharp.text.pdf.PRStream)refs.GetAsStream(name));
}
由于大多数其他注释类型没有 / EF 条目,因此很可能会在您的脸上爆炸,因此refs
为null
且refs.Keys
给出上升为例外。
不幸的是,集成的PDF签名是表单字段,即使不可见,也可以作为注释附加到某些页面。因此,签署PDF会在块2中弹出陷阱。
问题出现了为什么你无论如何都试图在Block 2中提取附件。根据PDF规范,文件附件注释必须包含if
查找的类型信息。因此,没有符合规范的PDF将使您的代码进入文件附件注释的块2。因此,您只需删除该块2。