Sayfa birleştirme (stitching), mevcut sayfaların içeriğini ortak bir tuval üzerine yerleştirir; bu işlem dosyaları birleştirmekten (merging) farklıdır. losLab PDF Kütüphanesi, Delphi için Form XObject sayfa birleştirme ve oluşturulabilir filigran şablonlarını uygular: StitchPageOverlay, StitchPagesSideBySide ve StitchPagesVertically yakalanan sayfaları tam vektör sadakatiyle herhangi bir ölçekte yerleştirir ve TPDFlibCompositeWatermark metin ve resim filigranlarını tek bir çağrıda bir sayfa aralığı boyunca üst üste yığar. Gerçekten ihtiyacınız olan şey, birkaç belgedeki tam sayfaları tek bir dosyaya eklemekse, bu birleştirme (merge) ailesidir ve hızlı bayt düzeyinde PDF birleştirme hakkındaki makalede ele alınmıştır; bu makale, sayfa içeriklerini tek bir koordinat alanı içinde birleştirmekle ilgilidir
Buraya yol açan talepler sıradan ve inatçıdır. Bir okul, kağıt kullanımını yarıya indirmek için yatay bir sayfaya iki sınav sayfasının basılmasını istiyor. Bir yerelleştirme inceleyicisi, İngilizce sayfayı ve çevirisini tek bir sayfada yan yana görmek ve birlikte kaydırmak istiyor. Bir hukuk ekibi, her taslağın aynı anda üç katmanla damgalanmasını istiyor: Köşede bir logo, ortada çapraz bir CONFIDENTIAL (GİZLİ) ibaresi ve yalnızca 1'den 3'e kadar olan sayfalarda küçük bir altbilgi satırı. Her üçü de aynı temel problemdir; yani halihazırda dizilmiş sayfa içeriğini bir bit eşleme (bitmap) düzeyine düşürmeden başka bir boyutta başka bir yere yerleştirmek
PDF içerik akışlarını (content streams) birleştirmek neden bozulur?
Kaynak sayfanın /Contents akışını hedef sayfaya kopyalayan naif birleştirme, üç yapısal nedenden dolayı başarısız olur. İlk olarak, koordinatlar çakışır: Her iki içerik akışı da kendi başlangıç noktasını kendi MediaBox'ının sol alt köşesinde varsayar, bu nedenle yapıştırılan içerik mevcut içeriğin üzerine yanlış yerde biner. İkinci olarak, kaynak adları çakışır: Her sayfa /F1 Tf ve /Im0 Do gibi operatörleri kendi /Resources sözlüğüne göre çözümler ve iki sayfa rutin olarak aynı adı farklı yazı tiplerine veya resimlere bağlar, bu nedenle bunlardan biri sessizce yanlış kaynakla işlenir. Üçüncü olarak, ham bir akış kopyası size hiçbir ölçeklendirme sağlamaz; yapabileceğiniz en iyi şey ötelemektir (translate)
Form XObject'leri her üçünü birden çözer ve losLab PDF Kütüphanesi'nin birleştirmesini bunların üzerine inşa etmesinin nedeni budur. ISO 32000-1 §8.10, bir form XObject'ini, kendi /Resources sözlüğüne ve kendi koordinat alanına sahip, etkin olan mevcut dönüşüm matrisi altında adını çağırarak bir sayfaya yerleştirilen bağımsız bir içerik akışı olarak tanımlar. CapturePage mevcut bir sayfanın tamamını (içerik artı kaynaklar) bir /Subtype /Form XObject'i içine sarar ve birleştirme işlevleri daha sonra bunu bir cm matrisi ile konumlandırır: Ölçeklendirme, öteleme, döndürme, istenildiği gibi. Kaynak vektör olarak kaldığı için, metin metin olarak kalır ve yollar herhangi bir yakınlaştırma düzeyinde yol olarak kalmaya devam eder; bu, vektör grafikleri ve gölgeleme desenlerini çözünürlükten bağımsız kılan özelliğin aynısıdır. Hiçbir şey rasterleştirilmez ve yalıtılmış kaynak sözlüğü, yakalanan sayfanın /F1 adı üzerinde hedef sayfayla kavga edemeyeceği anlamına gelir
İki PDF sayfasını tek bir sayfada nasıl birleştirirsiniz?
StitchPagesSideBySide(Page1, Page2, Gap, TargetHeight) doğrudan cevaptır: Her iki kaynak sayfayı yakalar, yeni ve daha geniş bir sayfa oluşturur ve yakalanan iki sayfayı aralarında bir boşlukla sola ve sağa yerleştirir, her biri TargetHeight değerine sığacak şekilde ölçeklendirilir. İşlev yeni sayfa numarasını (1 tabanlı) veya başarısızlık durumunda 0 döndürür ve her iki kaynak sayfa da işlemin bir parçası olarak yakalanır ve gizlenir. Sayfa başına iki sayfa sınav durumu üç satırlık bir iştir
var
Lib: TPDFlib;
NewPage: Integer;
begin
Lib := TPDFlib.Create;
try
Lib.LoadFromFile('exam.pdf', '');
// Sayfa 1 ve 2, aralarında 18pt boşluk olan yeni bir daha geniş sayfaya yerleştirilir,
// her ikisi de 595pt çıktı yüksekliğine (A4 yatay) ölçeklendirilir
NewPage := Lib.StitchPagesSideBySide(1, 2, 18, 595);
if NewPage > 0 then
Lib.SaveToFile('exam-2up.pdf');
finally
Lib.Free;
end;
end;
Dikey kompozisyon için, StitchPagesVertically(PageRanges, Gap, TargetWidth) tüm bir sayfa aralığını tek bir uzun, poster tarzı sayfa halinde yığar. PageRanges, '1-3,5' gibi standart aralık sözdizimini alır. Her kaynak sayfa, genişliği TargetWidth ile eşleşecek şekilde ölçeklendirilir, bu nedenle her sayfanın yükseklik katkısı kendi yüksekliği çarpı kendi ölçek faktörüdür ve çıktı sayfa yüksekliği bunların toplamı artı her çift arasındaki bir Gap değeridir. Bu, sürekli kaydırma inceleme belgeleri veya letter boyutundaki kaynaklardan bir araya getirilen uzun fişler için istediğiniz şekildir
Bir sayfayı diğerinin üzerine nasıl bindirirsiniz?
StitchPageOverlay(SourcePage, TargetPage, Left, Top, Width, Height, Opacity) yeni bir sayfa oluşturmak yerine mevcut bir sayfayı diğer mevcut bir sayfanın üzerine boyar. Kaynak sayfa bir form XObject'i olarak yakalanır ve hedef sayfada verdiğiniz dikdörtgene 0 ile 1 arasındaki Opacity (1 opaktır) değeriyle çizilir. Genişlik ve yükseklik serbest parametrelerdir, bu nedenle oranınız kaynak sayfanın kendi en boy oranından farklıysa yerleştirme esner; kaynağın bozulmamış bir küçük resmini istediğinizde orantılı bir çift geçirin. Tipik bir kullanım, onay bloğu kendi sayfası olarak sürdürülen ve kapağa damgalanan bir belgedir
var
Lib: TPDFlib;
begin
Lib := TPDFlib.Create;
try
Lib.LoadFromFile('report.pdf', '');
// Sayfa 5 onay bloğunu tutuyor; bunu sayfa 1'e yerleştirin
// 260 x 180'lik bir kutuda %45 opaklıkla. Sayfa 5 tüketilir:
// yakalanır ve gizlenir, böylece sayfa 6..n artık 5..n-1 olur
if Lib.StitchPageOverlay(5, 1, 300, 500, 260, 180, 0.45) = 1 then
Lib.SaveToFile('report-approved.pdf');
finally
Lib.Free;
end;
end;
Yakalama işleminden sonra sayfa numaralarına ne olur?
CapturePage kaynak sayfayı tüketir: İçeriği XObject'e taşınır ve artık boş olan sayfa gizlenir, böylece kaynağın üzerinde numaralandırılmış her sayfa hemen bir sıra aşağı kayar. Bu, tüm birleştirme API'sindeki en önemli anlambilimdir. losLab PDF Kütüphanesi her birleştirme çağrısının içindeki aritmetiği yönetir, hedef kaynağın üzerinde olduğunda StitchPageOverlay hedef dizini ayarlar ve StitchPagesSideBySide önce daha yüksek numaralı sayfayı yakalar, böylece ikinci yakalamanın dizini hala geçerli olur, ancak kendi çevreleyen kodunuz çağrılar arasındaki kaymayı hesaba katmalıdır. İki kural, çoklu birleştirme kodunu doğru tutar. İhtiyacınız olacak sayfa boyutlarını veya sayfa numaralarını ilk yakalamadan önce kaydedin, çünkü bunlar daha sonra değişir. Ve bir döngüde kendiniz birkaç sayfa yakaladığınızda, azalan sayfa sırasında yineleyin, böylece daha sonraki bir sayfayı gizlemek henüz yakalamadığınız daha önceki bir sayfanın dizinini asla bozmaz
Çok katmanlı bir filigranı bir sayfa aralığına nasıl uygularsınız?
PDFlibWatermark.pas içindeki filigran şablon katmanı, "birkez tanımla, birçok sayfaya uygula" yaklaşımını nesnelere dönüştürür. TPDFlibWatermarkBase, her filigranın paylaştığı şeyleri taşır: Dokuz noktalı bir Position (wpTopLeft'den wpBottomRight'e kadar, artı ham X/Y koordinatlarını kullanan wpCustom), derece cinsinden bir Angle, 0 ile 1 arasında bir Opacity ve boş bırakıldığında tüm sayfalar anlamına gelen bir PageRange dizgesi. TPDFlibTextWatermark metin, bir yazı tipi kimliği (varsayılan olarak Helvetica), boyut ve bir RGB rengi ekler; TPDFlibImageWatermark daha önce eklenmiş bir görüntüden bir görüntü kimliği artı bir yerleştirme genişliği ve yüksekliği ekler. TPDFlibCompositeWatermark alt filigranların bir listesini tutar ve bunları özyinelemeli olarak uygular ve TPDFlib.ApplyWatermark, şablonun kendi sayfa aralığını onurlandıran ve damgalanan sayfa sayısını döndüren tek çağrılı giriş noktasıdır. Üç katmanlı yasal damga şöyle görünür
var
Lib: TPDFlib;
Logo: TPDFlibImageWatermark;
Diagonal, Footer: TPDFlibTextWatermark;
Stack: TPDFlibCompositeWatermark;
begin
Lib := TPDFlib.Create;
try
Lib.LoadFromFile('draft.pdf', '');
Stack := TPDFlibCompositeWatermark.Create;
try
Logo := TPDFlibImageWatermark.Create;
Logo.ImageID := Lib.AddImageFromFile('logo.png', 0);
Logo.Position := wpTopRight;
Logo.Width := 90;
Logo.Height := 32;
Stack.Add(Logo);
Diagonal := TPDFlibTextWatermark.Create;
Diagonal.Text := 'CONFIDENTIAL';
Diagonal.Position := wpCenter;
Diagonal.Angle := 45;
Diagonal.FontSize := 60;
Diagonal.Opacity := 0.15;
Stack.Add(Diagonal);
Footer := TPDFlibTextWatermark.Create;
Footer.Text := 'Internal review copy';
Footer.Position := wpBottomCenter;
Footer.FontSize := 9;
Footer.Opacity := 0.6;
Stack.Add(Footer);
Stack.PageRange := '1-3'; // alt elemanlar bu aralığı miras alır
Lib.ApplyWatermark(Stack);
Lib.SaveToFile('draft-marked.pdf');
finally
Stack.Free; // bileşik kendi alt elemanlarını serbest bırakır
end;
finally
Lib.Free;
end;
end;
İki kompozisyon ayrıntısını açıklığa kavuşturmakta fayda var. Aralık miras alma tek yönlüdür ve tahrip edici değildir: Boş bir PageRange içeren bir alt eleman, Apply sırasında geçici olarak bileşiğin aralığını miras alırken, kendi aralığını ayarlayan bir alt eleman bunu korur, böylece çapraz damga yalnızca taslak bölümünü kaplarken altbilgiyi her sayfaya sabitleyebilirsiniz. Ve sahiplik bileşiği takip eder: TPDFlibCompositeWatermark.Destroy kendi alt elemanlarını serbest bırakır, bu nedenle yukarıdaki örnekte olduğu gibi bileşiği bir kez serbest bırakırsınız ve başka bir şeye dokunmazsınız
Bilinmesi gereken sınırlar
İki dürüst sınır geçerlidir ve her ikisi de mekanizmanın çalışma şeklinden kaynaklanır. İlk olarak, bir yakalama yalnızca sayfanın içerik akışını ve kaynaklarını sarar. Açıklamalar (annotations), bağlantılar, form alanları ve yorumlar içerik akışında değil, sayfa sözlüğünde ayrı nesneler olarak yaşarlar, bu nedenle XObject'e taşınmazlar; birleştirilmiş bir düzen, kaynaklarının görünür sayfa içeriğini taşır ancak etkileşimli katmanını taşımaz. İkinci olarak, dokuz noktalı metin konumlandırma bir yaklaşımdır: Tam bir düzen motoru olmadan kütüphane bir dizginin işlenen tam genişliğini bilemez, bu nedenle wpCenter gibi konumları çözerken metin kutusunu sayfa genişliğinin %40'ı olarak tahmin eder. Bu, kısa bir etiketi ortalamak için yeterince doğrudur, ancak uzun dizgelerin piksel hassasiyetinde yerleştirilmesi için wpCustom'a geçin ve koordinatları kendiniz hesaplayın
Yakalamak ve birleştirmek sayfa içeriğini yeniden kodlamak yerine nesne referanslarını manipüle ettiğinden, ölçek burada pratik bir kısıtlama değildir; kaynaklarınız yüzlerce megabaytsa, birleştirmeden önce doğrudan erişimle büyük dosya birleştirme ve bölme kılavuzunda açıklanan aynı disiplin geçerlidir. Burada gösterilen birleştirme işlevleri ve filigran şablon sınıfları, üç önceden oluşturulmuş birleştirme çağrısının kapsamadığı bir düzene ihtiyaç duyduğunuzda daha alt düzey CapturePage, DrawCapturedPage ve DrawCapturedPageMatrix temel öğelerinin yanında, Delphi, C# ve VB.NET için güncel losLab PDF Kütüphanesi içinde gönderilmektedir