C# 能否将PDF转换为可以从.NET打印的矢量图像格式?

C# 能否将PDF转换为可以从.NET打印的矢量图像格式?,c#,pdf,gdi,vector-graphics,C#,Pdf,Gdi,Vector Graphics,我们有一个.NET应用程序,它可以打印到真正的打印机和PDF,目前使用的是PDFsharp,不过如果有更好的选择,这部分可以更改。大多数输出都是生成的文本或图像,但可以有一个或多个页面附加到末尾。该页面由最终用户以PDF格式提供 当打印到纸张时,我们的用户使用预打印的纸张,但对于导出的PDF,我们将这些页面连接到末尾,因为它们已经是PDF格式 我们希望能够将这些PDF直接嵌入到打印流中,这样它们就不需要预打印纸张。然而,对于将PDF呈现到GDI页面(System.Drawing.Graphics

我们有一个.NET应用程序,它可以打印到真正的打印机和PDF,目前使用的是PDFsharp,不过如果有更好的选择,这部分可以更改。大多数输出都是生成的文本或图像,但可以有一个或多个页面附加到末尾。该页面由最终用户以PDF格式提供

当打印到纸张时,我们的用户使用预打印的纸张,但对于导出的PDF,我们将这些页面连接到末尾,因为它们已经是PDF格式

我们希望能够将这些PDF直接嵌入到打印流中,这样它们就不需要预打印纸张。然而,对于将PDF呈现到GDI页面(System.Drawing.Graphics),实际上并没有任何好的选项

是否有一种可以由外部程序将PDF转换为的矢量格式,该格式可以在不首先转换为位图的情况下呈现到GDI+页面?

可以输出PostScript(矢量文件),可以直接发送到某些类型的打印机。例如,如果您使用的是支持LPR的打印机,则可以使用以下项目将PS文件直接设置为该打印机:

还有一些商业选项可以打印PDF(尽管我不确定内部机制是基于矢量还是基于位图),例如,或者在一篇题为“我已经展示了如何使用我们的PDFOne.NET产品实现这一点”的文章中。EMF是矢量图形,您可以在打印机画布上渲染它们

另一篇题为“PDFOne”的文章中解释了一种更简单的替代方法,即PDF覆盖。PDFOne允许覆盖中的x-y偏移,从而允许在边缘上缝合页面。在这里引用的文章中,我通过将偏移设置为零,将页面覆盖在另一个页面上。您将其设置为页面宽度和高度


免责声明:我为Gnostice工作。

虽然不是开源的,也不是.NET本机(我相信是基于Delphi的,但提供了一个预编译的.NET库),可以将PDF呈现为EMF文件,您可以将其加载到图形对象中。

我最终发现有一个选项可以满足我在打印作业中嵌入矢量格式的一般要求,但它不适用于基于GDI的打印

可以使用.NET中包含的ReachFramework.dll从WPF打印Microsoft XPS Writer打印驱动程序创建的XPS文件格式。通过使用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");
打开文档:

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;
}

很抱歉,它并不是编译代码,我只是想提供一个使它工作所必需的代码片段的概述,以便让其他人在所有需要结合起来使它工作的不同片段上领先。尝试创建一个更通用的解决方案要比这个答案的范围复杂得多。

我们做了类似的事情,但先将PDF渲染为位图-使用高质量库加上高dpi值(最小值305,最佳值1200)进行渲染时,可以解决质量问题这需要一些内存/性能…前几天我注意到,PDFCreator()尽管主要用于创建PDF,但实际上可以用于将PDF文档打印为多种格式,包括SVG和位图图像。可能值得一看。这些PDF往往是带有线条艺术的文本。它们也会在一次运行中打印1000多次以上。将30 KB的PDF转换为5 MB的位图可能会使整个打印队列崩溃。我无法直接控制他们使用的打印机,我猜大多数打印机都设置为PCL,而不是Postscript。另一个问题是,他们希望将PDF放在其中一页的背面(因此是预打印的纸张),因此无法将其作为单独的打印作业发送。实际上,我们已经使用Delphi中的Gnostice PDF工具包将两个PDF缝合在一起,但我们正在将打印移到.NET,因此有更多选项可用。我在Delphi组件上没有看到GetPageMetafile(),这是一个新的添加,还是特定于.NET版本?另一个问题,它是否实际生成独立的.EMF文件?实际上,我们过去曾尝试使用一种产品,该产品本应允许您打印到.EMF,但输出文件只在打印程序打开时才起作用,因为它有对原始程序的回调,而当您关闭该程序时,原始程序就消失了。如果PDFOne.NET可以保证.EMF文件正常工作,那听起来像是我正在寻找的解决方案。PDFtoolkit有两种方法-RenderToDC(您可以向其传递打印机画布)和RenderToStream(您向其提供EMF流)。这些方法生成的EMF类似于PDFOne.NET的GetPageMetafile。在PDFOne.NET中,GetPageMetaFile仅在ProPlus版本中可用。在上面给出的第一篇文章中,我展示了在Windows图片和传真查看器中打开的EMF文件的屏幕截图。它是一个独立的EMF文件。PDFOne还有一个打印机组件,可以直接将PDF页面打印到打印机上。您不需要使用EMF文件。EMF文件可以直接在打印机画布上播放。两者都会起作用。