Technikai cikk

Betöltött PDF nyomtatása Delphiben a HotPDF és a TPrinter segítségével

A HotPDF három hívás segítségével nyomtatja ki a betöltött PDF-et fizikai nyomtatóra, bármely Windows eszköz-kontextusra (device context) vagy a vágólapra: a PrintLoadedDocument egy VCL TPrinter-t vezérel, a RenderLoadedPageToDC közvetlenül egy tetszőleges HDC-be rajzolja az oldalt, a RenderLoadedPageToClipboard pedig bitképként vagy vektoros metafile-ként másolja azt a vágólapra. A HotPDF egy natív VCL PDF komponens Delphihez és C++Builderhez, és ezt a prémium nyomtatási útvonalat a v2.331.0 verzióban vezette be, majd a v2.348.0 verzióban finomította, így többé nem kell kézzel megírnia a bitkép-renderelő köré épülő TPrinter ciklust. Mindhárom hívás közvetlenül oda rajzolja az oldal vektoros tartalmát, ahová kell, így a nyomtatás olyan éles marad, amilyet csak a nyomtató képes előállítani

Miért érdemes a PDF oldalt közvetlenül a nyomtatóra rajzolni bitkép helyett?

Egy PDF oldal vektoros rajzoló operátorok programja – útvonalak, szövegek és képek, amelyek az ISO 32000-1 grafikai modell szerint hajtódnak végre –, nem pedig pixelek rácsa. Nyomtatásának kézenfekvő módja az lenne, ha az oldalt bitképpé rasztereznénk, majd ezt a bitképet átvinnénk a nyomtató vásznára (canvas), ami működik is, de eldobja azt az egyetlen dolgot, amiben a nyomtató jó. Egy modern lézernyomtató 600 vagy 1200 DPI-t képes feloldani; egy 150 vagy 300 DPI-vel raszterezett, majd a mérethez nyújtott bitkép lágyan, életlenül érkezik meg, recés szövegszélekkel és látható interpolációval. A RenderLoadedPageToDC a jobb utat választja: újra lejátsza az oldal tartalomfolyamát közvetlenül a cél eszköz-kontextusba kibocsátott GDI hívásokként, így a vektoros szöveg és vonalas rajz vektorként éri el a nyomtatót, és a nyomtató saját felbontásán, a nyomtató által rasztereződik le egyszer

Hogyan nyomtatható egy betöltött PDF fizikai nyomtatóra Delphiben?

A HotPDF a betöltött dokumentumot a PrintLoadedDocument(Printer, Options) segítségével nyomtatja ki, amely egy hozzárendelt VCL TPrinter-t és egy THPDFPrintOptions rekordot vesz át, kinyomtatja a kiválasztott oldalakat, és visszaadja az elküldött oldalak számát. Először állítsa be a Printer.PrinterIndex-et az eszköz kiválasztásához, töltsön ki egy opciós rekordot – a THPDFPrintOptions.Default osztályfüggvény ésszerű értékeket ad –, és hívja meg egyszer. A könyvtár a nyomtatási feladatot a Printer.BeginDoc hívással nyitja meg, végigmegy az oldaltartományon egy-egy Printer.NewPage hívást kibocsátva az oldalak között, majd a Printer.EndDoc segítségével zárja le azt, így a feladat életciklusát soha nem kell manuálisan kezelnie

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;

A PageRange karakterlánc 1-alapú, és úgy olvasható, mint egy nyomtatási párbeszédpanel: a '1,3-5' az 1. oldalt és a 3-5. oldalakat nyomtatja, az üres karakterlánc pedig a teljes dokumentumot. A Copies közvetlenül a Printer.Copies-re képeződik le. Legyen azonban őszinte magához a Collate (szétválogatás) kapcsán: mivel a VCL a szétválogatást inkonzisztensen teszi közzé a Delphi verziók között, a HotPDF beállítja a másolatszámot, a szétválogatást pedig a nyomtató-illesztőprogram alapértelmezésére bízza, így ha garantált szétválogatási sorrendre van szüksége, állítsa azt be a meghajtón a TPrinterSetupDialog segítségével, ahelyett, hogy bízna a jelző átvitelében

