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

时间:2011-08-18 20:16:12

标签: c# pdf gdi vector-graphics

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

在打印到纸张时,我们的用户使用预先打印的纸张,但在导出PDF的情况下,我们会将这些页面连接到最后,因为它们已经是PDF格式。

我们希望能够将这些PDF直接嵌入到打印流中,因此它们不需要预先打印的纸张。但是,将PDF转换为GDI页面并没有什么好的选择(System.Drawing.Graphics)。

是否有一种矢量格式可以通过某些外部程序将PDF转换为可以转换为GDI +页面而不会因首先转换为位图而降级?

4 个答案:

答案 0 :(得分:2)

在一篇名为“How To Convert PDF to EMF In .NET”的文章中,我已经展示了如何使用我们的PDFOne .NET产品。 EMF是矢量图形,您可以在打印机画布上渲染它们。

另一个标题为“PDF Overlay - Stitching PDF Pages Together in .NET”的文章解释了PDF替代方案。 PDFOne允许叠加中的x-y偏移,允许您在边缘缝合页面。在这里引用的文章中,我通过将偏移设置为零将页面重叠在一起。您将其设置为页面宽度和高度。

免责声明:我为Gnostice工作。

答案 1 :(得分:0)

Ghostscript可以输出PostScript(矢量文件),可以直接发送到某些类型的打印机。例如,如果您使用的是支持LPR的打印机,则可以使用此项目之类的内容将PS文件直接设置为该打印机:http://www.codeproject.com/KB/printing/lpr.aspx

还有一些商业选项可以打印PDF(虽然我不确定内部机制是基于矢量还是位图),例如http://www.tallcomponents.com/pdfcontrols2-features.aspxhttp://www.tallcomponents.com/pdfrasterizer3.aspx

答案 2 :(得分:0)

我终于发现有一个选项可以满足我将矢量格式嵌入到打印作业中的一般要求,但它不适用于基于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);
}

很抱歉,这并不完全是编译代码,我只是想提供一些代码所需的代码概述,以便让其他人在需要聚集在一起以使其工作的所有不同部分上先行一步。尝试创建更通用的解决方案将比这个答案的范围复杂得多。

答案 3 :(得分:-1)

虽然不是开源而不是.NET原生(我相信Delphi,但提供预编译的.NET库),Quick PDF可以将PDF呈现为EMF文件,您可以将其加载到Graphics对象中。 / p>