简单介绍
iTextSharp是一个很强大的动态创建pdf的工具, 可是缺少一个可以直接转换html到pdf的功能, 而这个功能用ABCpdf.NET轻而易举的实现, 特此向大家介绍一下ABCpdf的用法
当然, iTextSharp是免费的, ABCpdf是需要付费的
First, 我们要把ABCpdf这个dll加入到工程的引用
Secod, 然后using其命名空间
using WebSupergoo.ABCpdf5; //一般加入这个声明就够了,下面2个基本上很少有用
using WebSupergoo.ABCpdf5.Objects;
using WebSupergoo.ABCpdf5.Atoms;
安装和分发:
ABCpdf的功能全部是2个DLL提供的
ABCpdfCE5.DLL 核心引擎库
ABCpdf.DLL dotNET接口库
它的安装程序会自动的把ABCpdf.dll加入到GAC, 把ABCpdfCE5.dll复制到System32目录下
对于我们开发来说,最简单的莫过于将这2个DLL都放置到BIN目录下即可
开始使用:
Doc theDoc = new Doc(); //创建一个Doc对象
XSettings.License = "change this text to your key"; //分发正式程序的时候需要设置License
如果是分发演示程序, 则可以设置为从PDFSettings这个程序里取得的试用授权码
theDoc.SetInfo(0, "License", "cd9b5c07db69df2bf57c0a04d9bca58b10c44889c9fb197984e592f49addfce5ec5fe85d7b9205bc");
字体和语言
如果你要输出的是英文文档,一般直接用其内置的基本字体就可以了。
基本字体包括:
Times-Roman
Times-Bold
Times-Italic
Times-BoldItalic
Helvetica
Helvetica-Bold
Helvetica-Oblique
Helvetica-BoldOblique
Courier
Courier-Bold
Courier-Oblique
Courier-BoldOblique
Symbol
ZapfDingbats
pdf的中文字体有2种实现,一种是内嵌字体(Embed),就是把用到的汉字的字体部分保存到pdf,这样即使在没有安装那种字体的机器上也能看到正确的字体显示,优点是文档在不同机器上的效果都能保持一致, 且显示的效率也比较高, 缺点就是文档会变大一点, 嵌入字体的时候可以通过设置subset来确定是否嵌入整个字体还是只有用到的部分
int theFont = theDoc.EmbedFont("Verdana", "Latin", false, true);
theDoc.FontSize = 12; //设置默认字体大小
这句表示嵌入一个Verdana的拉丁字体, false 代表水平显示, true 代表嵌入子集(这个我也没搞太明白)
theFont是返回字体的Object ID,这个ID可以直接赋给theDoc.Font来设置其为默认字体
另一种是引用字体(Refs), 这种方式因为是引用, 所以不会导致文档变大, 但是引用的方式必须要求观看文档的时候需要用较新版本的Acrobat (Reader), 并且必须安装有语言包才能正确显示文档
theDoc.Font = theDoc.AddFont("隶书", "ChineseS");
加入引用隶书这个中文字体, ChineseS是代表简体中文, 还有: Latin, Unicode, Korean, Japanese, ChineseT可以选择
字体的名字还可以用其英文(eg: LiSu)或文件名(eg: SIMLI.TTF)指示
坐标系
pdf的坐标系不同于Windows所用的左上为原点的坐标系, 它是采用左下为坐标原点的, 如果你实在不习惯使用这种坐标,你可以通过设置Doc的TopDown为true来改变原点的位置
Doc.Rect属性可能是最重要的属性了, 如果要输出什么东西的话, 都是输出到Rect所指定的矩形范围内
ABCpdf默认的文档大小为612x792 pixel,也就是8.5x11 inch, 默认DPI为72
HTML / CSS 呈现
ABCpdf完全支持HTML和CSS
ABCpdf使用Internet Explorer的HTML引擎来解析和预处理要插入到pdf的HTML
屏幕的解析度通常是96 dpi, 而pdf的dpi为72, 因此打印出来的文档会比屏幕上看到的要大
你可以使用CSS中的page-break-before, page-break-after 和 page-break-inside来控制分页, 但是需要注意以下的代码:
<div style="page-break-before:always"> </div>
... 会分页 ...
<div style="page-break-before:always"></div>
... 则不会分页, 我估计是因为空对象被优化掉了
下面的代码演示如何转换html到pdf
theDoc.Rect.Inset(24, 48);
//Rect默认是文档整个页面大小, 这里的Inset表示将Rect左右留出24的空白,上下留出48的空白
int theID = theDoc.AddImageUrl(edtURL.Text);
while (true)
{
if (!theDoc.Chainable(theID))
break;
theDoc.Page = theDoc.AddPage();
theID = theDoc.AddImageToChain(theID);
}
后面的这个循环很重要, 不然的话, 就只能把html输出到一页, 这一点不像iTextSharp是自动分页的
把一个复杂内容输出为多页, 都要采用这种循环加入Chain的方式, 比如需要添加很长一段的html或text
代码很简单, 无需多说, 需要注意的是HTML不管动态的还是静态的, 都应该没有问题, 但是如果是类似BBS之类基于Cookie的动态页面的话, 会取不到需要的页面的
再补充一点, 因为ABCpdf.NET本身是具有缓存设计的, 其获得网页是通过IE来获取的, 因此转换动态HTML的时候, 有可能会遇到没有更新的问题, 具体的描述请参阅帮助, 我就不多费口舌了
图像处理
用ABCpdf展现图片有2种方式, 一种是直通模式, 直接把图片添加到Doc对象里, 比如使用 Doc.AddImageFile, Doc.AddImageData方法
另一种是是非直接的方式, 在添加图像对象到文档之前, 先把数据画到图像对象里
相比之下, 非直接的方式有以下优点
因为每张图在转换为图像对象的时候就已经完全解码, 因此在这个时候就能够捕获到图像文件格式无效之类的错误, 虽然有问题的图像不是经常遇到, 但是如果你使用直通模式的话, 则很有可能导致pdf把有问题的图像文件包含进去, 从而导致pdf文档在浏览的时候报告错误
当然使用直通模式不需要解压和压缩图像, 会比非直接模式执行速度要快
Image对象一般使用Flate来压缩, 这种压缩方式与PNG图像的压缩方法一样, 这是一种无损的压缩方法, 这样可以保证图像的品质不会变差, 如果加入的图像是黑白的, ABCpdf会使用CCITT G4 fax压缩, 这种方法可以显著的减小图像的大小
下面这段代码就是采用的非直接模式来添加一个图像到指定的位置
XImage theImg = new XImage();
theImg.SetFile(@"C:\Cover.jpg");
theDoc.TopDown = true;
theDoc.Rect.Left = 100;
theDoc.Rect.Top = 100;
theDoc.Rect.Width = theImg.Width;
theDoc.Rect.Height = theImg.Height;
theDoc.Rect.Magnify(2, 2); //把图像放大2倍
theDoc.AddImageObject(theImg, false);
Grid & Rect
theDoc.Page = theDoc.AddPage(); //准备输出内容到新的一页
theDoc.AddGrid(); //这个是让页面输出类似坐标纸样的表格, 可以帮助开发者更好地定位输出
theDoc.Color.String = "0 255 0"; //设置默认颜色为绿色
theDoc.Width = 4; // 这个是设置刷子的宽度为4
theDoc.Rect.Position(100, 200); //指定左下角输出位置为100,200
theDoc.Rect.Width = 400;
theDoc.Rect.Height = 500;
theDoc.FrameRect(); //画Rect的边框
Header & Footer
如果我们是用PDF作为报表输出的话, 当然需要在每一页上出现表头和页脚
theDoc.Rect.String = "24 750 588 778"; //直接通过这种方式指定表头输出区域
theDoc.HPos = 0.5; //居中, 0代表居左, 1代表居右
theDoc.VPos = 0.5; //居中, 0代表靠上, 1代表靠下
theDoc.Color.String = "0 0 255"; //蓝色
for (int i = 1; i <= theDoc.PageCount; i++)
{
theDoc.PageNumber = i;
theDoc.AddHtml("this is <b><font pid=" + theFont.ToString() + ">header</font></b>");
// ABCpdf支持html语法, 这里的font标签可以让你选择使用不同的字体输出
theDoc.AddLine(24, 750, 588, 750); //画一条分隔线
}
画页脚和画页头是一样的, 主要就是位置和内容有不同
theDoc.Rect.String = "24 12 588 40";
theDoc.HPos = 1.0; //Right
theDoc.VPos = 0.5; //Middle
theDoc.Color.String = "0 0 255";
for (int i = 1; i <= theDoc.PageCount; i++)
{
theDoc.PageNumber = i;
theDoc.AddHtml("<u>this is footer</u> " + i.ToString() + " / " + theDoc.PageCount.ToString());
theDoc.AddLine(24, 40, 588, 40);
}
压缩pdf
在输出完所要输出的内容后, 我们可以调用Flatten来对生成的文档压缩一下, 因为加入的对象是分布在不同的层上, 所以调用这个函数可以合并当前页上的所有层, 同时重新压缩层上的数据
如果页面上的对象比较少的话, 压缩后是看不出有明显的效果, 但是如果页面上是有很复杂的表格之类的话, 压缩率甚至可以高达5倍以上
需要注意的是, 压缩之后, 之前保存的Object ID会不再有效, 因为对象已经被重新生成, 所以压缩操作最好放到最后来做
for (int i = 1; i <= theDoc.PageCount; i++)
{
theDoc.PageNumber = i;
theDoc.Flatten();
}
更高级的应用
ABCpdf还支持用AddMovies在pdf中嵌入Flash(SWF), AVI, MPEG和WMV
ABCpdf支持创建电子表单, 不过这已经超过我使用的目的了, 因为我要做的是用pdf输出报表
此外, 我感到不方便的就是,似乎ABC.net没有去封装文档属性里面的东西, 比如title, subject, author, 而是直接提供的Doc.SetInfo来修改, 而这个方法用起来不是很方便, 因为你必须要先了解Adobe PDF Specification, 才能用正确, 这一点上远不如iTextSharp方便