十年網(wǎng)站開(kāi)發(fā)經(jīng)驗(yàn) + 多家企業(yè)客戶 + 靠譜的建站團(tuán)隊(duì)
量身定制 + 運(yùn)營(yíng)維護(hù)+專業(yè)推廣+無(wú)憂售后,網(wǎng)站問(wèn)題一站解決
純Java的解決方案:
成都創(chuàng)新互聯(lián)-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價(jià)比新市網(wǎng)站開(kāi)發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫(kù),直接使用。一站式新市網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋新市地區(qū)。費(fèi)用合理售后完善,十載實(shí)體公司更值得信賴。
我們首先想到的自然就是JDK1.4提供的JPS(Java Printing Service)啦,不過(guò),這東西雖然說(shuō)支持PDF的Flavor,但是,不管是個(gè)人實(shí)驗(yàn)還是網(wǎng)上他人的評(píng)論,好像根本就是useless,可能如果說(shuō)你 的打印機(jī)Driver支持PDF的Flavor的話,JPS會(huì)檢測(cè)到你的driver的這個(gè)特性,能夠成功的打印PDF文檔出來(lái),但是,大部分情況下,這 種情形是不成立的,故此JPS死路一條啦!
讓我們看看PDF的老家Adobe那里有沒(méi)有什么法寶,我們發(fā)現(xiàn)一個(gè)Viewer Bean的組件,說(shuō)是可以將PDF以Bean組件的方式潛入到Swing中,哇,太爽了,不過(guò)慢著,協(xié)議上說(shuō)不提供任何支持,也不保證不出任何問(wèn)題,管那 么些,試過(guò)再說(shuō),一實(shí)驗(yàn)才知道,靠,Exception頻發(fā),而且這個(gè)組件較為陳舊,還是扔一邊吧!
還有一個(gè)PDFBox,Open Source的,不過(guò)對(duì)中文支持不好,而且好像開(kāi)發(fā)進(jìn)度也不是很好,沒(méi)有發(fā)布一個(gè)正式的版本,基本上不能用于生產(chǎn)環(huán)境;
最后,求助于Commercial的產(chǎn)品吧,實(shí)驗(yàn)了一下ActiveTree的JPrint,感覺(jué)不錯(cuò),完全可以勝任我們的需求而且恰到好處,不過(guò)授權(quán)費(fèi) 很貴,Email問(wèn)過(guò)之后的答復(fù)是2000USD的最低購(gòu)買,呵呵,雖然日本人很有錢,但也心疼這個(gè)銀子啊,所以最終也得作罷?。ˋctiveTree的 授權(quán)其實(shí)挺令我ft的,他其實(shí)在2003年的時(shí)候是可以免費(fèi)使用的,但之后就變卦了,呵呵,當(dāng)時(shí)記得我還給提過(guò)一些bug之類,算了,人家做出這個(gè)東西也 不容易)
其他商業(yè)產(chǎn)品也是價(jià)格不菲,所以,基本上純Java的solution到這里就否決了,讓我們看Java-Com的解決方案吧!
Java-Com 的解決方案:
在前一條路走不通之后,我痛定思痛,決定轉(zhuǎn)向自己不熟悉的領(lǐng)域,ms的領(lǐng)地,我打算從Java中調(diào)用Com組件,由Com組件來(lái)幫助我們實(shí)現(xiàn)PDF的打印 工作,不夠這條路也不是一帆風(fēng)順那!
我們知道,Acrobat Reader在發(fā)布的時(shí)候會(huì)隨同發(fā)布一個(gè)支持瀏覽器的com組件用來(lái)manipulate他的這個(gè)PDF文檔格式,所以,我們想要本地調(diào)用這個(gè)隨同發(fā)布的 Com組件來(lái)實(shí)現(xiàn)PDF打印。雖然Version5,6,7的這個(gè)組件格式不一樣(5,6是以ocx的格式發(fā)布,7是以dll的格式發(fā)布),但是,不管那 么些,先從7開(kāi)始吧!
要調(diào)用com,那么我們需要一個(gè)從java到com的Bridge,所以,jacob第一個(gè)躍入我的腦海,因?yàn)橹熬陀眠^(guò)嘛!但是麻煩來(lái)了,我們并不知道 這個(gè)com組件提供了那些調(diào)用接口??!哎,沒(méi)辦法,回學(xué)校求教熟悉.net的同學(xué),給好不容易弄出幾個(gè)需要的調(diào)用方法(哎,可憐我的周末啊),星期一就回 來(lái)用jacob調(diào)用啦,可是左試右試就是一直拋異常,我那個(gè)氣??!難道是jacob的為問(wèn)題?!我就又找了jcom和jcom2等類似的產(chǎn)品,但jcom 全是日文文檔,沒(méi)有辦法,而jcom2估計(jì)也是一個(gè)德行(我忘了為什么當(dāng)初否決了這個(gè)),所以就決定試一試商業(yè)產(chǎn)品吧!
這方面的商業(yè)產(chǎn)品主要有J-Integra,JPanel(好像叫這個(gè)名字)以及一個(gè)叫JNIWrapper的產(chǎn)品(這個(gè)是一個(gè)人用用來(lái)演示在java中 使用Acrobat5打印PDF的時(shí)候提到的)。這些商業(yè)產(chǎn)品好的地方就是他可以根據(jù)某個(gè)你要調(diào)用的com組件為你自動(dòng)生成相應(yīng)的Proxy對(duì)象java 代碼,這樣你就可以直接調(diào)用你熟悉的java代碼了。像jacob等開(kāi)源項(xiàng)目,如果給出一個(gè)類似的code generation工具的話,就完全不遜于這些商業(yè)產(chǎn)品啦。鑒于商業(yè)產(chǎn)品的價(jià)格,我最終還是否決了這些(日本人其實(shí)也聽(tīng)摳門的)。
這樣,Java-com也對(duì)這個(gè)問(wèn)題沒(méi)轍了。
不過(guò),最后在我的解決方案中,我還是使用了Jacob,這是后話,暫且不提...
那我們考慮一下,如果PDF打印不行,打印其他格式行不行?!比如圖片,這個(gè)JPS可以完全打印,所以,我們找一下有沒(méi)有將PDF格式轉(zhuǎn)換為其他格式的工 具吧!
PDF格式轉(zhuǎn)換的解決方案:
在這個(gè)領(lǐng)域,主要的就是有GhostScript/GView和ImageMagick,前者可以將PDF格式轉(zhuǎn)換為PostScript格式,但是好像 GhostScript也不能用JPS完全打印出來(lái);而后者是一個(gè)將PDF轉(zhuǎn)換為Image的API工具,他的Java實(shí)現(xiàn)叫JMagick,但他有一個(gè) 跟GhostScript同樣的問(wèn)題,就是要轉(zhuǎn)換,就必須在本地安裝,然后通過(guò)命令行的方式調(diào)用,這個(gè)顯然也不是很好,而且集成性很差,還是作罷!
剩下的一個(gè)是命令行調(diào)用啦,這是從itext網(wǎng)站找到的,你可以通過(guò)在命令行運(yùn)行AcroRd32 /p /h "path to PDF file"這樣的命令來(lái)打印你要打印的PDF文件,當(dāng)然,你可以在PDF文件生成后就將他們依次放入一個(gè)批處理文件來(lái)執(zhí)行這些打印命令,但是這個(gè)方案唯一 的問(wèn)題就是,每打印一個(gè)文件都會(huì)啟動(dòng)一個(gè)Acrobat Reader窗口而且必須手動(dòng)關(guān)閉,這現(xiàn)在不能滿足目前的系統(tǒng)要求。
好了,所有的方案基本上都羅列完了,也沒(méi)有找到一個(gè)可行的方案:-(
(沒(méi)有銀子嘛,不然Activetree的JPrint不錯(cuò)的說(shuō))
這些東西差不多郁悶了我3,4天吧,那幾天簡(jiǎn)直就是bored to death.
不過(guò),在郁悶的這幾天的結(jié)尾,卻有一道靈光閃過(guò)我的腦海...
能不能說(shuō)啟動(dòng)一個(gè)打印service,當(dāng)文檔要打印的時(shí)候,直接發(fā)送給它就行了那?!而恰好我發(fā)現(xiàn)一段在網(wǎng)頁(yè)中加載PDF文檔的Javascript代 碼,而且完全可以使用js來(lái)控制PDF的打印,所以,最終的這個(gè)方案就浮出水面了 ...
1-使用jacob啟動(dòng)一個(gè)IE進(jìn)程,并隱藏IE窗口;
if(ieAutomation == null)
ieAutomation = new ActiveXComponent("InternetExplorer.Application");
ieAutomation.setProperty("Visible",new Variant(false));
2-PDF前端在生成PDF文件之后發(fā)送生成后的文件到JacobPDFPrinter,JacobPDFPrinter根據(jù)出入的PDF文件的全路徑使 用Velocity模板引擎動(dòng)態(tài)生成一個(gè)包含使用Javascript代碼實(shí)現(xiàn)的PDF打印邏輯的HTML文檔(當(dāng)然,使用Velocity生成文檔這部 分邏輯我們單獨(dú)抽出到VeloIEPrinterGenerator類中);
3-在HTML生成之后,在JacobPDFPrinter中就可以使用jacob調(diào)用IE的Navigate2,將IE重定向到剛才生成的這個(gè)HTML 文件啦,這樣,IE就會(huì)在后臺(tái)調(diào)用JS代碼將PDF打印到默認(rèn)打印機(jī);
4-打印成功之后,清除臨時(shí)動(dòng)態(tài)生成的HTML文件;
5-當(dāng)主程序退出之前,Quit后臺(tái)IE進(jìn)程。
以上就是我能給出的一個(gè)solution,并不完美,但it works.
需要注意的幾個(gè)問(wèn)題是:
(1)需要設(shè)置IE的一個(gè)高級(jí)選項(xiàng),運(yùn)行本地腳本運(yùn)行;
(2)因?yàn)镴ava和Com線程模型的不一致,導(dǎo)致在最終Quit后臺(tái)IE進(jìn)程的時(shí)候會(huì)拋出Com調(diào)用異常,因?yàn)閷?duì)于Win平臺(tái)API以及相關(guān)編程模型不 是很熟悉,所以,這個(gè)問(wèn)題需要求助于別人幫忙解決;
(3)IE在執(zhí)行JS打印PDF的時(shí)候,同樣會(huì)后臺(tái)啟動(dòng)Acrobat的一個(gè)進(jìn)程,而這個(gè)進(jìn)程我們程序中無(wú)法控制其生命周期,所以,主程序退出后,我們沒(méi) 有辦法同時(shí)kill這個(gè)進(jìn)程,好在不管我們運(yùn)行多少次,這個(gè)進(jìn)程在后臺(tái)只有一個(gè),所以,性能負(fù)擔(dān)不是很大;
轉(zhuǎn)載
java導(dǎo)出pdf需要用到iText庫(kù),iText是著名的開(kāi)放源碼的站點(diǎn)sourceforge一個(gè)項(xiàng)目,是用于生成PDF文檔的一個(gè)java類庫(kù)。通過(guò)iText不僅可以生成PDF或rtf
的文檔,而且可以將XML、Html文件轉(zhuǎn)化為PDF文件。
iText的安裝非常方便,下載iText.jar文件后,只需要在系統(tǒng)的CLASSPATH中加入iText.jar的路徑,在程序中就可以使用
iText類庫(kù)了。
代碼如下:
public class createPdf {
//自己做的一個(gè)簡(jiǎn)單例子,中間有圖片之類的
//先建立Document對(duì)象:相對(duì)應(yīng)的 這個(gè)版本的jar引入的是com.lowagie.text.Document
Document document = new Document(PageSize.A4, 36.0F, 36.0F, 36.0F, 36.0F);
public void getPDFdemo() throws DocumentException, IOException{
//這個(gè)導(dǎo)出用的是 iTextAsian.jar 和iText-2.1.3.jar 屬于比較老的方法。 具體下在地址見(jiàn):
//首先
//字體的定義:這里用的是自帶的jar里面的字體
BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);
// 當(dāng)然你也可以用你電腦里面帶的字體庫(kù)
//BaseFont bfChinese = BaseFont.createFont("C:/WINDOWS/Fonts/SIMSUN.TTC,1",BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
//定義字體 注意在最新的包里面 顏色是封裝的
Font fontChinese8 = new Font(bfChinese, 10.0F, 0, new Color(59, 54, 54));
//生成pdf的第一個(gè)步驟:
//保存本地指定路徑
saveLocal();
document.open();
ByteArrayOutputStream ba = new ByteArrayOutputStream();
// PdfWriter writer = PdfWriter.getInstance(document, ba);
document.open();
//獲取此編譯的文件路徑
String path = this.getClass().getClassLoader().getResource("").getPath();
//獲取根路徑
String filePath = path.substring(1, path.length()-15);
//獲取圖片路徑 找到你需要往pdf上生成的圖片
//這里根據(jù)自己的獲取的路徑寫 只要找到圖片位置就可以
String picPath = filePath +"\\WebContent" +"\\images\\";
//往PDF中添加段落
Paragraph pHeader = new Paragraph();
pHeader.add(new Paragraph(" 你要生成文字寫這里", new Font(bfChinese, 8.0F, 1)));
//pHeader.add(new Paragraph("文字", 字體 可以自己寫 也可以用fontChinese8 之前定義好的 );
document.add(pHeader);//在文檔中加入你寫的內(nèi)容
//獲取圖片
Image img2 = Image.getInstance(picPath +"ccf-stamp-new.png");
//定義圖片在文檔中顯示的絕對(duì)位置
img2.scaleAbsolute(137.0F, 140.0F);
img2.setAbsolutePosition(330.0F, 37.0F);
//將圖片添加到文檔中
document.add(img2);
//關(guān)閉文檔
document.close();
/*//設(shè)置文檔保存的文件名
response.setHeader("Content-
disposition", "attachment;filename=\""+ new String(("CCF會(huì)員資格確認(rèn)
函.pdf").getBytes("GBK"),"ISO-8859-1") + "\"");
//設(shè)置類型
response.setContentType("application/pdf");
response.setContentLength(ba.size());
ServletOutputStream out = response.getOutputStream();
ba.writeTo(out);
out.flush();*/
}
public static void main(String[]args) throws DocumentException, IOException{
createPdf pdf= new createPdf();
pdf.getPDFdemo();
}
//指定一個(gè)文件進(jìn)行保存 這里吧文件保存到D盤的text.pdf
public void saveLocal() throws IOException, DocumentException{
//直接生成PDF 制定生成到D盤test.pdf
File file = new File("D:\\text2.pdf");
file.createNewFile();
PdfWriter.getInstance(document, new FileOutputStream(file));
}
}
具體步驟如下:
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.SimpleDoc;
import javax.print.attribute.DocAttributeSet;
import javax.print.attribute.HashDocAttributeSet;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.swing.JFileChooser;
public class PrintDemo {
public static void main(String[] args) {
JFileChooser fileChooser = new JFileChooser(); // 創(chuàng)建打印作業(yè)
File file = new File("f:/111.txt"); // 獲取選擇的文件
// 構(gòu)建打印請(qǐng)求屬性集
HashPrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
// 設(shè)置打印格式,因?yàn)槲创_定類型,所以選擇autosense
DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
// 定位默認(rèn)的打印服務(wù)
PrintService defaultService = PrintServiceLookup.lookupDefaultPrintService();
InputStream fis = null;
try {
DocPrintJob job = defaultService.createPrintJob(); // 創(chuàng)建打印作業(yè)
fis = new FileInputStream(file); // 構(gòu)造待打印的文件流
DocAttributeSet das = new HashDocAttributeSet();
Doc doc = new SimpleDoc(fis, flavor, das);
job.print(doc, pras);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}