發表於 程式分享

使用word功能變數,convert word to pdf,並解決中文顯示問題

使用xdocreport套件:https://github.com/opensagres/xdocreport

1.word / Ctrl + F9 => 編輯功能變數 => 設定"Merge Field",欄位名稱請加$

1.PNG1.PNG

2.程式碼

import java.awt.Color;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.poi.xwpf.converter.pdf.PdfOptions;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Font;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.PdfCopy;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.PdfWriter;
import fr.opensagres.xdocreport.converter.ConverterTypeTo;
import fr.opensagres.xdocreport.converter.ConverterTypeVia;
import fr.opensagres.xdocreport.converter.Options;
import fr.opensagres.xdocreport.core.XDocReportException;
import fr.opensagres.xdocreport.document.IXDocReport;
import fr.opensagres.xdocreport.document.registry.XDocReportRegistry;
import fr.opensagres.xdocreport.itext.extension.font.ITextFontRegistry;
import fr.opensagres.xdocreport.samples.docxandvelocity.model.Project;
import fr.opensagres.xdocreport.template.IContext;
import fr.opensagres.xdocreport.template.TemplateEngineKind;

public class Convert2PDF {
    public static void main(String[] args) throws DocumentException {
        try {             
              InputStream in = new FileInputStream(new File("A.docx"));
              IXDocReport report = XDocReportRegistry.getRegistry().loadReport(in, TemplateEngineKind.Velocity);
              IContext context = report.createContext();
              Project project = new Project("測試XDocReport");
              context.put("project", project);
              //功能變數替換
              context.put("fieldName1", "-1.FieldFirst中文");
              context.put("titleName2", "-2.中文MergeTitleTwo");
              context.put("parameter1", "-3.row1,value3");
              context.put("parameter2", "-4.row2,value1");
              context.put("parameter3", "-5.red,row3,value2");
             
              OutputStream out = new FileOutputStream(new File("A_Out.pdf"));
              PdfOptions pdfOptions = PdfOptions.create();
              pdfOptions.fontProvider( new ITextFontRegistry()
              {
                  public Font getFont( String familyName, String encoding, float size, int style, Color color )
                  {
                      try
                      {
                          BaseFont bfChinese =
                              BaseFont.createFont( "font/kaiu.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED );
                          Font fontChinese = new Font( bfChinese, size, style, color );
                          if ( familyName != null )
                              fontChinese.setFamily( familyName );
                          return fontChinese;
                      }
                      catch ( Throwable e )
                      {
                          e.printStackTrace();
                          // An error occurs, use the default font provider.
                          return ITextFontRegistry.getRegistry().getFont( familyName, encoding, size, style, color );
                      }
                  }
    
              } );
              
              Options options = Options.getTo(ConverterTypeTo.PDF).via(ConverterTypeVia.XWPF).subOptions(pdfOptions);
              report.convert(context, options, out);
             
              //加密            
              Document pdfDocument = new Document();
              PdfCopy pdfCopy = new PdfCopy(pdfDocument, new FileOutputStream("A_Out2.pdf"));
              String pwd = "testpwd";
              pdfCopy.setEncryption(pwd.getBytes(), pwd.getBytes(), 0,
                        PdfWriter.ENCRYPTION_AES_128);
              
              PdfReader pdfReader = new PdfReader("A_Out.pdf");
              int numberPage = pdfReader.getNumberOfPages();
              pdfDocument.open();
              for (int iPage = 1; iPage <= numberPage; iPage++) {
                  pdfCopy.addPage(pdfCopy.getImportedPage(pdfReader, iPage));
              }
              pdfDocument.close();
         } catch (IOException e) {
             e.printStackTrace();
         } catch (XDocReportException e) {
             e.printStackTrace();
         }
    }
}

3.執行後結果:開啟"A_Out2.pdf"

1) 顯示輸入密碼

1.PNG

2) 顯示內容

1

