Teknik Makale

PDFlibPas Karartma Uygulaması: RO, IC ve Kaydetme

/IC rengi olmadan çizilmiş bir karartma işareti, uygulama adımından şeffaf bir boşluk ya da içi boş bir kontur olarak çıkabilir; üstündeki gözden geçiren yorumu ise dosyada kalır. PDFlibPas, Redact annotationlarını ApplyRedactions ile uygular: kapsanan içerik önce gider, katman /ROdan ya da yedeği siyah olan /ICden gelir ve işaretin sözlüğü boşaltılır

İşaretlemek geri alınabilir, uygulamak alınamaz

ISO 32000-1 §12.5.6.23, karartmayı içerik tanımlama ile içerik silme olarak ikiye ayırır. Tanımlama sırasında bir Redact annotationı, kullanıcıların hâlâ görebileceği, taşıyabileceği ve yeniden tanımlayabileceği yalnızca bir tekliftir; bir inceleme turunu mümkün kılan da budur. Silme uygulamaya bırakılmıştır ve sıkı gereksinimlerle gelir: annotationın tanımladığı her şey gider, annotation gider ve kapsanan görüntü kısmının verisi yok edilir; çünkü piksellerin üstündeki bir kırpma yolu ya da görüntü maskesi yeterli sayılmaz. Anahtarlar ISO 32000-1in tablo 192sinde (ISO 32000-2de tablo 195) listelenir ve çoğu, neyin silineceğinden çok silme sonrası sayfanın nasıl görünmesi gerektiğini tanımlar

AnahtarŞemadaki rolüApplyRedactions ona ne yapar
QuadPointsKaldırılacak bölge, n adet dörtgen olarak; var olduğunda bölge olarak Rectin yerine geçerHer dörtgenin sınırlayıcı kutusunu ayrı ayrı siler; uzunluğu 8in katı olmayan bir dizi Recte döner
RectQuadPoints yokken kaldırılacak bölgeTers köşeler normalize edilerek kullanılır
ICSilme sonrası DeviceRGB dolgu; yokluğu şeffaf demektir; RO varken yok sayılırVar olduğunda korunur, yokken siyah olarak eklenir
ROForm XObject katmanı; IC, OverlayText, DA ile Qdan öncelik alırNormal görünüm olarak kurulur ve sayfaya düzleştirilir
OverlayText, RepeatBölgenin üzerine çizilen etiket, istenirse döşenirÜretilen katmana çizilir; Repeat doğru olduğunda döşenir
DA, QEtiketin fontu, boyu ve rengi; hizalamaBoy ile renk DAdan, hizalama Qdan okunur

AddRedactAnnotation ile işaret oluşturmak

TPDFlib.AddRedactAnnotation(Left, Top, Width, Height, FillR, FillG, FillB, OverlayText, RepeatOverlay), seçili sayfaya bir işaret ekler ve sayfanın yeni annotation sayısını döndürür; bu aynı zamanda işaretin 1 tabanlı indeksidir, hiçbir şey eklenmediğinde 0 döner. Koordinatlar geçerli kökeni ve birimleri izler; örnek bu yüzden sol üst kökene geçer ve orada Top üst kenardır. Çağrı /Rect ile, dolgu bileşenlerinden türlenmiş bir /ICi ve 10 puntolu beyaz metin için sabit bir /DA yazar: /F0 10 Tf 1 1 1 rg. Dolu bir OverlayText, ortalanmış bir etiket için /OverlayText, /Repeat ile /Q 1 ekler. Redact annotationları bir PDF 1.7 özelliğidir; daha eski bir başlık 1.7e yükseltilir. Henüz bir görünüm akışı yazılmaz; bekleyen işaret, gözden geçiren uygulamasının çizdiği gibi görünür. Etiket beyaza sabitlenmişken OverlayTexti koyu bir dolguyla eşleştirin; çünkü açık sarıda etiket kaybolur. İşaretler her PDFlibPas sürümünde oluşturulabilir

uses
  System.SysUtils, PDFlibrary;

procedure MarkForReview(const SourceFile, ReviewFile: string);
var
  Pdf: TPDFlib;
  Index: Integer;
