【注】PDF标准大致上有近千页,因而采用程序生成pdf并不是件容易的事情,好在有现成的第三方库可以使用,大大简化了生成pdf的过程。本文使用的是PDFlib ver10+版,采用c++接口,本文涉及PDFlib的一些使用基础,并重点说明了table制作的要点。
一. 简介
PDFlib 是一个用于生成和操作PDF文档的开发库,提供了C/C++、Java、Python等语言绑定,支持文本、矢量图形、图像、多媒体元素(如视频/音频)的嵌入,PDI功能支持导入现有PDF页面并保留交互元素(如注释、表单字段),适用于文档合并、页眉/页脚添加等场景,PDF符合ISO标准(如PDF/A、PDF/X、PDF/UA),确保跨平台输出一致性。
二.一些基础
1.选项设置的格式
PDFlib中,全局的配置项,文本的输出样式等都是通过一个称之为”optlist”的文本字符串来表达。optlist中,可以包含多个设置项,各设置项用空格分割,如下所示:
设置名称1=内容1 设置名称2=内容2 …
上面的“内容“中,可以是布尔值(true/false),数值或字符串(不加引号),如果其中包含空格,逗号等字符,可用{}将其“包裹”起来,标识其为一项内容,同样,如果这个设置中本身可以包含多项内容,也用{}将它们“包裹“起来,看起来如下所示:
设置称名={项1 项2},…}或 设置称名={{项1} {项2} …}
视具体设置,上面的“项”可以是一个子设置。
2.全局设置
要使PDFlib能正常工作,首先要配置一些全局的设置,其中最主要“searchpath“,例如字体的文件,就可以放置在searchpath下,注意searchpath可以包含多个目录,一个典型的searchpath示意如下:
"searchpath={C:\\Windows\Fonts XXX\\bind\\data}" \\XXX为PDFlib的安装目录
另一个全局设置是errorpolicy,一般设置为return,即
“errorpolicy=return”
return的意义是PDFlib的api发生错误时,返回一个错误值,与“抛出exception”相对应。
3.错误信息
PDFlib的api发生错误时,以下两个函数可以帮助我们判断为什么会发生错误,我们在写代码时,可以作为错误信息返回。
PDF_get_errmsg( )
PDF_get_apiname( )
4.元素的创建与销毁
PDFlib中元素的生命周期,类似于Qt,父元素销毁时,会将子元素也同时销毁,因而从理论上,我们只管创建元素,而无需考虑销毁它。PDFlib手册中的建议是,尽管可以不用考虑销毁,但手工销毁,会提高运行速度,例如table真正输出后,最好调用delete_table;独立的textflow输出后(加入table的textflow会在table销毁时会被销毁),最好调用delete_texflow等。
5.使用中文字符
在pdf中显示中文,应考虑2方面的问题:PDFlib函数字符串参数的编码和中文字库的载入。
传入(或传出)PDFlib函数字符串参数的编码
PDFlib函数可以接受unicode的多种编码,通过定义宏
PDFLIB_CPP_STRING
PDFLIB_CPP_U8STRING
PDFLIB_CPP_U16STRING
PDFLIB_CPP_U32STRING
来改变PDFlib函数可接受的字符串编码方式,通常定义PDFLIB_CPP_STRING或不定义,此时,PDFlib函数的字符串参数分别是std::string,std::wstring,它们又分别对应char(utf8)或wchar(utf16等)。
传入PDFlib函数的参数的来源有多种,例如来自源文件(即字符串常量),本地文件,网络流等,这里额外说明一下字符串常量(包含中文)的表达,它与使用的IDE有关,有时在IED中看起来没有问题,但不会得到最终的结果。
在Windows系统中,代码页(CodePage)是用于标识字符集编码的数字编号,其功能是建立字符与二进制编码的映射关系。例如代码页1200对应UTF-16 LE(Little Endian)编码,这是Windows内部处理Unicode文本的默认方式,代码页65001对应UTF-8,代码页936对应GB2312等。
这里,还要顺带说一下BOM。BOM(Byte Order Mark)是字节顺序标记,用于标识文本文件的编码格式(如UTF-8、UTF-16)和字节序(大端/小端)。它通常出现在文件开头,是一个文件“额外”的部分。Visual Studio可以识别BOM(即不会将它视为文件的内容),但其他编译器未必,因而如果想要跨平台,为减少麻烦,最好不要采用带BOM标示的文件。
此时,在VS中,问题就来了:如果没有BOM标记,VS会不能正确识别源文件的编码而采用默认的编码方式,而如果该文件是utf8,那么就会出错。
因而在windwos平台,如果源文件中包含中文,那么有两种方式:
- 采用代码页936(GB2312),编译选项无需做任何修改
- 采用代码页65001(TF-8,带BOM),编译选项无需做任何修改
- 采用代码页65001(TF-8,无BOM),在项目的C/C++命令行下添加/utf-8
最后一种方式是针对全项目文件的,如果是跨平台应用,虽然麻烦一些,却是应该采用的方式,即所有源文件都采用无BOM utf-8编码。
源字符集取得后,就可以采用对应版本的PDFlib函数,当然,也可以进行转换,例如源字符为utf-16,转换成utf-8后,传递给utf-8版本的PDFlib函数。
描述了这么多,推荐方式为:所有中文统一采用utf-8编码(包含源文件中或外部源,如果不是,在入口处就进行转换),VS添加/utf-8编译选项,采用std::string形式的PDFlib函数。
中文字符的载入
中文中最基本的字库是宋体,文件名为SimSun.ttf,需要特别注意的是,目前windows上的中文字库大多变成了.ttc格式,而PDFlib目前并不支持ttc文件格式,因而不能载入ttc格式的字库文件。关于ttf与ttc格式的区别,请参阅有关文档,网上有工具可以将ttc文件转换成ttf文件。
载入宋体字库的写法如下:
int font = pdf->load_font("SimSun", "unicode", "");
SimSun.ttf文件必须在pdflb的搜索目录下,注意文件名大小写,返回值不为-1表示成功,之后就能用此font编号或名称SimSun来指定字体。
6.中文编码转换
使用中文时,编码的转换一般不可避免,好在这不构成什么困难。
PDFlib中提供了一个字符编码转换的函数,声明如下:
string convert_to_unicode(string inputformat, string input, string optlist)
windows的ATL提供了A2W等一系列宏,可方便完成转换。当然根据应用场景,自己也可以写一个特定的转换函数(网上有许多示例)。
7.坐标系
将各种元素添加到页面时,一般要指定其位置。虽然PDFlib可以设置自定义的坐标,但还是采用其缺省的坐标为好:坐标的原点位于页面左下角,单位是磅(1/72英寸,约0.353mm),因此A4的页面,横向(X)最大为595,纵向(Y)最大为841。
8.样式设置
文本,图片等在pdf中的呈现样式,由样式字符串确定(pdf中参数名为optlist),其设计明显受了CSS的影响,二者有一定的相似性,因而在PDFlib中,设置元素样式字符串就是设置了诸如位置,字体,大小,颜色等内容。
【注】各种设置繁杂而多样,采用字符串方式进行索引和设置,会极大简化了接口设计。
9.版本兼容性
关于旧版本被抛弃的方法以及如何在版本10中采用替代方法,get_parameter( ),get_value( ),get_pdi_value( )等,可参阅《PDFlib-9.3.1-migration-guide.pdf》(官网)。
三.生成PDF的一般流程
使用PDFlib生成一个pdf一般的流程如下:

