Как обновить форматирование в неисчисляемых полях и обновить вычисляемые поля в заполняемой форме PDF

1

У меня есть файл в формате PDF, который я пытаюсь заполнить содержимым "MyDocument". Все поля заполняются нормально, но проблема в том, что поля "Вычисляемые" в моем PDF файле не обновляются, а также не форматируются в других полях. Как заставить обработанные поля обновлять и форматировать, используя ITextSharp? (Мне все равно, получаю ли я ответ на С# или VB.NET)

VB.NET:

  Public Shared Sub Serialize(ByVal stmt As MyDocument, ByVal file As FileInfo)
                    Dim reader As New PdfReader(TemplateFilePath.FullName)
                    Dim pdfStamper As New PdfStamper(reader, New FileStream(file.FullName, FileMode.Open))
                    Try
                        With itsDaDetailFields
                            .MoveFirst()
                            While Not .EOF
                                Dim pdfFieldName As String = NsT(Of String)(!PDFFieldName, Nothing)
                                If Not String.IsNullOrEmpty(pdfFieldName) Then
                                    Dim value As String = NsT(Of String)(stmt.GetValueFromPDFField(pdfFieldName), Nothing)
                                    If Not String.IsNullOrEmpty(value) Then
                                        pdfStamper.AcroFields.SetField(pdfFieldName, value)
                                    End If
                                End If
                                .MoveNext()
                            End While
                        End With

                    Finally
                        pdfStamper.FormFlattening = False
                        reader.Close()
                        pdfStamper.Close()
                    End Try
                End Sub

С#:

public static void Serialize(MyDocument stmt, FileInfo file)
{
    PdfReader reader = new PdfReader(TemplateFilePath.FullName);
    PdfStamper pdfStamper = new PdfStamper(reader, new FileStream(file.FullName, FileMode.Open));
    try {
        var _with1 = itsDaDetailFields;
        _with1.MoveFirst();
        while (!_with1.EOF) {
            string pdfFieldName = NsT<string>(_with1["PDFFieldName"], null);
            if (!string.IsNullOrEmpty(pdfFieldName)) {
                string value = NsT<string>(stmt.GetValueFromPDFField(pdfFieldName), null);
                if (!string.IsNullOrEmpty(value)) {
                    pdfStamper.AcroFields.SetField(pdfFieldName, value);
                }
            }
            _with1.MoveNext();
        }

    } finally {
        pdfStamper.FormFlattening = false;
        reader.Close();
        pdfStamper.Close();
    }
}
Теги:
itextsharp

2 ответа

3
Лучший ответ

Итак, я понял, как это сделать в .NET на основе следующего сообщения с помощью iText (java-версия ITextSharp - процедура немного отличается для .net). Не стесняйтесь прочитать следующий поток для полного объяснения и обсуждения той же проблемы в iText:

http://itext-general.2136553.n4.nabble.com/Setting-acroform-value-via-iText-messes-with-acrofield-formating-td2167101.html

Есть два способа сделать это:

(1) Укажите отображаемое значение, например:

pdfStamper.AcroFields.SetField(pdfFieldName, value, <formatted value>)

как в:

pdfStamper.AcroFields.SetField(pdfFieldName, 1000, "1,000")

Это не было оптимальным для меня, потому что я не мог вычислить программу из моего PDF файла, текстовые поля которого форматировали их содержимое в каком формате. У некоторых были несколько разные форматы (у некоторых было 2 десятичных разряда, у некоторых было 0, у некоторых было много), поэтому, если вы можете отслеживать, как текстовое поле форматирует свои данные или все они делают то же самое, тогда это может сработать. Это также не устранило проблему с вычисленными полями, а просто затруднило проблему форматирования.

(2) Предоставьте javascript для "DIRTY" значения, чтобы оно форматировалось и вычислялось:

Мой код превратился во что-то вроде следующего, поскольку мне нужно было только форматировать числовые значения, но это можно расширить, чтобы обрабатывать другие типы (см. обсуждение ниже).

Dim reader As New PdfReader(TemplateFilePath.FullName)
Dim pdfStamper As New PdfStamper(reader, New FileStream(file.FullName, FileMode.Open))

 With pdfStamper.AcroFields
     If IsNumeric(value) Then
        Dim js As String = String.Format("var f = this.getField('{0}'); f.value = 1 * f.value;", pdfFieldName)
        pdfStamper.JavaScript = js
     End If
     .SetField(pdfFieldName, value)
End With

reader.Close()
pdfStamper.Close()

Итак, фокус в том, что вам нужно использовать JavaScript, чтобы получить значение грязным, тогда Reader будет применять форматирование. Вы можете обобщить это больше и обрабатывать больше типов значений на основе полного решения, представленного ниже (извините, что оно находится в java, но может быть адаптировано к .net):

import java.io.IOException;
import java.util.ArrayList;

import com.lowagie.text.pdf.PRStream;
import com.lowagie.text.pdf.PdfDictionary;
import com.lowagie.text.pdf.PdfName;
import com.lowagie.text.pdf.PdfObject;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.PdfString;
import com.lowagie.text.pdf.AcroFields.Item;

public class AcroFieldJSScanner {

    protected ArrayList<String> functions = null;


    public void getFieldFunctions(Item item) throws IOException{

        PdfDictionary dict;

        for (int i = 0; i < item.size(); i++) {
            dict = item.getMerged(i);

            scanPdfDictionary(dict);

//          dict = item.getWidget(i);
//          
//          scanPdfDictionary(dict);
        }
    }

    protected void scanPdfDictionary(PdfDictionary dict) throws IOException{

        PdfObject objJS = null;
        String func = null;

        objJS = dict.get(PdfName.JS);
        if (dict.get(PdfName.S) != null &&  objJS != null && objJS.isString()){

            PdfString strJS = (PdfString)objJS;
            if (functions == null){
                functions = new ArrayList<String>();
            }

            func = strJS.toString();
            functions.add(func);
        }else if (dict.get(PdfName.S) != null &&  objJS != null){

            for(Object obj : dict.getKeys()){
                PdfName pdfName = (PdfName)obj;

                PdfObject pdfObj = dict.get(pdfName);

                if (pdfObj.isIndirect()){
                    PdfObject pdfIndirectObject = PdfReader.getPdfObject(pdfObj);

                    func = new String(PdfReader.getStreamBytes((PRStream)pdfIndirectObject));

                    if (functions == null){
                        functions = new ArrayList<String>();
                    }

                    functions.add(func);
                }else{
                    scanPdfObject(pdfObj);
                }

            }


        }else{
            for(Object obj : dict.getKeys()){
                PdfName pdfName = (PdfName)obj;

                PdfObject pdfObj = dict.get(pdfName);
                scanPdfObject(pdfObj);
            }
        }

    }

    protected void scanPdfObject(PdfObject parentPdfObject) throws IOException{

        if (parentPdfObject.isDictionary()){
            scanPdfDictionary((PdfDictionary)parentPdfObject);
        }else if (parentPdfObject.isIndirect()){
            PdfObject pdfObject = PdfReader.getPdfObject(parentPdfObject);
            scanPdfObject(pdfObject);
        }
    }

    public ArrayList<String> getFunctions() {
        return functions;
    }

    public String toString(){

        StringBuilder sb = null;

        if (getFunctions() != null){
            sb = new StringBuilder();

            for (int i =0; i< getFunctions().size();i++) {

                sb.append(getFunctions().get(i)).append("\n");      
            } 
        }else{
            return "No functions found";
        }

        return sb.toString();
    }

}

И тогда, если вы знаете сценарии javascript, которые будет вызывать Adobe (используя приведенный выше код), вы знаете, какой тип данных является таким, чтобы вы могли "DIRTY" данных. Ниже приведены некоторые типы данных adobe и javascript, которые находятся за этими типами данных:

public String getFieldFormat(Item item){ 

       PdfDictionary aa = (PdfDictionary) item.getMerged(0).get(PdfName.AA); 
        if (null != aa) 
            { 
                PdfDictionary f = (PdfDictionary)PdfReader.getPdfObject(aa.get(PdfName.F));
                 if (null != f) 
                { 
                    PdfString js = (PdfString)PdfReader.getPdfObject(f.get(PdfName.JS));
                     if (null != js) 
                    { 
                        String sScriptName = js.toString(); 
                        if (sScriptName.contains("AFNumber_Format")) 
                            System.out.println("Format : Number"); 
                        else if (sScriptName.contains("AFDate_Format")) 
                        System.out.println("Format : Date"); 
                        else if (sScriptName.contains("AFTime_Format")) 
                        System.out.println("Format : Time"); 
                        else if (sScriptName.contains("AFSpecial_Format")) 
                        System.out.println("Format : Special"); 
                        else if (sScriptName.contains("AFPercent_Format")) 
                        System.out.println("Format : Percent"); 
                        else 
                        System.out.println("Format : Custom");; 

                        System.out.println("JS: "); 
                        System.out.println(js); 
                    } 
                } 
            } 
} 
  • 0
    Я применил это решение к полю даты, и оно сработало. Одна проблема, с которой я столкнулся, заключается в том, что нажатие на поле даты в PDF снова меняет формат даты. Поэтому я должен сделать поле даты Только для чтения, чтобы оно работало.
  • 0
    Это решение не работает, если поле является символьным полем Comb.
1

В моем случае я узнал, что:

  • Использование FormFlattening не позволяет javascript обновлять поле
  • Установка поля с помощью SetField не приводит к форматированию.

Поэтому мне пришлось изменить javascript, чтобы на самом деле написать полное значение, а не просто загрязнять его. Например:

JS &= String.Format("var f = this.getField('{0}'); f.value = '{1}';",
                    FieldName.Key, NewFieldValue)

Я добавляю код javascript для каждого поля в строку JS, а затем я вызываю pdfStamper.Javascript = JS в конце.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню