Ekipa za obdelavo zahtevkov je imela trideset let papirnih spisov, ki so jih morali poslati skozi optični bralnik (skener). Skener je v mapo izvozil po eno sliko JPEG na stran z imeni 0001.jpg, 0002.jpg in tako naprej. Arhiv je dejansko potreboval eno datoteko PDF za vsak spis z urejenimi stranmi, da bi lahko ocenjevalec odprl en sam dokument, namesto da bi klikal skozi sto sličic. Ta zadnji korak – pretvorba oštevilčenega kupa skeniranih slik v en urejen dokument PDF – je naloga, ki jo bomo opisali.
PDFium VCL to opravi neposredno. Poleg izrisovanja in ekstrakcije besedila lahko komponenta zgradi dokument PDF iz nič: ustvari prazen dokument, doda prazno stran poljubne velikosti, postavi sliko na to stran v koordinatah uporabniškega prostora (user-space coordinates) in jo nato shrani. Celoten proces poteka v komponenti TPdf, zato je paketni pretvornik sestavljen le iz zanke čez imena datotek in nekaj klicov.
Zasnova pretvorbe
Za vsako skenirano sliko se morajo zgoditi tri stvari. Določiti morate velikost strani, postaviti sliko na stran z odmiki (margins) in se pomakniti na naslednjo stran. PDFium VCL vam za vsak korak ponuja metodo: AddPage ustvari prazno stran določene velikosti, AddImage (ali AddPicture, če že imate TPicture) izriše bitno sliko na trenutno stran, PageNumber pa komponenti pove, katero stran ciljajo naslednji klici za risanje.
Podrobnost, ki pogosto povzroča zmedo, je koordinatni sistem. Uporabniški prostor PDF postavi izhodišče v spodnji levi kot strani, pri čemer Y raste navzgor, kar je nasprotno od zaslonskih koordinat, po katerih razvijalci v Delphiju posegajo refleksno. Koordinati X, Y, ki ju posredujete metodi AddImage, predstavljata spodnji levi kot pravokotnika slike, Width, Height pa velikost postavitve v točkah in ne velikosti slikovnih pik (pixels) izvorne datoteke. Če to zamešate, bodo vaše skenirane slike pristale izven strani ali obrnjene na glavo glede na to, kar ste pričakovali.
Ustvarjanje dokumenta in dodajanje strani za vsak sken
Začnite s praznim dokumentom. Metoda CreateDocument ustvari nov PDF in pusti komponento aktivno, zato ni potreben ločen korak odpiranja. Od tam se pomikate skozi seznam skeniranih datotek, za vsako dodate stran, jo nastavite kot trenutno in nanjo postavite sliko. Dimenzije strani v tem primeru ustrezajo formatu A4 v točkah (595 × 842 pokončno), kar je standardna velikost lista za arhivirano korespondenco.
procedure TArchiveForm.ScansToPdf(const Files: TStrings; const OutputPath: string);
const
PageW = 595.0; // A4 width in points
PageH = 842.0; // A4 height in points
Margin = 36.0; // half-inch border around each scan
var
I: Integer;
Pdf: TPdf;
begin
Pdf := TPdf.Create(nil);
try
Pdf.CreateDocument; // new, empty, already active
for I := 0 to Files.Count - 1 do
begin
Pdf.AddPage(I + 1, PageW, PageH); // 1-based page index
Pdf.PageNumber := I + 1; // make the new page current
PlaceScan(Pdf, Files[I], PageW, PageH, Margin);
end;
Pdf.SaveAs(OutputPath);
finally
Pdf.Free;
end;
end;
Vsak korak zanke ustvari stran in takoj nastavi PageNumber nanjo. Ta druga vrstica je pomembna: AddPage sicer vstavi stran, vendar metode risanja delujejo na tisti strani, ki je trenutno nastavljena, zato nastavitev PageNumber usmeri metodo AddImage na stran, ki ste jo pravkar ustvarili. Če ta korak izpustite, se bodo vaše slike zložile na tisto stran, ki je bila naložena pred tem.
V tej zanki se skriva ena predpostavka: vrstni red datotek v Files. Skener poimenuje strani od 0001.jpg do 0100.jpg, vendar iskanje datotek v mapi ne vrne vedno urejenega seznama; ko naletite na primer, ko sta page9.jpg in page10.jpg skupaj, lahko preprosto razvrščanje nizov postavi stran 10 pred stran 9. Seznam pred zanko eksplicitno razvrstite, pri skeniranju pa uporabite imena z vodilnimi ničlami, da se leksikalni vrstni red ujema z vrstnim redom strani. Zaporedje strani je prva stvar, ki jo ocenjevalec opazi, in je hkrati najlažja napaka, ki jo lahko preprečite.
Postavitev skenirane slike ob ohranjanju razmerja stranic
Skenirana slika je redko enake oblike kot stran. Če jo raztegnete čez celoten list, popačite besedilo; če jo postavite v polni velikosti slikovnih pik, se razlije čez robove. Rešitev je, da jo skalirate glede na manjše od obeh razmerij (prilagajanje širini ali višini) in centrirate preostali prostor. Ker je izhodišče v spodnjem levem kotu, centriranje pomeni, da preostali prostor enakomerno razdelite in ga dodate koordinatama X in Y.
procedure TArchiveForm.PlaceScan(Pdf: TPdf; const FileName: string;
PageW, PageH, Margin: Double);
var
Pic: TPicture;
AvailW, AvailH, Scale, DrawW, DrawH, X, Y: Double;
begin
Pic := TPicture.Create;
try
Pic.LoadFromFile(FileName); // BMP, JPG, PNG, etc. via the VCL graphics units
AvailW := PageW - 2 * Margin;
AvailH := PageH - 2 * Margin;
// Fit inside the margins without distorting the scan.
Scale := Min(AvailW / Pic.Width, AvailH / Pic.Height);
DrawW := Pic.Width * Scale;
DrawH := Pic.Height * Scale;
// Center: leftover space split evenly. Y measured from the page bottom.
X := (PageW - DrawW) / 2;
Y := (PageH - DrawH) / 2;
Pdf.AddImage(FileName, X, Y, DrawW, DrawH);
finally
Pic.Free;
end;
end;
Ta postopek enkrat naloži datoteko, da prebere njene dimenzije v slikovnih pikah, izračuna enotno merilo in posreduje pravokotnik postavitve metodi AddImage. Metoda AddImage neposredno sprejme pot do datoteke in jo usmeri skozi enak proces kot AddPicture, zato katera koli oblika zapisa, ki jo prepoznajo grafične enote VCL, deluje brez dodatnih nastavitev. Če že imate sliko dekodirano v objektu TPicture iz predoglednega podokna, pokličite AddPicture(Pic, X, Y, DrawW, DrawH) z enakim pravokotnikom in preskočite drugo branje datoteke.
Preskok dekodiranja za skenirane JPEG slike
Optični bralniki skoraj vedno ustvarijo datoteke JPEG. Nalaganje JPEG slike v TPicture jo dekodira v bitno sliko, negativna stran tega pa je, da jo PDFium ob shranjevanju ponovno kodira, kar sta dva nepotrebna kroga pretvorb z izgubo kakovosti. Metoda AddJpegImage prek toka (stream) vgradi izvirne stisnjene bajte neposredno v stran, kar je hitrejše in vizualno čistejše pri večjih količinah paketnih pretvorb.
var
Stream: TFileStream;
begin
// ... after AddPage + PageNumber for the current page ...
Stream := TFileStream.Create(FileName, fmOpenRead);
try
// Embeds the JPEG bytes as-is; no decode/re-encode cycle.
Pdf.AddJpegImage(Stream, X, Y, DrawW, DrawH);
finally
Stream.Free;
end;
end;
Koordinate X, Y ter dimenziji DrawW in DrawH še vedno izračunate na enak način, saj za skaliranje potrebujete dimenzije slikovnih pik. Te preberite iz datoteke ali s hitro razčlenitvijo glave (header parse), naloge pa prenesite na AddJpegImage. Za skenirane slike PNG ali TIFF je prava pot uporaba AddImage; bližnjico za JPEG rezervirajte le za to obliko zapisa, ki ji je namenjena.
Označevanje posameznih strani
Arhivirane skene je lažje pregledovati, če vsaka stran vsebuje ime izvorne datoteke. Metoda AddText izriše niz znakov na koordinati uporabniškega prostora, tako da se napis nahaja tik pod sliko. Ne pozabite na obrnjeno os Y: da postavite napis pod sliko, morate odšteti od spodnjega roba slike in ne prišteti.
// Caption below the scan: Y decreases toward the page bottom.
Pdf.AddText('File: ' + ExtractFileName(FileName), 'Helvetica', 9,
X, Y - 14, clGray);
Zadnja točka glede shranjevanja. Metoda SaveAs je funkcija, ki vrne logično vrednost (Boolean), zato v produkcijski kodi preverite njen rezultat, namesto da predvidevate, da je bilo pisanje uspešno; poln disk ali zaklenjena izhodna pot sicer povzročita tiho napako. Ko se zanka zaključi in je datoteka zapisana, imate natanko to, kar je arhiv potreboval: en urejen PDF dokument za vsak spis, s stranmi, prilagojenimi velikosti, pripravljenimi za branje v katerem koli bralniku.
Isti gradniki pokrivajo sorodna opravila. Če zamenjate pravilo prilagajanja velikosti za posamezno stran, dobite fotoknjigo z eno sliko na list; če obdržite zanko, vendar berete iz večstranskega vira TIFF, dobite pretvornik faks arhivov. Če želite širšo sliko o programskem ustvarjanju PDF-jev, si oglejte članek o ustvarjanju PDF dokumentov iz nič s PDFium VCL; za kasnejši izris rezultata nazaj na zaslon pa si oglejte članek o pretvorbi PDF strani v slike JPEG s PDFium VCL.
Komponenta PDFium VCL Component podjetja loslab.com združuje API-je za ustvarjanje dokumentov, izrisovanje in delo z besedilom, ki so uporabljeni v tej seriji.