begin
  Pdf := TPDFlib.Create;
  try
    if Pdf.LoadFromFile(SourceFile, '') <> 1 then
      raise Exception.CreateFmt('Cannot open %s', [SourceFile]);
    Pdf.SetOrigin(1);            // sol üst köken: Top üst kenardır
    Pdf.SetMeasurementUnits(0);  // punto
    if Pdf.SelectPage(1) <> 1 then
      raise Exception.Create('Page 1 not found');
    // Tanık adı: siyah dolgu, ortalanmış beyaz etiket
    Index := Pdf.AddRedactAnnotation(72, 180, 220, 14, 0, 0, 0, 'REDACTED');
    if Index = 0 then
      raise Exception.Create('Mark was not added');
    // Hesap bloğu: muafiyet kodunu daha yüksek bir kutuya döşe
    Pdf.AddRedactAnnotation(72, 410, 300, 40, 0, 0, 0, '(b)(6)', 1);
    // Yalnızca işaretler; özgün içeriğin her baytı hâlâ duruyor
    Pdf.SaveToFile(ReviewFile);
  finally
    Pdf.Free;
  end;
end;

QuadPoints kaldırma alanına karar verir; yanıtlar metnini korur

Bir işaret bir kez /QuadPoints taşıdığında, o dörtgenler ApplyRedactionsun ne kaldıracağına karar verir ve Rect onları yalnızca gösterim için sınırlar. Metin seçme araçlarıyla yapılan işaretler genellikle seçilen satır başına bir dörtgen taşır; böyle bir işareti SetAnnotRectle boyutlandırmak çerçevesini ekranda oynatır ve kaldırma alanını yerinde bırakır. Bölgeyi oynatan çağrı SetAnnotQuadPointstır ve GetAnnotQuadCount, yalnızca Recte dayanan bir işaret için 0 döndürür. İşarete bağlı metin başka bir kuralı izler. İnceleme araçları notu /Contentste, yazarı /Tde tutar ve bir karartma işaretinin üstündeki not, silinen şeyin kendisini tanımlama eğilimindedir ("müşteri TCKN, hukuki onayla"). ApplyRedactions işaretin kendi sözlüğünü boşaltır; ama /IRT üzerinden altına dizilen yanıtlar ayrı annotationlardır ve yalnızca dikdörtgenleri bir karartma bölgesiyle çakıştığında silinir; kenar boşluğuna park edilmiş bir yanıt metnini korur. Aşağıdaki liste, her işareti dörtgen sayısıyla ve altına dizilmiş yanıtlarıyla basar

Delphi için PDFlibPas karartma akışında QuadPoints ile Rect anatomisi: her dörtgen kendi kaldırma alanını sınırlarken kenar boşluğundaki bir yanıt metnini korur
quadpoints kaldırmayı bir satırda bir sınırlar; işareti taşımak SetAnnotQuadPoints demektir ve bölgelerin dışındaki bir kenar yanıtı metnini korur
procedure ListPendingMarks(Pdf: TPDFlib);
var
  P, I, Parent: Integer;
begin
  for P := 1 to Pdf.PageCount do
  begin
    if Pdf.SelectPage(P) <> 1 then
      Continue;
    for I := 1 to Pdf.AnnotationCount do
      if Pdf.GetAnnotType(I) = 'Redact' then
        Writeln(Format('p%d #%d by %s, quads=%d: %s',
          [P, I, Pdf.GetAnnotTitle(I), Pdf.GetAnnotQuadCount(I),
           Pdf.GetAnnotContentsEx(I)]))
      else
      begin
        Parent := Pdf.GetAnnotReplyTo(I);   // /IRT yokken 0
        if (Parent > 0) and (Pdf.GetAnnotType(Parent) = 'Redact') then
          Writeln(Format('  reply #%d to #%d: %s',
            [I, Parent, Pdf.GetAnnotContentsEx(I)]));
      end;
  end;
end;

ApplyRedactions sonrası hangi katman görünür?

/RO girdisi, var olduğunda her zaman kazanır; tablo 192nin öncelik kuralı bunu gerektirir. ApplyRedactions o Form XObjectı annotationın normal görünümü (/AP /N) olarak kurar, varsa görünüm durumunu düşürür ve düzleştirir; /IC, /OverlayText, /DA ile /Q o işarette etkisiz kalır. Yerleşim, incelikli olan tek kısımdır. Şema, katmanın kökeninin Rectin sol alt köşesiyle hizalanacağını söyler; düzleştirme ise Formun BBoxını Matrixiyle Recte eşler — yani düzleştirmenin form field widgetlarına uyguladığı BBox ve Matrix yerleşimi. BBoxu [0 0 w h] olan, dikdörtgene boyanmış ve birim Matrixli bir katman iki okumada da aynı görünür; kendi araçlarınız /RO işareti üretirken o biçimi isteyin

