Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
個人需求,需要將html格式轉(zhuǎn)換成PDF并加上水印圖片。于是乎第一次接觸這種需求的小菜鳥博主我,在某度搜索引擎上不斷地查閱關(guān)鍵字資料、踩坑,終于有了一個相應(yīng)的解決方案。以下是解決步驟,記錄下來方便以后的回顧,以及各位大神們的品鑒。
1、在 NuGet 搜索 itextsharp 關(guān)鍵字 下載以下截圖圈中的兩個包,一般下載完后項(xiàng)目會自動引用。
2、在項(xiàng)目文件中引入以下命名空間(建議下面提及的代碼封裝成類庫,方便項(xiàng)目間調(diào)用,個人取舍)
3、Html字符串轉(zhuǎn)pdf文件流,加水印圖片以及未加水印重載 精簡幫助類(由博主踩坑整理,僅完成個人業(yè)務(wù)需求)
1 /// <summary>
2 /// Html字符串轉(zhuǎn)PDF輸出幫助類
3 /// </summary>
4 public class HtmlToPdfHelper
5 {
6 #region HtmlToPDF
7
8 /// <summary>
9 /// 判斷是否有亂碼
10 /// </summary>
11 /// <param name="txt"></param>
12 /// <returns></returns>
13 private static bool IsMessyCode(string txt)
14 {
15 var bytes=Encoding.UTF8.GetBytes(txt);
16 for (var i=0; i < bytes.Length; i++)
17 {
18 if (i < bytes.Length - 3)
19 if (bytes[i]==239 && bytes[i + 1]==191 && bytes[i + 2]==189)
20 {
21 return true;
22 }
23 }
24 return false;
25 }
26
27 /// <summary>
28 /// 將Html字符串 輸出到PDF檔里
29 /// </summary>
30 /// <param name="htmlText"></param>
31 /// <returns></returns>
32 public static byte[] ConvertHtmlTextToPdf(string htmlText)
33 {
34 return ConvertHtmlTextToPdf(htmlText, "", 0, 0, 0, 0);
35 }
36
37 /// <summary>
38 /// 將Html字符串 輸出到PDF檔里,并添加水印
39 /// </summary>
40 /// <param name="htmlText">網(wǎng)頁代碼</param>
41 /// <param name="picPath">水印路徑</param>
42 /// <param name="left">距離左邊距離</param>
43 /// <param name="top">距頂部距離</param>
44 /// <param name="width">水印寬度</param>
45 /// <param name="height">水印高度</param>
46 /// <returns></returns>
47 public static byte[] ConvertHtmlTextToPdf(string htmlText, string picPath, int left, int top, int width, int height)
48 {
49 if (string.IsNullOrEmpty(htmlText))
50 {
51 return null;
52 }
53 //避免當(dāng)htmlText無任何html tag標(biāo)簽的純文字時,轉(zhuǎn)PDF時會掛掉,所以一律加上<p>標(biāo)簽
54 htmlText="<p>" + htmlText + "</p>";
55 MemoryStream outputStream=new MemoryStream();//要把PDF寫到哪個串流
56 byte[] data=Encoding.UTF8.GetBytes(htmlText);//字串轉(zhuǎn)成byte[]
57 MemoryStream msInput=new MemoryStream(data);
58 Document doc=new Document();//要寫PDF的文件,建構(gòu)子沒填的話預(yù)設(shè)直式A4
59 PdfWriter writer=PdfWriter.GetInstance(doc, outputStream);
60 //指定文件預(yù)設(shè)開檔時的縮放為100%
61 PdfDestination pdfDest=new PdfDestination(PdfDestination.XYZ, 0, doc.PageSize.Height, 1f);
62 //開啟Document文件
63 doc.Open();
64
65 //寫入水印圖片
66 if (!string.IsNullOrEmpty(picPath))
67 {
68 Image img=Image.GetInstance(picPath);
69 //設(shè)置圖片的位置
70 img.SetAbsolutePosition(width + left, (doc.PageSize.Height - height) - top);
71 //設(shè)置圖片的大小
72 img.ScaleAbsolute(width, height);
73 doc.Add(img);
74 }
75 try
76 {
77 //使用XMLWorkerHelper把Html parse到PDF檔里
79 XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msInput, null, Encoding.UTF8);
80 //將pdfDest設(shè)定的資料寫到PDF檔
81 PdfAction action=PdfAction.GotoLocalPage(1, pdfDest, writer);
82 writer.SetOpenAction(action);
83 }
84 catch (Exception)
85 {
86 return null;
87 }
88 doc.Close();
89 msInput.Close();
90 outputStream.Close();
91 //回傳PDF檔案
92 return outputStream.ToArray();
94 }
95
96 #endregion
97
98 }
4、獲取網(wǎng)頁字符串的方法
1 /// <summary>
2 /// 獲取網(wǎng)站內(nèi)容,包含了 HTML+CSS+JS
3 /// </summary>
4 /// <returns>String返回網(wǎng)頁信息</returns>
5 public static string GetWebContent(string inpath)
6 {
7 try
8 {
9 WebClient myWebClient=new WebClient();
10 //獲取或設(shè)置用于向Internet資源的請求進(jìn)行身份驗(yàn)證的網(wǎng)絡(luò)憑據(jù)
11 myWebClient.Credentials=CredentialCache.DefaultCredentials;
12 //從指定網(wǎng)站下載數(shù)據(jù)
13 Byte[] pageData=myWebClient.DownloadData(inpath);
14 //如果獲取網(wǎng)站頁面采用的是GB2312,則使用這句
15 string pageHtml=Encoding.UTF8.GetString(pageData);
16 bool isBool=IsMessyCode(pageHtml);//判斷使用哪種編碼 讀取網(wǎng)頁信息
17 if (!isBool)
18 {
19 string pageHtml1=Encoding.UTF8.GetString(pageData);
20 pageHtml=pageHtml1;
21 }
22 else
23 {
24 string pageHtml2=Encoding.Default.GetString(pageData);
25 pageHtml=pageHtml2;
26 }
27 return pageHtml;
28 }
29 catch (WebException webEx)
30 {
31 return webEx.Message;
32 }
33 }
5、MVC設(shè)計模式下獲取控制器視圖Html方法,很XX的一個問題就是只能獲取調(diào)用此方法的控制器下所有視圖,不能跨控制器獲取視圖,有待優(yōu)化
1 /// <summary>
2 /// 獲取MVC視圖Html
3 /// </summary>
4 /// <param name="context">控制器上下文</param>
5 /// <param name="viewName">視圖名稱</param>
6 /// <param name="param"></param>
7 /// <returns></returns>
8 public static string GetViewHtml(ControllerContext context, string viewName)
9 {
10 if (string.IsNullOrEmpty(viewName))
11 viewName=context.RouteData.GetRequiredString("action");
12 using (var sw=new StringWriter())
13 {
14 ViewEngineResult viewResult=ViewEngines.Engines.FindPartialView(context, viewName);
15 var viewContext=new ViewContext(context, viewResult.View, context.Controller.ViewData, context.Controller.TempData, sw);
16 try
17 {
18 viewResult.View.Render(viewContext, sw);
19 }
20 catch (Exception ex)
21 {
22 throw;
23 }
24
25 return sw.GetStringBuilder().ToString();
26 }
27 }
6、將pdf流輸出至客戶瀏覽器下載方法
1 /// <summary>
2 /// 將pdf文件流輸出至瀏覽器下載
3 /// </summary>
4 /// <param name="pdfFile">PDF文件流</param>
5 public static void PdfDownload(byte[] pdfFile)
6 {
7 byte[] buffer=pdfFile;
8 Stream iStream=new MemoryStream(buffer);
9 try
10 {
11 int length;
12 long dataToRead;
13 string filename=DateTime.Now.ToString("yyyyMMddHHmmss") + ".pdf";//保存的文件名稱
14 dataToRead=iStream.Length;
15 HttpContext.Current.Response.Clear();
16 HttpContext.Current.Response.ClearHeaders();
17 HttpContext.Current.Response.ClearContent();
18 HttpContext.Current.Response.ContentType="application/pdf"; //文件類型
19 HttpContext.Current.Response.AddHeader("Content-Length", dataToRead.ToString());//添加文件長度,進(jìn)而顯示進(jìn)度
20 HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(filename, Encoding.UTF8));
21 while (dataToRead > 0)
22 {
23 if (HttpContext.Current.Response.IsClientConnected)
24 {
25 length=buffer.Length;
26 HttpContext.Current.Response.OutputStream.Write(buffer, 0, length);
27 HttpContext.Current.Response.Flush();
28 buffer=new Byte[length];
29 dataToRead=dataToRead - length;
30 }
31 else
32 {
33 dataToRead=-1;
34 }
35 }
36 }
37 catch (Exception ex)
38 {
39 HttpContext.Current.Response.Write("文件下載時出現(xiàn)錯誤!");
40 }
41 finally
42 {
43 if (iStream !=null)
44 {
45 iStream.Close();
46 }
47 //結(jié)束響應(yīng),否則將導(dǎo)致網(wǎng)頁內(nèi)容被輸出到文件,進(jìn)而文件無法打開
48 HttpContext.Current.Response.Flush();
49 HttpContext.Current.Response.End();
50
51 }
52 }
7、MVC控制器下調(diào)用Demo(步驟4、6 方法封裝至幫助類)
1 public class HomeController : Controller
2 {
3 //
4 // GET: /Home/
5
6 public ActionResult Index()
7 {
8 //從網(wǎng)址下載Html字符串(方法一)
9 string inpath=System.Web.HttpContext.Current.Server.MapPath("~/PDFTemplate/test.html");
10 string htmlText=HtmlToPdfHelper.GetWebContent(inpath);//此處調(diào)用步驟4方法
11
12 //獲取MVC視圖Html字符串(方法二)
13 //string htmlText=GetViewHtml(ControllerContext, "Test");//此處調(diào)用步驟5方法
14
15 //水印圖片路徑
16 string picPath=Server.MapPath("~/PDFTemplate/TemplateImg/authentication-iocn.png");
17 //html轉(zhuǎn)pdf并加上水印
18 byte[] pdfFile=HtmlToPdfHelper.ConvertHtmlTextToPdf(htmlText, picPath, 100, 200, 100, 100);
19 //輸出至客戶端
20 HtmlToPdfHelper.PdfDownload(pdfFile);//此處調(diào)用步驟6方法
21
22 return View();
23 }
24
25 public ActionResult Test()
26 {
27 return View();
28 }
29
30 /// <summary>
31 /// 獲取MVC視圖Html
32 /// </summary>
33 /// <param name="context"></param>
34 /// <param name="viewName">視圖名稱</param>
35 /// <returns></returns>
36 public static string GetViewHtml(ControllerContext context, string viewName)
37 {
38 if (string.IsNullOrEmpty(viewName))
39 viewName=context.RouteData.GetRequiredString("action");
40 using (var sw=new StringWriter())
41 {
42 ViewEngineResult viewResult=ViewEngines.Engines.FindPartialView(context, viewName);
43 var viewContext=new ViewContext(context, viewResult.View, context.Controller.ViewData,
44 context.Controller.TempData, sw);
45 try
46 {
47 viewResult.View.Render(viewContext, sw);
48 }
49 catch (Exception ex)
50 {
51 throw;
52 }
53
54 return sw.GetStringBuilder().ToString();
55 }
56 }
57 }
總結(jié):我理解的解決思路是將html讀取轉(zhuǎn)換成字符串,之后再通過 itextsharp 轉(zhuǎn)換成 pdf 比特幣 傳輸至客戶端或直接保存至服務(wù)器生成鏈接供用戶下載。(新手上路,不妥之處,歡迎各位大神指教)
以上代碼僅滿足個人業(yè)務(wù)邏輯需求,謝謝瀏覽。
html文件怎么轉(zhuǎn)成PDF文件?有的招聘網(wǎng)上的簡歷導(dǎo)成DOC文件,不能直接使用,這樣造成很大的困擾,那么它還有一個格式,那就是html格式。將文件導(dǎo)出成html格式,然后再轉(zhuǎn)成PDF文件,這樣便可以直接使用了。平常在項(xiàng)目中也是很多這樣的需求,需要把內(nèi)容轉(zhuǎn)成pdf文件。
下面我們來看下使用 iTextSharp實(shí)現(xiàn)HTML轉(zhuǎn)PDF的方法。
1、nuget 安裝iTextSharp。
using iTextSharp.text;
using iTextSharp.text.pdf;
2、將Html文檔轉(zhuǎn)換為pdf。
/// <summary>
/// 將Html文檔轉(zhuǎn)換為pdf
/// </summary>
/// <param name="htmlText"></param>
/// <returns></returns>
public byte[] ConvertHtmlTextToPDF(string htmlText)
{
if (string.IsOrEmpty(htmlText))
return ;
//避免當(dāng)htmlText無任何html tag標(biāo)簽的純文字時,轉(zhuǎn)PDF時會掛掉,所以一律加上<p>標(biāo)簽
htmlText="<p>" + htmlText + "</p>";
using (var outputStream=new MemoryStream())
{
byte[] data=Encoding.UTF8.GetBytes(htmlText);
var msInput=new MemoryStream(data);
var doc=new Document();//pdf文檔,默認(rèn)A4格式。
var writer=PdfWriter.GetInstance(doc, outputStream);
doc.Open();
//使用XMLWorkerHelper把Html parse到PDF
iTextSharp.tool.xml.XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msInput, , Encoding.UTF8, new UnicodeFontFactory());
//指定默認(rèn)縮放比例為100%
var pdfDest=new PdfDestination(PdfDestination.XYZ, 0, doc.PageSize.Height, 1f);
//將默認(rèn)設(shè)置寫入pdf
var action=PdfAction.GotoLocalPage(1, pdfDest, writer);
writer.SetOpenAction(action);
doc.Close();
msInput.Close();
outputStream.Close();
return outputStream.ToArray();
}
}
3、Unicode 字體支持。
/// <summary>
/// Unicode 字體支持
/// </summary>
public class UnicodeFontFactory : FontFactoryImp
{
public override Font GetFont(string fontname, string encoding, bool embedded, float size, int style, BaseColor color, bool cached)
{
//使用微軟雅黑字體解決中文亂碼的問題,因?yàn)檠藕谧煮w為字體集合所以需要使用,0來指定具體的字體。
//var chineseFontPath=Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts), "msyh.ttc,0");
//宋體
//BaseFont baseFont=BaseFont.CreateFont(@"c:\Windows\Fonts\simsun.ttc,0", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
//黑體
BaseFont baseFont=BaseFont.CreateFont(@"c:\Windows\Fonts\SIMHEI.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
//var baseFont=BaseFont.CreateFont(chineseFontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
return new Font(baseFont, size, style, color);
}
}
4、調(diào)用生成。
string content=temp.Content;
foreach (var dict in dicts)
{
content=content.Replace("{{" + dict.Key + "}}", dict.Value);
}
var path=_esignInfo.Value.ContractPath;
//if (entity.ContractType==ContractType.First)
//{
// path +="/" + appId + "/Agreements";
//}
entity.OriginalFileUrl=_pdfHelper.WritePdfFile(content, contractNo, path, "PDF");
bool isSucc=!String.IsOrEmpty(entity.OriginalFileUrl);
書接上文,本文記錄iText7實(shí)現(xiàn)PDF電子簽章
1、keystore文件,生成自簽名證書,猛戳:SpringBoot系列——啟用https
打開cmd,執(zhí)行以下命令
keytool -genkeypair -alias stamper -keypass 123456 -keyalg RSA -keysize 1024 -validity 365 -keystore e:/Java/stamper.keystore -storepass 123456
2、印章圖片,這里有個在線制作電子公章小工具:http://makepic.net/tool/signet.html
3、pom需要引入新依賴包
<!-- 條形碼、電子簽章 -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>barcodes</artifactId>
<version>${itext7.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>hyph</artifactId>
<version>${itext7.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>font-asian</artifactId>
<version>${itext7.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>sign</artifactId>
<version>${itext7.version}</version>
</dependency>
<!-- 加密軟件包 -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.69</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.69</version>
</dependency>
/**
* 電子簽章
* @param src 需要簽章的pdf文件路徑
* @param dest 簽完章的pdf文件路徑
*/
public static void sign(String src, String dest) {
final String KEYSTORE="E:\\Java\\stamper.keystore";//keystore文件路徑
final char[] PASSWORD="123456".toCharArray();// keystore密碼
final String STAMPER_SRC="E:\\Java\\stamper.gif";//印章圖片路徑
try (PdfReader reader=new PdfReader(src); FileOutputStream os=new FileOutputStream(dest);){
//讀取keystore ,獲得私鑰和證書鏈 jks
KeyStore ks=KeyStore.getInstance("JKS");
ks.load(new FileInputStream(KEYSTORE), PASSWORD);
String alias=ks.aliases().nextElement();
PrivateKey pk=(PrivateKey) ks.getKey(alias, PASSWORD);
Certificate[] chain=ks.getCertificateChain(alias);
//創(chuàng)建簽章工具PdfSigner、設(shè)定數(shù)字簽章的屬性
PdfSigner stamper=new PdfSigner(reader, os, new StampingProperties());
PdfSignatureAppearance appearance=stamper.getSignatureAppearance();
appearance.setReason("簽名原因:系統(tǒng)自動簽名蓋章");
appearance.setLocation("簽名地點(diǎn):xxx系統(tǒng)");
appearance.setContact("聯(lián)系方式:huanzi.qch@qq.com");
//加蓋圖章圖片
ImageData img=ImageDataFactory.create(STAMPER_SRC);
Image image=new Image(img);
appearance.setPageNumber(1);
appearance.setPageRect(new Rectangle(650, 50, image.getImageWidth(), image.getImageHeight()));
appearance.setSignatureGraphic(img);
appearance.setRenderingMode(PdfSignatureAppearance.RenderingMode.GRAPHIC);
//No such provider: BC : 問題解決,加BC庫支持
Security.addProvider(new BouncyCastleProvider());
//摘要算法
IExternalDigest digest=new BouncyCastleDigest();
//簽名算法
IExternalSignature signature=new PrivateKeySignature(pk, DigestAlgorithms.SHA256, BouncyCastleProvider.PROVIDER_NAME);
//調(diào)用itext簽名方法完成pdf簽章
stamper.setCertificationLevel(1);
stamper.signDetached(digest,signature, chain, null, null, null, 0, PdfSigner.CryptoStandard.CMS);
System.out.println("操作完成!");
}catch (Exception e){
e.printStackTrace();
System.err.println("操作異常...");
}
}
我們用 test() 生成的簡單PDF文件來進(jìn)行電子簽章測試
//測試
public static void main(String[] args) {
//test();
//html2pdf();
sign("E:\\Java\\test.pdf","E:\\Java\\test2.pdf");
}
作者:huanzi-qch
出處:https://www.cnblogs.com/huanzi-qch
若標(biāo)題中有“轉(zhuǎn)載”字樣,則本文版權(quán)歸原作者所有。若無轉(zhuǎn)載字樣,本文版權(quán)歸作者所有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,否則保留追究法律責(zé)任的權(quán)利.
*請認(rèn)真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。