Žalų administravimo komanda per lapinį skaitytuvą leido trisdešimties metų popierines bylas. Skaitytuvas į aplanką išspjovė po vieną JPEG kiekvienam lapui, pavadintus 0001.jpg, 0002.jpg ir taip toliau. Archyvui iš tikrųjų reikėjo po vieną PDF kiekvienai bylai, su puslapiais tvarkinga eile, kad recenzentas galėtų atverti vieną dokumentą, o ne spaudinėti šimtą vaizdų miniatiūrų. Tas paskutinis žingsnis, sunumeruotos skenuotų failų krūvos pavertimas vienu tvarkingu PDF, čia ir yra darbas
PDFium Component tai atlieka tiesiogiai. Be atvaizdavimo ir teksto ištraukimo, komponentas gali sukurti PDF nuo nulio: sukurti tuščią dokumentą, pridėti tuščią bet kokio dydžio puslapį, uždėti ant to puslapio vaizdą naudotojo erdvės koordinatėse ir išsaugoti. Visa grandinė gyvena TPdf komponente, todėl paketinis konvertavimas yra ciklas per failų vardus plius sauja iškvietimų
Konvertavimo forma
Kiekvienam skenuotam failui turi įvykti trys dalykai. Jūs nusprendžiate puslapio dydį, patalpinate vaizdą puslapio viduje paliekdami paraštę ir pereinate prie kito puslapio. PDFium Component kiekvienam duoda po metodą: AddPage sukuria tuščią nurodyto dydžio puslapį, AddImage (arba AddPicture, jei jau turite TPicture) nupiešia rastrą į dabartinį puslapį, o PageNumber pasako komponentui, į kurį puslapį taikosi tolesni piešimo iškvietimai
Viena detalė, ant kurios žmonės užkliūva, yra koordinačių sistema. PDF naudotojo erdvė pradžios tašką deda apatiniame kairiajame puslapio kampe, o Y auga aukštyn — priešingai nei ekrano koordinatėse, kurių Delphi kūrėjai griebiasi refleksiškai. X, Y, kuriuos paduodate į AddImage, yra apatinis kairysis vaizdo stačiakampio kampas, o Width, Height yra patalpinimo dydis punktais, o ne šaltinio failo pikselių dydis. Supainiokite tai ir jūsų skenuoti vaizdai nusileis už puslapio ribų arba apversti, palyginti su tuo, ko tikėjotės
Dokumento ir po puslapį kiekvienam skenuotam failui kūrimas
Pradėkite nuo tuščio dokumento. CreateDocument išskiria naują PDF ir palieka komponentą aktyvų, todėl atskiro atvėrimo žingsnio nėra. Nuo čia einate per skenuotų failų sąrašą ir kiekvienam pridedate puslapį, padarote jį dabartiniu ir patalpinate vaizdą. Puslapio matmenys čia yra A4 punktais (595 × 842 stačiai) — standartinis lapo dydis archyvuojamai korespondencijai
procedure TArchiveForm.ScansToPdf(const Files: TStrings; const OutputPath: string);
const
PageW = 595.0; // A4 plotis punktais
PageH = 842.0; // A4 aukštis punktais
Margin = 36.0; // pusės colio rėmelis aplink kiekvieną skenuotą vaizdą
var
I: Integer;
Pdf: TPdf;
begin
Pdf := TPdf.Create(nil);
try
Pdf.CreateDocument; // naujas, tuščias, jau aktyvus
for I := 0 to Files.Count - 1 do
begin
Pdf.AddPage(I + 1, PageW, PageH); // puslapio indeksas nuo 1
Pdf.PageNumber := I + 1; // padaryti naują puslapį dabartiniu
PlaceScan(Pdf, Files[I], PageW, PageH, Margin);
end;
Pdf.SaveAs(OutputPath);
finally
Pdf.Free;
end;
end;
Kiekviena iteracija sukuria puslapį ir iškart nustato į jį PageNumber. Ta antroji eilutė svarbi: AddPage puslapį įterpia, tačiau piešimo metodai veikia tą puslapį, kuris yra dabartinis, todėl būtent PageNumber nustatymas nutaiko AddImage į ką tik sukurtą puslapį. Praleiskite jį ir jūsų vaizdai susikraus ant to puslapio, kuris buvo įkeltas anksčiau
Tame cikle slepiasi viena prielaida: Files tvarka. Skaitytuvas puslapius pavadina nuo 0001.jpg iki 0100.jpg, tačiau katalogo perrinkimas ne visada grąžina juos surikiuotus, o vos tik pataikysite ant page9.jpg greta page10.jpg, paprastas eilučių rikiavimas 10 puslapį padės pirma 9. Prieš ciklą sąrašą surikiuokite aiškiai, o skenuodami rinkitės nuliais užpildytus vardus, kad leksinė tvarka sutaptų su puslapių tvarka. Puslapių eiliškumą recenzentas pastebi iš karto, ir tai pigiausiai išvengiama klaida
Skenuoto vaizdo patalpinimas išlaikant jo proporcijas
Skenuotas vaizdas retai būna tokios pat formos kaip puslapis. Ištempsite jį per visą lapą — iškraipysite tekstą; padėsite pilnu pikselių dydžiu — jis išsilies per kraštus. Sprendimas yra mastelį imti pagal mažesnį iš dviejų santykių, pločio arba aukščio, ir tai, kas lieka, sucentruoti. Kadangi pradžios taškas yra apatiniame kairiajame kampe, centravimas reiškia likusią vietą padalyti po lygiai ir pridėti prie abiejų X ir 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 ir kt. per VCL grafikos modulius
AvailW := PageW - 2 * Margin;
AvailH := PageH - 2 * Margin;
// Įtalpinti paraščių viduje neiškraipant skenuoto vaizdo.
Scale := Min(AvailW / Pic.Width, AvailH / Pic.Height);
DrawW := Pic.Width * Scale;
DrawH := Pic.Height * Scale;
// Centravimas: likusi vieta padalijama po lygiai. Y matuojamas nuo puslapio apačios.
X := (PageW - DrawW) / 2;
Y := (PageH - DrawH) / 2;
Pdf.AddImage(FileName, X, Y, DrawW, DrawH);
finally
Pic.Free;
end;
end;
Šis kodas failą įkelia vieną kartą, kad nuskaitytų jo pikselių matmenis, apskaičiuoja vieną vienodą mastelį ir paduoda patalpinimo stačiakampį į AddImage. AddImage priima failo kelią tiesiogiai ir nukreipia jį per tą pačią vaizdų grandinę kaip AddPicture, todėl bet kuris formatas, kurį atpažįsta VCL grafikos moduliai, veikia be atskirų atvejų. Jei vaizdą jau turite dekoduotą TPicture objekte iš peržiūros srities, iškvieskite AddPicture(Pic, X, Y, DrawW, DrawH) su tuo pačiu stačiakampiu ir praleiskite antrą failo skaitymą
Dekodavimo praleidimas JPEG skenuotiems vaizdams
Skaitytuvai beveik visada išveda JPEG. JPEG įkėlimas į TPicture jį dekoduoja į rastrą, o tada PDFium išsaugodamas jį užkoduoja iš naujo — du nuostolingi ciklai, kurių jums nereikia. AddJpegImage originalius suspaustus baitus iš srauto įterpia tiesiai į puslapį, o tai didelės apimties paketui yra ir greičiau, ir vizualiai švariau
var
Stream: TFileStream;
begin
// ... po AddPage + PageNumber dabartiniam puslapiui ...
Stream := TFileStream.Create(FileName, fmOpenRead);
try
// Įterpia JPEG baitus tokius, kokie yra; jokio dekodavimo ir pakartotinio kodavimo ciklo.
Pdf.AddJpegImage(Stream, X, Y, DrawW, DrawH);
finally
Stream.Free;
end;
end;
X, Y, DrawW ir DrawH vis tiek skaičiuojate taip pat, nes masteliui reikia pikselių matmenų. Nuskaitykite juos iš failo arba greitai išanalizuodami antraštę, o tada paduokite neapdorotą srautą į AddJpegImage. PNG ar TIFF skenuotiems vaizdams teisingas kelias yra AddImage; JPEG trumpinį palikite tam formatui, kuriam jis iš tikrųjų taikomas
Puslapių žymėjimas
Archyvuotus skenuotus vaizdus lengviau audituoti, kai kiekvienas puslapis neša savo šaltinio failo vardą. AddText nupiešia eilutę naudotojo erdvės koordinatėje, todėl antraštė atsisėda tiesiai po vaizdu. Prisiminkite apverstą Y ašį: kad etiketė atsidurtų po skenuotu vaizdu, iš apatinio vaizdo krašto reikia atimti, o ne prie jo pridėti
// Antraštė po skenuotu vaizdu: Y mažėja puslapio apačios link.
Pdf.AddText('File: ' + ExtractFileName(FileName), 'Helvetica', 9,
X, Y - 14, clGray);
Paskutinė pastaba apie išsaugojimą. SaveAs yra funkcija, grąžinanti loginę reikšmę, todėl gamybiniame kode tikrinkite jos rezultatą, o ne laikykite, kad įrašymas pavyko; kitaip pilnas diskas ar užrakintas išvesties kelias suklups tyliai. Kai ciklas baigiasi ir failas įrašytas, turite būtent tai, ko archyvui reikėjo: po vieną tvarkingą PDF kiekvienai bylai, puslapius su tinkamu masteliu, paruoštus skaityti bet kurioje peržiūros programoje
Tie patys statybiniai blokai apima ir giminingus darbus. Pakeiskite puslapio dydžio taisyklę ir gausite fotoknygą su vienu vaizdu lape; palikite ciklą, bet skaitykite iš daugiapuslapio TIFF šaltinio, ir turėsite faksų archyvo konverterį. Jei norite platesnio vaizdo apie programinį PDF kūrimą, žiūrėkite PDF dokumentų kūrimą nuo nulio su PDFium Component; o kaip rezultatą vėliau atvaizduoti ekrane, žiūrėkite PDF puslapių vertimą į JPEG vaizdus su PDFium Component
PDFium Component iš loslab.com sujungia dokumentų kūrimo, atvaizdavimo ir teksto API, naudojamus visoje šioje serijoje