PDFium Bileşeni, PDF birleştirmeyi tek bir yöntemle sunar: ImportPages. Model her zaman aynıdır: boş bir hedef belge oluşturun, her bir kaynak dosyayı açın, sayfaları kopyalamak için ImportPages yöntemini çağırın, kaynağı kapatın ve tekrarlayın. Döngü bittiğinde SaveAs sonucu diske yazar. Özel bir birleştirme modu, değiştirilecek bir yapılandırma yoktur. Karmaşıklık uç durumlarda yaşar ve uyarı yapmadan ısıran birkaç tane vardır
Çekirdek döngü
İhtiyacınız olan tek şey iki TPdf örneğidir. Biri, CreateDocument ile boş olarak oluşturulan hedef belgeyi tutar. Diğeri sırayla her kaynak dosyayı açar. Aşağıda bir dosya yolları listesi alan ve birleştirilmiş çıktıyı tek bir yola yazan bir prosedür bulunmaktadır:
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;
Bu kodda ilk okumada gözden kaçması kolay iki şey var. Birincisi, PDFium'un yükleme hatalarını nasıl rapor ettiğidir. Active := True hiçbir zaman istisna (exception) fırlatmaz: dosya eksikse, hasarlıysa veya parola korumalıysa, PDFium hatayı dahili olarak yakalar ve Active değerini False olarak bırakır. Satır 10'daki açık kontrol olmadan, bozuk bir dosya çıktıda hiçbir belirti olmadan sessizce birleştirmeden düşerdi. Son PDF'in beklanden daha az sayfası olurdu ve hangi dosyanın suçlu olduğunu bilemezdiniz
İkincisi InsertAt sayacıdır. ImportPages'in üçüncü argümanı, içe aktarılan ilk sayfanın indiği hedefteki 1 tabanlı konumdur. 1'den başlamak, ilk kaynak belgeyi boş bir dosyanın başına koyar. Her kaynaktan sonra sayaç PdfSrc.PageCount kadar ilerler, böylece bir sonraki sayfa grubu sonuncusundan sonra eklenir. Onu artırmayı unutursanız, sonraki her kaynak 1 konumundaki sayfaların üzerine yazar ve size listedeki son belgeyi verir ve başka hiçbir şey vermez
Seçici sayfa aralıkları
Bir kaynaktan her sayfayı almak zorunda değilsiniz. İkinci argüman olarak geçirilen aralık dizesi (range string) basit bir virgül ve tire biçimini izler: "1-3" 1'den 3'e kadar olan sayfaları alır, "2,4,6" belirli üç sayfayı seçer ve "1-" sayfa 1'den belgenin sonuna kadar anlamına gelir. Aralıklar tek bir dizede birleştirilebilir, bu nedenle "1-3,5,7-" sayfa 4 ve 6'yı atlar. Burada bir incelik önemlidir: numaralar, o sayfaların hedefte nereye vardıklarına bakılmaksızın her zaman kaynak belgedeki sayfaları, 1'den başlayarak ifade eder. 200 sayfalık bir katalogdan 40 ile 50 arasındaki sayfaları istiyorsanız, aralık dizesi hedefte halihazırda bulunanlara göre bir konum değil, "40-50" şeklindedir
// 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;
InsertAt artışını hesaplarken, kaynağın sayfa sayısını değil, fiilen içe aktardığınız sayfaları sayın. '1,3-5' geçerseniz 4 sayfayı içe aktarmışsınız demektir, bu yüzden 4 ilerletin. PdfSrc.PageCount kadar ilerlemek, boş hedef konumlarında bir boşluk bırakacak ve bir sonraki kaynak belgeyi dosyaya istenenden daha uzağa yerleştirecektir
ImportPages neyi korur ve neyi korumaz
ImportPages tarafından kopyalanan sayfalar görünür içeriklerini sağlam taşır. Metin, vektör grafikleri, tarama görüntüleri, gömülü yazı tipleri ve form XObject'lerinin hepsi sayfa içerik akışlarının bir parçası olarak aktarılır. Yorumlar, vurgular ve mürekkep vuruşları dahil olmak üzere sayfa düzeyindeki açıklamalar da gelir, çünkü belge düzeyinden ziyade sayfa sözlüğünün içinde saklanırlar
Belge düzeyindeki meta veriler farklı bir hikayedir. Kaynağın Info sözlüğündeki başlık, yazar, konu ve anahtar kelime dizeleri geride kalır. Hedef belge CreateDocument'ten sonra boş meta verilerle başlar, bu nedenle birleştirilmiş çıktının bu alanların doldurulmasına ihtiyacı varsa, SaveAs'i çağırmadan önce bunları doğrudan PdfDest'e atamanız gerekir. TPdf üzerindeki Title, Author, Subject, Keywords ve Creator özellikleri düz dizeler alır ve kaydederken Info sözlüğüne yazar
Etkileşimli form alanları daha karmaşıktır. AcroForm alan tanımları, tek tek sayfa akışlarından ziyade belge düzeyinde bir sözlükte yaşar. ImportPages form alanları içeren bir sayfayı kopyaladığında, bu alanların görsel görünümü sayfa içerik akışına işlendiği için aktarılır, ancak onları etkileşimli kılan alan widget'ları AcroForm yapısının bir parçasıdır ve onu takip etmez. Tipik bir birleştirmede, bir kaynak belgeden bir metin alanı içe aktarıldığı andaki değerini gösterir, ancak birleştirilmiş dosyada düzenlenebilir olmaz. Alanların doldurulabilir kalmasına ihtiyacınız varsa, içe aktarmadan önce bunları her kaynak belgede düzleştirin (flatten): bu, mevcut değerleri içerik akışına pişirir ve etkileşimli yerleşimi (overlay) kaldırarak, çıktıda bozuk widget'lar olmadan temiz bir görsel sonuç verir
Şifreli kaynak dosyalar
Parola korumalı kaynak belgeler şifrelenmemiş olanlarla aynı şekilde, önce ayarlanması gereken fazladan bir özellikle açılır. Active := True durumuna geçmeden önce parolayı PdfSrc.Password özelliğine atayın; PDFium açılış sırasında bunu kullanacaktır:
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;
Yanlış bir parola, eksik bir dosyayla aynı sessiz Active = False sonucuna neden olur, bu nedenle açık kontrol burada da aynı derecede gereklidir. Şifreleme hedefe aktarılmaz: korumalı bir kaynaktan içe aktarılan sayfalar hedefe korumasız içerik olarak iner. Birleştirilmiş çıktının da şifrelenmesi gerekiyorsa, SaveAs'i çağırmadan önce bunu PdfDest üzerinde yapılandırın
Sonucu kaydetme
TPdf üzerindeki SaveAs, bir dosya yolu veya TStream kabul eder. Çoğu birleştirme için dosya aşırı yüklemesi istediğiniz şeydir:
PdfDest.SaveAs('merged-output.pdf');
İsteğe bağlı ikinci argüman, kaydetme modunu kontrol eden bir TSaveOption'dır. Varsayılan olan saNone, belge bir dosyadan yüklenmişse artımlı bir güncelleme veya yeni oluşturulmuşsa tam bir yeniden yazma gerçekleştirir. CreateDocument ile oluşturulan bir hedef her zaman yeni olduğundan, çıktı kompakt tek revizyonlu bir dosya olacaktır. Üçüncü argüman TPdfVersion, belirli bir sürüm gerektiren aşağı akış tüketicileriniz (downstream consumers) olduğunda PDF sürüm başlığını sabitlemenize olanak tanır; pvUnknown'da bırakmak PDFium'un içeriğe göre seçim yapmasına olanak tanır
Burada gösterilen ImportPages ve SaveAs yöntemleri, Delphi ve C++Builder için PDFium Bileşeni'nin bir parçasıdır