Teknik Makale

Delphi'de HotPDF ile PDF Maskeleme ve N-up Yerleştirme

Masanıza bir istek düşüyor: zaten oluşturulmuş bir dizi hesap dökümünü alın, hesap numaralarını karartın ve kağıt tasarrufu için sayfa başına iki sayfa olarak gönderin. Bu işin iki yarısı da sizin üretmediğiniz bir PDF üzerinde içerik akışı cerrahisidir, bu yüzden üzerinde çizim yapacağınız dost bir sayfa tuvali yoktur ve yaslanabileceğiniz bir font yöneticisi de yoktur. Doğrudan açılmış belgenin nesne grafiğini düzenliyor, başka bir aracın yerleştirdiği bir sayfaya ham çizim işleçleri ekliyorsunuz. HotPDF bunun için tam olarak iki giriş noktası sunar ve daha tehlikeli olan, zararsız görünenidir

HotPDF, Delphi ve C++Builder için yerel bir VCL PDF bileşenidir. Dokuzuncu sürümün açılmış belge API'si, yepyeni içerik oluşturabilen ilk yöntemleri ekledi; diskten açtığınız, sıfırdan kurduğunuz bir sayfada çalışırlar. Burada ele aldığımız iki yöntem şunlardır: RedactLoadedRect, bir bölgenin üstünü opak bir dikdörtgenle örter ve StitchLoadedPage, bir sayfayı ölçekleyip başka bir sayfanın üzerine çizer. İkisi de sayfanın /Contents akışına ISO 32000-1 §8.5 içerik akışı işleçleri yazar. Bu işleçlerin ne yaptığını, daha da önemlisi ne yapmadığını anlamak, çalışan bir araç ile bir veri sızıntısı arasındaki farktır

Açılmış bir sayfaya işleç eklemek

Bir sayfayı normal HotPDF API'siyle oluşturduğunuzda, bileşen içerik akışının sahibi olur ve TextOut ile vektör çağrılarınızı sizin için serileştirir. Açılmış bir sayfa farklıdır: onun /Contents mevcut bir akış nesnesidir, belki paylaşılmıştır, belki bir içerik dizisinin parçasıdır ve halihazırda orada olanı bozmeden buna ekleme yapmanız gerekir. Dokuzuncu sürüm bunu güvenli hale getiren üç küçük yardımcı ekledi. NewIndirectStream yeni bir dolaylı THPDFStreamObject boş bir tamponla ve bir /Length 0 girdisiyle ayırır; ResolveLoadedStream bir dolaylı başvuruyu alttaki akışa kadar çözer; ve AppendLoadedStream akışın sonuna ham baytlar yazar ve /Length yeniden yazar, böylece kaydedilen nesne düzgün biçimli kalır

Her iki genel yöntemin izlediği desen aynıdır. Sayfanın /Contents değerini bulun, bunu bir akışa çözün ve kullanılabilir bir akış yoksa bir tane oluşturup ekleyin. Ardından işleçleri ekleyin. Yeni baytlar akışın sonuna eklendiği için, boyama modeli bunların özgün düzenin çizdiği her şeyin üzerinde görünmesini garanti eder. Sade kırmızı maske dikdörtgeninin arkasındaki mekanizma budur ve aynı zamanda o dikdörtgenin çoğu kişinin sandığı şey olmamasının nedenidir

RedactLoadedRect: silen değil, örten bir kaplama

RedactLoadedRect sıfır tabanlı bir sayfa dizini, kullanıcı uzayında dört koordinat ve 0 ile 1 arasında üç renk bileşeni alır:

var
  Pdf: THotPDF;
begin
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('statement.pdf') > 0 then
    begin
      // Cover the account-number band on page 1 with solid black.
      // Coordinates are PDF user space: origin bottom-left, points.
      Pdf.RedactLoadedRect(0, 56, 690, 320, 706, 0, 0, 0);
      Pdf.SaveLoadedDocument('statement-covered.pdf');
    end;
  finally
    Pdf.Free;
  end;
end;

İçeride yöntem içerik akışına üç işleç yazar: DeviceRGB ile bir dolgu rengi ayarı (r g b rg), bir dikdörtgen yolu (x y w h re) ve bir dolgu (f). Genişlik ve yükseklik X2 - X1 ve Y2 - Y1 olarak türetilir, yani siz iki karşı köşe verirsiniz ve kapsamı yönteme hesaplattırırsınız. Renk için 0, 0, 0 verirseniz siyah bir şerit elde edersiniz; beyaz sayfaya uyan beyaz bir şerit istiyorsanız 1, 1, 1 verin. Koordinatlar yüklediğiniz sayfanın kendi kullanıcı uzayıdır, yani başlangıç sol alt köşedir ve birimler puntodur. Bu aynı zamanda bir şeyleri doğru yerleştirmek için sayfanın /MediaBox değerine ihtiyaç duyduğunuz anlamına gelir; GetLoadedPageBox ile pbMediaBox size bunu verir

