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

发布于 2024-11-30 16:44:47 字数 372 浏览 1 评论 0原文

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

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

我们希望能够将这些 PDF 直接嵌入到打印流中,这样它们就不需要预先打印的纸张。然而,实际上并没有什么好的选择可以将 PDF 渲染到 GDI 页面 (System.Drawing.Graphics)。

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

We have a .NET app which prints to both real printers and PDF, currently using PDFsharp, although that part can be changed if there's a better option. Most of the output is generated text or images, but there can be one or more pages that get appended to the end. That page(s) are provided by the end-user in PDF format.

When printing to paper, our users use pre-printed paper, but in the case of an exported PDF, we concatenate those pages to the end, since they're already in PDF format.

We want to be able to embed those PDFs directly into the print stream so they don't need pre-printed paper. However, there aren't really any good options for rendering a PDF to a GDI page (System.Drawing.Graphics).

Is there a vector format the PDF could be converted to by some external program, that could rendered to a GDI+ page without being degraded by conversion to a bitmap first?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

各自安好 2024-12-07 16:44:47

在一篇标题为“如何在 .NET 中将 PDF 转换为 EMF”的文章中,我已经展示了如何使用我们的 PDFOne .NET 产品来做到这一点。 EMF 是矢量图形,您可以将它们渲染在打印机画布上。

对您来说,更简单的替代方案是另一篇标题为“PDF 覆盖 - 将 PDF 页面拼接在一起的文章中介绍的 PDF 覆盖在 .NET 中。” PDFOne 允许叠加中的 xy 偏移,从而允许您在边缘缝合页面。在此处引用的文章中,我通过将偏移量设置为零来将页面重叠在另一页面上。您将其设置为页面宽度和高度。

免责声明:我为 Gnostice 工作。

In an article titled "How To Convert PDF to EMF In .NET," I have shown how to do this using our PDFOne .NET product. EMFs are vector graphics and you can render them on the printer canvas.

A simpler alternative for you is PDF overlay explained in another article titled "PDF Overlay - Stitching PDF Pages Together in .NET." PDFOne allows x-y offsets in overlays that allows you stitch pages on the edges. In the article cited here, I have overlaid the pages one over another by setting the offsets to zero. You will have set it to page width and height.

DISCLAIMER: I work for Gnostice.

薄凉少年不暖心 2024-12-07 16:44:47

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

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

I finally figured out that there is an option that addresses my general requirement of embedding a vector format into a print job, but it doesn't work with GDI based printing.

The XPS file format created by Microsoft XPS Writer print driver can be printed from WPF, using the ReachFramework.dll included in .NET. By using WPF for printing instead of GDI, it's possible to embed an XPS document page into a larger print document.

The downside is, WPF printing works quite a bit different, so all the support code that directly uses stuff in the Sytem.Drawing namespace has to be re-written.

Here's the basic outline of how to embed the XPS document:

Open the document:

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");

Then create a descendant of DocumentPaginator, that will do your actual printing. Override the abstract methods, in particular the GetPage should return DocumentPages in the correct order. Here's my proof of concept code that demonstrates how to append custom content to a list of Xps documents:

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

When trying to print to another XPS document, it gives an exception "FixedPage cannot contain another FixedPage", and a post by H.Alipourian demonstrates how to fix it: 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);
}

Sorry that it's not exactly compiling code, I just wanted to provide an overview of the pieces of code necessary to make it work to give other people a head start on all the disparate pieces that need to come together to make it work. Trying to create a more generalized solution would be much more complex than the scope of this answer.

-残月青衣踏尘吟 2024-12-07 16:44:47

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

Ghostscript can output PostScript (which is a vector file) which can be directly sent to some types of printers. For example, if you're using an LPR capable printer, the PS file can be directly set to that printer using something like this project: http://www.codeproject.com/KB/printing/lpr.aspx

There are also some commercial options which can print a PDF (although I'm not sure if the internal mechanism is vector or bitmap based), for example http://www.tallcomponents.com/pdfcontrols2-features.aspx or http://www.tallcomponents.com/pdfrasterizer3.aspx

故事与诗 2024-12-07 16:44:47

虽然不是开源的,也不是 .NET 原生的(我相信是基于 Delphi,但提供了预编译的 .NET 库),Quick PDF 可以将 PDF 渲染为 EMF 文件,您可以将其加载到 Graphics 对象中。

While not open source and not .NET native (Delphi based I believe, but offers a precompiled .NET library), Quick PDF can render a PDF to an EMF file which you could load into your Graphics object.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文