2011-08-18 52 views
6

我們有一個.NET應用程序,可以打印到真正的打印機和PDF,目前使用PDFsharp,儘管如果有更好的選項可以更改該部分。大多數輸出​​是生成文本或圖像,但可以有一個或多個頁面附加到結尾。該頁面由最終用戶以PDF格式提供。可以將PDF轉換爲可以從.NET打印的矢量圖像格式嗎?

打印到紙張上時,我們的用戶使用預先打印的紙張,但對於導出的PDF,我們將這些頁面連接到最後,因爲它們已經是PDF格式。

我們希望能夠將這些PDF直接嵌入到打印流中,因此它們不需要預先打印的紙張。但是,將PDF呈現到GDI頁面(System.Drawing.Graphics)沒有任何好的選擇。

PDF是否可以通過某些外部程序轉換爲矢量格式,可以將其轉換爲GDI +頁面而不會先通過轉換爲位圖進行降級?

+0

我們做了類似的事情,但首先將PDF渲染爲位圖 - 當使用高質量庫和高DPI值(最少305,最佳1200)進行渲染時,會產生質量問題,這會降低一些內存/性能... – Yahia

+1

我注意到有一天,PDFCreator(http://sourceforge.net/projects/pdfcreator/)雖然主要針對PDF創建,但實際上可以用來將PDF文檔打印成各種格式,包括SVG和位圖圖像。也許值得一瞧。 –

+0

這些PDF往往是一些線條藝術的文字。他們也會在一次運行中打印1000次以上。將30 KB PDF轉換爲5 MB位圖可能會使整個打印隊列癱瘓。 –

回答

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工作。

+0

我們實際上已經使用Delphi中的Gnostice PDF工具包將兩個PDF拼接在一起,但我們正在將打印移到.NET所以有更多的選擇。我沒有看到Delphi組件上的GetPageMetafile(),是一個新的增加,還是特定於.NET版本? –

+0

另一個問題是否確實會生成獨立的.EMF文件?我們實際上曾嘗試過使用本應允許您打印到.EMF的產品,但輸出文件只在打印程序打開時才起作用,因爲它關閉了原始程序,並在關閉程序時消失。如果PDFOne.NET可以保證工作.EMF文件,這聽起來像我正在尋找的解決方案。 –

+0

PDFtoolkit有兩種方法 - RenderToDC(您可以傳遞打印機畫布)和RenderToStream(向您提供EMF流)。這些方法生成類似於PDFOne .NET的GetPageMetafile的EMF。在PDFOne .NET中,GetPageMetaFile僅在ProPlus版本中可用。 – BZ1

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

+0

我沒有任何直接控制他們使用的打印機,我的猜測是大多數設置爲PCL,而不是Postscript。另一個問題是他們希望在其中一個頁面的背面(即預先打印的紙張)背面輸入PDF,因此無法將其作爲單獨的打印作業發送。 –

+0

嗯,GhostPCL(http://ghostscript.com/GhostPCL.html)確實也存在:) – userx

-1

Quick PDF雖然不是開放源代碼,而不是.NET本地(我相信基於德爾福,但提供了一個預編譯的.NET庫),但可以將PDF渲染爲可加載到Graphics對象中的EMF文件。

0

我終於明白,有一個選項可以解決將矢量格式嵌入到打印作業中的一般要求,但它不適用於基於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"); 

然後創建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不能包含另一個固定頁」和發佈者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); 
} 

比較遺憾的是它不完全編譯代碼,我只是想提供必要的代碼片段概觀,使工作給其他人一個頭從所有需要共同努力的不同部分開始工作。試圖創建一個更通用的解決方案將比這個答案的範圍複雜得多。

相關問題