C#使用PDFsharp创建PDF

PDFSharp

简介

PDFsharp是一个免费开源的.net pdf库,使用它可以轻松创建pdf文件。下面是官方的介绍:

PDFsharp Library is a .NET library for processing PDF files. You create PDF pages using drawing routines known from GDI+ (WinForms). Almost anything that can be done with GDI+ will also work with PDFsharp. Only basic text layout is supported by PDFsharp, and page breaks are not created automatically. The same drawing routines can be used for screen, PDF, or meta files.

特点

  • 从任何 .NET 语言动态创建 PDF 文档
  • 易于理解的对象模型来编写文档
  • 完全用 C# 编写,可用于 .NET Framework 4.6.2 / Standard 2.0、.NET 6 和 .NET 8
  • 在 Windows 上:一个源代码,用于在 PDF 页面以及窗口或打印机上绘图
  • 修改、合并和拆分现有 PDF 文件
  • 具有透明度的图像(彩色蒙版、单色蒙版、Alpha 蒙版)
  • 字体嵌入和子集化
  • 基于 GDI 或 WPF 的图形实现(仅在 Windows 上)

简单例子

创建一个pdf,并绘制线条、文字

创建工程,从Nuget添加PDFsharp库,然后编写代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
static void Test1()
{
// Create a new PDF document.
var document = new PdfDocument();
document.Info.Title = "Created with PDFsharp";
document.Info.Subject = "Just a simple Hello-World program.";

// Create an empty page in this document.
var page = document.AddPage();
//page.Size = PageSize.Letter;

// Get an XGraphics object for drawing on this page.
var gfx = XGraphics.FromPdfPage(page);

// Draw two lines with a red default pen.
var width = page.Width.Point;
var height = page.Height.Point;
gfx.DrawLine(XPens.Red, 0, 0, width, height);
gfx.DrawLine(XPens.Red, width, 0, 0, height);

// Draw a circle with a red pen which is 1.5 point thick.
var r = width / 5;
gfx.DrawEllipse(new XPen(XColors.Red, 1.5), XBrushes.White, new XRect(width / 2 - r, height / 2 - r, 2 * r, 2 * r));

// Create a font.
var font = new XFont("Times New Roman", 20, XFontStyleEx.BoldItalic);

// Draw the text.
gfx.DrawString("Hello, PDFsharp!", font, XBrushes.Black,
new XRect(0, 0, page.Width.Point, page.Height.Point), XStringFormats.Center);
// Save the document...
var filename = PdfFileUtility.GetTempPdfFullFileName("samples/HelloWorldSample");
document.Save(filename);
// ...and start a viewer.
PdfFileUtility.ShowDocument(filename);
}

自定义字体

绘制文字时,需要创建XFont对象,该对象需要指定一种字体。PDFSharp自带的字体不支持中文,对于中文和特殊字符,所以我们需要自定义字体。
自定义字体需要继承IFontResolver接口,该接口需要实现以下两个方法:

1. public byte[]? GetFont(string faceName)

参数:
faceName为字体的相关信息

返回:
返回字体对应ttf文件的二进制数组即可。(似乎支支持ttf格式)

2. public FontResolverInfo? ResolveTypeface(string familyName, bool bold, bool italic)

参数:
familyName:new XFont时的familyName
bold:是否为粗体
italic: 是否为斜体

返回:
如果字体不存在,返回null
如果字体存在,返回FontResolverInfo object

比如我们要创建的pdf文档只有一种字体,那么无脑返回该字体文件的的二进制数组和任意FontResolverInfo即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class CustomFontResolver : IFontResolver
{
public byte[]? GetFont(string faceName)
{
return File.ReadAllBytes("SourceHanSansSC-Medium-Min.ttf");
}

public FontResolverInfo? ResolveTypeface(string familyName, bool bold, bool italic)
{
return new FontResolverInfo("some string here");

}
}

修改PDFSharp的GlobalFontSettings.FontResolver,启用自定义字体:

1
2
GlobalFontSettings.FontResolver = new CustomFontResolver();
GlobalFontSettings.FallbackFontResolver = new FailsafeFontResolver();

