Artikel Teknis

Preflight PDF/A dan PDF/UA di Delphi dengan PDF Library for Delphi

PDF/A dan PDF/UA menjawab dua pertanyaan yang sama sekali tidak berkaitan, dan memperlakukan keduanya sebagai satu kotak centang aksesibilitas-dan-pengarsipan adalah cara berkas rusak masuk ke arsip sambil mengenakan label kepatuhan. PDF/A bertanya apakah sebuah berkas masih akan dirender dengan setia dua puluh tahun lagi. PDF/UA bertanya apakah teknologi bantu dapat membacanya hari ini. Sebuah dokumen bisa lolos yang satu tanpa cela dan gagal di yang lain, jadi vonis yang jujur hanya datang dari menjalankan keduanya, dan dari menjalankannya sebelum berkas ditulis keluar, bukan setelah sistem hilir memercayai pengidentifikasi konformansi yang tertanam di metadatanya. Pengidentifikasi itu adalah deklarasi diri. Tidak ada apa pun dalam formatnya yang mengharuskan ia benar, dan aplikasi yang menulis "PDF/A-1b" ke dalam XMP tanpa memvalidasi terhadap standarnya menghasilkan berkas yang tampak patuh bagi setiap konsumen yang hanya membaca labelnya. losLab PDF Library (PDF Library for Delphi) menutup celah itu untuk Delphi dan C++Builder dengan membangun kedua validator ke dalam pustaka, sehingga pemeriksaannya berjalan di dalam proses tanpa layanan eksternal yang perlu didirikan

Dua standar yang menggagalkan berkas karena alasan berlawanan

ISO 19005 (PDF/A) adalah kontrak reproduksi. Berkas yang konforman harus dirender identik puluhan tahun dari sekarang di perangkat lunak yang tidak pernah melihat sistem yang memproduksinya, jadi aturannya menyerang ketergantungan eksternal: setiap font tertanam, warna berjangkar pada OutputIntent ICC yang tertanam atau dinyatakan dalam ruang yang tidak bergantung perangkat, tanpa enkripsi pada PDF/A-1, tanpa JavaScript, metadata XMP yang selaras dengan kamus informasi dokumen. ISO 14289 (PDF/UA) justru merupakan kontrak semantik. Teknologi bantu harus dapat menyusuri dokumen dan pulang membawa makna, dan makna itu tinggal di lapisan yang sama sekali berbeda: pohon struktur yang lengkap, teks alternatif pada gambar, judul dokumen yang ditetapkan untuk ditampilkan, tingkat heading yang tidak melompat, hubungan header tabel yang tetap bertahan begitu halamannya lepas dari layar

Karena kedua standar mengawasi lapisan yang berbeda, berkas yang menggigit Anda adalah yang duduk di antara keduanya. Dokumen yang sempurna untuk arsip bisa bisu di hadapan pembaca layar. Dokumen yang ditandai dengan indah bisa merujuk font desktop yang tidak akan ada sepuluh tahun lagi. Penerbitan sektor publik adalah tempat lazim kedua persyaratan itu mendarat sekaligus, dan pipeline di sana tidak boleh meruntuhkannya menjadi satu gerbang. Temuannya pergi ke orang yang berbeda. Font yang tidak tertanam adalah cacat pada kode yang menghasilkan PDF, sedangkan teks alternatif yang hilang adalah urusan pemilik templat konten, dan laporan yang mencampur keduanya cuma akan diteruskan dua kali

Bagian PDF/A mana yang Anda bidik sama pentingnya dengan apakah Anda mengenainya. PDF/A-1 dibekukan pada PDF 1.4 dan menolak transparansi serta JPEG2000, dua hal yang dijangkau keluaran pelaporan modern tanpa berpikir. PDF/A-2 (ISO 19005-2, dibangun di atas ISO 32000-1) menerima keduanya dan merupakan default yang waras untuk arsip baru. PDF/A-3 melangkah lebih jauh dan mengizinkan berkas tertanam bertipe apa pun, dan itulah yang diandalkan format e-invoicing teregulasi. Tim yang pada 2026 masih membakukan PDF/A-1b biasanya sedang memanggul persyaratan yang ditulis seseorang lima belas tahun lalu, dan merundingkan ulang bagian yang dibidik sering lebih murah daripada mengupas transparansi dari setiap bagan yang dipancarkan sistem

Diagram PDF Library for Delphi yang membandingkan kontrak reproduksi PDF/A dengan kontrak semantik PDF/UA ditambah matriks lolos-gagal dokumen yang memenuhi satu dan gagal yang lain
PDF/A mengamankan rendering setia puluhan tahun ke depan sementara PDF/UA mengamankan pembacaan asistif hari ini, dan tidak ada vonak yang mengimplikasikan yang lain

Temuan terstruktur pada saat penerimaan

Titik masuk di API datar adalah CheckFileCompliance, dengan pemilih uji 1 untuk PDF/A dan 2 untuk PDF/UA. Ia menyerahkan handle string-list yang itemnya adalah temuan individual, satu per baris, dan itu persis bentuk yang ingin disusuri sebuah gerbang otomatis:

