Teknik Makale

Delphi'de Erişilebilir PDF için Otomatik Yapı Etiketleme

PDFlibPas bir belgeyi çizilirken etiketleyebilir. SetAutoTagMode'u açın ve sıradan DrawText çağrıları paragrafa dönüşür, RegisterHeading'den hemen sonra çizilen metin o düzeyde bir başlık olur, sabit üst ve alt başlıklar ile sayfa numaraları okuyucunun atladığı yapı öğelerine dönüşür, görseller şekil olur ve DrawTableRows tabloyu, satırlarını ve hücrelerini yapı ağacına taşır

Alternatifi ve eskiden tek seçenek olan yöntem her çizim çağrısını elle BeginTag ve EndTag içine sarmaktı. Bu çalışır ve olağandışı yapısı olan belgeler için hâlâ doğru araçtır. Sıradan bir rapor, fatura veya ekstre için ise çıktının erişilebilirliği, hiç kimsenin herhangi bir şey çizen her kod yolunda bir çifti unutmamasına bağlı olur

Mod bitleri neyi kapsar?

SetAutoTagMode bir bit maskesi alır ve önceden yürürlükte olan modu döndürür. AUTOTAG_TEXT (1) metni paragraf olarak, veya sırası geldiğinde başlık olarak etiketler. AUTOTAG_FURNITURE (2) sabit üst ve alt başlıklar ile sayfa numaralarını yapı öğesi olarak işaretler. AUTOTAG_FIGURE (4) çizilen bir görseli şekle, veya dekoratif olarak bildirilmişse yapı öğesine dönüştürür. AUTOTAG_TABLE (8) çizilen tabloları yapı ağacına taşır. AUTOTAG_DEFAULT 15'tir, yani dördünün hepsi

Modun açılması aynı zamanda belgeyi etiketli olarak işaretler ve bu adım kulağa geldiğinden daha az kozmetiktir. Bir okuyucu, katalog aksini söylemedikçe bir belgeyi etiketsiz sayar (ISO 32000-1 §14.7.1), dolayısıyla /MarkInfo bildirimi olmadan tam bir yapı ağacı taşıyan bir dosya, yardımcı teknoloji tarafından hiç yapısı yokmuş gibi duyurulur. Ağaç oradadır; hiçbir şey onu okumaz

var
  Lib: TPDFlib;
begin
  Lib := TPDFlib.Create;
  try
    Lib.SetOrigin(1);
    Lib.SetAutoTagMode(AUTOTAG_DEFAULT);   // text + furniture + figures + tables
    Lib.AddStandardFont(4);
    Lib.SetTextSize(18);
    Lib.RegisterHeading(1, 'Annual service report');
    Lib.DrawText(72, 96, 'Annual service report');   // becomes H1
    Lib.SetTextSize(11);
    Lib.DrawText(72, 130, 'Every unit installed before 2024 was inspected.');
    Lib.SaveToFile('report.pdf');
  finally
    Lib.Free;
  end;
end;

Bir başlık, hangi metne ait olduğunu nasıl bilir?

RegisterHeading çizilecek sonraki metin için düzeyi adlandırır ve metni bekler. Araya bir görsel çizilirse görsel şekil olur ve başlık kendisinden sonra gelecek metin için beklemeye devam eder. Bu davranış kasıtlıdır: alternatif olan, görselin başlık düzeyini alması, dekoratif bir çizginin başlığın altında çizildiği belgelerde o çizginin başlık olarak duyurulduğu çıktılar üretti

Aynı "tek öğede tüketilir" kuralı şekiller için de geçerlidir. RegisterFigure sonraki görselin taşıyacağı açıklamayı sağlar ve RegisterDecoration sonraki görseli hiçbir anlam taşımayan bir çizgi, kenarlık veya arka plan olarak bildirir. İkisi de tek bir görsel tarafından tüketilir, dolayısıyla daha sonraki bir görsel asla daha önceki bir görsel için verilmiş bir açıklamayı miras almaz; elle etiketlenen koddaki alternatif metnin yanlış resme nasıl yapıştığı tam olarak budur

Açıklama, erişilebilir bir belgede başka herhangi bir tek dizeden daha fazla önem taşır. Görme engelli bir okuyucu resmin yerine açıklamayı alır ve aldığı şeyin tamamı budur. "Grafik" bir açıklama değildir; "Bölgeye göre üç aylık gelir, üçüncü çeyrekte doğu bölgesi en yüksek" açıklamadır

Lib.RegisterFigure('Exploded view of the gearbox assembly');
Lib.AddImageFromFile('gearbox.png', 0);      // becomes a tagged Figure

