HotPDF stampa un PDF caricato su una stampante fisica, su qualsiasi device context di Windows o negli appunti tramite tre chiamate: PrintLoadedDocument gestisce un TPrinter VCL, RenderLoadedPageToDC disegna una pagina direttamente in qualsiasi HDC, e RenderLoadedPageToClipboard copia una pagina come bitmap o come metafile vettoriale. HotPDF è un componente PDF VCL nativo per Delphi e C++Builder, che ha introdotto questo percorso di stampa nativo nella versione v2.331.0, perfezionandolo nella versione v2.348.0, in modo da non dover più creare manualmente un ciclo TPrinter attorno a un renderer bitmap. Tutte e tre le chiamate disegnano il contenuto vettoriale della pagina direttamente dove serve, così la stampa rimane nitida quanto consentito dalla stampante
Perché disegnare una pagina PDF direttamente nella stampante invece di una bitmap?
Una pagina PDF è un programma di operatori di disegno vettoriale — tracciati, testo e immagini eseguiti rispetto al modello grafico ISO 32000-1 — non una griglia di pixel. Il modo ovvio di stamparne una consiste nel rasterizzare la pagina in una bitmap e trasferire tale bitmap sull'area di disegno della stampante; funziona, ma vanifica l'unico aspetto in cui una stampante eccelle. Una moderna stampante laser ha una risoluzione di 600 o 1200 DPI; una bitmap rasterizzata a 150 o 300 DPI e poi allungata per adattarsi alla pagina risulterà sfocata, con bordi di testo frastagliati e interpolazione visibile. RenderLoadedPageToDC adotta una strada migliore: riproduce il content stream della pagina come chiamate GDI emesse direttamente nel device context di destinazione, in modo che il testo vettoriale e la grafica lineare raggiungano la stampante come vettori e vengano rasterizzati una sola volta, dalla stampante stessa, alla sua risoluzione nativa
Come si stampa un PDF caricato su una stampante fisica in Delphi?
HotPDF stampa un documento caricato con PrintLoadedDocument(Printer, Options), che accetta un TPrinter VCL assegnato e un record THPDFPrintOptions, stampa le pagine selezionate e restituisce il numero di pagine inviate. Imposta prima Printer.PrinterIndex per scegliere un dispositivo, compila un record di opzioni — la funzione di classe THPDFPrintOptions.Default fornisce valori sensati — e chiamala una volta. La libreria apre il processo con Printer.BeginDoc, scorre l'intervallo di pagine emettendo una chiamata a Printer.NewPage tra una pagina e l'altra, e lo chiude con Printer.EndDoc, in modo da non dover mai gestire manualmente il ciclo di vita del processo di stampa
uses Printers;
var
Pdf: THotPDF;
Opts: THPDFPrintOptions;
begin
Pdf := THotPDF.Create(nil);
try
if Pdf.LoadFromFile('invoice.pdf') > 0 then
begin
Printer.PrinterIndex := -1; // -1 seleziona la stampante predefinita
Opts := THPDFPrintOptions.Default; // tutte le pagine, 300 DPI, FitPage, colore
Opts.PageRange := '1,3-5'; // a base 1; vuoto stampa tutte le pagine
Opts.Copies := 2;
Pdf.PrintLoadedDocument(Printer, Opts);
end;
finally
Pdf.Free;
end;
end;
La stringa PageRange è a base 1 e si legge come una finestra di dialogo di stampa: '1,3-5' stampa la pagina 1 e le pagine da 3 a 5, mentre una stringa vuota stampa l'intero documento. Copies mappa direttamente su Printer.Copies. Sii onesto con te stesso riguardo a Collate, tuttavia: poiché la VCL espone la collazione in modo incoerente tra le versioni di Delphi, HotPDF imposta il numero di copie e lascia la collazione alle impostazioni predefinite del driver della stampante, quindi quando hai bisogno di un ordine di collazione garantito, impostalo sul driver tramite TPrinterSetupDialog anziché affidarti al flag per gestirlo
In che modo DPI e FitPage decidono la scala di stampa?
FitPage e DPI interagiscono in un modo che vale la pena comprendere prima del rilascio. Con FitPage impostato su True — il valore predefinito — HotPDF legge il MediaBox di ciascuna pagina, lo ridimensiona a Printer.PageWidth e Printer.PageHeight preservando le proporzioni, ed esegue il rendering alla scala che consente alla pagina di riempire la carta. In questa modalità Options.DPI viene effettivamente ignorato dalla scala di adattamento, poiché l'output deve corrispondere alle dimensioni fisiche della pagina della stampante. Con FitPage impostato su False, HotPDF esegue il rendering di ciascuna pagina 1:1 esattamente a Options.DPI, mappando 72 unità PDF a pixel del dispositivo DPI, che è ciò che desideri quando la pagina sorgente e la carta hanno già le stesse dimensioni e ti interessa una risoluzione esatta. Utilizza FitPage quando le dimensioni della pagina sorgente e del vassoio differiscono; scegli 1:1 quando corrispondono e desideri un ridimensionamento deterministico
Due opzioni aggiunte nella versione v2.348.0 correggono le stampe che appaiono quasi corrette. Ogni stampante fisica ha un margine hardware — un bordo non stampabile che l'hardware non può raggiungere — e per impostazione predefinita l'origine della pagina si trova al suo interno, quindi una pagina a tutta area perde una striscia su due bordi. Imposta IgnoreHardMargin su True e HotPDF interrogherà i valori PHYSICALOFFSETX e PHYSICALOFFSETY della stampante, quindi sposterà l'origine del dispositivo per annullare tale offset in modo che l'origine della pagina si mappi sul vero angolo della carta. La seconda opzione, AutoRotate, è attiva per impostazione predefinita: legge il MediaBox di ciascuna pagina e, quando una pagina è più larga che alta, imposta la stampante in orientamento orizzontale in modo che una pagina larga venga stampata senza ritagli invece di essere tagliata in orientamento verticale. AutoRotate viene ignorata nel momento in cui imposti Orientation in modo esplicito, quindi una scelta deliberata dell'orientamento prevale sempre
Come si esegue il rendering di una pagina PDF in un qualsiasi device context?
RenderLoadedPageToDC(PageIndex, DC, DPI, W, H) è la primitiva alla base del ciclo di stampa ed è utile anche da sola. PrintLoadedDocument la chiama una volta per pagina sul canvas della stampante, mas la destinazione può essere un qualsiasi HDC di Windows: un DC in memoria fuori schermo, il canvas di un controllo in un visualizzatore personalizzato o una superficie di anteprima di stampa. PageIndex è a base 0, W e H sono le unità di dispositivo della superficie di destinazione, e il renderer scorre i /Contents della pagina emettendo chiamate GDI nel tuo DC. Vale la pena conoscere un comportamento intenzionale: non disegna alcun riempimento di sfondo. Il chiamante possiede la superficie, quindi se desideri carta bianca dietro la pagina devi riempire tu stesso il DC prima del rendering, che è esattamente ciò che consente di comporre una pagina sopra un canvas esistente quando lo desideri
// Disegna la pagina 1 in una superficie a 24 bit fuori schermo a 150 DPI
var
Surface: TBitmap;
begin
Surface := TBitmap.Create;
try
Surface.PixelFormat := pf24bit;
Surface.SetSize(1275, 1650); // 8,5 x 11 pollici a 150 DPI
Surface.Canvas.Brush.Color := clWhite;
Surface.Canvas.FillRect(Surface.Canvas.ClipRect); // il chiamante dipinge lo sfondo
Pdf.RenderLoadedPageToDC(0, Surface.Canvas.Handle, 150, Surface.Width, Surface.Height);
// Surface ora contiene la pagina composta, pronta per il blit o il salvataggio
finally
Surface.Free;
end;
end;
Quando hai semplicemente bisogno di un TBitmap completo — una miniatura, un'esportazione di immagini, un'anteprima da salvare in cache — fai riferimento a RenderLoadedPageToBitmap, trattato nell'articolo di accompagnamento su rendering delle pagine PDF in bitmap. La differenza sta in chi possiede la superficie: la chiamata bitmap alloca e restituisce un buffer di pixel, mentre RenderLoadedPageToDC disegna in un device context già in tuo possesso, che è esattamente ciò che ti viene fornito dal canvas della stampante o da un gestore di pittura. Entrambi condividono lo stesso interprete di content-stream e lo stesso motore di glifi incorporati, quindi in entrambi i casi il testo viene generato con i contorni incorporati esatti
Come si fa a incollare una pagina PDF in Word o in un editor di immagini?
RenderLoadedPageToClipboard(PageIndex, DPI, AsMetafile) inserisce una pagina negli appunti di Windows, pronta per essere incollata in Word, PowerPoint, in un'e-mail o in un editor di immagini. Il flag AsMetafile sceglie il formato, e la scelta è più importante di quanto sembri. Passando False, HotPDF inserisce una bitmap del dispositivo a 24 bit (CF_BITMAP) renderizzata al tuo DPI — una griglia fissa di pixel che può essere incollata ovunque ma che sgranerà quando il destinatario la ingrandirà. Passando True, inserisce un enhanced metafile (CF_ENHMETAFILE) in cui il testo della pagina e la grafica vettoriale viaggiano come comandi di disegno GDI, in modo che il risultato incollato rimanga nitido a qualsiasi livello di zoom e si adatti a qualsiasi dimensione indicata nel documento di destinazione
// Copia la pagina 2 come metafile vettoriale scalabile da incollare in Word
Pdf.RenderLoadedPageToClipboard(1, 300, True);
// Copia invece la stessa pagina come bitmap fissa a 300 DPI
Pdf.RenderLoadedPageToClipboard(1, 300, False);
La regola empirica è semplice. Se un utente deve incollare la pagina in un documento e potrebbe ridimensionarla — ad esempio una figura in una relazione o una clausola inserita nella bozza di un contratto — utilizza il metafile, poiché il testo vettoriale viene stampato e ingrandito in modo nitido. Se la destinazione comprende solo dati raster, o se desideri specificamente un'istantanea statica a una risoluzione nota, utilizza la bitmap. Per estrarre le parole da una pagina anziché un'immagine di esse, questo è un lavoro completamente diverso, gestito dall'API di estrazione del testo, che restituisce i caratteri e le loro posizioni invece di un'immagine renderizzata
Dove si ferma il percorso di stampa
Tutto su questa pagina è specifico per Windows, ed è bene dichiararlo chiaramente. PrintLoadedDocument, RenderLoadedPageToDC e RenderLoadedPageToClipboard sono basati su TPrinter, sul modello di device-context GDI, sugli appunti di Windows e su enhanced metafile — tutti costrutti Win32 e Win64. Su altre piattaforme il resto di HotPDF crea, modifica e legge comunque i PDF, ma questa superficie di stampa e appunti basata su GDI non è disponibile. Il renderer si rivolge anche al sottoinsieme comune di documenti composto da testo, tracciati e immagini, quindi le prove di progettazione ricche di sfumature e la stampa a colori gestita da ICC generano un'anteprima fedele piuttosto che una prova colorimetrica, lo stesso limite che caratterizza il renderer bitmap
Per la stampa batch su molti file, carica e stampa ogni documento a sua volta e monitora l'occupazione di memoria: PrintLoadedDocument esegue il rendering di una pagina alla volta, ma il grafo del documento caricato rimane in memoria per l'intera durata del processo. Quando gestisci una coda di stampa su centinaia di file di grandi dimensioni, l'API in streaming Direct File API per flussi di lavoro PDF di grandi dimensioni si abbina bene con il percorso di stampa — dividi, unisci o seleziona prima su disco le pagine necessarie, quindi carica solo il risultato ridotto per la stampa. È così che PrintLoadedDocument, RenderLoadedPageToDC e RenderLoadedPageToClipboard vengono forniti come parte di HotPDF Component per Delphi e C++Builder — una libreria VCL nativa senza dipendenze da DLL esterne che copre creazione, modifica, estrazione di testo, rendering e ora stampa diretta in TPrinter, su qualsiasi device context o negli appunti