function GateArchiveUpload(Pdf: TPDFlib; const FileName: string): Boolean;
var
  ListId, I: Integer;
begin
  ListId := Pdf.CheckFileCompliance(FileName, '', 1, 0);  // 1 = PDF/A
  if ListId = 0 then
  begin
    // 0 berarti "tidak ada temuan" ATAU "berkas tak terbaca" -- pilah dulu sebelum meluluskan
    Result := Pdf.LastErrorCode = 0;
    Exit;
  end;
  for I := 0 to Pdf.GetStringListCount(ListId) - 1 do
    LogFinding(FileName, Pdf.GetStringListItem(ListId, I));
  Pdf.ReleaseStringList(ListId);
  Result := False;
end;

Dua detail menentukan apakah ini bisa berjalan tanpa penunggu. Yang pertama adalah nilai kembalian yang berarti dua hal berlawanan. CheckFileCompliance mengembalikan 0 ketika berkasnya sepenuhnya patuh dan juga ketika berkasnya sama sekali tidak dapat dibuka, karena secara internal daftar hasil yang kosong runtuh menjadi 0 pada kedua kasus. Gerbang yang membaca 0 sebagai lulus akan melambaikan unggahan rusak masuk ke arsip, jadi pilah dengan LastErrorCode sebelum Anda memercayai nol itu, seperti yang dilakukan gerbang di atas. Yang kedua menyangkut posisi berkas dalam siklus hidupnya. Pemeriksanya berjalan di atas pembaca streaming milik pustaka alih-alih model dokumen penuh, membuka berkas langsung dengan berbagi baca dan tidak pernah memanggil LoadFromFile, dan itulah sebabnya ia sanggup mengunyah masukan multi-gigabyte tanpa membangun pohon objek. Pembukaan streaming yang sama gagal selama proses lain masih memegang berkas itu untuk ditulisi, dan unggahan yang sedang berjalan persis berada dalam keadaan tersebut. Gerbangkan setelah transfernya selesai

Rancangan streaming itu berbuah lagi saat beban tinggi. Setiap pemeriksaan membuka masukannya read-only dan membagikannya untuk dibaca, sehingga audit korpus dapat diskalakan melebar ke banyak thread atau proses pekerja dengan satu instance TPDFlib per pekerja dan tanpa perebutan di antara mereka. Sumber daya yang menuntut disiplin adalah handle-nya sendiri. Setiap hasil bukan-nol dari CheckFileCompliance tetap teralokasi sampai Anda memanggil ReleaseStringList, dan gerbang yang berjalan lama lalu lupa melepaskannya tidak akan crash, ia hanya merembeskan memori perlahan sampai ada yang mencari tahu sebabnya

Laporan untuk manusia, diff untuk gerbang build

Daftar temuan adalah bentuk yang tepat untuk sebuah gerbang dan bentuk yang keliru untuk surel ke tim templat. CreatePreflightReport merender analisis yang sama sebagai prosa yang enak dibaca, CreatePreflightReportEx menambahkan pemilih format laporan, dan SavePreflightReport menulisnya ke disk sehingga laporan itu dapat ikut berjalan di dalam paket dokumen yang dikirimkan. Banyak kontrak pengarsipan menjadikan laporan itu sebagai kiriman tersendiri, bukan sekadar artefak internal

Anggota keluarga ini yang diam-diam paling berjasa adalah ComparePreflightReports. Kepatuhan adalah permukaan regresi seperti perilaku lain mana pun. Sebuah penyesuaian templat, font korporat yang baru dilisensikan, atau peningkatan pustaka masing-masing bisa memunculkan temuan yang tidak ada di rilis lalu, dan tak satu pun mengumumkan dirinya. Simpan laporan emas untuk sekumpulan dokumen representatif di bawah kendali versi, bangkitkan ulang setelah setiap perubahan, dan jalankan ComparePreflightReports untuk menghitung deltanya. Diff yang kosong adalah artefak rilis yang layak disimpan. Temuan tak terduga menggagalkan build, dan itu tempat yang jauh lebih murah untuk menemukannya ketimbang saat audit

Menghasilkan keluaran yang lolos pada percobaan pertama

Preflight membuktikan nilainya pada berkas yang datang dari tempat lain. Untuk dokumen yang diproduksi kode Anda sendiri, menemukan pelanggaran setelah pembangkitan lalu menambalnya kembali adalah jalan memutar yang lambat. PDF Library for Delphi membawa mode sisi pembangkitan untuk masing-masing standar, dan Anda bisa menyalakan keduanya untuk dokumen yang sama:

Diagram PDF Library for Delphi tentang penyerapan preflight berskala dengan satu instance pustaka streaming per pekerja, pembukaan bergerbang setelah unggahan selesai, dan daftar temuan yang dilepas
Gerbang hanya terbuka setelah transfer selesai, setiap worker mengalirkan input read-only melalui instance library privat, dan setiap handle yang dikembalikan berutang satu release
var
  Pdf: TPDFlib;
  Diag: WideString;