Hogyan határozza meg a DPI és a FitPage a nyomtatási méretarányt?

A FitPage és a DPI kölcsönhatását érdemes megérteni a szállítás előtt. Ha a FitPage értéke True – ez az alapértelmezett –, a HotPDF beolvassa az egyes oldalak MediaBox-át, a képarány megtartásával leképezi a Printer.PageWidth és Printer.PageHeight méretekre, és olyan léptékkel rendereli, amellyel az oldal kitölti a papírt. Ebben a módban a Options.DPI értéket gyakorlatilag felülírja az illesztési lépték, mivel a kimenetnek meg kell egyeznie a nyomtató fizikai oldalméreteivel. Ha a FitPage értéke False, a HotPDF minden oldalt 1:1 arányban renderel pontosan az Options.DPI szerint, 72 PDF egységet leképezve DPI eszközpixelre, ami akkor kívánatos, ha a forrásoldal és a papír már eleve azonos méretű, és Önnek a pontos felbontás számít. Válassza a FitPage-et, ha a forrásoldal mérete és a tálca mérete eltér; válassza az 1:1 arányt, ha megegyeznek, és determinisztikus léptékezést szeretne

A v2.348.0 verzióban hozzáadott két opció kijavítja azokat a nyomatokat, amelyek majdnem jól néznek ki. Minden fizikai nyomtatónak van egy kemény margója (hard margin) – egy nem nyomtatható szegély, amelyet a hardver nem ér el –, és alapértelmezés szerint az oldal kezdőpontja ezen belül landol, így a kifutó (full-bleed) oldal elveszít egy csíkot két szélén. Állítsa az IgnoreHardMargin értékét True-ra, és a HotPDF lekérdezi a nyomtató PHYSICALOFFSETX és PHYSICALOFFSETY értékeit, majd eltolja a készülék kezdőpontját az eltolás kiküszöbölésére, hogy az oldal kezdőpontja a papír valódi sarkára képeződjön le. A második opció, az AutoRotate, alapértelmezés szerint be van kapcsolva: beolvassa az egyes oldalak MediaBox-át, és ha egy oldal szélesebb, mint amilyen magas, átváltja a nyomtatót fekvő (landscape) módba, így a széles oldal levágás nélkül nyomtatódik az álló módú csonkítás helyett. Az AutoRotate félreáll abban a pillanatban, amikor az Orientation-t explicit módon beállítja, így a szándékos tájolásválasztás mindig győz

Hogyan renderelhető a PDF oldal bármilyen eszköz-kontextusba?

A RenderLoadedPageToDC(PageIndex, DC, DPI, W, H) a nyomtatási ciklus alatti primitív, és önmagában is hasznos. A PrintLoadedDocument oldalonként egyszer hívja meg ezt a nyomtató vásznán (canvas), de a cél bármilyen Windows HDC lehet: egy képernyőn kívüli memóriabeli DC, egy vezérlő vászna egy egyéni megjelenítőben, vagy egy nyomtatási előnézet felülete. A PageIndex 0-alapú, a W és H a célfelület eszközegységei, a renderelő pedig bejárja az oldal /Contents bejegyzését, és GDI hívásokat bocsát ki a DC-jébe. Egy szándékos viselkedést érdemes tudni: nem rajzol háttérkitöltést. A hívó birtokolja a felületet, így ha fehér papírt szeretne az oldal mögé, a renderelés előtt magának kell kitölteniez a DC-t, ami pontosan lehetővé teszi, hogy egy oldalt egy meglévő vászonra vetítsen, amikor erre van szükség

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

Ha csak egy kész TBitmap-re van szüksége – egy bélyegképre, egy kép-exportra vagy egy gyorsítótárazott előnézetre –, használja helyette a RenderLoadedPageToBitmap metódust, amelyről a PDF oldalak renderelése bitképpé szóló cikk ír. A különbség az, hogy kié a felület: a bitkép-hívás lefoglal és visszaad egy pixelpuffert, míg a RenderLoadedPageToDC egy már meglévő eszköz-kontextusba rajzol, amit a nyomtatóvászon vagy a rajzkezelő átad Önnek. Mindkettő ugyanazt a tartalomfolyam-értelmezőt és beágyazott glifmotort használja, így a szöveg mindkét esetben a pontos beágyazott körvonalakkal jelenik meg

