2013-04-18 79 views
1

我有一個PDF模板文件,我試圖用「MyDocument」的內容填充。所有的字段填充正常,但問題是我的PDF中的「計算」字段沒有刷新,也沒有在其他字段上設置格式。如何使計算的字段刷新和格式化以使用ITextSharp? (如果我得到一個C#或VB.NET回答我不在乎)如何刷新非計算字段上的格式並刷新可填寫PDF表單中的計算字段

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

根據此鏈接引用的2006年的帖子,這不支持http://stackoverflow.com/a/500999/231316。有可能在過去的7年中發生了一些變化,但我猜測並非如此。 –

+0

任何地方我可以找到更多關於這方面的信息? – Denis

+0

我會直接進入iText郵件列表。首先,搜索是否有更近的答案,然後詢問你是否找不到任何東西。 https://lists.sourceforge.net/lists/listinfo/itext-questions –

回答

3

所以我想通了如何做進去。 NET基於以下使用iText的文章(ITextSharp的java版本 - 該程序與.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來,這樣會將它格式化&計算「髒」的值:

我的代碼變成像下面這樣,因爲我只需要格式化數值,但可以擴展到處理其他類型(見下面的討論)。

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將調用(使用上面的代碼)你知道什麼類型的數據,所以你可以「髒」的數據。這裏有一些土坯數據類型,這是這些數據類型背後的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中的日期字段會更改日期格式。所以我必須使日期字段爲只讀才能使其工作。 – rizzz86

+0

如果該字段是Comb字符字段,則此解決方案不起作用。 – rizzz86

1

就我而言,我發現:

  1. 使用FormFlattening阻止javascript的更新該領域
  2. 使用SetField設置字段不會觸發格式。

所以我不得不改變JavaScript來寫實際的值,而不是隻是弄髒它。像這樣:

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

我每個字段的javascript代碼追加到字符串JS,然後我叫pdfStamper.Javascript = JS末。