Tim za obradu zahtjeva imao je trideset godina papirnatih spisa koje je trebalo provući kroz skener s automatskim uvlačenjem listova. Skener je izbacivao jedan JPEG po stranici u mapu, s nazivima 0001.jpg, 0002.jpg i tako dalje. Ono što je arhivi zapravo trebalo bio je jedan PDF po spisu predmeta, s uredno poredanim stranicama, tako da recenzent može otvoriti jedan dokument umjesto da klikće kroz stotinu sličica slika. Taj posljednji korak, pretvaranje numerirane hrpe skeniranih slika u jedan poredani PDF, naš je zadatak ovdje.
PDFium VCL to rješava izravno. Osim renderiranja i ekstrakcije teksta, ova komponenta može izgraditi PDF od nule: stvara prazan dokument, dodaje praznu stranicu željene veličine, postavlja sliku na tu stranicu u koordinatama korisničkog prostora te je sprema. Cijeli se proces odvija na komponenti TPdf, pa se grupni pretvarač (batch converter) svodi na petlju kroz nazive datoteka i nekoliko poziva.
Struktura pretvorbe
Za svaki skenirani dokument moraju se dogoditi tri stvari. Određujete veličinu stranice, postavljate sliku unutar stranice ostavljajući marginu i prelazite na sljedeću stranicu. PDFium VCL vam pruža metodu za svaku od tih radnji: AddPage stvara praznu stranicu zadane veličine, AddImage (ili AddPicture ako već imate TPicture) crta bitmapu na trenutnu stranicu, a PageNumber govori komponenti na koju se stranicu odnose sljedeći pozivi za crtanje.
Jedan detalj koji često zbunjuje programere jest koordinatni sustav. Korisnički prostor PDF-a postavlja ishodište u donji lijevi kut stranice, pri čemu se os Y povećava prema gore, što je suprotno od koordinata zaslona koje Delphi programeri refleksno koriste. Vrijednosti X, Y koje prosljeđujete metodi AddImage predstavljaju donji lijevi kut pravokutnika slike, a Width, Height su dimenzije smještaja u točkama, a ne veličina u pikselima izvorne datoteke. Ako to pogriješite, vaše će slike završiti izvan stranice ili okrenute naopako u odnosu na ono što ste očekivali.
Stvaranje dokumenta i stranice za svaki skenirani dokument
Započnite s praznim dokumentom. Metoda CreateDocument stvara novi PDF i ostavlja komponentu aktivnom, tako da nema zasebnog koraka otvaranja. Od tuda prolazite kroz popis skeniranih datoteka te za svaku dodajete stranicu, činite je trenutnom i postavljate sliku. Dimenzije stranice ovdje su A4 u točkama (595 × 842 okomito), što je standardna veličina lista za arhiviranu korespondenciju.
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;
Svaka iteracija stvara stranicu i odmah postavlja PageNumber na nju. Taj drugi redak je izuzetno važan: AddPage umeće stranicu, ali metode crtanja djeluju na onu stranicu koja je trenutno postavljena, pa je postavljanje svojstva PageNumber ono što usmjerava AddImage na stranicu koju ste upravo stvorili. Preskočite to i vaše će se slike naslagati na stranicu koja je prije toga bila učitana.
U toj se petlji skriva jedna pretpostavka: redoslijed popisa Files. Skener imenuje stranice od 0001.jpg do 0100.jpg, ali izlistanje direktorija ne vraća ih uvijek sortirane. Onog trenutka kada naiđete na page9.jpg pored page10.jpg, obično sortiranje nizova stavit će stranicu 10 ispred stranice 9. Eksplicitno sortirajte popis prije petlje i preferirajte nazive s vodećim nulama prilikom skeniranja kako bi leksički redoslijed odgovarao redoslijedu stranica. Slijed stranica je prva stvar koju će recenzent primijetiti i to je najjednostavnija pogreška koju možete spriječiti.
Pozicioniranje slike i očuvanje omjera širine i visine
Skenirana slika rijetko je istog oblika kao i stranica. Ako je rastegnete kako bi ispunila cijeli list, izobličit ćete tekst; ako je postavite u punoj veličini piksela, premašit će granice stranice. Rješenje je skaliranje prema manjem od dvaju omjera (prilagodba širini ili prilagodba visini) i centriranje preostalog prostora. Budući da se ishodište nalazi u donjem lijevu kutu, centriranje znači podjelu preostalog prostora na pola i njegovo dodavanje na X i 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;
Ovaj postupak jednom učitava datoteku kako bi pročitao njezine dimenzije u pikselima, izračunava jedinstvenu uniformnu skalu i prosljeđuje pravokutnik smještaja metodi AddImage. Metoda AddImage izravno prihvaća putanju datoteke i usmjerava je kroz isti proces obrade slika kao i AddPicture, tako da svaki format koji grafičke jedinice VCL-a prepoznaju radi bez ikakvih posebnih prilagodbi. Ako sliku već imate dekodiranu u TPicture iz okna pregleda, pozovite AddPicture(Pic, X, Y, DrawW, DrawH) s istim pravokutnikom i preskočite drugo čitanje datoteke.
Preskakanje dekodiranja za JPEG slike
Skeneri gotovo uvijek generiraju JPEG slike. Učitavanje JPEG slike u TPicture dekodira je u bitmapu, a zatim je PDFium ponovno kodira prilikom spremanja, što su dva nepotrebna kruga pretvorbe s gubitkom kvalitete. Metoda AddJpegImage ugrađuje originalne komprimirane bajtove izravno na stranicu iz toka podataka (stream), što je i brže i vizualno čišće za obradu velikih količina podataka.
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;
I dalje izračunavate X, Y, DrawW, i DrawH na isti način jer su vam potrebne dimenzije piksela za skaliranje. Pročitajte ih iz datoteke ili brzim parsiranjem zaglavlja, a zatim predajte sirovi tok podataka metodi AddJpegImage. Za PNG ili TIFF slike, putanja AddImage je ispravan izbor; rezervirajte JPEG prečac samo za format na koji se stvarno odnosi.
Označavanje svake stranice
Arhivirane dokumente lakše je provjeravati kada svaka stranica nosi naziv svoje izvorne datoteke. Metoda AddText crta tekst na koordinatama korisničkog prostora, tako da opis stoji odmah ispod slike. Zapamtite obrnutu os Y: da biste natpis postavili ispod slike, oduzimate vrijednost od donjeg ruba slike umjesto da je dodajete.
// Caption below the scan: Y decreases toward the page bottom.
Pdf.AddText('File: ' + ExtractFileName(FileName), 'Helvetica', 9,
X, Y - 14, clGray);
Još jedna napomena o spremanju. SaveAs je funkcija koja vraća Boolean vrijednost, pa u produkcijskom kodu provjerite njezin rezultat umjesto da pretpostavljate da je pisanje uspjelo; puni disk ili zaključana izlazna putanja u protivnom tiho zakazuju. Nakon što petlja završi i datoteka se zapiše, imate upravo ono što je arhivi trebalo: jedan poredani PDF po predmetu, sa stranicama skaliranim da pristaju listu, spreman za čitanje u bilo kojem pregledniku.
Isti gradivni blokovi pokrivaju slične zadatke. Promijenite pravilo promjene veličine po stranici i dobit ćete knjigu fotografija s jednom slikom po listu; zadržite petlju, ali čitajte iz višestranog TIFF izvora i dobit ćete pretvarač arhive faks poruka. Ako želite širu sliku o programskom stvaranju PDF-ova, pogledajte članak o stvaranju PDF dokumenata od nule pomoću PDFium VCL-a; da biste rezultat kasnije renderirali natrag na zaslon, pogledajte članak o pretvaranju PDF stranica u JPEG slike pomoću PDFium VCL-a.
Komponenta PDFium VCL Component s loslab.com objedinjuje API-je za stvaranje dokumenata, renderiranje i obradu teksta koji se koriste u ovoj seriji članaka.