【问题标题】:Flattening PDF without /AcroForm fields with /Annot Widget使用 /Annot Widget 展平不带 /AcroForm 字段的 PDF
【发布时间】:2016-11-10 14:18:27
【问题描述】:

我正在努力使用 iTextSharp 5.5.10 进行展平。此代码代表了按照 SO 和 Google 搜索中找到的代码拼合此 PDF 的各种努力。

void Process()
{
    PdfReader reader = new PdfReader(mInFileName);
    // 1 type of fields
    AcroFields formFields = reader.AcroFields;
    int countAcroFields = formFields.Fields.Count;
    // 2 another type of fields
    PRAcroForm form = reader.AcroForm;
    List<PRAcroForm.FieldInformation> fieldList = form.Fields;
    // 3 i think this is the same as 2
    PdfDictionary acroForm = reader.Catalog.GetAsDict(PdfName.ACROFORM);
    PdfArray acroFields = (PdfArray)PdfReader.GetPdfObject(acroForm.Get(PdfName.FIELDS), acroForm);
    // 4 another type of fields
    XfaForm xfaForm = formFields.Xfa;
    bool flatten = false;

    if (countAcroFields > 0)
    {
        //No fields found
    }
    else if (fieldList.Count > 0)
    {
        //No fields found
    }
    else if (xfaForm.XfaPresent == true)
    {
        //No xfaForms found
        ReadXfa(reader);
    }
    else
    {
        // Yes, there are annotations and this code extracts them but does NOT flatten them
        PdfDictionary page = reader.GetPageN(1);
        PdfArray annotsArray = page.GetAsArray(PdfName.ANNOTS);
        if ( annotsArray == null)
            return;
        else
        {
            List<string> namedFieldToFlatten = new List<string>();
            foreach (var item in annotsArray)
            {
                var annot = (PdfDictionary)PdfReader.GetPdfObject(item);

                var type = PdfReader.GetPdfObject(annot.Get(PdfName.TYPE)).ToString(); //Expecting be /Annot
                var subtype = PdfReader.GetPdfObject(annot.Get(PdfName.SUBTYPE)).ToString(); //Expecting be /Widget
                var fieldType = PdfReader.GetPdfObject(annot.Get(PdfName.FT)).ToString(); //Expecting be /Tx

                if (annot.Get(PdfName.TYPE).Equals(PdfName.ANNOT) &&
                    annot.Get(PdfName.SUBTYPE).Equals(PdfName.WIDGET))
                {
                    if (annot.Get(PdfName.FT).Equals(PdfName.TX))
                    {
                        flatten = true;
                        var textLabel = PdfReader.GetPdfObject(annot.Get(PdfName.T)).ToString(); //Name of textbox field
                        namedFieldToFlatten.Add(textLabel);
                        var fieldValue = PdfReader.GetPdfObject(annot.Get(PdfName.V)).ToString(); //Value of textbox
                        Console.WriteLine($"Found Label={textLabel} Value={fieldValue}");
                    }
                }
            }

            if (flatten == true)
            {
                // Flatten the PDF [11/9/2016 15:10:06]
                string foldername = Path.GetDirectoryName(mInFileName);
                string basename = Path.GetFileNameWithoutExtension(mInFileName);
                string outName = $"{foldername}\\{basename}_flat.pdf";
                using (var fStream = new FileStream(outName, FileMode.Create))
                {
                    //This totally removes the fields instead of flattening them
                    var stamper = new PdfStamper(reader, fStream) { FormFlattening = true, FreeTextFlattening = true, AnnotationFlattening = true };
                    var stamperForm = stamper.AcroFields;
                    stamperForm.GenerateAppearances = true;
                    foreach (var item in namedFieldToFlatten)
                    {
                        stamper.PartialFormFlattening(item);
                    }
                    stamper.Close();
                    reader.Close();
                }
            }
        }
    }
}

关于如何在 Acrobat 中将“字段”转换为文本的任何提示?

This 是我要拼合的 PDF。

This 是这段代码的输出。

【问题讨论】:

    标签: c# pdf itext


    【解决方案1】:

    问题是您的表单已损坏。它确实有/Annots,并且这些注释是widget annotations,它们也有条目是字段字典中的条目,但PDF中没有表格.或者更确切地说:有一个表单,但是/Fields 数组是空的。

    由于/Fields 数组为空,因此没有要展平的字段。小部件注释已删除,您看不到任何内容。这不是 iText 错误:您需要在填写之前修复表单。

    在 Java 中,您可以像这样修复表单:

    PdfReader reader = new PdfReader(src);
    PdfDictionary root = reader.getCatalog();
    PdfDictionary form = root.getAsDict(PdfName.ACROFORM);
    PdfArray fields = form.getAsArray(PdfName.FIELDS);
    
    PdfDictionary page;
    PdfArray annots;
    for (int i = 1; i <= reader.getNumberOfPages(); i++) {
        page = reader.getPageN(i);
        annots = page.getAsArray(PdfName.ANNOTS);
        for (int j = 0; j < annots.size(); j++) {
            fields.add(annots.getAsIndirectObject(j));
        }
    }
    PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
    stamper.close();
    reader.close();
    

    将它移植到 C# 应该相当容易。我不是 C# 开发人员,但这是一个(未经测试的)移植尝试:

    PdfReader reader = new PdfReader(src);
    PdfDictionary root = reader.Catalog;
    PdfDictionary form = root.GetAsDict(PdfName.ACROFORM);
    PdfArray fields = form.GetAsArray(PdfName.FIELDS);
    PdfDictionary page;
    PdfArray annots;
    for (int i = 1; i <= reader.NumberOfPages; i++) {
        page = reader.GetPageN(i);
        annots = page.GetAsArray(PdfName.ANNOTS);
        for (int j = 0; j < annots.Size; j++) {
            fields.Add(annots.GetAsIndirectObject(j));
        }
    }
    PdfStamper stamper = new PdfStamper(reader, new FileStream(dest, FileMode.Create));
    stamper.Close();
    reader.Close();
    

    一旦你像这样修复了表单,你就可以正确地展平它了。

    【讨论】:

    • 谢谢布鲁诺。这行得通。如果我可以问一个后续问题,是否有一种简单的方法来检测像这样的“损坏”表单?还是我只需要检查现有代码的输出以使用 /Widgets 检查 0 字段?
    • 是的,没有 /AcroForm 对象或空的 /Fields 数组,而有与页面关联的 /Widget 类型的 /Annots 表明表单没有正确创建。
    猜你喜欢
    • 2019-08-29
    • 1970-01-01
    • 2013-12-29
    • 1970-01-01
    • 2019-08-06
    • 1970-01-01
    • 1970-01-01
    • 2021-12-22
    • 1970-01-01
    相关资源
    最近更新 更多