„PDFium VCL“ leidžia sujungti PDF failus naudojant vieną metodą: ImportPages. Veiksmų seka visada ta pati: sukuriate tuščią tikslinį dokumentą, atidarote kiekvieną šaltinio failą, iškviečiate ImportPages puslapiams nukopijuoju, uždarote šaltinį ir kartojate procesą. Ciklui pasibaigus, funkcija SaveAs įrašo rezultatą į diską. Nėra jokio specialaus sujungimo režimo ar papildomų nustatymų. Visas sudėtingumas slypi specifiniuose niuansuose, apie kuriuos verta žinoti iš anksto.
Pagrindinis ciklas
Jums reikės tik dviejų TPdf komponento egzempliorių. Vienas skirtas tiksliniam dokumentui (sukuriamas tuščias su CreateDocument), o kitas paeiliui atidaro kiekvieną šaltinio failą. Žemiau pateikta procedūra priima failų kelių sąrašą ir įrašo sujungtą rezultatą nurodytu adresu:
procedure MergeFiles(const FileList: TStrings; const OutputPath: string);
var
PdfDest, PdfSrc: TPdf;
InsertAt, I: Integer;
begin
PdfDest := TPdf.Create(nil);
PdfSrc := TPdf.Create(nil);
try
PdfDest.CreateDocument;
InsertAt := 1; // ImportPages uses 1-based destination position
for I := 0 to FileList.Count - 1 do
begin
PdfSrc.FileName := FileList[I];
PdfSrc.Active := True;
if not PdfSrc.Active then
raise Exception.CreateFmt('Cannot open: %s', [FileList[I]]);
PdfDest.ImportPages(
PdfSrc,
'1-' + IntToStr(PdfSrc.PageCount), // full document range
InsertAt);
Inc(InsertAt, PdfSrc.PageCount);
PdfSrc.Active := False;
end;
PdfDest.SaveAs(OutputPath);
finally
PdfSrc.Free;
PdfDest.Free;
end;
end;
Šiame kode lengva nepastebėti dviejų svarbių dalykų. Pirmasis – kaip PDFium praneša apie įkėlimo klaidas. Savybės Active := True nustatymas nesukelia išimčių: jei failo nėra, jis pažeistas arba apsaugotas slaptažodžiu, PDFium apdoroja klaidą viduje ir tiesiog palieka Active reikšmę lygią False. Jei neatliksite patikrinimo, sugadintas failas bus tyliai praleistas, o sujungtame PDF dokumente bus mažiau puslapių nei tikėtasi, nežinant, kuris failas sukėlė problemą.
Antrasis dalykas – InsertAt skaitiklis. Trečiasis ImportPages parametras nurodo poziciją tiksliniame dokumente (pradedant nuo 1), kai bus įterptas pirmasis importuojamas puslapis. Pradėjus nuo 1, pirmasis šaltinio dokumentas patalpinamas tuščio failo pradžioje. Po kiekvieno importavimo skaitiklis padidinamas pridedant PdfSrc.PageCount, todėl kita puslapių grupė bus įterpta po jau esamų puslapių. Jei pamiršite padidinti šį skaitiklį, kiekvienas kitas šaltinis perrašys puslapius nuo pirmosios pozicijos, ir galutiniame faile turėsite tik patį paskutinį sąrašo dokumentą.
Pasirinktiniai puslapių rėžiai
Jums nebūtina kopijuoti visų puslapių iš šaltinio dokumento. Puslapių rėžius nurodanti eilutė (antrasis parametras) naudoja kablelių ir brūkšnelių formatą: "1-3" nukopijuoja puslapius nuo 1 iki 3, "2,4,6" pasirenka tris konkrečius puslapius, o "1-" nurodo puslapius nuo pirmojo iki pat dokumento pabaigos. Rėžius galima apjungti vienoje eilutėje, pavyzdžiui, "1-3,5,7-" praleis 4 ir 6 puslapius. Svarbus niuansas: nurodyti skaičiai visada žymi puslapius šaltinio dokumente (pradedant nuo 1), nepriklausomai nuo to, kurioje vietoje jie bus įterpti tiksliniame faile. Jei norite išgauti puslapius nuo 40 iki 50 iš 200 puslapių katalogo, nurodote rėžį "40-50".
// Extract cover plus a three-page executive summary from a long report
PdfSrc.FileName := 'annual-report.pdf';
PdfSrc.Active := True;
if PdfSrc.Active then
begin
// Page 1 is the cover; pages 3-5 are the summary
PdfDest.ImportPages(PdfSrc, '1,3-5', InsertAt);
Inc(InsertAt, 4); // 1 cover + 3 summary pages = 4 pages added
PdfSrc.Active := False;
end;
Apskaičiuodami InsertAt pokytį, skaičiuokite tik tuos puslapius, kuriuos iš tikrųjų importavote, o ne bendrą šaltinio puslapių skaičių. Jei nurodėte '1,3-5', importavote 4 puslapius, todėl skaitiklį padidinkite 4 vienetais. Padidinus jį visa PdfSrc.PageCount reikšme, tiksliniame faile atsiras tuščių puslapių tarpų.
Ką ImportPages perkelia ir ko ne
Puslapiai, nukopijuoti naudojant ImportPages, pilnai išlaiko savo matomą turinį. Tekstas, vektorinė grafika, rastriniai vaizdai, įterptieji šriftai ir formų objektai perkeliami kaip puslapio turinio dalis. Puslapio lygio anotacijos, tokios kaip komentarai, paryškinimai ar piešimo linijos, taip pat sėkmingai persikelia, nes jos saugomos puslapio žodyne, o ne dokumento lygiu.
Dokumento lygio metaduomenys nėra perkeliami. Šaltinio Info žodyne esantys pavadinimo, autoriaus, temos ir raktinių žodžių laukai lieka nepakeisti. Naujai sukurtas tikslinis dokumentas iš pradžių netriukšmingas, neturi jokių metaduomenų, todėl jei norite užpildyti šiuos laukus, turite juos priskirti PdfDest komponentui tiesiogiai prieš iškviesdami SaveAs. Savybės Title, Author, Subject, Keywords ir Creator priima paprastas tekstines eilutes ir įrašo jas išsaugojimo metu.
Interaktyvios formos yra sudėtingesnis klausimas. „AcroForm“ laukų aprašymai saugomi dokumento lygio žodyne, o ne atskirų puslapių srautuose. Kai ImportPages nukopijuoja puslapį su formos laukais, matomas lauko vaizdas persikelia, nes jis yra nupieštas puslapio sraute, tačiau patys interaktyvūs valdikliai (widgets) nepersikelia. Sujungtame dokumente teksto laukas rodys tą reikšmę, kurią jis turėjo importavimo metu, tačiau jo redaguoti nebus galima. Jei norite, kad formos laukai išliktų užpildomi, prieš sujungimą atlikite jų plokštinimą (flattening) kiekviename šaltinio dokumente: tai įbrėžia reikšmes tiesiai į puslapio turinį ir pašalina interaktyvųjį sluoksnį, užtikrindama tvarkingą vaizdą be neveikiančių formos elementų.
Šifruoti šaltinio failai
Slaptažodžiu apsaugoti failai atidaromi taip pat, kaip ir nešifruoti, tik prieš tai reikia nustatyti vieną papildomą savybę. Priskirkite slaptažodį savybei PdfSrc.Password prieš nustatydami Active := True:
PdfSrc.Password := 'user-password';
PdfSrc.FileName := 'protected.pdf';
PdfSrc.Active := True;
if not PdfSrc.Active then
raise Exception.Create('Wrong password or file cannot be opened');
PdfDest.ImportPages(PdfSrc, '1-' + IntToStr(PdfSrc.PageCount), InsertAt);
Inc(InsertAt, PdfSrc.PageCount);
PdfSrc.Active := False;
Neteisingas slaptažodis sukels tokią pačią tylią nesėkmę (Active = False) kaip ir trūkstamas failas, todėl patikrinimas yra būtinas. Šifravimas nėra perkeliamas į tikslinį failą: puslapiai iš apsaugoto šaltinio sujungtame dokumente tampa neapsaugoti. Jei norite apsaugoti ir galutinį PDF failą, nustatykite jo šifravimo parametrus PdfDest komponente prieš išsaugodami.
Rezultato išsaugojimas
Metodas SaveAs priima failo kelią arba TStream srautą. Sujungimui dažniausiai naudojamas failo kelias:
PdfDest.SaveAs('merged-output.pdf');
Pasirinktinis antrasis parametras TSaveOption valdo išsaugojimo režimą. Numatytoji reikšmė saNone atlieka inkrementinį atnaujinimą, jei dokumentas buvo atidarytas iš failo, arba pilną perrašymą, jei jis buvo sukurtas nuo nulio. Kadangi tikslinis failas su CreateDocument visada yra kuriamas iš naujo, rezultatas bus kompaktiškas. Trečiasis parametras TPdfVersion leidžia nurodyti konkrečią PDF formato versiją, jei to reikalauja kitos jūsų naudojamos sistemos; palikus pvUnknown, PDFium versiją parinks automatiškai.
Šiame straipsnyje aprašyti ImportPages ir SaveAs metodai yra dalis bibliotekos PDFium VCL Component, skirtos Delphi ir C++Builder programuotojams.