begin
  Pdf := TPDFlib.Create;
  try
    Pdf.NewDocument;
    Pdf.SetPDFAMode(1);
    Pdf.LoadOutputIntentProfile('sRGB-IEC61966-2.1.icc', 'RGB');
    Pdf.SetPDFUAMode('en-US');
    Pdf.SetInformation(1, 'Quarterly Statement');  // /Title: wajib untuk PDF/UA
    // ... gambar konten bertanda di sini ...
    Diag := Pdf.GetPDFUADiagnostics;
    if Diag <> '' then
      Writeln('fix before shipping: ', Diag);
    Pdf.SaveToFile('statement.pdf');
    // preflight yang benar-benar berarti dijalankan pada berkas tersimpan:
    Writeln(Pdf.CreatePreflightReport('statement.pdf', '', 1, 0));
  finally
    Pdf.Free;
  end;
end;

Jebakannya bersembunyi pada saat penyimpanan. Beberapa perbaikan konformansi terjadi ketika dokumen sedang diserialisasi, bukan ketika Anda menyalakan modenya: memaksa flag print pada anotasi, menulis AFRelationship bawaan untuk berkas tertanam PDF/A-3, menormalkan tab order dan deskripsi field formulir untuk PDF/UA. Dokumen yang duduk di memori tidak identik byte demi byte dengan yang mendarat di disk, sehingga satu-satunya vonis preflight yang berarti adalah yang dihitung dari berkas tersimpan. Validasi statement.pdf itu sendiri. Jangan menyimpulkan kepatuhan dari objek yang masih di memori, sebab byte yang akan Anda nilai bukan byte yang Anda kirimkan

Diagram PDF Library for Delphi tentang fixup conformance saat penyimpanan yang diterapkan selama serialisasi, itulah mengapa preflight berlaku pada berkas PDF tersimpan alih-alih model in-memory
Serialisasi memaksa flag cetak annotasi, menyetel default AFRelationship, dan menormalkan tab order, sehingga inspeksi memori menilai byte yang tak pernah dikirim siapa pun

Skenario faktur yang membawa XML terbaca mesin berdampingan dengan dokumen visualnya mengikuti pola ZUGFeRD dan Factur-X, yang dibangun di atas PDF/A-3. Skenario itu sebaiknya menetapkan hubungan lampiran secara eksplisit dengan SetPDFA3DefaultAFRelationship, sebab ISO 19005-3 mengharuskan setiap berkas tertanam menyatakan perannya relatif terhadap dokumen. Biarkan ia tak diset dan XML tertanam itu hanyalah gumpalan tanpa maksud yang dinyatakan, dan validator akan menyadarinya

Wasit independen: veraPDF dan Acrobat

Produsen tidak boleh menjadi satu-satunya hakim atas keluarannya sendiri. Pemeriksa PDF Library for Delphi memberi Anda vonis yang cepat dan terstruktur di dalam proses, dan itulah yang Anda inginkan di jalur panas, tetapi gerbang rilis untuk batch arsip tetap sebaiknya melewatkan keluarannya melalui validator yang tidak ditulis siapa pun di tim Anda. veraPDF adalah implementasi rujukan yang dipelihara komunitas untuk PDF/A dan alat yang paling sering disebut arsip dalam kriteria penerimaannya, jadi itulah yang perlu dicocoki. Profil preflight Acrobat menjadi pemecah imbang yang berguna ketika veraPDF dan pemeriksaan di dalam proses berselisih. Catat nama validator dan versinya di samping setiap laporan yang disimpan. Klaim bahwa sebuah berkas lolos veraPDF hanya berarti sedikit tanpa nomor build yang meluluskannya, sebab alat itu memperketat aturannya antar rilis

Validator memang berselisih di tepian standar, dan ketika itu terjadi jawabannya bukan memilih alat yang Anda sukai. Ciutkan berkasnya menjadi sampel minimal yang masih memicu perselisihan itu lalu bacalah terhadap teks standarnya. Satu jam melakukan itu biasanya menyingkap salah satu dari dua hal: bug alat yang sungguhan dan layak dilaporkan ke hulu, atau sebuah klausul yang selama ini salah dibaca tim Anda dan sebaiknya dituliskan di catatan kepatuhan supaya orang berikutnya tidak menyidangkannya lagi

Masukan terenkripsi mendapat jalan pintas. Kedua pemeriksa menerima argumen kata sandi, tetapi berkas PDF/A-1 dengan kamus enkripsi sudah tidak konforman sejak awal, karena ISO 19005-1 melarang enkripsi secara mutlak, sehingga kiriman terenkripsi dapat ditolak sebelum analisis yang lebih dalam berjalan. Menelusuri apa yang sebenarnya diberikan sebuah kamus enkripsi adalah tugas tersendiri, yang dibahas di audit enkripsi dan izin PDF

Temuan PDF/UA hampir selalu berpangkal pada bagaimana pohon strukturnya disusun sejak awal, dan teknik penandaan di baliknya ada di membangun pohon struktur tagged PDF di Delphi. Arsip yang juga menuntut tanda tangan digital sebaiknya memasangkan gerbang ini dengan alur kerja di penandatanganan dan validasi PAdES. Referensi API preflight selengkapnya ada di halaman produk losLab PDF Library for Delphi