菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
452
0

.Net下的PDF打印

原创
05/13 14:22
阅读数 65968

简单研究了一下.Net下的PDF打印,一路发现了很多小坑。

第三方组件

这里使用的解析PDF的组件是mupdf,特点和C#调用在 这里 有介绍。

实现的功能

支持页面大小、边距、打印机选择、打印机dpi、打印范围、单双面、奇偶页、缩放、对齐、填充、打印份数、自动旋转等。

关于pt、px、dpi、inch的解释

  1. pt 点(Point)。pt是一种固定长度的度量单位,是能够使用测量设备测得的长度。绝对单位作用有限,因为它们不能够缩放。

    1点 = 0.376毫米 = 1.07英美点 = 0.0148英尺 = 0.1776英寸。

    1英寸 = 72点。

  2. px 像素(Pixel),屏幕最小的显示单元。常见分辨率,如高清的1920*1080,即表示横纵分别有1920和1080个像素点。

  3. dpi 每英寸(Inch)长度内的像素点数。dpi越高,即每英寸内的像素点越多,描述细节的能力也就越高,即清晰度越高。

  4. Inch 即英寸。

    1英寸 = 2.54厘米。

  5. 通过以上可以得到下面的公式。注意这个计算在后续频繁用到。

    dx/dpi = inch = pt /72

    即,dx = pt * dpi / 72

打印配置类

.Net的System.Drawing.Printing下面支持的打印功能类基本满足了开发需要。其中,

  1. PageSettings类初始化后即为当前的默认打印机的页面属性配置。值得注意的是,PageSettings.Bounds的单位是百分之一英尺,这一点十分重要!
  2. PrinterSettings类初始化后即为当前默认打印机的属性配置。同样,PrinterSettings.PaperSizesPaperSize的集合,即打印机支持的纸张类型。PaperSize的单位,同样是百分之一英尺

PDF的页面的尺寸

在mupdf中,pdf的页面尺寸是由函数pdf_bound_page计算得到的,其单位是pt,注意了,这个单位和上面打印配置的纸张尺寸单位是不一致的。

打印实现方式

mupdf本身没有支持打印,这里使用mupdf将pdf页面转换成图片(System.Drawing.Bitmap),使用.Net的打印组件将图片渲染到打印机。因此,打印过程需要自己控制各项打印配置。其中,纸张大小、打印颜色、单双面打印等可以在打印配置类中配置,而自动旋转、缩放、打印范围、奇偶页打印等需要自行控制。如果没有考虑上述单位不一致的问题,会导致使用PrintDocument.DrawImage时,渲染的图片实际偏小。考虑到:

设打印机配置的纸张尺寸数值为SzP0,以英尺为单位的纸张尺寸为SzP1。以pt为单位的纸张尺寸为SzP2,则

SzP0 / 100 = SzP1 = SzP2 / 72,即

SzP2 = SzP0 / 100 * 72

因此,当pdf使用单位为pt时,纸张使用百分之一英尺的数值会让纸张尺寸实际偏大。

关于打印dpi

不同打印机支持不同的打印dpi,有的打印机甚至可以配置打印dpi。打印dpi影响什么呢?例如,一个a0 Inch(pt单位的数值为a1)的纸张(仅用一个维度说明),其dpi为dpi0,图片的尺寸为a2 px,那么可以做如下计算:

a2 / dpi0 = a0 = a1 / 72

其中,a0和a1大小对应且固定不变,则dpi0越大,a2也将会越大。结论是:

打印出结果的物理尺寸不变的情况下,dpi越高,待打印图片的像素要求也将越高。因此,为了保证打印结果足够的清晰度,需要调高打印机的dpi(如果支持)。而为了保证得到预期的结果尺寸,则同时需要提供更高分辨率的图片。

关于预览

demo的界面使用wpf实现,打印预览是通过Control.OnRender中的DrawingContext绘制图片来实现的。为了提高性能,预览的图片可以适当减小渲染精度(尺寸),因为本身预览图是缩放了的。

另外,为了保持不同纸张的预览图尺寸相对固定,使用固定尺寸的ViewBox来控制预览控件的大小。

遇到的异常

值“0”不是枚举“PaperSourceKind”的有效值

英文报错为:The value '0' is not a valid value for the enum 'PaperSourceKind。

这个问题是因为,某些打印驱动,对枚举PaperSourceKind给的值是0,属于非法的枚举值,当调用ToString方法时,就会抛出异常。根据了解到会发生这个问题的打印驱动包括:Solid Pdf CreatorPCL6 Driver for Universal Print(问题参考这里)。下面给出正常和异常的值示例:

// Microsoft Pdf Printer
{[PaperSource unknown Kind=FormSource]}
    Kind: FormSource
    RawKind: 15
    SourceName: "unknown"

// Solid Pdf Creator
{System.Drawing.Printing.PaperSource}
    Kind: 0
    RawKind: 0
    SourceName: "unknown"

感谢

感谢wmjordan提供的mupdf的.Net调用和图片转换教程

发表评论

0/200
452 点赞
0 评论
收藏