Articol tehnic

Imprimarea unui PDF încărcat în Delphi cu HotPDF și TPrinter

HotPDF imprimă un PDF încărcat la o imprimantă fizică, la orice context de dispozitiv (device context) Windows sau în clipboard prin intermediul a trei apeluri: PrintLoadedDocument controlează o componentă VCL TPrinter, RenderLoadedPageToDC desenează o pagină direct în orice HDC, iar RenderLoadedPageToClipboard copiază o pagină sub formă de bitmap sau metafile vectorial. HotPDF este o componentă nativă VCL PDF pentru Delphi și C++Builder și a adăugat această cale de imprimare directă în v2.331.0, optimizând-o în v2.348.0, astfel încât nu mai trebuie să scrieți manual o buclă TPrinter în jurul unui generator de randare bitmap. Toate cele trei apeluri desenează conținutul vectorial al paginii direct unde este nevoie, astfel încât rezultatul imprimat rămâne la fel de clar pe cât îl poate reda imprimanta

De ce să desenați o pagină PDF direct în imprimantă în loc de un bitmap?

O pagină PDF este o suită de operatori de desenare vectorială — căi, text și imagini executate în raport cu modelul grafic ISO 32000-1 —, nu o grilă de pixeli. Modul evident de a imprima o pagină este rasterizarea acesteia la un bitmap și transferul (blitting) acelui bitmap pe canvas-ul imprimantei; acest lucru funcționează, pero elimină singurul lucru la care o imprimantă este bună. O imprimantă laser modernă are o rezoluție de 600 sau 1200 DPI; un bitmap rasterizat la 150 sau 300 DPI și apoi extins pentru a se potrivi devine șters, cu margini de text zimțate și interpolare vizibilă. RenderLoadedPageToDC alege o cale mai bună: reproduce fluxul de conținut al paginii ca apeluri GDI emise direct în contextul de dispozitiv țintă, astfel încât textul vectorial și desenele liniare ajung la imprimantă ca vectori și sunt rasterizate o singură dată, de către imprimantă, la rezoluția proprie a acesteia

Cum se imprimă un PDF încărcat la o imprimantă fizică în Delphi?

HotPDF imprimă un document încărcat folosind PrintLoadedDocument(Printer, Options), care primește o componentă VCL TPrinter alocată și o înregistrare THPDFPrintOptions, imprimă paginile selectate și returnează numărul de pagini trimise. Setați mai întâi Printer.PrinterIndex pentru a alege un dispozitiv, completați o înregistrare de opțiuni — funcția de clasă THPDFPrintOptions.Default vă oferă valori rezonabile — și apelați-o o singură dată. Biblioteca deschide lucrarea cu Printer.BeginDoc, parcurge intervalul de pagini emițând un apel Printer.NewPage între pagini și o închide cu Printer.EndDoc, astfel încât nu trebuie să gestionați niciodată manual ciclul de viață al lucrării de imprimare

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 selects the default printer
      Opts := THPDFPrintOptions.Default;  // all pages, 300 DPI, FitPage, colour
      Opts.PageRange := '1,3-5';          // one-based; empty prints every page
      Opts.Copies := 2;
      Pdf.PrintLoadedDocument(Printer, Opts);
    end;
  finally
    Pdf.Free;
  end;
end;

Cum decid DPI și FitPage scara de imprimare?

Opțiunile FitPage și DPI interacționează într-un mod care merită înțeles înainte de livrare. Cu FitPage setat pe True — valoarea implicită —, HotPDF citește structura MediaBox a fiecărei pagini, o scalează la dimensiunile Printer.PageWidth și Printer.PageHeight păstrând raportul de aspect, și randează la scara care face ca pagina să umple hârtia. În acest mod, Options.DPI este practic suprascris de scara de potrivire, deoarece ieșirea trebuie să corespundă dimensiunilor fizice ale paginii imprimantei. Cu FitPage setat pe False, HotPDF randează fiecare pagină 1:1 la valoarea exactă a Options.DPI, mapând 72 de unități PDF la pixelii de dispozitiv DPI, ceea ce este de dorit atunci când pagina sursă și hârtia au deja aceeași dimensiune și aveți nevoie de o rezoluție exactă. Apelați la FitPage când dimensiunea paginii sursă și cea a tăvii diferă; alegeți 1:1 când acestea se potrivesc și doriți o scalare deterministă