Bunu iki kez okuyun: doldurulmuş bir dikdörtgen içeriği görsel olarak örter, ama onu silmez. Dikdörtgenin altındaki metin, görüntü ya da vektör sanat hâlâ PDF'de durur, hâlâ nesne grafiğindedir, sayfayı kopyalayan, bir metin çıkarıcı çalıştıran ya da içerik akışından dikdörtgeninizi basitçe silen herkes tarafından hâlâ çıkarılabilir durumdadır. Bu, hukuki ya da güvenlik anlamında redaksiyon değil, görsel maskelemedir. Gerçekten hassas veriyi gizliyorsanız - hesap numaraları, tıbbi kayıtlar, kimlikler, düzenlemeye tabi her şey - üstünü siyah bir kutuyla kapatıp dosyayı göndermek, gün yüzüne çıkmayı bekleyen bir veri sızıntısıdır. Gerçek redaksiyon, alttaki içerik nesnelerini kaldırmayı gerektirir, üstlerini boyamayı değil

Yöntem adı "Redact" diyor ve bu, sonucun nasıl yanlış okunacağına dair yararlı bir uyarıdır, neyi sildiğine dair bir vaat değil. Uygulama bununla ilgili kendi yorumunda dürüst davranır: kendisini "görsel redaksiyon ilkeli" diye adlandırır ve içerik kaldıran redaksiyonun, mevcut işleçleri dolaşıp yeniden yazan bir içerik akışı yorumlayıcısı gerektirdiğini söyler. HotPDF'nin açılmış belge yolu burada bunu yapmaz. Bu yüzden güvenli kural dardır: RedactLoadedRect hassas olmayan kozmetik maskeleme için kullanın, taslak filigranını gizlemek, ekran görüntüsünden önce bir bölgeyi boşaltmak, iç prova üzerinde eski bir logoyu örtmek gibi. Kutunun altındaki şey sızarsa önemi olacaksa, bu yöntem yanlış araçtır ve doğru cevap belgeyi veriyi çıkarmadan yeniden üretmek ya da gerçek bir içerik kaldırma hattı kullanmaktır

StitchLoadedPage: ölçekle, ötele, çiz

N-up yerleştirme daha dost bir problemdir, çünkü hiçbir şey gizlenmez, yalnızca yeniden düzenlenir. StitchLoadedPage sıfır tabanlı bir hedef sayfa dizini, bir kaynak sayfa dizini, bir X/Y ofseti ve bir ölçek katsayısı alır, kaynak sayfayı o konumda ve o boyutta hedefin üzerine çizer:

// Overlay page 2 (index 1) onto page 1 (index 0),
// scaled to 70% and nudged up-right.
Pdf.StitchLoadedPage(0, 1, 40, 380, 0.7);

// Convenience 2-up: source page on the right half of the target.
Pdf.StitchLoadedPageSideBySide(0, 1);

Eklediği işlemci dizisi standart bir dönüştür ve boya sırasıdır: q grafik durumunu kaydetmek için bir cm matrisi, ölçeği köşegende ve ofseti öteleme yuvalarında taşır, /StitchSrc Do dış bir nesneyi çağırmak için, ve Q durumu geri yüklemek için. q/Q çifti önemlidir: dönüştürmeyi yalıtır, böylece dikilmiş sayfa kendi koordinat sistemini sonradan eklenen hiçbir şeye sızdırmaz. Yöntem ayrıca bariz hataları da denetler, aralık dışı dizinler, kaynağa eşit bir hedef, pozitif olmayan bir ölçek (bunu 1.0 değerine kırpar) ve yükseltme yapmadan sessizce çıkar, bu yüzden girdilerinizi kontrol edin, çünkü sessiz bir no-op başarıyla aynı görünür

StitchLoadedPageSideBySide genel yöntemin ince bir kolaylık katmanıdır. Hedefin media box genişliğini okur, bunu ikiye böler ve StitchLoadedPage ile bu yarım genişliği X ofseti olarak, sabit 0.5 ölçeğiyle çağırır, kaynağı sağ yarıya yerleştirir. Bu sabit 0,5, kaynak ve hedefin genişliği paylaştığını varsayar; paylaşmıyorlarsa kaynak yarısını düzgün doldurmaz ve kendi hesaplayacağınız bir ölçekle genel StitchLoadedPage yöntemini isteyeceksiniz

