PDFium Component siūlo PDF failų sujungimą naudojant vieną metodą: ImportPages. Šablonas visada yra toks pat: sukurkite tuščią paskirties dokumentą, atidarykite kiekvieną šaltinio failą, iškvieskite ImportPages, kad nukopijuotumėte puslapius, uždarykite šaltinį ir pakartokite. Kai ciklas baigiasi, SaveAs įrašo rezultatą į diską. Nėra jokio specialaus sujungimo režimo ar konfigūracijos, kurią reikėtų keisti. Sudėtingumas slypi kraštutiniuose atvejuose, ir yra keletas, kurie gali netikėtai sukelti problemų
Pagrindinis ciklas
Jums tereikia dviejų TPdf egzempliorių. Viename saugomas paskirties dokumentas, sukurtas tuščias su CreateDocument. Kitas atidaro kiekvieną šaltinio failą paeiliui. Žemiau pateikta procedūra, kuri priima failų kelių sąrašą ir įrašo sujungtą rezultatą į vieną kelią:
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;
Skaitant pirmą kartą, lengva nepastebėti dviejų dalykų šiame kode. Pirmasis – tai, kaip PDFium praneša apie įkėlimo klaidas. Active := True niekada nesukelia išimties: jei failo trūksta, jis sugadintas arba apsaugotas slaptažodžiu, PDFium klaidą sugauna viduje ir palieka Active reikšmę False. Be aiškaus patikrinimo 10 eilutėje, blogas failas tyliai iškristų iš sujungimo be jokių požymių išvestyje. Galutinis PDF turėtų mažiau puslapių nei tikėtasi, ir jūs nežinotumėte, kuris failas buvo kaltininkas
Antrasis yra InsertAt skaitiklis. Trečiasis ImportPages argumentas yra 1 pagrindu nurodyta pozicija paskirties vietoje, kur atsiduria pirmasis importuotas puslapis. Pradedant nuo 1, pirmasis šaltinio dokumentas dedamas į tuščio failo pradžią. Po kiekvieno šaltinio skaitiklis pasislenka per PdfSrc.PageCount, todėl kita puslapių partija pridedama po paskutiniojo. Pamirškite jį padidinti, ir kiekvienas paskesnis šaltinis perrašys puslapius 1 pozicijoje, suteikdamas jums tik paskutinį dokumentą sąraše ir nieko daugiau
Atrankiniai puslapių diapazonai
Jums nereikia imti kiekvieno puslapio iš šaltinio. Diapazono eilutė, perduodama kaip antrasis argumentas, atitinka paprastą kablelio ir brūkšnelio formatą: "1-3" ima puslapius nuo 1 iki 3, "2,4,6" parenka tris konkrečius puslapius, o "1-" reiškia nuo 1 puslapio iki dokumento pabaigos. Diapazonus galima derinti vienoje eilutėje, todėl "1-3,5,7-" praleidžia 4 ir 6 puslapius. Čia svarbi viena subtilybė: skaičiai visada nurodo puslapius šaltinio dokumente, pradedant nuo 1, neatsižvelgiant į tai, kur tie puslapiai atsiduria paskirties vietoje. Jei norite puslapių nuo 40 iki 50 iš 200 puslapių katalogo, diapazono eilutė yra "40-50", o ne pozicija, susijusi su tuo, kas jau yra paskirties vietoje
// 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 prieaugį, skaičiuokite puslapius, kuriuos iš tikrųjų importavote, o ne šaltinio puslapių skaičių. Jei perduodate '1,3-5', jūs importavote 4 puslapius, todėl perkelkite per 4. Perkėlimas per PdfSrc.PageCount paliktų tuščių paskirties pozicijų tarpą ir patalpintų kitą šaltinio dokumentą toliau į failą nei planuota
Ką ImportPages išsaugo ir ko ne
Puslapiai, nukopijuoti naudojant ImportPages, išlaiko savo matomą turinį nepažeistą. Tekstas, vektorinė grafika, rastriniai vaizdai, įterptieji šriftai ir formų XObjects perkeliami kaip puslapio turinio srautų dalis. Puslapio lygio anotacijos, įskaitant komentarus, paryškinimus ir rašalo brūkšnius, taip pat perkeliamos, nes jos saugomos puslapio žodyne, o ne dokumento lygiu
Dokumento lygio metaduomenys yra visai kita istorija. Pavadinimo, autoriaus, temos ir raktinių žodžių eilutės šaltinio Info žodyne perkeliamos nebus. Paskirties dokumentas po CreateDocument prasideda su tuščiais metaduomenimis, todėl, jei sujungtoje išvestyje reikia užpildyti tuos laukus, turite priskirti juos tiesiogiai PdfDest prieš iškviesdami SaveAs. Title, Author, Subject, Keywords ir Creator ypatybės objekte TPdf priima paprastas eilutes ir įrašo į Info žodyną išsaugant
Interaktyvūs formų laukai yra sudėtingesnis atvejis. „AcroForm“ laukų apibrėžimai gyvena dokumento lygio žodyne, o ne atskiruose puslapių srautuose. Kai ImportPages kopijuoja puslapį, kuriame yra formų laukų, vizualinė tų laukų išvaizda perkeliama, nes ji atvaizduojama puslapio turinio sraute, tačiau laukų valdikliai, darantys juos interaktyvius, yra „AcroForm“ struktūros dalis ir jie neperkeliami. Tipinio sujungimo metu šaltinio dokumento teksto laukas parodys reikšmę, kurią turėjo importavimo metu, tačiau jo nebus galima redaguoti sujungtame faile. Jei norite, kad laukai išliktų užpildyti, prieš importuodami kiekviename šaltinio dokumente juos „suplokštinkite“ (flatten): tai įrašo dabartines reikšmes į turinio srautą ir pašalina interaktyvią perdangą, suteikiant švarų vizualinį rezultatą be neveikiančių valdiklių išvestyje
Užšifruoti šaltinio failai
Slaptažodžiu apsaugoti šaltinio dokumentai atidaromi taip pat, kaip ir nešifruoti, tik pirmiausia reikia nustatyti vieną papildomą ypatybę. Priskirkite slaptažodį PdfSrc.Password prieš perjungdami Active := True, ir PDFium jį panaudos atidarymo metu:
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;
Dėl neteisingo slaptažodžio gaunamas toks pat tylus Active = False rezultatas kaip ir trūkstant failo, todėl čia taip pat būtinas aiškus patikrinimas. Šifravimas neperkeliamas į paskirties vietą: puslapiai, importuoti iš apsaugoto šaltinio, atsiduria paskirties vietoje kaip neapsaugotas turinys. Jei sujungtai išvesčiai taip pat reikia šifravimo, sukonfigūruokite jį objekte PdfDest prieš iškviesdami SaveAs
Rezultato išsaugojimas
Objekto TPdf metodas SaveAs priima arba failo kelią, arba TStream. Daugeliui sujungimų failo kelio variantas yra tai, ko jums reikia:
PdfDest.SaveAs('merged-output.pdf');
Pasirenkamas antrasis argumentas yra TSaveOption, kuris valdo išsaugojimo režimą. Numatytasis saNone įrašo laipsnišką atnaujinimą, jei dokumentas buvo įkeltas iš failo, arba visišką perrašymą, jei jis buvo sukurtas naujas. Kadangi su CreateDocument sukurta paskirties vieta visada yra nauja, išvestis bus kompaktiškas vienos revizijos failas. Trečiasis argumentas TPdfVersion leidžia prisegti PDF versijos antraštę, kai turite tolesnių vartotojų, kuriems reikia konkrečios versijos; palikus jį pvUnknown, PDFium leidžiama pasirinkti atsižvelgiant į turinį
Čia parodyti metodai ImportPages ir SaveAs yra PDFium Component, skirto Delphi ir C++Builder, dalis