项目需要在线生成PDF文件,我首先考虑采用itextsharp控件来实现。具体方法参考 https://sourceforge.net/projects/itextsharp/
1.首先利用nuget 引入该控件包。
2 然后直接创建就可以了。
using iTextSharp.text;
using iTextSharp.text.pdf;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
public class CreatePDF
{
private static CreatePDF instance;
public static CreatePDF GetInstance()
{
if (instance == null)
{
instance = new CreatePDF();
}
return instance;
}
private static Document doc;
//string fontdb = AppDomain.CurrentDomain.BaseDirectory + "Template\\msyh.ttc";
//private static BaseFont bf = BaseFont.CreateFont(@"C://Windows/Fonts/simsun.ttc,0", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
static string fontdb = (AppDomain.CurrentDomain.BaseDirectory + "Template\\msyh.ttf").Replace("\\", "/");
private static BaseFont bf = BaseFont.CreateFont(fontdb + "", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
//四种字体
private static Font fontBig = new Font(bf, 14, Font.BOLD);
private static Font fontSmall = new Font(bf, (float)10.5, Font.BOLD);
private static Font fontSmallNoBold = new Font(bf, (float)10.5);
private static float IndentationLeft = 50;//距左边距
//如果要传参数进来,可自定义
public string GeneratePDF(string name)
{
doc = new Document(PageSize.A4);
string filePath = string.Empty;
try
{
//MemoryStream ms2 = new MemoryStream();
string fileName = string.Format("{0}.pdf", DateTime.Now.ToString("yyyyMMddHHmmss"));
filePath = AppDomain.CurrentDomain.BaseDirectory + "Template\\" + fileName;
FileStream fs = new FileStream(filePath, FileMode.Create);//创建临时文件,到时生成好后删除
PdfWriter writer = PdfWriter.GetInstance(doc, fs);
writer.CloseStream = false;//把doc内容写入流中
doc.Open();
//核心操作
CreateLine(name);//生成一条下横线
#region 添加水印
string waterMarkName = "机密";
#endregion
doc.Close();
MemoryStream ms = new MemoryStream();
if (fs != null)
{
byte[] bytes = new byte[fs.Length];//定义一个长度为fs长度的字节数组
fs.Read(bytes, 0, (int)fs.Length);//把fs的内容读到字节数组中
ms.Write(bytes, 0, bytes.Length);//把字节内容读到流中
fs.Flush();
fs.Close();
}
MemoryStream waterMS = SetWaterMark(ms, filePath, waterMarkName);//先生成水印,再删除临时文件
//if (File.Exists(filePath))//判断临时文件是否存在,如果存在则删除
//{
// File.Delete(filePath);
// GC.Collect();//回收垃圾
//}
//SendFile(fileName, waterMS);//把PDF文件发送回浏览器
}
catch (DocumentException ex)
{
throw new Exception(ex.Message);
}
return filePath;
}
#region 生成一条横线
private static void CreateLine(string name)
{
PdfPTable table = new PdfPTable(1);//一个单元格的
PdfPCell cell = new PdfPCell();
Image gif = Image.GetInstance(AppDomain.CurrentDomain.BaseDirectory + "Template\\logo.png");
gif.ScaleAbsoluteWidth(100);
cell.AddElement(gif);
cell.BorderWidth = 0f;
cell.BorderWidthBottom = 0.2f;
table.AddCell(cell);
doc.Add(table);
}
#endregion
#region 生成页码
private static void AddPageNumberContent()
{
var content = new Paragraph("共 页 第 页", fontSmall);
content.IndentationRight = IndentationLeft + 20;
content.Alignment = 2; //居左
doc.Add(content);
}
#endregion
#region 生成单元格
private static PdfPCell GetPdfCell(string content, Font font, int horizontalAlignment)
{
Paragraph paragraph = new Paragraph(content, font);
paragraph.FirstLineIndent = 2;
paragraph.SetLeading(10, 20);
paragraph.SpacingAfter = 10;
PdfPCell cell = new PdfPCell(paragraph);
cell.HorizontalAlignment = horizontalAlignment;//水平位置
cell.VerticalAlignment = Element.ALIGN_CENTER;//垂直居中
cell.MinimumHeight = 20;//单元格的最小高度
cell.Border = 0;
return cell;
}
#endregion
#region 生成水印
private static MemoryStream SetWaterMark(MemoryStream ms, string filePath, string waterMarkName, string waterMarkAddr = null)
{
MemoryStream msWater = new MemoryStream();
PdfReader pdfReader = null;
PdfStamper pdfStamper = null;
try
{
pdfReader = new PdfReader(filePath);
pdfStamper = new PdfStamper(pdfReader, msWater);
int total = pdfReader.NumberOfPages + 1;//获取PDF的总页数
iTextSharp.text.Rectangle psize = pdfReader.GetPageSize(1);//获取第一页
float width = psize.Width;//PDF页面的宽度,用于计算水印倾斜
float height = psize.Height;
PdfContentByte waterContent;
BaseFont basefont = BaseFont.CreateFont(@"C:\WINDOWS\Fonts\SIMFANG.TTF", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
PdfGState gs = new PdfGState();
for (int i = 1; i < total; i++)
{
waterContent = pdfStamper.GetOverContent(i);//在内容上方加水印
//透明度
waterContent.SetGState(gs);
//开始写入文本
waterContent.BeginText();
waterContent.SetColorFill(BaseColor.RED);
waterContent.SetFontAndSize(basefont, 18);
waterContent.SetTextMatrix(0, 0);
if (waterMarkAddr == null || waterMarkAddr == "")
{
waterContent.ShowTextAligned(Element.ALIGN_CENTER, waterMarkName, width / 2, height / 2, 55);
}
else
{
waterContent.ShowTextAligned(Element.ALIGN_CENTER, waterMarkName, width / 2, height / 2 + 100, 55);
waterContent.ShowTextAligned(Element.ALIGN_CENTER, waterMarkAddr, width / 2, height / 2 - 100, 55);
}
waterContent.EndText();
}
}
catch (Exception)
{
return ms;
}
finally
{
if (pdfStamper != null)
pdfStamper.Close();
if (pdfReader != null)
pdfReader.Close();
}
return msWater;
}
#endregion
//-----------------------发送PDF文件回浏览器端----------------------
public static void SendFile(string fileName, MemoryStream ms, Encoding encoding = null)
{
fileName = (fileName + "").Replace(" ", "");
encoding = encoding ?? Encoding.UTF8;
if (ms != null && !string.IsNullOrEmpty(fileName))
{
System.Web.HttpResponse response = System.Web.HttpContext.Current.Response;
response.Clear();
response.Charset = encoding.BodyName;// "utf-8";
if (!HttpContext.Current.Request.UserAgent.Contains("Firefox") && !HttpContext.Current.Request.UserAgent.Contains("Chrome"))
{
fileName = HttpUtility.UrlEncode(fileName, encoding);
}
response.AddHeader("Content-Disposition", "attachment;filename=" + fileName);
//为了解决打开,导出NPOI生成的xlsx文件时,提示发现不可读取内容。
if (!(fileName + "").ToLower().EndsWith(".xlsx"))
{
response.AddHeader("Content-Type", "application/octet-stream");
response.BinaryWrite(ms.GetBuffer());
}
else
{
response.BinaryWrite(ms.ToArray());
}
ms.Close();
ms = null;
response.Flush();
response.End();
}
}
}
特别需要注意一点的是,如果对字体有特殊要求,可以将字库文件放在项目目录下,但字库的文件类型不同,引用时略有差别。
ttc文件
BaseFont.CreateFont(@"C://Windows/Fonts/simsun.ttc,0", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
ttf文件
BaseFont.CreateFont(@"C://Windows/Fonts/simsun.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
这种模式的弊端在于调整文档的格式太痛苦了,你想按照预定的模板生成pdf,格式要按照他的机制一点点写,如果是篇幅比较长的文档,耐心和时间缺一不可。
在我埋头写了一天之后,同事路过看到我一脸狰狞,细问之,马上丢给我一个包,十分钟后搞定。没有广告,工具类马上贴上来。
本方法依赖于Aspose.Words,因为版权问题,不要直接用nuget引入,需要去网上down一个破解版。然后将需要生成的文件内容置于一个word中,相应参数用字符标识后,方便替换。最后加入以下工具类直接调用就OK了。
(破解dll可以在这里自取 链接: https://pan.baidu.com/s/1o7XpCqI 密码: kwpt)
CrackWord.cs
using System;
using System.Reflection;
class CrackWord
{
///
/// 16.10.1.0
///
public static void Crack()//使用前调用一次即可
{
string[] stModule = new string[8]
{
"\u000E\u2008\u200A\u2001",
"\u000F\u2008\u200A\u2001",
"\u0002\u200A\u200A\u2001",
"\u000F",
"\u0006",
"\u000E",
"\u0003",
"\u0002"
};
Assembly assembly = Assembly.GetAssembly(typeof(Aspose.Words.License));
Type typeLic = null, typeIsTrial = null, typeHelper = null;
foreach (Type type in assembly.GetTypes())
{
if ((typeLic == null) && (type.Name == stModule[0]))
{
typeLic = type;
}
else if ((typeIsTrial == null) && (type.Name == stModule[1]))
{
typeIsTrial = type;
}
else if ((typeHelper == null) && (type.Name == stModule[2]))
{
typeHelper = type;
}
}
if (typeLic == null || typeIsTrial == null || typeHelper == null)
{
throw new Exception();
}
object lic = Activator.CreateInstance(typeLic);
int findCount = 0;
foreach (FieldInfo field in typeLic.GetFields(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance))
{
if (field.FieldType == typeLic && field.Name == stModule[3])
{
field.SetValue(null, lic);
++findCount;
}
else if (field.FieldType == typeof(DateTime) && field.Name == stModule[4])
{
field.SetValue(lic, DateTime.MaxValue);
++findCount;
}
else if (field.FieldType == typeIsTrial && field.Name == stModule[5])
{
field.SetValue(lic, 1);
++findCount;
}
}
foreach (FieldInfo field in typeHelper.GetFields(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance))
{
if (field.FieldType == typeof(bool) && field.Name == stModule[6])
{
field.SetValue(null, false);
++findCount;
}
if (field.FieldType == typeof(int) && field.Name == stModule[7])
{
field.SetValue(null, 128);
++findCount;
}
}
if (findCount < 5)
{
throw new NotSupportedException("无效的版本");
}
}
}
ReplaceAndInsertImage.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Aspose.Words;
using Aspose.Words.Replacing;
public class ReplaceAndInsertImage : IReplacingCallback
{
///
/// 需要插入的图片路径
///
public string Url { get; set; }
public ReplaceAndInsertImage(string url)
{
this.Url = url;
}
public ReplaceAction Replacing(ReplacingArgs e)
{
//获取当前节点
var node = e.MatchNode;
//获取当前文档
Document doc = node.Document as Document;
DocumentBuilder builder = new DocumentBuilder(doc);
//将光标移动到指定节点
builder.MoveTo(node);
//插入图片
builder.InsertImage(Url);
return ReplaceAction.Replace;
}
}
Cv.cs 调用生成类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Aspose.Words;
public class Cv
{
///
/// 生成录用offer文档
///
/// 模板文件
/// 生成的PDF目录
///
public static void Run(string source, string filespath,)
{
var dic = new Dictionary();
//替换模板文件的参数
dic.Add("{xingming}","参数");
CrackWord.Crack();
Aspose.Words.Document doc = new Aspose.Words.Document(source);
foreach (var key in dic.Keys)
{
#pragma warning disable 618
doc.Range.Replace(key, dic[key], false, false);
#pragma warning restore 618
}
doc.Save(filespath, SaveFormat.Pdf);
}
}
source 为模板文件目录,本例中为word 文件。