2

这似乎是一件应该很快做的事情,但在实践中似乎存在问题。我有一堆包含表单域和嵌入式 javascript 的 PDF 表单。我想安全地删除 javascript 代码,但保留 PDF 表单字段不变。

到目前为止,我已经找到了很多解决方案,但是所有解决方案要么消除了 javascript 和表单字段,要么都保持原样。

这是解决方案A;它复制表单字段和javascript:

var pdfReader = new PdfReader(infilename);
using (MemoryStream memoryStream = new MemoryStream()) {
    PdfCopyFields copy = new PdfCopyFields(memoryStream);
    copy.AddDocument(pdfReader);
    copy.Close();
    File.WriteAllBytes(rawfilename, memoryStream.ToArray());
}

或者,我有解决方案 B,它去掉了表单字段和 javascript:

Document document = new Document();
using (MemoryStream memoryStream = new MemoryStream()) {
    PdfWriter writer = PdfWriter.GetInstance(document, memoryStream);
    document.Open();
    document.AddDocListener(writer);
    for (int p = 1; p <= pdfReader.NumberOfPages; p++) {
        document.SetPageSize(pdfReader.GetPageSize(p));
        document.NewPage();
        PdfContentByte cb = writer.DirectContent;
        PdfImportedPage pageImport = writer.GetImportedPage(pdfReader, p);
        int rot = pdfReader.GetPageRotation(p);
        if (rot == 90 || rot == 270) {
            cb.AddTemplate(pageImport, 0, -1.0F, 1.0F, 0, 0, pdfReader.GetPageSizeWithRotation(p).Height);
        } else {
            cb.AddTemplate(pageImport, 1.0F, 0, 0, 1.0F, 0, 0);
        }
    }
    document.Close();
    File.WriteAllBytes(rawfile, memoryStream.ToArray());
}

有谁知道如何修改解决方案 A 或 B 以消除 javascript 但保留表单字段?

编辑:解决方案代码在这里!

using (MemoryStream memoryStream = new MemoryStream()) {
    PdfStamper stamper = new PdfStamper(pdfReader, memoryStream);
    for (int i = 0; i <= pdfReader.XrefSize; i++) {
        object o = pdfReader.GetPdfObject(i);
        PdfDictionary pd = o as PdfDictionary;
        if (pd != null) {
            pd.Remove(PdfName.AA);
            pd.Remove(PdfName.JS);
            pd.Remove(PdfName.JAVASCRIPT);
        }
    }
    stamper.Close();
    pdfReader.Close();
    File.WriteAllBytes(rawfile, memoryStream.ToArray());
}
4

2 回答 2

4

要操作单个 PDF,您应该使用该类PdfStamper并操作其内容,在您的情况下迭代现有表单字段并删除 JavaScript 条目。

iTextSharp 示例AddJavaScriptToForm.cs对应于iText in Action — 第 2 版的第 13 章中的AddJavaScriptToForm.java ,展示了如何将 JavaScript 操作添加到字段,中心代码为:

PdfStamper stamper = new PdfStamper(reader, ms);

AcroFields form = stamper.AcroFields;
AcroFields.Item fd = form.GetFieldItem("married");

PdfDictionary dictYes = (PdfDictionary) PdfReader.GetPdfObject(fd.GetWidgetRef(0));
PdfDictionary yesAction = ...;
dictYes.Put(PdfName.AA, yesAction);

因此,要删除此类 JavaScript 表单字段操作,您必须遍历所有这些 PDF 表单字段并删除相关字典中的/AA值:

dictXXX.Remove(PdfName.AA);

编辑:( 由 Ted Spence 提供)这是成功删除 javascript 同时保持所有表单字段完整的最终代码:

using (MemoryStream memoryStream = new MemoryStream())
{
    PdfStamper stamper = new PdfStamper(pdfReader, memoryStream);
    for (int i = 0; i <= pdfReader.XrefSize; i++)
    {
        PdfDictionary pd = pdfReader.GetPdfObject(i) as PdfDictionary;
        if (pd != null)
        {
            pd.Remove(PdfName.AA); // Removes automatic execution objects
            pd.Remove(PdfName.JS); // Removes javascript objects
            pd.Remove(PdfName.JAVASCRIPT); // Removes other javascript objects
        }
    }
    stamper.Close();
    pdfReader.Close();
    File.WriteAllBytes(rawfile, memoryStream.ToArray());
}

编辑:( 通过 mkl)上面的解决方案有点过头了,因为它触及了每一个间接字典对象。另一方面,它忽略了内联字典(不过,我还没有检查规范;也许所有/AA/JS/JAVASCRIPT条目只出现在必须是间接对象的字典中,或者至少被此代码)。

如果完成这项任务是我的工作,我会尝试更具体地访问可能携带 JavaScript 的对象。

但是,这种超额完成过程的优点可能是,即使是 PDF 对象也被检查,这些对象当前未指定为携带 JavaScript,但将在以后的 PDF 版本中。

于 2013-05-07T08:45:38.857 回答
0

在 for 循环之后添加以下行以保留 AcroForm:

var form = pdfReader.AcroForm;
if (form != null)
   writer.CopyAcroForm(reader);
于 2013-05-07T03:55:20.737 回答