Как добавить текстовое поле, если в ABCPDF уже есть существующее текстовое поле?

#c# #pdf #abcpdf

#c# #PDF #abcpdf

Вопрос:

Добавить текстовое поле с помощью ABCPDF довольно просто:

 public FormField AddTextField(string inRect, string inName, string inText)
{
    int fieldId = mDoc.AddObject("<</Type /Annot /Subtype /Widget /F 4 /FT /Tx /Ff 4096 /Q 1>>");
    mDoc.SetInfo(fieldId, "/V:Text", inText);
    RegisterField(fieldId, inName, inRect);
    return new FormField(fieldId, mDoc);
}
  

С этим в качестве реализации:

 FormField text = AddTextField("40 530 300 580", "TextField1", "Hello World!");
text.DefaultAppearance = "/TimesRoman 36 Tf 0 0 1 rg";
text.BorderColor = "0 0 0";
text.FillColor = "220 220 220";
text.TextAlign = "Left";
  

Если мне нужно добавить два поля с одинаковыми именами, это немного сложнее:

 public int AddGroupField(FormField[] inKids, string inName, string inValue)
{
    if (inKids.Length == 0)
        throw new Exception("Cannot have a group field with no kids");
    string ft = null, dv = null;
    int fieldId = mDoc.AddObject("<< /Kids [] >>");
    foreach (FormField kid in inKids)
    {
        mDoc.SetInfo(fieldId, "/Kids[]:Ref", kid.Id.ToString());
        mDoc.SetInfo(kid.Id, "/Parent:Ref", fieldId);
        if (ft == null)
            ft = mDoc.GetInfo(kid.Id, "/FT");
        if (dv == null)
            dv = mDoc.GetInfo(kid.Id, "/DV");
        mDoc.SetInfo(kid.Id, "/FT:Del", "");
        mDoc.SetInfo(kid.Id, "/V:Del", "");
        mDoc.SetInfo(kid.Id, "/DV:Del", "");
    }
    mDoc.SetInfo(fieldId, "/FT", ft);
    mDoc.SetInfo(fieldId, "/T:Text", inName);
    mDoc.SetInfo(fieldId, "/V:Text", inValue);
    if (dv != null)
        mDoc.SetInfo(fieldId, "/DV:Text", dv);
    int eid = mDoc.GetInfoInt(mDoc.Root, "/AcroForm:Ref");
    mDoc.SetInfo(eid, "/Fields*[]:Ref", fieldId);
    return fieldId;
}
  

С этим в качестве реализации:

 FormField[] kids = new FormField[2];
kids[0] = AddTextField("40 230 300 280", null, null);
kids[1] = AddTextField("40 170 300 220", null, null);
int id = AddGroupField(kids, "TextField1", "Hello World!");
  

Однако у меня возникают проблемы с добавлением текстового поля в PDF, где текстовое поле уже существует с тем же именем. Итак, например, если в моем PDF-файле уже есть поле с именем «TextField1», а затем я хочу добавить другое поле с тем же именем, ни одна из вышеуказанных реализаций не будет работать.

Комментарии:

1. Вы можете просмотреть документ с дублированными полями, а затем попытаться создать его заново.

2. Да, я собирался попробовать просмотреть фрагменты PDF, а затем отредактировать их. Ваша идея звучит на один уровень лучше, чем это. 🙂

3. Ну, если кто-то знает, как это должно выглядеть, это документ, если он создан правильно…

Ответ №1:

Я смог получить ответ от службы поддержки ABCPDF. И, как вы можете видеть, это не совсем простой процесс. Я не уверен, что кто-нибудь мог бы просто разобраться в этом самостоятельно, не тратя месяцы на исследования спецификации PDF и продукта ABCPDF.

 public FormField AddTextField(string inRect, string inName, string inText)
{
    bool fieldAlreadyExists = mDoc.Form[inName] != null;

    int fieldId = mDoc.AddObject("<</Type /Annot /Subtype /Widget /F 4 /FT /Tx /Ff 4096 /Q 1>>");
    mDoc.SetInfo(fieldId, "/V:Text", inText);
    RegisterField(fieldId, inName, inRect);
    var field = new FormField(fieldId, mDoc);

    if (fieldAlreadyExists)
    {
        InteractiveForm form = new InteractiveForm(mDoc);
        form.AddFieldIntoExistingGroup(field, true);
    }

    return field;
}


