1

我有一个 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();
    }
}
4

2 回答 2

4

因此,我根据使用 iText 的以下帖子(Java 版本的 ITextSharp - .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”值,以便对其进行格式化和计算:

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

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

}

然后,如果您知道 Adob​​e 将调用的 javascript 脚本(使用上面的代码),您就知道数据是什么类型,因此您可以“弄脏”数据。以下是一些 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); 
                    } 
                } 
            } 
} 
于 2013-06-03T18:46:59.550 回答
1

就我而言,我发现:

  1. 使用 FormFlatning 可以防止 javascript 更新字段
  2. 使用 SetField 设置字段不会触发格式化。

所以我不得不更改 javascript 以实际编写完整的值,而不是仅仅弄脏它。像这样:

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

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

于 2014-01-21T20:15:57.707 回答