个人需求,需要将html格式转换成PDF并加上水印图片。于是乎第一次接触这种需求的小菜鸟博主我,在某度搜索引擎上不断地查阅关键字资料、踩坑,终于有了一个相应的解决方案。以下是解决步骤,记录下来方便以后的回顾,以及各位大神们的品鉴。
1、在 NuGet 搜索 itextsharp 关键字 下载以下截图圈中的两个包,一般下载完后项目会自动引用。
2、在项目文件中引入以下命名空间(建议下面提及的代码封装成类库,方便项目间调用,个人取舍)
3、Html字符串转pdf文件流,加水印图片以及未加水印重载 精简帮助类(由博主踩坑整理,仅完成个人业务需求)
1 /// <summary>
2 /// Html字符串转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">网页代码</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 //避免当htmlText无任何html tag标签的纯文字时,转PDF时会挂掉,所以一律加上<p>标签
54 htmlText="<p>" + htmlText + "</p>";
55 MemoryStream outputStream=new MemoryStream();//要把PDF写到哪个串流
56 byte[] data=Encoding.UTF8.GetBytes(htmlText);//字串转成byte[]
57 MemoryStream msInput=new MemoryStream(data);
58 Document doc=new Document();//要写PDF的文件,建构子没填的话预设直式A4
59 PdfWriter writer=PdfWriter.GetInstance(doc, outputStream);
60 //指定文件预设开档时的缩放为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 //设置图片的位置
70 img.SetAbsolutePosition(width + left, (doc.PageSize.Height - height) - top);
71 //设置图片的大小
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设定的资料写到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、获取网页字符串的方法
1 /// <summary>
2 /// 获取网站内容,包含了 HTML+CSS+JS
3 /// </summary>
4 /// <returns>String返回网页信息</returns>
5 public static string GetWebContent(string inpath)
6 {
7 try
8 {
9 WebClient myWebClient=new WebClient();
10 //获取或设置用于向Internet资源的请求进行身份验证的网络凭据
11 myWebClient.Credentials=CredentialCache.DefaultCredentials;
12 //从指定网站下载数据
13 Byte[] pageData=myWebClient.DownloadData(inpath);
14 //如果获取网站页面采用的是GB2312,则使用这句
15 string pageHtml=Encoding.UTF8.GetString(pageData);
16 bool isBool=IsMessyCode(pageHtml);//判断使用哪种编码 读取网页信息
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设计模式下获取控制器视图Html方法,很XX的一个问题就是只能获取调用此方法的控制器下所有视图,不能跨控制器获取视图,有待优化
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());//添加文件长度,进而显示进度
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("文件下载时出现错误!");
40 }
41 finally
42 {
43 if (iStream !=null)
44 {
45 iStream.Close();
46 }
47 //结束响应,否则将导致网页内容被输出到文件,进而文件无法打开
48 HttpContext.Current.Response.Flush();
49 HttpContext.Current.Response.End();
50
51 }
52 }
7、MVC控制器下调用Demo(步骤4、6 方法封装至帮助类)
1 public class HomeController : Controller
2 {
3 //
4 // GET: /Home/
5
6 public ActionResult Index()
7 {
8 //从网址下载Html字符串(方法一)
9 string inpath=System.Web.HttpContext.Current.Server.MapPath("~/PDFTemplate/test.html");
10 string htmlText=HtmlToPdfHelper.GetWebContent(inpath);//此处调用步骤4方法
11
12 //获取MVC视图Html字符串(方法二)
13 //string htmlText=GetViewHtml(ControllerContext, "Test");//此处调用步骤5方法
14
15 //水印图片路径
16 string picPath=Server.MapPath("~/PDFTemplate/TemplateImg/authentication-iocn.png");
17 //html转pdf并加上水印
18 byte[] pdfFile=HtmlToPdfHelper.ConvertHtmlTextToPdf(htmlText, picPath, 100, 200, 100, 100);
19 //输出至客户端
20 HtmlToPdfHelper.PdfDownload(pdfFile);//此处调用步骤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 }
总结:我理解的解决思路是将html读取转换成字符串,之后再通过 itextsharp 转换成 pdf 比特币 传输至客户端或直接保存至服务器生成链接供用户下载。(新手上路,不妥之处,欢迎各位大神指教)
以上代码仅满足个人业务逻辑需求,谢谢浏览。
html文件怎么转成PDF文件?有的招聘网上的简历导成DOC文件,不能直接使用,这样造成很大的困扰,那么它还有一个格式,那就是html格式。将文件导出成html格式,然后再转成PDF文件,这样便可以直接使用了。平常在项目中也是很多这样的需求,需要把内容转成pdf文件。
下面我们来看下使用 iTextSharp实现HTML转PDF的方法。
1、nuget 安装iTextSharp。
using iTextSharp.text;
using iTextSharp.text.pdf;
2、将Html文档转换为pdf。
/// <summary>
/// 将Html文档转换为pdf
/// </summary>
/// <param name="htmlText"></param>
/// <returns></returns>
public byte[] ConvertHtmlTextToPDF(string htmlText)
{
if (string.IsOrEmpty(htmlText))
return ;
//避免当htmlText无任何html tag标签的纯文字时,转PDF时会挂掉,所以一律加上<p>标签
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文档,默认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());
//指定默认缩放比例为100%
var pdfDest=new PdfDestination(PdfDestination.XYZ, 0, doc.PageSize.Height, 1f);
//将默认设置写入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)
{
//使用微软雅黑字体解决中文乱码的问题,因为雅黑字体为字体集合所以需要使用,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、调用生成。
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实现PDF电子签章
1、keystore文件,生成自签名证书,猛戳:SpringBoot系列——启用https
打开cmd,执行以下命令
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);
//创建签章工具PdfSigner、设定数字签章的属性
PdfSigner stamper=new PdfSigner(reader, os, new StampingProperties());
PdfSignatureAppearance appearance=stamper.getSignatureAppearance();
appearance.setReason("签名原因:系统自动签名盖章");
appearance.setLocation("签名地点:xxx系统");
appearance.setContact("联系方式: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);
//调用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文件来进行电子签章测试
//测试
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
若标题中有“转载”字样,则本文版权归原作者所有。若无转载字样,本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利.
*请认真填写需求信息,我们会在24小时内与您取得联系。