这个流程中,复杂的部分就是在页面添加各类元素以及设置它们显示的样式,依应用场景,分页判断有时需要自己完成。
图中标示了“页范围”和“文档范围”,范围的开始一般用begin_XXX()标识,范围的结束一般用end_XXX()标识,pdf函数有其应用范围,例如setfont,要在begin_page_ext()与end_page_ext()之间使用,而load_font可以在文档范围内使用。PDFlib中还有其他“范围”,例如path范围,template范围等。
制作PDF,如同在一张张指定大小的画布上绘制各类元素,元素在画布中的位置和大小(一般称为box,即在box中渲染元素),以及在状况下换新“画布”,都需要指定。PDFlib中提供了各种方法,用于判断元素被渲染后的各种信息,可以帮助解决元素排版和换页问题。
四.多行文本输出
多行文本的输出显然比单行文本复杂得多,因而PDFlib中,它们采用了两组不同的函数。涉及多行文本的函数有:
|
函数 |
意义 |
|
add_textflow( )/ create_textflow( ) |
创建 |
|
fit_textflow( ) |
放置 |
|
info_textflow( ) |
获取信息 |
|
delete_textflow( ) |
删除 |
大部分页面元素的函数都采用类似的设计与命名风格,在使用时应注意。
678

被折叠的 条评论
为什么被折叠?



