前言:這兩個星期一直在弄在Core上導(dǎo)出pdf文件没龙,并且pdf文件是屬于比較復(fù)雜铺厨,所以需要用到模板來填充數(shù)據(jù),遇到了很多的問題硬纤!
- 使用的是Core,iTextsharp最新的版本5.x與之不兼容解滓,并且最新的版本已經(jīng)不開源了,商業(yè)用途需要收費的筝家。
- 我使用的是版本4.x洼裤,還是零幾年的一個版本。這個版本有一個問題就是凡是編碼的字體都會嵌入到pdf中溪王,所以一個原本只有幾十k大小的pdf變成了4m多腮鞍,而且這只是一個pdf值骇,如果有批量導(dǎo)出的話,五十個就是幾百m了移国,可怕吱瘩!
- 最關(guān)鍵的是所有的注釋全部都是英文,而且是一段落一段落的迹缀,而且相關(guān)的問題百度到的壓根沒有參考價值使碾,只能去stackoverflow找答案,看的腦子都漿糊了...
所以在此將我所遇到的一些坑記錄一下祝懂,防止有人重走我的老路票摇!
詳細步驟
pdf模板制作
下載adobe acrobat pro這個軟件,當(dāng)然是收費么砚蓬,不過我大天朝嘛(ps:大家有錢的還是要支持支持正版呀矢门,當(dāng)然我很窮。)然后打開一個pdf文檔灰蛙,點擊導(dǎo)航欄的表單祟剔,可以看到有很多選項:表單向?qū)亲詣訋湍氵x擇區(qū)域(將空白的部分劃分成一個區(qū)域),你也可以自己添加區(qū)域來編輯缕允。類似下圖峡扩,那一個一個藍色的就是一個一個區(qū)域蹭越,回頭可以直接賦值的
pdf模板賦值
首先需要導(dǎo)入iTextsharp這個庫障本,如果你不是Core的話直接導(dǎo)入最新版本就好了,如果你用Core的話我在里面貌似沒找到5.x之前的版本响鹃,我導(dǎo)的是iTextSharp.LGPLv2.Core,這是伊朗的一位C#開發(fā)者封裝的一個工具類驾霜。
-
導(dǎo)入庫之后就可以來對模板進行賦值,代碼如下
//獲取中文字體,第三個參數(shù)表示為是否潛入字體,但只要是編碼字體就都會嵌入。 BaseFont baseFont = BaseFont.CreateFont(@"C:\Windows\Fonts\simsun.ttc,1",BaseFont.IDENTITY_H,BaseFont.NOT_EMBEDDED); //讀取模板文件 PdfReader reader = new PdfReader(@"C:\Users\Administrator\Desktop\template.pdf"); //創(chuàng)建文件流用來保存填充模板后的文件 MemoryStream stream = new MemoryStream(); PdfStamper stamp = new PdfStamper(reader, stream); //設(shè)置表單字體死讹,在高版本有用蛔屹,高版本加入這句話就不會插入字體,低版本無用 //stamp.AcroFields.AddSubstitutionFont(baseFont); AcroFields form = stamp.AcroFields; //表單文本框是否鎖定 stamp.FormFlattening = true; //填充表單,para為表單的一個(屬性-值)字典 foreach (KeyValuePair<string, string> parameter in para) { //要輸入中文就要設(shè)置域的字體; form.SetFieldProperty(parameter.Key, "textfont", baseFont, null); //為需要賦值的域設(shè)置值; form.SetField(parameter.Key, parameter.Value); }
還可以對模板添加圖片烘浦,代碼如下
// 通過域名獲取所在頁和坐標(biāo),左下角為起點
float[] positions = form.GetFieldPositions("sender");
int pageNo = (int)positions[0];
float x = positions[1];
float y = positions[2];
// 讀圖片
Image image = Image.GetInstance(@"C:\Users\Administrator\Desktop\02.png");
// 獲取操作的頁面
PdfContentByte under = stamp.GetOverContent(pageNo);
// 根據(jù)域的大小縮放圖片
image.ScaleToFit(positions[3] - positions[1], positions[4] - positions[2]);
// 添加圖片
image.SetAbsolutePosition(x, y);
under.AddImage(image);
這里大家可能對**positions**不太了解,他的注釋:
>Gets the field box positions in the document. The return >is an array of float multiple of 5. For each of this groups the values are: [page, llx, lly, urx, ury]. The coordinates have the page rotation in consideration.
大概意思就是獲取pdf一個域的坐標(biāo)寞酿,返回了一個數(shù)組,盛放的分別是:[當(dāng)前是第幾頁]脱柱,[區(qū)域左下方的X坐標(biāo)]伐弹,[區(qū)域左下方的Y坐標(biāo)],[區(qū)域右上方的X坐標(biāo)]榨为,[區(qū)域右上方的Y坐標(biāo)]惨好。通過四個點就知道這塊區(qū)域的大小煌茴,然后再定位到是第幾頁。(語文水平不太高日川,聽不懂就.....see more times)
最后按順序關(guān)閉io流
stamp.Close();
reader.Close();
這里是單個模板賦值蔓腐,單個模板生成多個pdf就加個for循環(huán)就好,多個模板的話也差不多龄句,單個模板搞定了合住,其他都簡單了
合并生成的多個pdf文件
在上面我這里沒有生成pdf文件,而是用MemoryStream將賦值完成的pdf放到了內(nèi)存中撒璧,然后再將他們合并發(fā)送到客戶端直接下載透葛,這樣就避免了許多的文件io操作,提升點效率卿樱。(當(dāng)然如果文件太多太大的話可能會內(nèi)存溢出而掛掉吧)
代碼如下:
Document document = new Document();
//將合并后的pdf依舊以流的方式保存在內(nèi)存中
MemoryStream mergePdfStream = new MemoryStream();
//這里用的是smartCopy僚害,整篇文檔只會導(dǎo)入一份字體。屬于可接受范圍內(nèi)
PdfSmartCopy copy = new PdfSmartCopy(document, mergePdfStream);
document.Open();
for (int i = 0; i < pdfStreams.Count; i++)
{
for循環(huán)讀取之前生成的單個pdf字節(jié)數(shù)組繁调,這里將流保存在數(shù)組中傳遞過來使用的話不行萨蚕,會報錯,我也不知道為什么蹄胰,所以用了字節(jié)數(shù)組(如果有人知道的話還請告訴我岳遥,不勝感激)
byte[] stream = pdfStreams[i];
PdfReader reader = new PdfReader(stream);
//for循環(huán)新增文檔頁數(shù),并copy pdf數(shù)據(jù)
document.NewPage();
PdfImportedPage imported = copy.GetImportedPage(reader, 1);
copy.AddPage(imported);
reader.Close();
}
copy.Close();
document.Close();
//這里將合并后的pdf流傳出去裕寨,方法我沒全復(fù)制過來浩蓉。(你們也不能光復(fù)制就想著直接用吧,好歹動下頭腦)
return mergePdfStream;
pdf在瀏覽器中下載
這是最后一步了宾袜,我用的是MVC,不過不管用什么都一樣的原理
FileResult fileResult = new FileContentResult(mergePdfStream.ToArray(), "application/pdf");
fileResult.FileDownloadName = "4.pdf";
然后直接返回fileResult就行捻艳,因為它是繼承于ActionResult的,應(yīng)該是MVC框架的一個專門返回文件的類庆猫。(.net就是爽认轨,微軟封裝的太好了)
and最終
趁還在,多陪陪身邊的人月培,莫等到失去才開始后悔嘁字。
另外廈門是個好地方!
聯(lián)系方式
- GitHub: 大貓傳說中的gitHud地址
- 郵箱: 不常用杉畜,回復(fù)慢的話請原諒1974469025@qq.com