private bool AddFieldIntoExistingGroup(FormField field, bool refreshForm)
{
    bool duplicatesFound = false;
    int acroFormID = mDoc.GetInfoInt(mDoc.Root, "/AcroForm:Ref");
    int parentID = mDoc.GetInfoInt(field.Id, "/Parent:Ref");
    ArrayAtom kids;
    if (parentID > 0)
    {
        kids = mDoc.ObjectSoup.Catalog.Resolve(Atom.GetItem(mDoc.ObjectSoup[parentID].Atom, "Kids")) as ArrayAtom;
    }
    else
    {
        kids = mDoc.ObjectSoup.Catalog.Resolve(Atom.GetItem(mDoc.ObjectSoup[acroFormID].Atom, "Fields")) as ArrayAtom;
    }
    Dictionary<string, List<IndirectObject>> items = new Dictionary<string, List<IndirectObject>>();
    for (int i = 0; i < kids.Count; i  )
    {
        IndirectObject io = mDoc.ObjectSoup.Catalog.ResolveObj(kids[i]);
        if (io == null)
        {
            continue; // shouldn't really happen
        }
        string name = mDoc.GetInfo(io.ID, "/T:Text");
        if (!items.ContainsKey(name))
        {
            items[name] = new List<IndirectObject>();
        }
        items[name].Add(io);
    }
    foreach (KeyValuePair<string, List<IndirectObject>> pair in items)
    {
        if (pair.Value.Count > 1)
        {
            duplicatesFound = true;
            // shift field down to be a child of a new field node
            int id = mDoc.AddObject("<< >>");
            if (parentID > 0)
            {
                mDoc.SetInfo(parentID, "/Kids[]:Ref", id);
                mDoc.SetInfo(id, "/Parent:Ref", parentID);
            }
            else
            {
                mDoc.SetInfo(acroFormID, "/Fields[]:Ref", id);
            }
            string[] dictEntries = new[] { "/FT", "/T", "/TU", "/Ff", "/V", "/DV" };
            foreach (IndirectObject io in pair.Value)
            {
                foreach (string dictEntry in dictEntries)
                {
                    string val = mDoc.GetInfo(io.ID, dictEntry);
                    if (!string.IsNullOrEmpty(val))
                    {
                        mDoc.SetInfo(id, dictEntry, val);
                        mDoc.SetInfo(io.ID, dictEntry   ":Del", "");
                    }
                }
                ArrayRemoveOneRefAtom(kids, io.ID);
                mDoc.SetInfo(id, "/Kids[]:Ref", io.ID);
                mDoc.SetInfo(io.ID, "/Parent:Ref", id);
            }
        }
    }
    if ((refreshForm) amp;amp; (duplicatesFound))
    {
        mDoc.Form.Refresh();
    }
    return duplicatesFound;
}

private static bool ArrayRemoveOneRefAtom(ArrayAtom array, int id)
{
    if (array != null)
    {
        for (int i = 0; i < array.Count; i  )
        {
            RefAtom refAtom = array[i] as RefAtom;
            if ((refAtom != null) amp;amp; (refAtom.ID == id))
            {
                ArrayRemoveAt(array, i);
                return true;
            }
        }
    }
    return false;
}

private static void ArrayRemoveAt(ArrayAtom array, int index)
{
    if (index == 0)
    { // Workaround for bug in some versions of ABCpdf
        Atom[] copy = new Atom[array.Count];
        array.CopyTo(copy, 0);
        array.Clear();
        for (int i = 1; i < copy.Length; i  )
            array.Add(copy[i]);
    }
    else
    {
        array.RemoveAt(index);
    }
}