2014年12月17日 星期三

iText pdf writer template

一般報表會用到pdf資訊,就表示是只能讀(不然報表用xls可以再做運算,是更好分析的)
所以會比較偏向,產出正式文件報告或是紙本列印的功能取向...
當然就少不了固定的格式,頁首頁尾,或是套表之類的~
這時候,當然就是用template囉~

iText在java界應該算是個有名的project...也不少年了~
而且還大改過版~不知道該高興或難過,資源太多~很容易找到過時的Orz...

所以版號很重要,使用的package要看清楚,使用的方式要看清楚,不然就會像我一樣一直被表一_一|||...

現在用的是新版5+...package在 com.itextpdf.text.xxxxxx..
主要用以產生pdf...先說手刻pdf,和使用template的方式,兩邊實作的寫法差很多...
雖然官方文件看起來寫得精美,但是因為一直看到手刻的作法不同,然後一直被誤導Orz..

要先說~基本常用的document.add(xxxx)在使用template後是無效的,所以一旦使用template,就得全都用template的解法處理同一頁面(也許是因為我的template本來就是一整頁了...動態資訊用套表的方式寫入)...而Font,BaseFont,基本上也只是對手刻有用~在PdfContentByte裡,只有部分有效...
Paragraph 和 PdfContentByte不同,請把PdfContentByte當成是canvas的Stoke來想,會合理一點Orz...

#基本的template import
import com.itextpdf.text.*;
import com.itextpdf.text.*;

// Create PDF
Document document = new Document(PageSize.A4);
PdfWriter writer = PdfWriter.getInstance(document, fos);
document.open();
PdfContentByte pcb = writer.getDirectContent();

// Load existing PDF(template)
PdfReader reader = new PdfReader(fis);
PdfImportedPage page = writer.getImportedPage(reader, 1);

// PDF new page
writer.setPageEmpty(true);
document.newPage();

// Add Template
pcb.addTemplate(page, 0, 0);

document.close();

#若在template裡面要加圖,其圖檔也要做成template才能匯入
//Read Image to template
Image img = Image.getInstance(img1);
img.scalePercent(imgscale);    //unit %
img.setAbsolutePosition(0, 0);    //must
PdfTemplate myimg1 = pcb.createTemplate(img.getWidth(), img.getHeight());
myimg1.addImage(img);

//Put Image into template position p(X,Y)
pcb.addTemplate(myimg1, p.getX(), p.getY());

#在template裡加文字(數字基本上就是自己轉好文字format加對齊方式丟進去)
#begin/EndText 是必須的,就跟open/closePath那種一樣~
#如果要換行時怎麼辦呢~基本上他是不認\n,所以,就自己算位置吧~囧/
pcb.beginText();     //must
pcb.setFontAndSize(bf, pis.getFontsize());
//number align right
//pcb.showTextAligned(Element.ALIGN_RIGHT, p.getValue(), p.getX(), p.getY(), 0);
//string align left
pcb.showTextAligned(Element.ALIGN_LEFT, p.getValue(), p.getX(), p.getY(), 0);
pcb.endText();    //must

#文字指定顏色,粗體(bold/strong)...這裡就很奸詐了,因為在這裡pcb調用的BaseFont,只有字型和字型大小有用。但是文字的顏色與特效就需要特別的方式來寫..去改BaseFont只會讓你一直翻桌而已一.一
#重點在於setTextRenderingMode要改,不過粗體字線要多粗,是自己設定的
#因為 PdfContentByte 運作的方式跟canvas的方式非常相似,所以顏色,線條,特效改過後,再下次使用要重設定,不然就會看到後面一整串字都一起紅通通了XD
//font color and bold
pcb.beginText();     //must
pcb.setFontAndSize(bf, pis.getFontsize());                           
pcb.setRGBColorFill(255, 0, 0); //for change color
pcb.setLineWidth(0.3f);  //for bold
pcb.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE);
pcb.endText();    //must

//reset to normal text
pcb.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL);

#其他要補充的就是,PDF的坐標計算方式,是每一頁的左下角為0,0(第一象限)...和一般程式以左上角為0,0(第四象限)不同~~
#還有其實偶搞不太懂他的計算單位為何(反正每個lib用的單位都不一樣,誰記得那麼多鬼單位!!),所以對位置時,可以先用程式在每100單位的地方做標記或先畫格線出來看一下~應該就很清楚是要加要減...
#圖片的px在讀進來轉換也是,可能是dpi的關係~先試寫縮圖看看效果,再想下一步,才不會在最後一刻才發現圖跟鬼一樣XD...

沒有留言: