使用打印代码输出图形文件






4.88/5 (23投票s)
将您的 PrintDocument “打印” 到常见的图形文件格式。
引言
您是否希望您的应用程序支持保存为不同的图形文件格式? 假设您已经实现了打印预览,事实证明它比您想象的要容易。 这是一篇围绕 GDI+ Image.Save
方法的小文章。
使用代码
使用该代码再简单不过了。
只需将 PrintControllerFile.cs 文件添加到您的项目中,并像这样使用它
using ( PrintDocument doc = new MyPrintDocument( ... ) )
{
ImageFormat format = ImageFormat.Jpeg;
float scale = 1f;
long quality = 75L;
string output = "Output";
PrintController controller =
new PrintControllerFile( format, scale, quality, output );
doc.PrintController =
new PrintControllerWithStatusDialog( controller, "Exporting" );
doc.Print();
}
PrintControllerFile
构造函数的参数是
format
:ImageFormat
类中的静态格式之一。scale
:一个简单的缩放比例,用于控制输出的大小。quality
:仅由 JPEG 编码器使用。 默认值约为 75。output
:输出文件的基本文件路径。
瞧! 输出是图形文件的集合,每页一个文件。
工作原理
基本上,PrintControllerFile
使用 PreviewPrintController
生成元文件,然后将它们保存为输出。
此方法的优点是输出将始终与您的打印预览中的外观相同。
它也为我们节省了很多工作。 如果您在 Reflector 中查看 PreviewPrintController
,您会发现它使用各种 GDI+ 方法为每页设置一个 Graphics
对象。 我们希望我们的输出与打印预览完全相同,因此让 PreviewPrintController
完成这项工作是有意义的。
因此,PrintControllerFile
派生自 PreviewPrintController
,并重写了 OnEndPage
方法以在生成时保存每一页。 我本可以让 PreviewPrintController
生成所有页面,然后保存它们,但我希望在生成每一页后立即保存它们,这样如果您取消打印,您就可以获得到该点的输出。
internal class PrintControllerFile : PreviewPrintController
{
...
public override void OnEndPage( PrintDocument document, PrintPageEventArgs e )
{
base.OnEndPage( document, e );
// Get the current Metafile
PreviewPageInfo[] ppia = GetPreviewPageInfo();
PreviewPageInfo ppi = ppia[ ppia.Length - 1 ];
Image image = ppi.Image;
_Metafile = ( Metafile ) image;
if ( _Format == ImageFormat.Emf )
{ _Metafile.Save( PagePath, _Format ); return; }
if ( _Format == ImageFormat.Wmf )
{ _Metafile.Save( PagePath, _Format ); return; }
SaveViaBitmap( document, e );
}
...
}
保存增强型元文件和 Windows 元文件格式的输出就像使用所需的格式在 Metafile 实例上调用 Save
一样简单。
但是,此方法不适用于其他图形格式,因为您无法控制输出。 例如,将标准页面保存为位图会导致文件大小超过 100MB。 显然,这不是必需的。
解决方案是创建一个具有所需属性的 Bitmap
图像,将其播放到其中,然后保存 Bitmap
。 这使我们能够控制我们需要的输出。
protected void SaveViaBitmap( PrintDocument document, PrintPageEventArgs e )
{
int width = e.PageBounds.Width ;
int height = e.PageBounds.Height ;
using ( Bitmap bitmap = new Bitmap( ( int ) ( width * _Scale ),
( int ) ( height * _Scale ) ) )
using ( Graphics graphics = Graphics.FromImage( bitmap ) )
{
graphics.Clear( Color.White );
if ( _Scale != 1 ) graphics.ScaleTransform( _Scale, _Scale );
Point point = new Point( 0, 0 );
Graphics.EnumerateMetafileProc callback =
new Graphics.EnumerateMetafileProc( PlayRecord );
graphics.EnumerateMetafile( _Metafile, point, callback );
Save( bitmap );
}
}
我需要设置 Bitmap
对象的唯一参数是 scale
参数。 输出的大小由 PrintPageEventArgs
的 PageBounds
乘以 scale
参数设置。 实际上,您通常希望输出为标准大小,但大约从 0.5 到 2.0 的 scale
值可能很有用。 如果设置了 scale
,则将 ScaleTransform
应用于 Graphics
对象,因此您的打印代码不必修改。
从 Bitmap
创建一个 Graphics
对象并将元文件播放到其中,然后只是样板代码。
然后,以所需的格式保存 Bitmap
很简单,除了 JPEG 格式,它需要设置 Quality
参数才能用于编码器。 此值必须在 0(最高压缩,最低质量)到 100(最低压缩,最高质量)的范围内。 默认值似乎约为 75。
protected void Save( Bitmap bitmap )
{
if ( _Format == ImageFormat.Jpeg )
{
EncoderParameters parameters = new EncoderParameters( 1 );
EncoderParameter parameter =
new EncoderParameter( Encoder.Quality, _Quality );
parameters.Param[ 0 ] = parameter;
bitmap.Save( PagePath, _Codec, parameters );
return;
}
bitmap.Save( PagePath, _Format );
}
主文件 PrintControllerFile.cs 只有大约 200 行长,而且非常容易理解。 如果您有兴趣,请看一看。
关注点
Image.Save
方法非常强大,但不能直接用于元文件。 创建一个中间 Bitmap
,然后保存它,这让我们能够控制输出。
如果能有更多控制就好了,但如果您只想生成可以在图像编辑器中修改的图形文件,那么这就可以了。
历史
2005 年 3 月 22 日 - 版本 1.0