Basitleştirilmiş XObject stratejisi ve ISO bedeli

Burada uygulama, çıktıya farklı görüntüleyicilerde güvenmeden önce bilmeniz gereken kasıtlı bir kestirme yapar. Doğru bir N-up yerleştirme, kaynak sayfanın içeriğini ISO 32000-1 §8.10.1'in taşıması gerektiğini söylediği, kendi başına çizilebilir bir nesne olan Form XObject içine sarar, bu nesnede /Type /XObject, /Subtype /Form ve kendi /BBox kırpma kutusu bulunur. HotPDF'nin dokuzuncu sürüm stitch'i bu sarmalayıcıyı kurmaz. Bunun yerine kaynak sayfa sözlüğünün kendisini hedefin /Resources /XObject doğrudan altına StitchSrc adıyla kaydeder, sonra onu Do ile çizer. Bir sayfa sözlüğü ile bir Form XObject, içerik modelinin yeterince kısmını paylaşır, çünkü ikisi de bir içerik akışına ve bir kaynak sözlüğüne başvurur, bu yüzden birçok okuyucu sonucu işler

Ama bu, uyumlu bir Form XObject değildir./Subtype /Form işaretleyicisi ve kendi /BBox yoktur, bu da sıkı bir tüketicinin Do öğesini yok sayma ya da beklediğinizden farklı biçimde kırpma hakkı olduğu anlamına gelir. Bu turun TechnicalNotes'unun açıkça söylediği gibi, yaklaşım "çoğu okuyucuda çalışır" ama "katı biçimde ISO uyumlu bir Form XObject değildir", ve tam uyum için gerçek bir Form XObject akışını ayrı bir adımda üretmek gerekir. Bu yüzden stitch çıktısına uyumsuz bir yapıymış gibi davranın: onu yalnızca makinenizdeki görüntüleyicide değil, müşterilerinizin kullandığı belirli görüntüleyicilerde doğrulayın ve arşiv kalitesinde ya da sıkı doğrulayıcıdan geçen PDF'lere ihtiyacınız varsa bu yola güvenmeyin. Aynı disiplin, yüklenmiş nesne grafiği üzerinde kurduğunuz her şeye de uygulanır, bu yüzden Delphi'de PDF preflight geçişi belgeyi programlı olarak değiştirdiğiniz her seferde yayın hattında yerini hak eder

Bunların nerede işe yaradığı ve nerede yaramadığı

İki yöntem de içerik akışı aracıdır, bu yüzden zihinsel model doğrudan çizim için kullandığınızla aynıdır. Bileşenle sıfırdan sayfa oluşturduysanız, bu çağrıların arkasındaki vektör ve renk işleçleri size HotPDF canvas drawing in Delphi; fark yalnızca burada başkasının yazdığı bir akışa ekleme yapıyor olmanız, kendinize ait olana değil. Üç sınırı akılda tutun:

  • Redaksiyon görsel bir maskelemedir. RedactLoadedRect içeriğin üstünü boyar ve onu asla silmez. Hassas olan her şey için kaynağı yeniden üretin ya da gerçek içerik kaldırma kullanın, siyah kutu güvenlik değildir
  • Stitch, tasarım gereği standartlara uymaz. Kaynak sayfa, §8.10.1'deki /Subtype /Form ve /BBox olmadan yalancı bir XObject olarak referanslanır, bu yüzden çıktıyı hedef görüntüleyicilerinizde doğrulayın ve katı doğrulama gereken yerlerde bundan kaçının
  • Koordinatlar sayfanın kullanıcı uzayıdır. Sol alt köşe başlangıçtır, birimler puntodur ve sayfanın kendi media box'ı belirleyicidir. Bir şey yerleştirmeden önce kutuyu GetLoadedPageBox kontrol edin, çünkü yüklediğiniz sayfa sandığınız boyutta olmayabilir

Bu sınırlar içinde kullanıldığında, ikili gerçek bir iş akışını kapsar: baskı için sayfaları yeniden düzenleyin, gizli olmayan bölgeleri maskeleyin ve sonucu SaveLoadedDocument ile, tam bir yeniden oluşturma yapmadan geri yazın. Bu stitch ve maske ilkellerini içeren açılmış belge API'si, HotPDF Component Delphi ve C++Builder için, aynı turun form alanı, açıklama ve FDF yöntemleriyle birlikte gelir