İşaretli içerik, ISO 32000-1 §14.6'nın sayfa içeriğini etiketlemek için tanımladığı mekanizmadır ve etiketli PDF ile PDF/UA'nın ikisi de onun üzerine inşa edilmiştir. PDFium Component onu doğrudan ortaya koyar: PageObjectMarks bir sayfa nesnesinden her BDC etiketini ve özellik listesini okur, AddPageObjectMark bir tane yazar, RemovePageObjectMark bir tane siler ve PageObjectMarkedContentID içeriği yapı ağacına bağlayan MCID'yi raporlar
Yapı ağacı tanımladığı içeriğe geri bağlanana dek, erişilebilirlik araçları tahminden ibarettir. Yapı ağacı "bu bir başlıktır" der; MCID o başlığın gerçekte hangi sayfada hangi işaretler olduğunu söyler. Bir uygulama etiketlemeyi denetleyebilmesi, onarabilmesi veya raporlayabilmesi için iki yarının da okunabilir olması gerekir
Bir işaret, bayt olarak nedir?
Bir etiket adı ve isteğe bağlı bir özellik listesi taşıyan, EMC ile kapanan bir BDC işlecidir. İçerik akışında /P <</MCID 3>> BDC ... EMC olarak görünür: /P etiketi rolü adlandırır, sözlük özellikleri taşır ve işleçler arasındaki her şey işaretli içeriktir. O yayılma içindeki bir sayfa nesnesi işareti taşır; bu da PDFium'in geri verdiği ve PDFium Component'in bir kayda çevirdiği şeydir
TPdfContentMark bir tanıtıcı, Name etiketi ve bir TPdfContentMarkParam dizisi taşır. Her parametre bir Key, bir Kind ve o tür tarafından seçilen bir anlamlı değer alanı içerir: pmpInt, pmpFloat, pmpString veya pmpBlob. Tür, hangi alıcının başarılı olduğundan değil PDFium'in kendi tür raporundan gelir; bu da bir özellik listesini okumak ile onu tahmin etmek arasındaki farktır
var
Marks: TPdfContentMarks;
M: TPdfContentMark;
P: TPdfContentMarkParam;
I: Integer;
begin
Pdf.PageNumber := 1; // PageNumber is 1-based
for I := 0 to Pdf.ObjectCount - 1 do // page object indexes are 0-based
begin
Marks := Pdf.PageObjectMarks(I);
for M in Marks do
begin
Memo1.Lines.Add('mark ' + M.Name +
' (MCID ' + IntToStr(Pdf.PageObjectMarkedContentID(I)) + ')');
for P in M.Params do
case P.Kind of
pmpInt: Memo1.Lines.Add(' ' + P.Key + ' = ' + IntToStr(P.IntValue));
pmpString: Memo1.Lines.Add(' ' + P.Key + ' = ' + P.StringValue);
pmpFloat: Memo1.Lines.Add(' ' + P.Key + ' = ' + FloatToStr(P.FloatValue));
pmpBlob: Memo1.Lines.Add(' ' + P.Key + ' = ' +
IntToStr(Length(P.BlobValue)) + ' bytes');
end;
end;
end;
end;
pmpUnknown neden iki farklı şey ifade eder?
pmpUnknown, PDFium FPDF_OBJECT_UNKNOWN raporladığında döndürülür ve PDFium ayrıca var olmayan bir anahtar için de onu döndürür. İki durum bu katmanda birbirinden ayırt edilemez ve başka türlü davranmak olduğunu söylemekten daha kötüdür
Kodunuz için pratik sonuç: pmpUnknown'u yine de çözebileceğiniz bir tür olarak değil "burada kullanılabilir bir değer yok" olarak ele alın. Bir özellik iş akışınız için önemliyse, tanıdığınız bir türle mevcut olduğunu doğrulayın ve bilinmeyenden yokluğu çıkarsamayın; özellik listesini okuyamadığınız bir işaret, sessizce kabul etmeniz değil raporlamanız gereken bir işarettir
Bir işaret kaydı, sahip olduğunuz bir tanıtıcı değil bir anlık görüntüdür
Handle alanı kitaplığa aittir. İşaret kaldırıldığında, sayfa nesnesi yok edildiğinde veya sayfa kaldırıldığında bayatlaşır, dolayısıyla kayıt kısa ömürlü, salt okunur bir anlık görüntüdür. Onu bir sayfa geçişi boyunca önbelleğe alın ve motorun geri reclaim ettiği belleğe bir işaretçi tutmuş olursunuz
Bu, sayfa nesnesi tanıtıcıları için PDFium'da genel olarak geçerli olan aynı disiplindir ve insanları aynı yerde yakalar: işaret kayıtlarıyla doldurulmuş bir liste denetimi, kullanıcı başka bir sayfaya gider ve bir gezinmeden bağımsız görünen bir çökme. İhtiyaç duyduğunuz değerleri (adı, anahtarları, sayıları) dışarı kopyalayın ve tanıtıcıyı bırakın. dönüşümden sonra bayatlaşan sayfa nesnesi tanıtıcıları notları genel kuralı ve başka nerelerde ısırdığını ele alır
İşaret ekleme ve kolayca kaçırılan kaydetme adımı
AddPageObjectMark, sayfa nesnesi indeksini, bir etiket adını ve tam bir parametre kümesini alır. Parametreler tek tek yamalanan yerine bir küme olarak yazılır; bu da TPdfContentMarkParam'in neden Has* gözcülerine sahip olmadığıdır; onların koruyacağı "var olan bir kaydın tek bir alanını güncelle" durumu ortaya çıkmaz
Açıkça söylemeye değer kısım: bir işaret eklemek, etiketin bir kaydetmeyi atlatması için sayfa içerik akışını yeniden inşa eder. Bu açık olmak zorundaydı çünkü SaveAs içeriği kendi başına yeniden üretmez; yalnızca nesne modelinde yaşayan bir değişiklik atılır ve kaydedilen dosya başladığınızın tıpkısı görünürdü. PDFium sayfasına bir şey ekleyip çıktıda eksik bulduysanız, genellikle neden budur
var
Params: TPdfContentMarkParams;
begin
SetLength(Params, 1);
Params[0].Key := 'MCID';
Params[0].Kind := pmpInt;
Params[0].IntValue := NextMcid;
Pdf.AddPageObjectMark(ObjectIndex, 'P', Params); // rebuilds the content stream
Pdf.UpdatePage;
Pdf.SaveAs('tagged-out.pdf');
end;
Bu bir belgeyi ne yapar ve ne yapmaz?
İşaretler yalnızca etiketli bir PDF yapmaz. Uyumlu bir etiketli belge, öğeleri bu MCID'lere başvuran bir yapı ağacı, belgenin işaretli olduğunu bildiren bir /MarkInfo girdisi ve standardın dediğini ifade eden rol adları ister. Hiçbir yapı öğesinin işaret etmediği bir MCID'ye sahip bir /P işareti yazmak, etiketli olduğunu iddia eden içerik ve onu hiç anmayan bir yapı ağacı verir
İşaretli içeriğin bu düzeyde gerçekten karşılığını verdiği yer inceleme ve onarımdır: hangi sayfa nesnelerinin etiketli olduğunu denetleme, yapı öğesi olarak işaretlenmiş olması gerekenleri bulma veya yapı ağacına karşı MCID'leri eşleştirip yetimleri bulma. O işin yapı ağacı yarısı için PDF/UA yapı ağacı doğrulaması yazısına ve etiketlerin nihai olarak olduğu okuma deneyimi için Delphi'de erişilebilir PDF okuyucu inşa etme notlarına bakın
PDFium Component, Delphi, C++Builder ve Lazarus uygulamalarına PDFium motoru üzerinden üst düzey bir VCL API'si sunar; işaretli içerik, yapı ağaçları ve erişilebilirlik doğrulaması sıradan Pascal kodundan ulaşılabilirdir; tam API yüzeyi için PDFium Component ürün sayfasına bakın