可以将PDF转换为可以从.net打印的矢量图像格式吗?
本文关键字:图像 格式 net PDF 转换 打印 | 更新日期: 2023-09-27 18:05:57
我们有一个。net应用程序,可以打印到真正的打印机和PDF,目前使用PDFsharp,虽然这部分可以改变,如果有一个更好的选择。大多数输出是生成的文本或图像,但末尾可能会附加一个或多个页面。这些页面由最终用户以PDF格式提供。
当打印到纸上时,我们的用户使用预打印的纸,但在导出PDF的情况下,我们将这些页面连接到最后,因为它们已经是PDF格式了。
我们希望能够将这些pdf文件直接嵌入到打印流中,这样他们就不需要预先打印的纸张了。然而,没有任何好的选择来将PDF渲染到GDI页面(System.Drawing.Graphics)。
是否有一种矢量格式的PDF可以转换为一些外部程序,可以呈现为GDI+页面而不降级转换为位图首先?
在一篇题为"如何在。net中将PDF转换为EMF "的文章中,我已经展示了如何使用我们的PDFOne . net产品来实现这一点。emf是矢量图形,您可以在打印机画布上渲染它们。
对你来说一个更简单的选择是PDF覆盖,在另一篇题为"PDF覆盖-在。net中将PDF页面拼接在一起"的文章中解释。PDFOne允许x-y偏移覆盖,允许您在边缘缝合页面。在这里引用的文章中,我通过将偏移量设置为零,将页面一个一个地覆盖在另一个页面上。你需要将它设置为页面宽度和高度。
免责声明:我为Gnostice工作。
Ghostscript可以输出PostScript(这是一个矢量文件),可以直接发送到某些类型的打印机。例如,如果您使用的是支持LPR的打印机,则可以使用以下项目将PS文件直接设置为该打印机:http://www.codeproject.com/KB/printing/lpr.aspx
也有一些可以打印PDF的商业选项(虽然我不确定内部机制是基于矢量还是位图),例如http://www.tallcomponents.com/pdfcontrols2-features.aspx或http://www.tallcomponents.com/pdfrasterizer3.aspx
我终于发现有一个选项可以解决我在打印作业中嵌入矢量格式的一般要求,但它不适用于基于GDI的打印。
由Microsoft XPS Writer打印驱动程序创建的XPS文件格式可以使用。net中包含的ReachFramework.dll从WPF中打印。通过使用WPF而不是GDI进行打印,可以将XPS文档页面嵌入到更大的打印文档中。
缺点是,WPF打印的工作方式有点不同,所以所有的支持代码都直接使用系统中的东西。绘图命名空间必须重写
下面是如何嵌入XPS文档的基本大纲:
打开文档
XpsDocument xpsDoc = new XpsDocument(filename, System.IO.FileAccess.Read);
var document = xpsDoc.GetFixedDocumentSequence().DocumentPaginator;
// pass the document into a custom DocumentPaginator that will decide
// what order to print the pages:
var mypaginator = new myDocumentPaginator(new DocumentPaginator[] { document });
// pass the paginator into PrintDialog.PrintDocument() to do the actual printing:
new PrintDialog().PrintDocument(mypaginator, "printjobname");
然后创建DocumentPaginator的后代,它将执行实际的打印。覆盖抽象方法,特别是GetPage应该以正确的顺序返回DocumentPages。下面是我的概念验证代码,演示了如何将自定义内容附加到Xps文档列表中:
public override DocumentPage GetPage(int pageNumber)
{
for (int i = 0; i < children.Count; i++)
{
if (pageNumber >= pageCounts[i])
pageNumber -= pageCounts[i];
else
return FixFixedPage(children[i].GetPage(pageNumber));
}
if (pageNumber < PageCount)
{
DrawingVisual dv = new DrawingVisual();
var dc = dv.Drawing.Append();
dc = dv.RenderOpen();
DoRender(pageNumber, dc); // some method to render stuff to the DrawingContext
dc.Close();
return new DocumentPage(dv);
}
return null;
}
当试图打印到另一个XPS文档,它给出了一个异常"FixedPage不能包含另一个FixedPage",和一个帖子由H.Alipourian演示如何修复它:http://social.msdn.microsoft.com/Forums/da/wpf/thread/841e804b-9130-4476-8709-0d2854c11582
private DocumentPage FixFixedPage(DocumentPage page)
{
if (!(page.Visual is FixedPage))
return page;
// Create a new ContainerVisual as a new parent for page children
var cv = new ContainerVisual();
foreach (var child in ((FixedPage)page.Visual).Children)
{
// Make a shallow clone of the child using reflection
var childClone = (UIElement)child.GetType().GetMethod(
"MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic
).Invoke(child, null);
// Setting the parent of the cloned child to the created ContainerVisual
// by using Reflection.
// WARNING: If we use Add and Remove methods on the FixedPage.Children,
// for some reason it will throw an exception concerning event handlers
// after the printing job has finished.
var parentField = childClone.GetType().GetField(
"_parent", BindingFlags.Instance | BindingFlags.NonPublic);
if (parentField != null)
{
parentField.SetValue(childClone, null);
cv.Children.Add(childClone);
}
}
return new DocumentPage(cv, page.Size, page.BleedBox, page.ContentBox);
}
对不起,这不是编译代码,我只是想提供一个必要的代码片段的概述,使其工作,让其他人在所有不同的部分需要聚集在一起,使其工作。尝试创建一个更通用的解决方案将比这个答案的范围要复杂得多。
虽然不是开源的,也不是。net原生的(我相信是基于Delphi的,但提供了一个预编译的。net库),但Quick PDF可以将PDF渲染为EMF文件,您可以将其加载到图形对象中。