如何刷新非计算字段上的格式并刷新可填写PDF表单中的计算字段

时间:2013-04-18 21:12:54

标签: c# vb.net itextsharp

我有一个PDF模板文件,我试图填充" MyDocument"的内容。所有的字段都很好,但问题是"计算"我的PDF中的字段不会刷新,也不会在其他字段上设置格式。如何使用ITextSharp使计算字段刷新和格式化? (我不在乎我是否得到C#或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

C#:

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();
    }
}

2 个答案:

答案 0 :(得分:3)

所以我基于以下文章使用iText(ITextSharp的java版本 - 这个过程与.net略有不同)想出了如何在.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”值,使其格式化&amp;计算:

我的代码变成了类似下面的内容,因为我只需要格式化数值,但可以扩展它以处理其他类型(请参阅下面的讨论)。

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();
    }

}

然后,如果您知道Adobe将调用的javascript脚本(使用上面的代码),您就知道数据的类型是什么,这样您就可以“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); 
                    } 
                } 
            } 
} 

答案 1 :(得分:1)

就我而言,我发现:

  1. 使用FormFlattening可防止javascript更新字段
  2. 使用SetField设置字段不会触发格式化。
  3. 所以我不得不改变javascript来实际写出完整的值而不是弄脏它。像这样:

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

    我将每个字段的javascript代码附加到字符串JS中,然后我在最后调用pdfStamper.Javascript = JS