Două opțiuni adăugate în v2.348.0 corectează documentele imprimate care par aproape corecte. Fiecare imprimantă fizică are o marjă hardware (hard margin) — o bordură neimprimabilă la care hardware-ul nu poate ajunge — și în mod implicit originea paginii este plasată în interiorul acesteia, astfel încât o pagină imprimată complet pierde o bandă pe două margini. Setați IgnoreHardMargin pe True, iar HotPDF va interoga parametrii imprimantei PHYSICALOFFSETX și PHYSICALOFFSETY, then va deplasa originea dispozitivului pentru a anula acea diferență, astfel încât originea paginii să se mapeze pe colțul real al hârtiei. A doua opțiune, AutoRotate, este activă în mod implicit: citește structura MediaBox a fiecărei paginii și, când o pagină este mai lată decât înaltă, comută imprimanta în modul landscape, astfel încât o pagină lată se imprimă complet în loc să fie decupată în modul portrait. AutoRotate se dezactivează în momentul în care setați în mod explicit orientarea Orientation, astfel încât o alegere deliberată a orientării va avea întotdeauna prioritate

Cum se randează o pagină PDF în orice context de dispozitiv?

RenderLoadedPageToDC(PageIndex, DC, DPI, W, H) este primitiva aflată la baza buclei de imprimare și este utilă în sine. PrintLoadedDocument o apelează o dată pe pagină în raport cu canvas-ul imprimantei, dar ținta poate fi orice HDC Windows: un DC de memorie off-screen, canvas-ul unui control dintr-un vizualizator personalizat sau o suprafață de previzualizare a imprimării. PageIndex este bazat pe zero, W și H sunt unitățile de dispozitiv ale suprafeței țintă, iar generatorul de randare parcurge elementul /Contents al paginii și emite apeluri GDI în DC-ul dvs. Merită reținut un comportament deliberat: acesta nu desenează nicio umplere a fundalului. Apelantul deține suprafața, așa că dacă doriți hârtie albă în spatele paginii, trebuie să umpleți singuri DC-ul înainte de randare, ceea ce vă permite să suprapuneți o pagină peste un canvas existent atunci când doriți

// Draw page 1 into an off-screen 24-bit surface at 150 DPI
var
  Surface: TBitmap;
begin
  Surface := TBitmap.Create;
  try
    Surface.PixelFormat := pf24bit;
    Surface.SetSize(1275, 1650);           // 8.5 x 11 in at 150 DPI
    Surface.Canvas.Brush.Color := clWhite;
    Surface.Canvas.FillRect(Surface.Canvas.ClipRect);  // caller paints the background
    Pdf.RenderLoadedPageToDC(0, Surface.Canvas.Handle, 150, Surface.Width, Surface.Height);
    // Surface now holds the composited page, ready to blit or save
  finally
    Surface.Free;
  end;
end;

Când aveți nevoie doar de un obiect TBitmap finalizat — o miniatură (thumbnail), un export de imagine, o previzualizare pe care o veți stoca în cache —, apelați la RenderLoadedPageToBitmap, funcție descrisă în articolul însoțitor despre randarea paginilor PDF la o imagine bitmap. Diferența constă în cine deține suprafața: apelul bitmap alocă și returnează un buffer de pixeli, în timp ce RenderLoadedPageToDC desenează într-un context de dispozitiv pe care îl dețineți deja, ceea ce vă oferă exact canvas-ul unei imprimante sau un paint handler. Ambele folosesc același interpret de flux de conținut și motor de glife încorporate, astfel încât textul este generat cu contururile încorporate exacte în ambele cazuri

