2007年3月12日 星期一

Oracle + Java - PDF Issue using iText

如上一篇
善用Oracle 9i上的Java技術
讓EBS擴充上更有彈性

雖然XML Publisher已經可以產生非常漂亮的PDF格式報表
但是在我還不知道XML Publisher時
測試也可以透過萬能的Java技術來完成PDF報表的製作

當時我所碰到的需求是
將text格式的報表結果
轉換為pdf格式...

透過itext
還可以加頁首頁尾/浮水印/密碼限制
都有詳細的範例碼
雖然沒有XML Publisher方便
但是功能上甚至比XML Publisher更多變...
因為它是Java base PDF creator..

1. 確認版本與loadjava
 
 itext並不像javax一樣...已經在資料庫中了
 但Oracle Client有提供loadjava的機制
因此沒有也沒關係啦...把它放上去就好了~~~

然而itext有1.4.5版..load上去會因為11.5.10.2的jdk版本問題而無法正確compile
 因此後來改用itext1.3的版本

loadjava –user apps/apps@SERVER–resolve –force itext-1.3.jar

2. Java Source and Compile

CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED "iTextJPDF"
AS import java.awt.Color;
import java.io.FileOutputStream;
import java.io.*;
import com.lowagie.text.Annotation;
import com.lowagie.text.Chunk;
import com.lowagie.text.Document;
import com.lowagie.text.Element;
import com.lowagie.text.ExceptionConverter;
import com.lowagie.text.Font;
import com.lowagie.text.Image;
import com.lowagie.text.PageSize;
import com.lowagie.text.Paragraph;
import com.lowagie.text.Phrase;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfGState;
import com.lowagie.text.pdf.PdfPTable;
import com.lowagie.text.pdf.PdfPageEventHelper;
import com.lowagie.text.pdf.PdfTemplate;
import com.lowagie.text.pdf.PdfWriter;
/*
* Modify form iText tutorial
* by zhxiang @ 2006-11-14
*/
public class iTextJPDF extends PdfPageEventHelper {
/** An Image that goes in the header. */
public Image headerImage;
/** The Graphic state */
public PdfGState gstate;
/** A template that will hold the total number of pages. */
public PdfTemplate tpl;
/** The font that will be used. */
public BaseFont helv;

public static int JCvtPDF1 (String file_src,String file_des){
try {
// step 1: creating the document
Document doc = new Document(PageSize.A4, 50, 50, 20, 20);
// step 2: creating the writer
PdfWriter writer = PdfWriter.getInstance(doc, new FileOutputStream(file_des));
// step 3: initialisations + opening the document
writer.setPageEvent(new iTextJPDF());
//-------------
Font NewFont = new Font(Font.COURIER, 9, Font.BOLD);
FileReader fr1 = new FileReader(file_src);
BufferedReader buf_fr1 = new BufferedReader(fr1);
String strReadLine;
//-------Metadata------
doc.addTitle("Invoice and Packing List");
doc.addSubject("Twinhead Invoice and Packing List");
doc.addCreator("Twinhead MIS using iText java tech");
doc.addAuthor("Twinhead MIS");
//-------------
doc.open();
// step 4: adding content
Annotation ann = new Annotation(250f, 400f, 350f, 500f,
"http://www.twinhead.com/");
doc.add(ann);
Image jpg = Image.getInstance("/tmp/logo.jpg");
jpg.scalePercent(90);
jpg.setAnnotation(ann);
doc.add(jpg);
strReadLine = buf_fr1.readLine();
while (strReadLine != null)
{
if (strReadLine.length()==0){
strReadLine=" ";
}
doc.add(new Paragraph(strReadLine,NewFont));
strReadLine = buf_fr1.readLine();
}

buf_fr1.close();
// step 5: closing the document
doc.close();
}
catch ( Exception e ) {
e.printStackTrace();
}
return 1;
}

public void onOpenDocument(PdfWriter writer, Document document) {
try {
// initialization of the header table
headerImage = Image.getInstance("/tmp/logo.jpg");

// initialization of the Graphic State
gstate = new PdfGState();
gstate.setFillOpacity(0.3f);
gstate.setStrokeOpacity(0.3f);
// initialization of the template
tpl = writer.getDirectContent().createTemplate(100, 100);
tpl.setBoundingBox(new Rectangle(-10, -10, 100, 100));
// initialization of the font
helv = BaseFont.createFont("Helvetica", BaseFont.WINANSI, false);
}
catch(Exception e) {
throw new ExceptionConverter(e);
}
}

public void onEndPage(PdfWriter writer, Document document) {
PdfContentByte cb = writer.getDirectContent();
cb.saveState();

// compose the footer
String text = "Page " + writer.getPageNumber() + " of ";
float textSize = helv.getWidthPoint(text, 9);
float textBase = document.bottom() - 10;
cb.beginText();
cb.setFontAndSize(helv, 9);
// for odd pagenumbers, show the footer at the left
//if ((writer.getPageNumber() & 1) == 1) {
cb.setTextMatrix((document.right()-document.left())/2, textBase);
cb.showText(text);
cb.endText();
cb.addTemplate(tpl, (document.right()-document.left())/2 + textSize, textBase);
cb.saveState();
// draw a Rectangle around the page
cb.setColorStroke(Color.black);
cb.setLineWidth(1);
cb.rectangle(20, 20, document.getPageSize().width() - 40, document.getPageSize().height() - 40);
cb.stroke();
cb.restoreState();
// starting on page 3, a watermark with an Image that is made transparent
if (writer.getPageNumber() >= 0) {
cb.setGState(gstate);
cb.setColorFill(Color.pink);
cb.beginText();
cb.setFontAndSize(helv, 48);
cb.showTextAligned(Element.ALIGN_CENTER, "Twinhead International Corp.", document.getPageSize().width() / 2, document.getPageSize().height() / 2, 45);
cb.endText();

cb.restoreState();
}
}


public void onCloseDocument(PdfWriter writer, Document document) {
tpl.beginText();
tpl.setFontAndSize(helv, 9);
tpl.setTextMatrix(0, 0);
tpl.showText("" + (writer.getPageNumber() - 1));
tpl.endText();
}

}
/


itext的使用很簡單(如果看懂的話:p)
主要是五個步驟
step 1: creating the document
step 2: creating the writer
step 3: initialisations + opening the document
step 4: adding content
step 5: closing the document

這段程式中
我是把一整個純文字文件轉為PDF格式
(利用java.io.FileOutputStream的buffer讀寫檔案進去)
並且加頁碼/浮水印與Metadata...
而首頁再加公司logo並超連結到公司首頁

對於CJK的問題
則需要改
helv = BaseFont.createFont("Helvetica", BaseFont.WINANSI, false); 這一句
改為用server上某一個字型檔

3. PL/SQL call Java

CREATE OR REPLACE
FUNCTION tw_cvt_pdf01
( Xfilefrom IN varchar2,
Xfileto IN varchar2)
RETURN number IS
LANGUAGE JAVA
NAME 'iTextJPDF.JCvtPDF1(java.lang.String,java.lang.String) return int';
/

4. Grant Java Permission

主要是我讀純文字報表檔與放pdf結果的位置access權限

exec dbms_java.grant_permission('APPS',
'java.io.FilePermission',
'/report_out_dir/*',
'read');

exec dbms_java.grant_permission('APPS',

'java.io.FilePermission',
'/tmp/*',
'read, write');

5. Application..

如此可以用tw_cvt_pdf01
輕而易舉地轉出PDF檔案...

沒有留言: