Artikel Teknis

Penandaan Struktur Otomatis untuk PDF Aksesibel di Delphi

PDFlibPas dapat menandai sebuah dokumen sementara dokumen itu sedang digambar. Aktifkan SetAutoTagMode dan panggilan DrawText biasa menjadi paragraf, teks yang digambar tepat setelah RegisterHeading menjadi heading pada level tersebut, running header dan footer menjadi artefak yang dilewati pembaca, gambar menjadi figure, dan DrawTableRows membawa tabel, baris dan selnya ke dalam pohon struktur

Alternatifnya — dan sampai baru-baru ini satu-satunya pilihan — adalah membungkus setiap panggilan gambar dengan BeginTag dan EndTag secara manual. Itu berhasil, dan untuk dokumen dengan struktur tidak biasa alat itu tetap tepat. Untuk laporan, faktur atau rekening pada umumnya, berarti aksesibilitas output bergantung pada tidak ada seorang pun yang pernah lupa sepasang panggilan, di setiap jalur kode yang menggambar sesuatu

Apa saja yang dicakup bit mode

SetAutoTagMode menerima bit mask dan mengembalikan mode yang sebelumnya aktif. AUTOTAG_TEXT (1) menandai teks sebagai paragraf, atau sebagai heading ketika sudah saatnya. AUTOTAG_FURNITURE (2) menandai running header, footer dan nomor halaman sebagai artefak. AUTOTAG_FIGURE (4) mengubah gambar yang digambar menjadi figure, atau menjadi artefak ketika dideklarasikan dekoratif. AUTOTAG_TABLE (8) membawa tabel yang digambar ke dalam pohon struktur. AUTOTAG_DEFAULT adalah 15, yaitu keempatnya

Mengaktifkan mode itu juga menandai dokumen sebagai tagged, dan langkah itu tidak sekadar kosmetik seperti yang terdengar. Sebuah pembaca menganggap dokumen tidak ditandai kecuali katalog menyatakan sebaliknya (ISO 32000-1 §14.7.1), jadi file yang membawa pohon struktur lengkap tanpa deklarasi /MarkInfo diumumkan oleh teknologi asistif sebagai tidak memiliki struktur sama sekali. Pohonnya ada; tidak ada yang membacanya

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;

Bagaimana sebuah heading tahu teks mana miliknya?

RegisterHeading menetapkan level untuk teks berikutnya yang digambar, dan ia menunggu teks. Jika sebuah gambar digambar di antaranya, gambar itu menjadi figure dan heading tetap tertunda untuk teks yang menyusul. Perilaku itu disengaja: alternatifnya, di mana gambar mengambil level heading, menghasilkan dokumen di mana garis dekoratif di bawah sebuah judul diumumkan sebagai judul itu sendiri

Aturan "dihabiskan untuk satu item" yang sama mengatur figure. RegisterFigure menyediakan deskripsi yang dibawa gambar berikutnya, dan RegisterDecoration mendeklarasikan gambar berikutnya sebagai garis, border atau latar yang tidak membawa makna. Keduanya dikonsumsi oleh satu gambar, jadi gambar yang muncul kemudian tidak pernah mewarisi deskripsi yang dimaksudkan untuk gambar sebelumnya — yang merupakan cara alt text akhirnya menempel pada gambar yang salah dalam kode yang ditandai manual

Deskripsi lebih penting daripada string tunggal lainnya dalam dokumen aksesibel. Pembaca yang tidak dapat melihat mendapatkan deskripsi itu sebagai pengganti gambar, dan itu adalah seluruh yang mereka dapatkan. "Chart" bukan deskripsi; "Pendapatan kuartalan per wilayah, dengan wilayah timur tertinggi di Q3" adalah

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

Tabel, header dan di mana keputusan pengulangan berada

Dengan bit tabel aktif, DrawTableRows membawa tabel, baris dan selnya ke dalam pohon struktur, sehingga pembaca dapat mengatakan di kolom mana sebuah nilai berada alih-alih membaca seluruh tabel sebagai deretan teks tidak terkait. SetTableHeaderRowCount menetapkan berapa banyak baris terdepan adalah header; baris itu ditulis sebagai sel header yang membawa cakupan kolom, yang memungkinkan pembacer mengumumkan heading dari nilai yang sedang dituju pengguna

Baris header yang dinamai dengan cara ini tetap di tempatnya. Mengulanginya di bagian atas setiap halaman adalah keputusan layout, dan itu tetap demikian: DrawTaggedTableRows mengambil argumen RepeatHeaderRows untuk persis tujuan itu. Memisahkan keduanya menghindari pohon struktur mendapatkan salinan header kedua untuk setiap page break, yang akan dihasilkan oleh pengulangan otomatis

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;

Mencampur penandaan otomatis dan manual

Penandaan otomatis menyingkir di dalam tag yang dibuka secara manual. Sebagian dokumen dapat dijelaskan oleh kode Anda dan sisanya diserahkan ke library, tanpa keduanya saling bersarang — yang merupakan susunan yang diinginkan sebagian besar dokumen nyata. Halaman sampul dan blok tanda tangan memiliki struktur yang hanya Anda pahami; dua ratus halaman teks isi di antaranya tidak

Dua aturan pengaman menjaga output tetap bersih. Tidak ada yang ditandai di dalam artefak, karena konten yang ditandai sebagai artefak tidak boleh membawa elemen struktur. Dan teks kosong tidak membuka elemen apa pun, jadi DrawText yang tersesat dengan string kosong tidak dapat menghasilkan elemen struktur yang akan diumumkan pembaca sebagai kosong. Keduanya adalah jenis cacat yang diakumulasikan dokumen yang ditandai manual secara diam-diam dan yang dilaporkan validator secara massal berbulan-bulan kemudian

Apa yang masih tidak diputuskan untuk Anda oleh penandaan otomatis

Urutan baca di luar urutan gambar, peran semantik yang bukan paragraf, heading, figure atau tabel, dan deklarasi bahasa. Penandaan otomatis menetapkan struktur dalam urutan konten digambar — jika kode layout Anda menggambar sidebar sebelum badan, itulah urutan yang direkam pohon. Untuk dokumen di mana urutan visual dan urutan baca benar-benar berbeda, API penandaan manual tetap menjadi alat yang tepat, dan panduan tagged PDF dan struktur aksesibilitas membahas peran, cakupan dan ikatan header secara rinci

Saat dokumen selesai, validasi alih-alih berasumsi: catatan tentang preflight PDF/A dan PDF/UA menunjukkan cara mendapatkan vonis pada struktur yang Anda hasilkan, dan panduan ekspor laporan berbasis dataset membahas di mana panggilan ini cocok dalam mesin laporan yang menghasilkan layout dari data

PDFlibPas adalah library PDF Pascal native untuk Delphi, C++Builder dan Lazarus tanpa runtime PDF eksternal, jadi output aksesibel dihasilkan oleh kode yang sama yang menggambar dokumen — lihat halaman produk PDFlibPas untuk daftar API dan platform lengkap