Cum se introduce (paste) o pagină PDF în Word sau într-un editor de imagini?

RenderLoadedPageToClipboard(PageIndex, DPI, AsMetafile) plasează o pagină în clipboard-ul Windows, gata de a fi lipită (paste) în Word, PowerPoint, un e-mail sau un editor de imagini. Flagul AsMetafile selectează formatul, iar această alegere contează mai mult decât pare. Transmiteți False, iar HotPDF plasează un bitmap de dispozitiv pe 24 de biți (CF_BITMAP) randat la rezoluția DPI indicată — o grilă fizică de pixeli care poate fi lipită oriunde, dar se pixelizează atunci când destinatarul o mărește. Transmiteți True, iar acesta plasează un metafile îmbunătățit (CF_ENHMETAFILE) în care textul paginii și arta vectorială sunt transmise sub formă de comenzi de desenare GDI, astfel încât rezultatul lipit rămâne clar la orice nivel de zoom și se adaptează la orice dimensiune pe care o oferă documentul de destinație

// Copy page 2 as a scalable vector metafile for pasting into Word
Pdf.RenderLoadedPageToClipboard(1, 300, True);

// Copy the same page as a fixed 300-DPI bitmap instead
Pdf.RenderLoadedPageToClipboard(1, 300, False);

Regula generală este simplă. Dacă un utilizator va lipi pagina într-un document și s-ar putea să o redenumească — o figură într-un raport, o clauză introdusă într-un proiect de contract —, folosiți metafile-ul, deoarece textul vectorial se imprimă și se mărește clar. Dacă destinația acceptă doar date raster sau doriți în mod special o captură fixă la o anumită rezoluție, folosiți bitmap-ul. Pentru extragerea cuvintelor dintr-o pagină, mai degrabă decât a unei imagini a acestora, aceasta este o sarcină complet diferită, gestionată de API-ul de extragere a textului, care returnează caracterele și pozițiile acestora în loc de o imagine randată

Unde se oprește calea de imprimare

Totul de pe această pagină este specific doar pentru Windows, iar acest lucru trebuie afirmat în mod clar. Metodele PrintLoadedDocument, RenderLoadedPageToDC și RenderLoadedPageToClipboard sunt construite pe TPrinter, modelul de context de dispozitiv GDI, clipboard-ul Windows și Enhanced Metafiles — toate concepte specifice Win32 și Win64. Pe alte platforme țintă, restul funcțiilor HotPDF continuă să creeze, să editeze și să citească PDF-uri, dar această suprafață de imprimare și clipboard bazată pe GDI nu este disponibilă. De asemenea, generatorul de randare vizează subsetul comun de documente format din text, căi și imagini, astfel încât schițele de design cu multe degradeuri și imprimările color gestionate prin profile ICC se imprimă ca o previzualizare fidelă, mai degrabă decât ca o dovadă colorimetrică exactă, aceeași limită pe care o are și randarea bitmap

Pentru imprimarea în masă a multor fișiere, încărcați și imprimați fiecare document la rând și monitorizați consumul de memorie: PrintLoadedDocument randează o singură pagină deodată, dar structura documentului încărcat rămâne în memorie pe parcursul întregii lucrări. Când gestionați o coadă de imprimare pentru sute de fișiere mari, modul Direct File API pentru fluxuri de fișiere PDF mari funcționează perfect cu calea de imprimare — divizați, îmbinați sau selectați paginile de care aveți nevoie pe disc mai întâi, apoi încărcați doar rezultatul mai mic pentru imprimare. Astfel sunt livrate PrintLoadedDocument, RenderLoadedPageToDC și RenderLoadedPageToClipboard ca parte a HotPDF Component pentru Delphi și C++Builder — o bibliotecă nativă VCL fără dependențe de DLL-uri externe care acoperă crearea, editarea, extragerea textului, randarea și acum imprimarea PDF direct în TPrinter, în orice context de dispozitiv sau în clipboard