補充:pdf檔案加密,需於執行此程式時,請下載 bcprov-jdk16-146.jar (http://www.java2s.com/Code/Jar/b/Downloadbcprovjdk16146jar.htm),
執行時classpath加上bcprov-jdk16-146.jar

補充說明:我使用的xdocReport是使用iText2,原本是要用iText7開發套表成pdf檔,但需購買pdf writer,且iText7/iText5應該需要購買商業版權,關於iText license說明如下-https://zh.wikipedia.org/wiki/IText說明請參考:

iTextSharp 4.1.6/iText 4.2.0之前的版本是在MPLLGPL許可證下分發的,
允許用戶在閉源軟體專案中使用。
2009年底,iText第5版發布,其許可證被更換為Affero通用公共許可證第3版。 
那些不願意提供其原始碼的專案,可以購買iText第5版的商業許可,
或沒有任何變化的繼續使用iText的以前版本(其許可證更寬鬆)。
然而,開發商Bruno Lowagie警告說,
第5版之前的版本可能包含非LGPL授權的代碼,
因而以前版本的閉源專案的用戶可能需要為侵犯版權負責。
雖然AGPL庫可以連結到GPL的程式,但AGPL許可證與GPL許可證不相容。
發表於 程式分享

使用iText將多個pdf檔合併成一個pdf檔

範例如下,請參考:

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfSmartCopy;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Map;

public class mergePDF {
    public static void main(String args[]) throws IOException, DocumentException {
        //merge
        String[] files = {"filled_out_job_application.pdf", "replace_stream.pdf"};
        mergeFiles(files, "a.pdf", true);
        mergeFiles(files, "b.pdf", false);
    }

    public void mergeFiles(String[] files, String result, boolean smart) throws IOException, DocumentException {
        Document document = new Document();
        PdfCopy copy;
        if (smart)
            copy = new PdfSmartCopy(document, new FileOutputStream(result));
        else
            copy = new PdfCopy(document, new FileOutputStream(result));
        document.open();

        com.itextpdf.text.pdf.PdfReader[] reader = new com.itextpdf.text.pdf.PdfReader[3];
        for (int i = 0; i < files.length; i++) {
            reader[i] = new com.itextpdf.text.pdf.PdfReader(files[i]);
            copy.addDocument(reader[i]);
            copy.freeReader(reader[i]);
            reader[i].close();
        }
        document.close();
    }
}
發表於 程式分享

使用iText套表產生新的pdf檔~一併解決中文字顯示issue

1.先使用Adobe Acrobat Pro DC 產生 Field Properties(Edit PDF => Prepare Form)

1.PNG

2.下載iText7

http://developers.itextpdf.com/itext-7-java

3.程式如下

import com.itextpdf.forms.PdfAcroForm;
import com.itextpdf.forms.fields.PdfFormField;
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.kernel.color.Color;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.pdf.*;

ublic class testPDF { 
    public static final String SRC = "pdf/src/subscribe.pdf";
    public static final String DEST = "pdf/dest/subscribe_result.pdf";
 
    public static void main(String args[]) throws IOException {
        new testPDF().manipulatePdf(SRC, DEST);
    }
 
    public void manipulatePdf(String src, String dest) throws IOException {
        //Initialize PDF document
        PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(dest)); 
 
        PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true);
        Map<String, PdfFormField> fields = form.getFormFields();
        //中文字issue 
        PdfFont font = PdfFontFactory.createFont("font/kaiu.ttf", PdfEncodings.IDENTITY_H, true);
        fields.get("personal.name").setFont(font); 
        fields.get("personal.loginname").setFont(font);
        fields.get("personal.password").setFont(font);
        fields.get("personal.reason").setFont(font);
        
        fields.get("personal.name").setValue("測試名字").setBackgroundColor(Color.ORANGE);
        fields.get("personal.loginname").setValue("NickName").setBackgroundColor(Color.WHITE);
        fields.get("personal.password").setValue("a12345678").setBackgroundColor(Color.WHITE);
        fields.get("personal.reason").setValue("原因是...").setBackgroundColor(Color.WHITE);
        
        form.flattenFields();
        pdfDoc.close();
    }
}

4.執行後產生之PDF如下圖

2.PNG

