C#生成pdf -- iText7 设置自定义字体和表格
itextsharp已经不再更新,由iText 7来替代
安装
nuget 安装 itext7

注册自定义字体
下载字体文件 .ttc或.ttf到项目目录,设置更新则拷贝到输出目录,这样构建的时候会把字体文件拷贝过去

windows系统自带黑体, 可以直接复制到项目目录, 其路径是
C:\Windows\Fonts\simhei.ttf
因为字体注册只需要一次,所以建议放到StartUp中. 其中的simhei.ttf换为你的字体文件
iText.Kernel.Font.PdfFontFactory.Register("simhei.ttf");

新建pdf文档
using PdfWriter writer = new ("list.pdf");
PdfDocument pdf = new (writer);
Document doc = new (pdf);
PdfWriter可以传入pdf文件目标路径或者Stream,如果不想保存到本地,那用MemoryStream保存在内存中即可. 后边的例子我们就是直接用MemoryStream来保存数据
设置字体
PdfFont sysFont = PdfFontFactory.CreateRegisteredFont("simhei", PdfEncodings.IDENTITY_H, PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED, true);
doc.SetFont(sysFont)
.SetFontSize(12);//设置字体大小
示例
public class OrderDto
{
public string Name { get; set; } public string Gender { get; set; } public string Address { get; set; } public string Phone { get; set; } public List<ProductDto> Products { get; set; } public string Remark { get; set; }
} public class ProductDto
{
public string Code { get; set; } public string Name { get; set; } public string Category { get; set; } public string Unit { get; set; } public string Sku { get; set; } public decimal Price { get; set; } public int Quantity { get; set; }
}
[HttpGet("pdf")]
public IActionResult ExportPdf()
{
MemoryStream stream = new ();
PdfWriter writer = new (stream);
PdfDocument pdf = new (writer);
Document doc = new (pdf);
//黑体
PdfFont sysFont = PdfFontFactory.CreateRegisteredFont("simhei", PdfEncodings.IDENTITY_H, PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED, true);
doc.SetFont(sysFont)
.SetFontSize(12);//设置字体大小
doc.Add(new Paragraph("订单列表")
.SetBold()//粗体
.SetTextAlignment(iText.Layout.Properties.TextAlignment.CENTER)//居中
);
var headerTexts = new[] {
"序号", "姓名", "性别", "居住地址", "联系电话",
"货号", "产品名称", "分类", "单位", "规格", "售价", "数量",
"备注"
};
var table = new Table(headerTexts.Length) // 设置表格列数
.SetTextAlignment(iText.Layout.Properties.TextAlignment.CENTER)
;
//添加表头
foreach (var header in headerTexts)
{
table.AddHeaderCell(new Cell()
.Add(new Paragraph(header))
.SetBold()//设置粗体
);
}
var orders = new[]
{
new OrderDto
{
Name = "法外", Gender = "男", Address = "江苏省南京市江宁区梧桐路325号", Phone = "13545781245", Remark = "就这?",
Products = new List<ProductDto>{ new ProductDto { Code="XGRD102", Name = "格子衫", Category = "男装", Unit = "件", Sku = "紫色", Price = 39, Quantity = 1} }
},
new OrderDto
{
Name = "狂徒", Gender = "男", Address = "重庆市江北区朝鸽大道北777号", Phone = "15845568956", Remark = "代码敲得好,备胎当到老",
Products = new List<ProductDto>
{
new ProductDto { Code="FUS458", Name = "Amd R7 5800X", Category = "电子产品", Unit = "个", Sku = "盒装", Price = 2499, Quantity = 1},
new ProductDto { Code="TFES982", Name = "程序员帽子", Category = "配饰", Unit = "件", Sku = "绿色", Price = 666, Quantity = 1},
}
},
new OrderDto
{
Name = "张三", Gender = "女", Address = "辽宁省大连市甘井子区伞兵路2333号", Phone = "15952415263", Remark = "rnm, 退钱!!!",
Products = new List<ProductDto>{ new ProductDto { Code="TOP10", Name = "Rnm,退钱同款长袖", Category = "男装", Unit = "件", Sku = "红色", Price = 69, Quantity = 1} }
},
};
for (int i = 0; i < orders.Length; i++)
{
int rowSpan = orders[i].Products.Count;//商品行有多少个,基本信息列就要跨对应多少行
table.StartNewRow();//第一列开启新行
table
.AddCell(new Cell(rowSpan,1).Add(new Paragraph((i + 1).ToString()))//序号
.SetVerticalAlignment(iText.Layout.Properties.VerticalAlignment.MIDDLE))
.AddCell(new Cell(rowSpan, 1).Add(new Paragraph(orders[i].Name)).SetMinWidth(25)//姓名 设置最小列宽25,方便名字横向显示
.SetVerticalAlignment(iText.Layout.Properties.VerticalAlignment.MIDDLE))
.AddCell(new Cell(rowSpan, 1).Add(new Paragraph(orders[i].Gender))//性别
.SetVerticalAlignment(iText.Layout.Properties.VerticalAlignment.MIDDLE))
.AddCell(new Cell(rowSpan, 1).Add(new Paragraph(orders[i].Address))//居住地址
.SetVerticalAlignment(iText.Layout.Properties.VerticalAlignment.MIDDLE))
.AddCell(new Cell(rowSpan, 1).Add(new Paragraph(orders[i].Phone))//联系电话
.SetVerticalAlignment(iText.Layout.Properties.VerticalAlignment.MIDDLE));
//添加一行商品信息 (因为table只能按顺序从左到右一个cell一个cell地加)
table
.AddCell(new Cell(1,1).SetVerticalAlignment(iText.Layout.Properties.VerticalAlignment.MIDDLE)
.Add(new Paragraph(orders[i].Products[0].Code)//货号
))
.AddCell(new Cell().SetVerticalAlignment(iText.Layout.Properties.VerticalAlignment.MIDDLE)
.Add(new Paragraph(orders[i].Products[0].Name)//产品名称
))
.AddCell(new Cell().SetVerticalAlignment(iText.Layout.Properties.VerticalAlignment.MIDDLE)
.Add(new Paragraph(orders[i].Products[0].Category))
.SetMinWidth(25)
)//分类
.AddCell(new Cell().SetVerticalAlignment(iText.Layout.Properties.VerticalAlignment.MIDDLE)
.Add(new Paragraph(orders[i].Products[0].Unit)//单位
))
.AddCell(new Cell()
.SetVerticalAlignment(iText.Layout.Properties.VerticalAlignment.MIDDLE)
.Add(new Paragraph(orders[i].Products[0].Sku)//规格
.SetMinWidth(25)
))
.AddCell(new Cell().SetVerticalAlignment(iText.Layout.Properties.VerticalAlignment.MIDDLE)
.Add(new Paragraph(orders[i].Products[0].Price.ToString("0.00"))//售价
))
.AddCell(new Cell()
.SetVerticalAlignment(iText.Layout.Properties.VerticalAlignment.MIDDLE)
.Add(new Paragraph(orders[i].Products[0].Quantity.ToString())//数量
))
.AddCell(new Cell(rowSpan, 1).SetVerticalAlignment(iText.Layout.Properties.VerticalAlignment.MIDDLE)
.Add(new Paragraph(orders[i].Remark))
);//备注
//商品行大于1, 需要添加多行商品信息
if (orders[i].Products.Count > 1)
{
for (int j = 1; j < orders[i].Products.Count; j++)
{
table
.AddCell(new Cell(1, 1).SetVerticalAlignment(iText.Layout.Properties.VerticalAlignment.MIDDLE)
.Add(new Paragraph(orders[i].Products[j].Code)//货号
))
.AddCell(new Cell().SetVerticalAlignment(iText.Layout.Properties.VerticalAlignment.MIDDLE)
.Add(new Paragraph(orders[i].Products[j].Name)//产品名称
))
.AddCell(new Cell().SetVerticalAlignment(iText.Layout.Properties.VerticalAlignment.MIDDLE)
.Add(new Paragraph(orders[i].Products[j].Category))
.SetMinWidth(25)
)//分类
.AddCell(new Cell().SetVerticalAlignment(iText.Layout.Properties.VerticalAlignment.MIDDLE)
.Add(new Paragraph(orders[i].Products[j].Unit)//单位
))
.AddCell(new Cell()
.SetVerticalAlignment(iText.Layout.Properties.VerticalAlignment.MIDDLE)
.Add(new Paragraph(orders[i].Products[j].Sku)//规格
.SetMinWidth(25)
))
.AddCell(new Cell().SetVerticalAlignment(iText.Layout.Properties.VerticalAlignment.MIDDLE)
.Add(new Paragraph(orders[i].Products[j].Price.ToString("0.00"))//售价
))
.AddCell(new Cell()
.SetVerticalAlignment(iText.Layout.Properties.VerticalAlignment.MIDDLE)
.Add(new Paragraph(orders[i].Products[j].Quantity.ToString())//数量
));
}
}
}
doc.Add(table);
pdf.Close();//记得关闭PdfDocument和PdfWriter
writer.Close();
return File(stream.ToArray(), "application/pdf");
}
结果如下