Lib.RegisterDecoration;                       // meaningless rule
Lib.AddImageFromFile('divider.png', 0);       // drawn inside a layout artifact

Tablolar, başlıklar ve yineleme kararının nerede olduğu

Tablo biti açıkken DrawTableRows tabloyu, satırlarını ve hücrelerini yapı ağacına taşır, böylece okuyucu bir değerin hangi sütunda durduğunu söyleyebilir, tüm tabloyu alakasız metinler dizisi olarak okumak yerine. SetTableHeaderRowCount kaç baştaki satırın başlık olduğunu adlandırır; bu satırlar sütun kapsamı taşıyan başlık hücreleri olarak yazılır ve bu, okuyucunun kullanıcının üzerinde bulunduğu değerin başlığını duyurabilmesini sağlar

Bu şekilde adlandırılan başlık satırları oldukları yerde kalır. Bunları her sayfanın üstünde yinelemek bir yerleşim kararidir ve öyle kalır: DrawTaggedTableRows tam olarak bu amaçla bir RepeatHeaderRows argümanı alır. İkisini ayrı tutmak, yapı ağacının her sayfa sonu için başlığın ikinci bir kopyasını edinmesini önler; otomatik bir yineleme tam olarak bunu üretirdi

var
  TableID: Integer;
begin
  TableID := Lib.CreateTable(40, 3);
  Lib.SetTableHeaderRowCount(TableID, 1);       // row 1 is the header band
  Lib.SetTableCellContent(TableID, 1, 1, 'Part');
  Lib.SetTableCellContent(TableID, 1, 2, 'Torque');
  Lib.SetTableCellContent(TableID, 1, 3, 'Unit');
  // ... fill the data rows ...
  // Draw rows 1..40 into a 600pt band, repeating one header row per page
  Lib.DrawTaggedTableRows(TableID, 72, 150, 600, 1, 40, 1);
end;

Otomatik ve elle etiketlemenin karıştırılması

Otomatik etiketleme, elle açılmış bir etiketin içinde kenara çekilir. Bir belgenin bir bölümü kodunuz tarafından tanımlanabilir ve geri kalanı kitaplığa bırakılabilir, ikisi birbirinin içine yerleşmeden; çoğu gerçek belgenin istediği düzen budur. Kapak sayfası ve imza bloğu yalnızca sizin anladığınız bir yapıya sahiptir; aralarındaki iki yüz sayfalık gövde metninin yok

İki güvenlik kuralı çıktıyı temiz tutar. Bir yapı öğesi içinde hiçbir şey etiketlenmez, çünkü yapı öğesi olarak işaretlenen içerik hiçbir yapı öğesi taşımamalıdır. Ve boş metin hiçbir öğe açmaz, dolayısıyla boş bir dizeyle yapılan bir başıboş DrawText okuyucunun boş olarak duyuracağı bir yapı öğesi üretemez. İkisi de elle etiketlenen belgelerin sessizce biriktirdiği ve bir doğrulayıcının aylar sonra toplu olarak raporladığı türden kusurlardır

Otomatik etiketlemenin hâlâ sizin için karar vermediği şeyler

Çizim sırasının ötesinde okuma düzeni; paragraf, başlık, şekil veya tablo olmayan anlamsal roller; ve dil bildirimleri. Otomatik etiketleme, içerik çizildikçe yapı öğesini o sırada atar; yerleşim kodunuz gövdeden önce kenar çubuğunu çiziyorsa, ağacın kaydettiği sıra odur. Görsel sıra ile okuma sırasının gerçekten ayrıştığı belgeler için elle etiketleme API'si doğru araç olarak kalır ve etiketli PDF ve erişilebilirlik yapısı üzeri yazı rolleri, kapsamları ve başlık bağlarını ayrıntılı olarak ele alır

Belge tamamlandığında varsaymak yerine doğrulayın: PDF/A ve PDF/UA preflight notları ürettiğiniz yapı öğesi üzerinde bir karar almayı gösterir ve veri kümesi tabanlı rapor dışa aktarımı yazısı bu çağrıların yerleşimini veriden üreten bir rapor motorunda nereye oturduğunu ele alır

PDFlibPas, Delphi, C++Builder ve Lazarus için harici bir PDF çalışma zamanı olmaksızın yerel bir Pascal PDF kitaplığıdır, dolayısıyla erişilebilir çıktıyı belgeyi çizen kod üretir; tam API ve platform listesi için PDFlibPas ürün sayfasına bakın