5.若使用iText5,中文字的處理如下範例

        PdfReader reader = new PdfReader(src);
        PdfStamper stamper = new PdfStamper(reader,
                new FileOutputStream(dest));
        
        AcroFields fields = stamper.getAcroFields();
        //中文字處理
        BaseFont font = BaseFont.createFont("font/kaiu.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED );
        fields.setFieldProperty("name","textfont",font,null);        
        fields.setField("name", "ROC 台灣");

        stamper.setFormFlattening(true);
        stamper.close();
        reader.close();
發表於 程式分享

jquery bootstrapValidator如何驗證2個欄位只輸入其一即可

期望的畫面如下

1
畫面的html如下

1

 

1.jquery bootstrapValidator如何驗證2個欄位只輸入其一即可

    //被授權人
    $('#rowAddAuthForm').bootstrapValidator({
        excluded: [':disabled'],
        fields: {
            telNo: {
                group: '.col-md-3',
                validators: {
                    callback: {
                        callback: function(value, validator, $field) {
                            var field_name = $($field).attr('name');
                            if (value.length == 0 && $('#mobileNo_auth').val() == '') {
                                return {
                                    valid: false,
                                    message: '連絡電話、手機請至少輸入其一'
                                }
                            }
                            
                            if ($('#mobileNo_auth').val() == '') {
                                $('#rowAddAuthForm').bootstrapValidator('resetField', 'mobileNo' )
                                     .bootstrapValidator('updateStatus', 'mobileNo', 'VALID');
                                $('#rowAddAuthForm').bootstrapValidator('disableSubmitButtons', false);
                            }
                            
                            $('#rowAddCommForm').data('bootstrapValidator').resetForm(true);
                            if (value.length != 0) {
                                var pattern = /^[0-9]+$/;        
                                if (value.length  8) {
                                    return {
                                        valid: false,
                                        message: '電話 長度需為6~8'
                                    }
                                } else if (pattern.test(value) == false) {
                                    return {
                                        valid: false,
                                        message: '電話 請輸入數字'
                                    }
                                } else {
                                    return true;
                                }                                
                            } else {
                                $('#rowAddAuthForm').bootstrapValidator('resetField', field_name )
                                     .bootstrapValidator('updateStatus', field_name, 'NOT_VALIDATED');
                                $('#rowAddAuthForm').bootstrapValidator('disableSubmitButtons', false);
                                return true;
                            }
                        }
                    }
                }
            },
            mobileNo: {
                group: '.col-md-3',
                validators: {
                    callback: {
                        callback: function(value, validator, $field) {
                            var field_name = $($field).attr('name');
                            if (value.length == 0 && $('#telNo_auth').val() == '') {
                                return {
                                    valid: false,
                                    message: '連絡電話、手機請至少輸入其一'
                                }
                            }
                            
                            if ($('#telNo_auth').val() == '') {
                                $('#rowAddAuthForm').bootstrapValidator('resetField', 'telNo' )
                                        .bootstrapValidator('updateStatus', 'telNo', 'VALID');  
                                $('#rowAddAuthForm').bootstrapValidator('disableSubmitButtons', false);
                            }
                            
                            if (value.length != 0) {
                                var pattern = /^[0-9]+$/;        
                                if (value.length != 10) {
                                    return {
                                        valid: false,
                                        message: '手機號碼 長度需為10'
                                    }
                                } else if (pattern.test(value) == false) {
                                    return {
                                        valid: false,
                                        message: '手機號碼 請輸入數字'
                                    }
                                } else {
                                    return true;
                                }                                
                            } else {
                                $('#rowAddAuthForm').bootstrapValidator('resetField', field_name )
                                        .bootstrapValidator('updateStatus', field_name, 'NOT_VALIDATED');  
                                $('#rowAddAuthForm').bootstrapValidator('disableSubmitButtons', false);
                                return true;
                            }
                            
                        }
                    }
                }
            }
        }
    }).on('success.form.bv', function(e) {
        e.preventDefault();
        myfootable.auth_save(e);
        $("#addAuthModal").modal("hide");
    });    

2.bootstrapValidator如何判斷A欄位有值,B欄位也應有值 (反之,若A欄位無值,則B欄位無需有值)

    //被授權人
    $('#rowAddAuthForm').bootstrapValidator({
        excluded: [':disabled'],
        fields: {
            ...
            telRC: {
                validators: {
                    stringLength: {
                        min: 2,
                        max: 4,
                        message: '電話區碼 長度需為2~4'
                    },
                    regexp: {
                        regexp: /^[0-9]+$/,
                        message: '電話區碼 請輸入數字'
                    },
                    callback: {
                        callback: function(value, validator, $field) {
                            var field_name = $($field).attr('name');
                            if (value.length == 0 && $('#telNo_auth').val().length > 0) {
                                return {
                                    valid: false,
                                    message: '請輸入電話區碼'
                                }
                            } else {
                                return true;
                            }
                        }
                    }
                }                
            },
            ...
        }
    }).on('success.form.bv', function(e) {
        e.preventDefault();
        myfootable.auth_save(e);
        $("#addAuthModal").modal("hide");
    });    

註:bootstrapValidator的相關文件可參考 http://bv.doc.javake.cn/api/