/ROsuzken ApplyRedactions sözlüğü normalleştirir ve görünümü kendisi kurar. /C ile /BSi siler ve /Borderi [0 0 0]e kurar: bu girdiler, genellikle renkli bir kontur olan bekleyen işareti tanımlar ve onu son sayfaya yakmak, bitmiş bir karartmayı bitmemiş gösterirdi. Kontur gittikten sonra dolgu bütün dikdörtgeni kaplar. Etiket, üretilen Formun içinde çizilir; boyu ve rengi /DAdan, hizası /Qdan, döşemesi /Repeatten gelir ve F0 font adı, o Formun kendi kaynaklarında standart Helveticaya bağlanır. O bağ, dosyalar araçlar arasında gezerken önemlidir: ISO 32000-1 §12.7.3.3, bir DA font adını etkileşimli formun varsayılan kaynaklarındaki (/DR) bir girdi olarak tanımlar; form fieldı olmayan bir belgede öyle bir kaynak yoktur ve aynı işareti uygulayan başka bir uygulama bir yedek fonta geçebilir. PDFlibPas o aramayı atlar ve Helvetica ile etiket, REDACTED gibi ya da bir muafiyet kodu gibi Latin yazılı metne yakışır

Delphi için PDFlibPasta ApplyRedactions sonrası katman karar akışı: var olan RO kazanır ve düzleşir, eksik IC siyaha düşer
bir RO form XObjectı normal görünüm olarak kurulur ve düzleştirilir; olmayan işaretler ise yeniden kurulan bir görünüm alır ve IC yokken siyah dolgu

Eksik /IC siyah bir kutuya döner

Şemanın yok bir /IC için varsayılanı şeffaf bir iç yüzdür ve PDFlibPas bundan bilerek sapar. Silme sonrasında şeffaf bir iç yüz kâğıdı gösterir; bir zamanlar bir adın durduğu beyaz bir boşluk. O boşluk, hiçbir zaman orada bir şey olmamış bir düzenden ayırt edilemez. Okuyucu karartılanı boştan ayıramaz ve gözden geçiren, çıkarılan metni karşılaştırmadan karartmanın yapıldığını doğrulayamaz. Yalnızca konturlu bir işaretin bekleyen görünümünü düzleştiren bir uygulama adımının üreteceği içi boş çerçeve ise başka türlü düşer: kimse üzerine işlem yapmamış bir teklif gibi okunur. Varsayılanı harfi harfine izlemeyi tarttık ve siyah kutuyu seçtik; çünkü bir şeyin saklandığının görünür işareti, karartılmış bir belgenin okuyucusuna söylediğinin parçasıdır ve seçim, yalnızca yazarı hiç dolgu bildirmemiş işaretleri etkiler. Sözlükte zaten var olan bir /IC, değeri ne olursa olsun kullanılır; beyaz isteyen bir üretici beyazı alır

Katman çizilmeden önce ne gitmiştir?

ApplyRedactions sayfa sayfa çalışır ve hiçbir katmanı düzleştirmeden önce bütün silmeyi tamamlar; dolayısıyla bir katman kendi bölgesine asla yakalanamaz. Her sayfa için dörtgen başına bir dikdörtgen, dörtgeni olmayan işaretler için Rect toplar ve her içerik katmanını bunların her birine karşı siler:

  • Metin glif glif kesilir; sayfa fontlarından ve tam metin durumundan ölçülür ve kısmen kapsanan bir dizgenin gerisi özgün konumunda kalır
  • Bölgenin içine boyayan vektör yolları, satır içi görüntüler ve renk geçişleri içerik akışından silinir
  • Form XObjectlarına özyinelemeli girilir; öbür sayfaların ya da yerleşimlerin de çizdiği bir Form, özel bir kopya üzerinden karartılır, böylece o sayfalar özgünü korur
  • Görüntü XObjectları yalnızca kapsanan pikselleri yitirir; siyahla (CMYK için tam K mürekkebi) üzerine yazılır. JPEG, JPEG 2000, JBIG2 ve CCITT görüntüleri çözülür ve kayıpsız Flate akışları olarak geri saklanır
  • Etiketli PDFte, silinen işaretli içeriğe bağlı /Alt ile /ActualText, sayfa içeriğinde ve yapı ağacında temizlenir
  • Dikdörtgeni bölgeye değen öbür annotationlar silinir ve widgetları orada duran form fieldları değerlerini yitirir

Piksel adımı, şemanın görüntü maddesinin uygulamadaki hâlidir. Taranan bir pasaportun üstüne boyanmış siyah bir dikdörtgen gözü doyurur ve yine de §12.5.6.23e takılır; çünkü özgün örnekler, birisi görüntüyü çıkarır çıkarmaz çözülür. Aynı motor, hiçbir annotation okumadan, doğrudan geçtiğiniz bir dikdörtgenin içeriğini temizleyen ve SanitizeDocument ile eşleşen RedactRegionin de arkasındadır. İçerik gittikten sonra her işaret düzleştirilir ve sözlüğü /Type ile /Subtypea dek temizlenir. Düzleştirme, annotationı sayfanın /Annots dizisinden çıkarır; ama sözlük hâlâ belgenin içinde bir nesnedir ve onu yazan bir kaydetme, /Contents, /RC, /T ile inceleme izinin gerisini alıcıya teslim eder

