我们有一个.NET应用程序,可以打印到真正的打印机和PDF,目前使用的是PDFsharp,但如果有更好的选择,这一部分可以更改。大多数输出都是生成的文本或图像,但可以有一个或多个页面附加到末尾。该页面由最终用户以PDF格式提供。
当打印到纸张时,我们的用户使用预先打印的纸张,但在导出PDF的情况下,我们将这些页面连接到末尾,因为它们已经是PDF格式。
我们希望能够将这些PDF直接嵌入到打印流中,这样它们就不需要预先打印的纸张。然而,没有任何好的选项可以将PDF呈现为GDI页面(System.Drawing.Graphics)。
有没有一种矢量格式的PDF可以转换成一些外部程序,可以渲染到一个GDI+页面,而不是通过转换为位图首先降级?
发布于 2011-08-19 13:01:20
在一篇题为"How To Convert PDF to EMF In .NET“的文章中,我展示了如何使用我们的PDFOne .NET产品来实现这一点。EMF是矢量图形,您可以在打印机画布上渲染它们。
另一个更简单的选择是PDF overlay,在另一篇标题为“PDF Overlay - Stitching PDF Pages Together in .NET”的文章中进行了解释。PDFOne允许在叠层中使用x-y偏移量,从而允许您在边缘上拼接页面。在这里引用的文章中,我通过将偏移量设置为零,将页面逐个覆盖。您需要将其设置为页面宽度和高度。
免责声明:我为Gnostice工作。
发布于 2011-08-19 05:10:28
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
发布于 2012-11-14 06:38:34
我最终发现,有一个选项可以满足我在打印作业中嵌入矢量格式的一般要求,但它不适用于基于GDI的打印。
由Microsoft XPS Writer打印驱动程序创建的XPS文件格式可以使用.NET中包含的ReachFramework.dll从WPF打印。通过使用WPF而不是GDI进行打印,可以将XPS文档页面嵌入到较大的打印文档中。
缺点是,WPF打印的工作原理有很大的不同,所以所有直接使用Sytem.Drawing命名空间中的东西的支持代码都必须重写。
下面是如何嵌入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);
}很抱歉,它并不是在编译代码,我只是想概述一下让它工作所必需的代码片段,让其他人在所有需要组合在一起才能使它工作的不同的代码片段上领先一步。尝试创建一个更通用的解决方案将比这个答案的范围复杂得多。
https://stackoverflow.com/questions/7113590
复制相似问题