完整测试代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
static void Test2()
{
GlobalFontSettings.FontResolver = new CustomFontResolver();
GlobalFontSettings.FallbackFontResolver = new FailsafeFontResolver();
// Create a new PDF document.
var document = new PdfDocument();
document.Info.Title = "Created with PDFsharp";
document.Info.Subject = "Just a simple Hello-World program.";

// Create an empty page in this document.
var page = document.AddPage();
//page.Size = PageSize.Letter;

// Get an XGraphics object for drawing on this page.
var gfx = XGraphics.FromPdfPage(page);

// Draw two lines with a red default pen.
var width = page.Width.Point;
var height = page.Height.Point;
gfx.DrawLine(XPens.Red, 0, 0, width, height);
gfx.DrawLine(XPens.Red, width, 0, 0, height);

// Draw a circle with a red pen which is 1.5 point thick.
var r = width / 5;
gfx.DrawEllipse(new XPen(XColors.Red, 1.5), XBrushes.White, new XRect(width / 2 - r, height / 2 - r, 2 * r, 2 * r));

// Create a font.
var font = new XFont("Times New Roman", 20, XFontStyleEx.BoldItalic);

// Draw the text.
gfx.DrawString("Hello, PDFsharp!", font, XBrushes.Black,
new XRect(0, 0, page.Width.Point, page.Height.Point), XStringFormats.Center);

gfx.DrawString("你好 PDF Sharp!", font, XBrushes.Black,
new XRect(0, 25, page.Width.Point, page.Height.Point), XStringFormats.Center);

// Save the document...
var filename = PdfFileUtility.GetTempPdfFullFileName("samples/HelloWorldSample");
document.Save(filename);
// ...and start a viewer.
PdfFileUtility.ShowDocument(filename);
}

绘制图形/二维码

我们可以通过 XGraphics的DrawImage方法绘制XImage到pdf文档,同时可以使用XImage.FromStream将图片的Stream转换成XImage格式。所以,我们使用Nuget安装SkiaSharp.QrCode库,并使用它生成二维码图像Stream,然后写入PDF文档。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
static MemoryStream GenQRImgMem(string qrstr,int size)
{
MemoryStream memory = new MemoryStream();
var qrobj = new QRCodeGenerator();
var qr = qrobj.CreateQrCode(qrstr, ECCLevel.M);
var info = new SKImageInfo(size, size);
using (var surface = SKSurface.Create(info))
{
var canvas = surface.Canvas;

// 渲染二维码到Canvas
canvas.Render(qr, info.Width, info.Height);

// 输出到文件
using (var image = surface.Snapshot())
using (var data = image.Encode(SKEncodedImageFormat.Png, 100))
{
data.SaveTo(memory);
memory.Position = 0;
}
}
return memory;
}
static void Test3()
{
// Create a new PDF document.
var document = new PdfDocument();
document.Info.Title = "Created with PDFsharp";
document.Info.Subject = "Just a simple Hello-World program.";

// Create an empty page in this document.
var page = document.AddPage();
//page.Size = PageSize.Letter;

// Get an XGraphics object for drawing on this page.
var gfx = XGraphics.FromPdfPage(page);

// Draw two lines with a red default pen.
var width = page.Width.Point;
var height = page.Height.Point;
gfx.DrawLine(XPens.Red, 0, 0, width, height);
gfx.DrawLine(XPens.Red, width, 0, 0, height);

// Draw a circle with a red pen which is 1.5 point thick.
var r = width / 5;
gfx.DrawEllipse(new XPen(XColors.Red, 1.5), XBrushes.White, new XRect(width / 2 - r, height / 2 - r, 2 * r, 2 * r));

// Create a font.
var font = new XFont("Times New Roman", 20, XFontStyleEx.BoldItalic);

// Draw the image
int qr_size = 300;
var imgMem = GenQRImgMem("你好 PDF Sharp!", qr_size);
int x = (int)(page.Width.Point - qr_size) / 2;
int y = (int)(page.Height.Point - qr_size) / 2;
gfx.DrawImage(XImage.FromStream(imgMem), x, y);

// Save the document...
var filename = PdfFileUtility.GetTempPdfFullFileName("samples/HelloWorldSample");
document.Save(filename);
// ...and start a viewer.
PdfFileUtility.ShowDocument(filename);
}

demo下载