Karartılmamış revizyonla kaydetmemek

Artımlı bir kaydetme, yukarıdakilerin hepsini geri alır. §7.5.6 altında (ISO 32000-1 ile ISO 32000-2de aynı numara), artımlı bir güncelleme değişen nesneleri dosyanın sonuna ekler ve özgün baytları olduğu gibi bırakır; dolayısıyla özgün revizyon — sayfa içeriği, görüntüleri ve işaretlenmiş annotationlarıyla — dosyayı eski %%EOFten kesen herkes tarafından okunabilir kalır. PDFlibPas Small Business sürümündeki ExtractDocumentRevision bunu tek çağrıda yapar. ApplyRedactions sonrasında yeni bir dosyayı SaveToFile ile yazın; asla ekleyen SaveChanges ile değil. Kaydetmeden önce GarbageCollectObjects, nesne tablosunu tarar ve artık hiçbir şeyin başvurmadığı nesneleri düşürür; uygulama adımından önce işaretlerin taşıdığı görünüm akışları gibi. Tam bir kaydetme, SetGarbageCollect açmadıkça ya da SaveToFileOptionsa geçtiğiniz TPDFlibSaveOptions kaydının GarbageCollect alanını kurmadıkça o taramayı atlar. Meta veri kalan boşluktur. SanitizeDocument(SANITIZE_METADATA or SANITIZE_XMP_PACKET), Author, Subject, Keywords, Creator ile Produceri boşaltır ve XMP akışını kaldırır; Titleı denetlemeniz için bırakır. Burada SANITIZE_ALLden kaçının: SANITIZE_ANNOTATIONSi içerir ve belgede kalan her annotationı siler; aralarında saklamak istediğiniz notlar da vardır

Delphi için PDFlibPasta ApplyRedactions sonrası kaydetme zaman çizgisi: artımlı bir ekleme özgünü kurtarılabilir bırakır; o yüzden sürüm adımı sanitize, çöp toplama ve tam yeniden yazım koşturur
uygulamadan sonra sürüm yolu, meta verileri temizlemek, başvurulmayan nesneleri süpürmek ve yeni bir dosya kaydetmektir; çünkü artımlı kaydetme, karartılmamış revizyonu okunabilir tutar

ApplyRedactions, RedactRegion gibi Enterprise sürümünde bulunur. Sıradan bir TPDFlib üzerinde 0 döndürür ve LastErrorCodeu PDFLIB_ERROR_ENTERPRISE_REQUIRED (900)e kurar; dolayısıyla sürüm adımı, PDFlibEnterprise biriminden TPDFlibEnterprise kullanır

uses
  System.SysUtils, PDFlibrary, PDFlibEnterprise;

procedure ApplyAndRelease(const ReviewFile, ReleaseFile: string);
var
  Pdf: TPDFlibEnterprise;
  Applied, Orphans: Integer;
begin
  Pdf := TPDFlibEnterprise.Create;
  try
    if Pdf.LoadFromFile(ReviewFile, '') <> 1 then
      raise Exception.CreateFmt('Cannot open %s', [ReviewFile]);
    Applied := Pdf.ApplyRedactions;   // her sayfadaki her Redact işareti
    if Applied = 0 then
      raise Exception.CreateFmt('No marks applied (error %d)',
        [Pdf.LastErrorCode]);
    // Info ve XMP, sayfaların artık göstermediğini hâlâ yazabilir
    Pdf.SanitizeDocument(SANITIZE_METADATA or SANITIZE_XMP_PACKET);
    Orphans := Pdf.GarbageCollectObjects;
    // Yeni dosyaya tam yeniden yazım; karartmadan sonra asla SaveChanges
    if Pdf.SaveToFile(ReleaseFile) <> 1 then
      raise Exception.Create('Save failed');
    Writeln(Format('%d marks applied, %d unreferenced objects dropped',
      [Applied, Orphans]));
  finally
    Pdf.Free;
  end;
end;

Beklenen: ApplyRedactions, bütün sayfalara düzleştirdiği Redact işaretlerinin sayısını döndürür — MarkForReviewin yazdığı inceleme kopyası için 2 — ve GarbageCollectObjects, taramanın düşürdüğü başvurulmayan nesne sayısını döndürür

Hangi araç bir işareti çizmiş olursa olsun, onun /RO ile /ICsi alıcının sayfada ne göreceğine karar verir; PDFlibPas Enterprise for Delphideki uygulama adımı ise altında neyin gittiğine karar verir