有几个要点
- 单元格合并是通过跨行或跨列来实现的, new Cell(2, 2)表示此单元格跨2行 2列
- 单元格设置居中最好是放在Add(new Paragraph("xx"))之前
- 添加单元格只能从左到右一个一个地加,所以有合并行的时候要把第一行全部添加完再添加下边的几行,如图所示.

- 新的一行要先调用table.StartNewRow() 然后table.AddCell()才会添加到新行
- 表格的列数是在new Table(13) 时传入的, 传入13就表示有13列
C#生成pdf -- iText7 设置自定义字体和表格的更多相关文章
- Android Studio设置自定义字体
Android Studio设置自定义字体 (1)进入设置页面,File->Settings (2)自定义字体Editor->Colors&Fonts->Font (3)点击 ...
- poi生成excel整理(设置边框/字体/颜色/加粗/居中/)
转: poi生成excel整理(设置边框/字体/颜色/加粗/居中/) 2016年12月02日 11:05:23 吃奶的牛 阅读数:34324 HSSFWorkbook wb = new HSSFW ...
- freemark+ITextRenderer 生成PDF,设置pdf的页面大小
在html中添加样式,仅生成pdf是生效,浏览器展示时是不会生效的: <style> @page{ size : 200mm 300 mm; } </style>
- c# iText 生成PDF 有文字,图片,表格,文字样式,对齐方式,页眉页脚,等等等,
#region 下载说明书PDF protected void lbtnDownPDF_Click(object sender, EventArgs e) { int pid = ConvertHel ...
- PHP生成PDF并转换成图片爬过的坑
需求描述:根据订单通过模板合同生成新的PDF合同通过e签宝签约后转为图片给用户下载. 需求整理: 1.如何生成PDF文件:使用TCPDF扩展生成.思考: ⑴为了方便将模板中的固定占位符替换为订单中的内 ...
- CSS自定义字体的实现,前端实现字体压缩
CSS中使用自定义字体,首先需要下载你需要的字体ttf或者otf文件 这里推荐一个网站:http://www.zitixiazai.org/ /********css中********/ @font- ...
- iOS自定义字体
1.下载字体库,如:DINCond-Bold.otf 2.双击,在mac上安装 3.把下载的字体库拖入工程中: 4.配置info.plist文件 5.xib方式设置自定义字体:Font选Custom, ...
- CSS怎么在项目里引入自定义字体(@font-face)
前言: 以前我一直用内置的默认字体给文字设置字体,直到一天UI妹纸给了我下面的字体 当时我是蒙蔽的,这个字体的效果如下 默认字体并无该字体,直接设置是没有效果的,这时就需要用到自定义字体了 下面 ...
- Java使用iText7生成PDF
前言 我们之前使用js库html2canvas + jspdf实现html转PDF.图片,并下载(详情请戳:html页面转PDF.图片操作记录),大致原理是将页面塞到画布里,以图片的方式放到PDF中, ...
随机推荐
- React-Router示例(重定向与withRouter)
1.withRouter作用:把不是通过路由切换过来的组件中,将react-router 的 history.location.match 三个对象传入props对象上 默认情况下必须是经过路由匹 ...
- 大爽Python入门教程 0-2 什么是IDE?python选什么IDE好?
大爽Python入门公开课教案 点击查看教程总目录 一 感受IDE 什么是IDE? 在这里,我并不想直接给出一个回答, 因为这个回答对初学者来说,可能有些抽象. 我想先带大家感受下IDE. 1 比较不 ...
- [cf1349D]Slime and Biscuits
枚举最终的获得所有饼干的人$i$(以下简称"获胜者"),对于$i$获胜的情况,令其贡献为游戏轮数,否则其贡献为0,记$F_{i}$为期望贡献(即所有情况概率*贡献之和),答案即为$ ...
- C#中使用protobuf-net进行序列化
前一篇文章我们看到使用Google.Protobuf有诸多不便(参考<如何在C#中使用Google.Protobuf工具>),这次我们来看看另一个工具的使用体验. 相关资料.链接: git ...
- SpringCloud微服务实战——搭建企业级开发框架(二十六):自定义扩展OAuth2实现短信验证码登录
现在手机验证码登录似乎是每个网站必备的功能,OAuth2支持扩展自定义授权模式,前面介绍了如何在系统集成短信通知服务,这里我们进行OAuth2的授权模式自定义扩展,使系统支持短信验证码登录. 1.在g ...
- 如何根据fasta快速统计基因组大小及其各染色体长度?
基因组长度 利用seqkit统计长度 seqkit stat test.fa 结果如下: file format type num_seqs sum_len min_len avg_len max_l ...
- 【机器学习与R语言】5-规则学习算法
目录 1.分类规则原理 1.1 1R单规则算法 1.2 RIPPER算法 2. 规则学习应用示例 1)收集数据 2)探索和准备数据 3)训练数据 4)评估性能 5)提高性能 6)选择决策树中的分类规则 ...
- xshell的快捷复制粘贴设置
今天试着用xshell连接Linux,运行一些命令的时候想快点复制粘贴实现效率,却发现还要右键选择复制,再右键选择粘贴,很是麻烦. 看了一下xshell的设置,其实可以自己设置成快捷方式 以xshel ...
- perl 子函数传入多个数组
perl中的引用和C中的指针一样,用"\"标识,引用后可使用符号"->"取值.解引用则在对应的数据类型前加$,@ 或%. 这里这里用两数组求和做示例,引用 ...
- 52-Linked List Cycle
Linked List Cycle My Submissions QuestionEditorial Solution Total Accepted: 102785 Total Submissions ...