Hogyan illeszthető be a PDF oldal a Wordbe vagy egy képszerkesztőbe?

A RenderLoadedPageToClipboard(PageIndex, DPI, AsMetafile) egy oldalt helyez el a Windows vágólapján, készen arra, hogy beillesszék Wordbe, PowerPointba, e-mailbe vagy képszerkesztőbe. Az AsMetafile jelző választja ki a formátumot, és a választás többet számít, mint amennyinek látszik. Ha False értéket ad meg, a HotPDF egy 24 bites eszköz-bitképet (CF_BITMAP) helyez el az Ön DPI-jén renderelve – ez egy rögzített pixelrács, amely bárhová beilleszthető, de pixelre esik szét, amikor a fogadó felnagyítja. Ha True értéket ad meg, akkor egy kiterjesztett metafile-t (CF_ENHMETAFILE) helyez el, amelyben az oldal szövege és vektoros grafikája GDI rajzolási parancsokként utazik, így a beillesztett eredmény bármilyen nagyításnál éles marad, és igazodik ahhoz a mérethez, amelyet a céldokumentum ad neki

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

Az aranyszabály egyszerű. Ha egy felhasználó beilleszti az oldalt egy dokumentumba, és átméretezheti azt – egy ábra egy jelentésben, egy szerződési tervezetbe ejtett záradék –, használja a metafile-t, mert a vektoros szöveg élesen nyomtatódik és nagyítódik. Ha a célpont csak raszteres adatokat ért meg, vagy kifejezetten egy rögzített felbontású pillanatképet szeretne, használja a bitképet. A szavak kinyerése az oldalról teljesen más feladat, amelyet a szövegkivonó API kezel, ami a karaktereket és pozícióikat adja vissza a renderelt kép helyett

Ahor a nyomtatási útvonal véget ér

Minden ezen az oldalon lévő dolog csak Windows-on működik, és ezt érdemes nyíltan kimondani. A PrintLoadedDocument, a RenderLoadedPageToDC és a RenderLoadedPageToClipboard a TPrinter-re, a GDI eszköz-kontextus modellre, a Windows vágólapra és a kiterjesztett metafile-okra épülnek – mind Win32 és Win64 konstrukciók. Más célpontokon a HotPDF többi része továbbra is létrehozza, szerkeszti és olvassa a PDF-et, de ez a GDI-alapú nyomtatási és vágólap-felület nem érhető el. A renderelő a szövegek, útvonalak és képek általános dokumentum-részhalmazát is megcélozza, így a színátmenetekben gazdag tervvázlatok és az ICC-kezelt színek hű előnézetként nyomtatódnak, nem pedig kolorimetrikus igazolásként, ami megegyezik a bitkép-renderelő korlátaival

Sok fájlon átnyúló kötegelt nyomtatáshoz töltse be és nyomtassa ki az egyes dokumentumokat sorban, és ügyeljen a memóriaszámlára: a PrintLoadedDocument egyszerre egy oldalt renderel, de maga a betöltött dokumentumgráf a memóriában él a teljes feladat alatt. Ha több száz nagy fájl felett hajt végre nyomtatási sort, a közvetlen fájl API nagy PDF-munkafolyamatokhoz jól párosul a nyomtatási útvonallal – először válassza szét, egyesítse vagy válassza ki a szükséges oldalakat a lemezen, majd csak a karcsúbb eredményt töltse be a nyomtatáshoz. Így érkezik a PrintLoadedDocument, a RenderLoadedPageToDC és a RenderLoadedPageToClipboard a Delphihez és C++Builderhez készült HotPDF Component részeként – egy natív VCL könyvtár külső DLL-függőségek nélkül, amely kiterjed a PDF-készítésre, -szerkesztésre, szövegkivonásra, renderelésre, és most már a közvetlen nyomtatásra is a TPrinter-re, bármely eszköz-kontextusra vagy a vágólapra