2011-08-18 7 views
6

Abbiamo un'app .NET che stampa sia su stampanti reali che su PDF, che attualmente utilizza PDFsharp, sebbene tale parte possa essere modificata se esiste un'opzione migliore. La maggior parte dell'output è generata da testo o immagini, ma può esserci una o più pagine che vengono aggiunte alla fine. Quella pagina (s) sono forniti dall'utente finale in formato PDF.È possibile convertire un PDF in un formato di immagine vettoriale che può essere stampato da .NET?

Quando si stampa su carta, i nostri utenti utilizzano carta prestampata, ma nel caso di un PDF esportato, concateniamo tali pagine fino alla fine, poiché sono già in formato PDF.

Vogliamo essere in grado di incorporare tali PDF direttamente nel flusso di stampa in modo che non abbiano bisogno di carta prestampata. Tuttavia, non ci sono davvero buone opzioni per il rendering di un PDF in una pagina GDI (System.Drawing.Graphics).

Esiste un formato vettoriale in cui il PDF potrebbe essere convertito da un programma esterno, che potrebbe essere sottoposto a una pagina GDI + senza essere prima degradato dalla conversione in una bitmap?

+0

facciamo qualcosa di simile, ma rendiamo il PDF prima di tutto in un bitmap: il problema della qualità può essere ottenuto quando si esegue il rendering utilizzando una libreria di alta qualità più un valore di alta risoluzione (minimo 305, migliore 1200) che costa un po 'di memoria/prestazioni ... – Yahia

+1

Ho notato l'altro giorno che PDFCreator (http://sourceforge.net/projects/pdfcreator/), nonostante sia principalmente finalizzato alla creazione di PDF, può essere effettivamente utilizzato per stampare documenti PDF in una vasta gamma di formati, tra cui Immagini SVG e bitmap. Potrebbe meritare un'occhiata. –

+0

Questi PDF tendono ad essere di testo con alcune linee art. Avrebbero anche stampato più di 1000 volte di seguito. La conversione di un PDF da 30 KB in una bitmap da 5 MB probabilmente porterebbe l'intera coda di stampa in ginocchio. –

risposta

2

In un articolo intitolato "How To Convert PDF to EMF In .NET," ho mostrato come fare questo usando il nostro prodotto PDFOne .NET. I campi elettromagnetici sono grafica vettoriale e puoi renderli sulla tela della stampante.

Un'alternativa più semplice per te è la sovrapposizione PDF spiegata in un altro articolo intitolato "PDF Overlay - Stitching PDF Pages Together in .NET". PDFOne consente gli offset x-y nelle sovrapposizioni che consentono di cucire le pagine sui bordi. Nell'articolo citato qui, ho sovrapposto le pagine una sull'altra impostando gli offset su zero. Lo avrai impostato su larghezza e altezza della pagina.

DISCLAIMER: Lavoro per Gnostice.

+0

In realtà utilizziamo già il toolkit Gnostice PDF in Delphi per unire i due PDF insieme, ma stiamo spostando la stampa su .NET. quindi ci sono più opzioni disponibili. Non vedo GetPageMetafile() sul componente Delphi, è una nuova aggiunta o è specifico per la versione .NET? –

+0

L'altra domanda, in realtà genera file .EMF autonomi? In passato abbiamo provato a utilizzare un prodotto che doveva consentire di stampare su .EMF, ma il file di output funzionava solo fino a quando il programma di stampa era aperto, perché aveva callback al programma originale che scompariva quando si chiudeva quel programma . Se PDFOne.NET è in grado di garantire il funzionamento dei file .EMF, sembra la soluzione che sto cercando. –

+0

PDFtoolkit ha due metodi: RenderToDC (a cui è possibile passare il canvas della stampante) e RenderToStream (a cui si fornisce un flusso EMF). Questi metodi generano EMF simile a GetPageMetafile di PDFOne .NET. In PDFOne .NET, GetPageMetaFile è disponibile solo nell'edizione ProPlus. – BZ1

0

Ghostscript può emettere PostScript (che è un file vettoriale) che può essere inviato direttamente ad alcuni tipi di stampanti. Ad esempio, se si utilizza una stampante LPR, il file PS può essere impostato direttamente su quella stampante usando qualcosa come questo: http://www.codeproject.com/KB/printing/lpr.aspx

Ci sono anche alcune opzioni commerciali che possono stampare un PDF (anche se sono non è sicuro se il meccanismo interno è vettoriale o bitmap a base), per esempio http://www.tallcomponents.com/pdfcontrols2-features.aspx o http://www.tallcomponents.com/pdfrasterizer3.aspx

+0

Non ho alcun controllo diretto sulla stampante che usano, la mia ipotesi è che molti sono configurati come PCL, non come Postscript. L'altro problema è che vogliono il PDF sul retro di una delle pagine (quindi la carta prestampata), quindi non può essere inviato come un processo di stampa separato. –

+0

Beh, anche GhostPCL (http://ghostscript.com/GhostPCL.html) esiste :) – userx

-1

Sebbene non sia open source e non nativo .NET (basato su Delphi, ma offre una libreria .NET precompilata), Quick PDF può eseguire il rendering di un PDF in un file EMF che è possibile caricare nell'oggetto Graphics.

0

Alla fine ho capito che esiste un'opzione che affronta il mio requisito generale di incorporare un formato vettoriale in un lavoro di stampa, ma non funziona con la stampa basata su GDI.

Il formato di file XPS creato dal driver di stampa Microsoft XPS Writer può essere stampato da WPF, utilizzando ReachFramework.dll incluso in .NET. Utilizzando WPF per la stampa anziché GDI, è possibile incorporare una pagina del documento XPS in un documento di stampa più grande.

Lo svantaggio è che la stampa WPF funziona in modo un po 'diverso, quindi tutto il codice di supporto che utilizza direttamente elementi nello spazio dei nomi Sytem.Drawing deve essere riscritto.

Ecco lo schema di base di come incorporare il documento XPS:

Aprire il documento:

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

quindi creare un discendente di DocumentPaginator, che farà la stampa vera e propria.Sovrascrivi i metodi astratti, in particolare GetPage dovrebbe restituire DocumentPages nell'ordine corretto. Ecco il mio codice di prova che dimostra come aggiungere contenuti personalizzati a un elenco di documenti 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; 
} 

Quando si tenta di stampare su un altro documento XPS, dà un'eccezione "FixedPage non può contenere un altro FixedPage", e un messaggio di H.Alipourian dimostra come risolvere il problema: 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); 
} 

dispiace che non è esattamente la compilazione del codice, volevo solo fornire una panoramica dei pezzi di codice necessario per farlo funzionare per dare ad altre persone una testa inizia su tutti i pezzi disparati che devono venire insieme per farlo funzionare. Cercare di creare una soluzione più generalizzata sarebbe molto più complesso dello scopo di questa risposta.

Problemi correlati