Artikel Teknis

Mengotomatiskan Pemeriksaan Preflight PDF di Delphi dengan HotPDF

File itu terbuka dengan mulus di mesin Anda. Acrobat menampilkannya, print preview terlihat benar, setiap halaman ada. Lalu file itu dikirim ke biro cetak, atau ke sistem arsip yang menelan batch bulanan Anda, dan kembali ditolak: gambar RGB dalam sebuah job CMYK, tidak ada kunci /Trapped, sebuah output intent yang tidak cocok dengan press. Tidak ada yang salah pada dokumen itu yang bisa dilihat siapa pun. Dokumen itu salah terhadap sebuah profil, dan profil itu diperiksa di tempat yang bukan tempat Anda berada. Preflight adalah nama prepress untuk pemeriksaan itu, dan pertanyaan sesungguhnya adalah di mana pemeriksaan itu seharusnya berada ketika PDF-nya keluar dari kode Delphi Anda sendiri, bukan dari desktop seorang desainer

HotPDF tidak memberi Anda sebuah fungsi preflight untuk dipanggil. Komponen ini membawa sebuah window laporan preflight dalam demo GUI-nya, namun tidak ada API di baliknya yang bisa dipanggil sebuah service atau build script, dan berpura-pura sebaliknya hanya akan membuat Anda mencari sebuah method yang tidak ada di sana. Kedengarannya seperti sebuah celah sampai Anda menyadari bahwa untuk file yang Anda hasilkan sendiri, memanggil sebuah validator pada output Anda sendiri sebenarnya bentuk yang salah. Anda sudah mengendalikan setiap property yang akan diperiksa sebuah validator. Pemisahan yang berguna adalah membuat generator tidak mampu menghasilkan file yang buruk, lalu membuktikannya dengan tool yang bukan Anda yang menulisnya

Diagram pipeline preflight Delphi di mana pengaturan kepatuhan HotPDF mencegah PDF buruk selama pembuatan dan veraPDF plus Acrobat Preflight membuktikan hasilnya secara eksternal
Pencegahan memanggang aturan PDF/A dan PDF/X ke dalam generasi HotPDF itu sendiri sementara validator eksternal menyediakan vonak yang tak sanggup dinilai generator untuk dirinya sendiri

Mengapa Anda memeriksa output Anda sendiri secara berbeda

Preflight tradisional mengasumsikan file milik orang asing. Seorang desainer, aplikasi lain, sebuah rantai edit yang tidak diketahui menghasilkannya, dan Anda memeriksanya karena Anda tidak tahu sama sekali apa isinya. Sebuah dokumen yang dihasilkan kode Anda sendiri bukanlah orang asing. Penanaman font, ruang warna, output intent, blok metadata: program Anda memutuskan semua itu beberapa milidetik sebelum file itu menyentuh disk. Memeriksanya belakangan untuk menemukan pilihan yang baru saja Anda buat sendiri adalah pekerjaan sia-sia. Langkah yang lebih murah adalah membatasi pilihan-pilihan itu sehingga sebuah file yang tidak patuh tidak pernah ada untuk ditangkap

Ada juga alasan kredibilitas untuk menjaga verifikasi tetap eksternal. Sebuah library yang memberkati outputnya sendiri sama saja dengan menilai ujiannya sendiri. Ketika sistem arsip pelanggan atau RIP percetakan menolak file Anda, "komponen kami bilang ini baik-baik saja" tidak punya bobot apa pun. Sebuah putusan dari veraPDF atau Acrobat punya bobot, karena pihak lain menjalankan tool yang sama

Jadikan kepatuhan sebuah pengaturan, bukan sebuah checklist

Lapisan pencegahan hanyalah soal konfigurasi. Atur PDFACompliance atau PDFXCompliance sebelum BeginDoc dan HotPDF akan menegakkan aturan yang sesuai untuk seluruh proses generasi: ia menanamkan font, mengawasi penggunaan DeviceRGB dan DeviceCMYK terhadap output intent yang Anda deklarasikan, dan menolak fitur yang dilarang profil tersebut. Kontradiksi muncul ke permukaan di EndDoc, tempat gerbang kepatuhan memunculkan error alih-alih diam-diam mengirim sesuatu yang akan gagal di hilir. Begitu file disimpan, property yang sama membaca kembali apa yang sebenarnya sudah ditegakkan, dan itulah satu fakta yang paling dibutuhkan pipeline log Anda:

// Setelah EndDoc: catat profil yang ditegakkan bersama metadata run
if Pdf.PDFACompliance <> '' then
  Log('Generated as PDF/A level ' + Pdf.PDFACompliance);
if Pdf.PDFXCompliance <> '' then
  Log('Generated as PDF/X profile ' + Pdf.PDFXCompliance);

Tempatkan flag-flag itu pada baris log yang sama dengan hash data input dan versi HotPDF. Pada hari sebuah validator dan generator Anda berbeda pendapat tentang sebuah file, baris itu memberi tahu Anda template mana yang menghasilkannya dan build library mana yang dimuat, dan perdebatan yang seharusnya menghabiskan satu sore penuh berubah menjadi sebuah grep. Output intent, profil ICC, dan tagging yang berada di balik flag-flag ini dijelaskan secara rinci di panduan tentang output PDF/A, PDF/X, dan PDF/UA dengan HotPDF

Gerbang pertama yang murah untuk file yang bukan Anda hasilkan

Tidak semua pipeline murni bersifat generatif. Pelanggan meng-upload PDF, scanner menjatuhkannya ke sebuah folder, mitra melampirkannya ke email. Mendorong setiap satu di antaranya melalui validator struktural penuh membuang waktu antrean untuk file yang bahkan tidak akan pernah terbuka. Direct File API milik HotPDF membaca cukup banyak dari struktur sebuah file untuk menjawab "apakah ini PDF yang bisa dipakai sama sekali" tanpa memuat seluruh object tree, yang menjadikannya tempat yang baik untuk gagal dengan cepat:

function TriagePdf(Pdf: THotPDF; const FileName: string): Boolean;
var
  Handle, Pages: Integer;
begin
  Result := False;
  Handle := Pdf.DAOpenFileReadOnly(FileName, '');
  if Handle <= 0 then
    Exit;  // tidak terbaca secara struktural: karantina, jangan divalidasi
  try
    Pages := Pdf.DAGetPageCount(Handle);
    Result := Pages > 0;
  finally
    Pdf.DACloseFile(Handle);
  end;
end;

Ada dua fakta tentang API ini yang menentukan bagaimana Anda membungkusnya. Jalan pintas memori datar hanya berlaku untuk input yang tidak terenkripsi; berikan DAOpenFileReadOnly sebuah password dan ia diam-diam turun ke full parse, sehingga file yang Anda tahu terenkripsi seharusnya melewati DecryptFile menjadi salinan kerja biasa sebelum triase. Dan DAGetPageCount tidak berarti apa-apa pada sebuah handle yang tidak terbuka dengan mulus, sehingga pemeriksaan handle tetap ketat dan hasil yang tidak positif adalah sebuah penolakan, bukan percobaan ulang. Lebih banyak pola semacam ini ada di artikel Direct File API untuk workflow PDF besar

veraPDF, dijalankan sebagai bagian dari build

Untuk apa pun yang Anda klaim sebagai PDF/A atau PDF/UA, veraPDF adalah validator yang perlu dihubungkan. Ia berjalan headless, menerima sebuah batch, menghasilkan XML atau JSON, dan menamai setiap kegagalan berdasarkan klausul ISO-nya, sehingga sebuah kegagalan aturan terhadap ISO 19005-1 klausul 6.2.2 langsung menunjuk kembali ke sebuah pengaturan generator alih-alih membiarkan Anda menebak-nebak. Menjalankannya dari Delphi hanyalah kontrol proses biasa:

function RunVeraPdf(const PdfFile, ReportFile: string): Cardinal;
var
  Cmd: string;
  SI: TStartupInfo;
  PI: TProcessInformation;
begin
  Cmd := Format('cmd /c verapdf.bat --format xml "%s" > "%s"',
    [PdfFile, ReportFile]);
  FillChar(SI, SizeOf(SI), 0);
  SI.cb := SizeOf(SI);
  if not CreateProcess(nil, PChar(Cmd), nil, nil, False,
      CREATE_NO_WINDOW, nil, nil, SI, PI) then
    RaiseLastOSError;
  try
    WaitForSingleObject(PI.hProcess, 120000);  // batasi waktu tunggu per file
    GetExitCodeProcess(PI.hProcess, Result);
  finally
    CloseHandle(PI.hThread);
    CloseHandle(PI.hProcess);
  end;
end;

Timeout itu memang layak digunakan. Sebuah file yang cacat bisa mendorong parser mana pun ke sudut yang tidak pernah bisa ia keluar darinya, dan sebuah penantian tanpa batas di dalam queue worker menyeret sisa antrean turun bersamanya. Batasi waktu tunggunya, beri timeout kode kegagalannya sendiri, dan sisihkan file itu untuk ditangani manusia. Ketika Anda membaca hasilnya, parsing XML-nya untuk mencari identifier aturan, bukan teks yang bisa dibaca manusia. ID aturan bertahan melewati upgrade validator; kata-kata pada pesan tidak bertahan, dan sebuah kode yang stabil adalah sesuatu yang bisa dicari seorang support engineer terhadap tiket-tiket lama

Bagaimana Anda menjalankan batch itu sama pentingnya dengan apakah setiap file lolos. Satu proses per file, bukan satu per batch, sehingga input yang beracun hanya membebani Anda dengan timeout file itu saja dan tidak lebih. Batasi jumlah proses validator sebanyak jumlah core, karena membangun laporan XML bersifat CPU-bound dan oversubscription hanya akan membuatnya terengah-engah. Dan pasang batas ukuran di titik intake, karena sebuah buku hasil pindaian dua gigabyte akan menguasai seluruh antrean tidak peduli seberapa sabar parser itu. Tidak satu pun dari itu adalah preflight dalam arti ketat. Itu adalah perbedaan antara sebuah gerbang yang bertahan melewati volume akhir bulan dan yang dimatikan pada malam pertama ia membuat pipeline macet pukul 2 pagi

Diagram gerbang batch Delphi yang menjalankan satu proses veraPDF per PDF di bawah timeout terbatas, menambang ID aturan XML alih-alih pesan, dan mengarsipkan setiap laporan di samping berkasnya
Penjaga intake membatasi beban queue sementara satu worker veraPDF segar per file mencegah input beracun mengganjal build

PDF/X adalah tempat semua ini menemui batasnya. veraPDF tidak memvalidasinya, sehingga pemeriksaan yang benar-benar berjalan tetap Preflight milik Acrobat dengan profil ISO 15930 yang disebutkan oleh percetakan Anda. Acrobat membutuhkan manusia, yang berarti pengambilan sampel alih-alih cakupan penuh: file pertama dari sebuah template baru, ditambah sebuah pengambilan acak kecil dari setiap batch, sementara gerbang otomatis menangani semua yang bisa ditangani tanpa manusia. Sebuah pemeriksaan sampel yang benar-benar berjalan mengalahkan sebuah otomatisasi lengkap yang selamanya tinggal setengah jadi

Sebuah laporan yang masih akan Anda butuhkan setahun kemudian

Sebuah gerbang preflight memberi manfaat dua kali. Sekali ketika ia menghentikan sebuah file buruk di pintu, dan sekali lagi jauh kemudian ketika seseorang bertanya mengapa sebuah file tertentu diloloskan. Momen kedua itulah yang seharusnya menentukan formatnya, karena itulah momen ketika sebuah laporan yang tipis membuat Anda terdampar. Untuk setiap file yang diperiksa, simpan hash input, flag kepatuhan generator serta versi library dari baris log di atas, nama dan versi validator, profil yang menjadi acuan pemeriksaannya, lulus atau gagal, dan ID aturan yang gagal beserta nomor halaman di mana pun validator memberikannya. Simpan laporan itu di samping file yang dijelaskannya. Letakkan di sistem yang terpisah dan sistem itu akan dinonaktifkan sebelum arsip yang didokumentasikannya

Pengecualian juga perlu dicatat. Ketika seorang pelanggan bersikeras mengirim sebuah file yang tidak disukai gerbang tersebut, jawabannya bukanlah melonggarkan aturan untuk semua orang. Catat siapa yang menyetujui file ini, atas dasar apa, dan hingga tanggal berapa, lalu lampirkan waiver itu ke laporannya. Sebuah waiver dengan nama dan tanggal kedaluwarsa adalah keputusan yang dimiliki seseorang. Sebuah pemeriksaan yang di-comment out "sementara" adalah insiden yang sedang menunggu tanggalnya

Satu kebiasaan lagi yang terbukti berharga: ketika sebuah file gagal, salin ke sebuah folder regresi bernama sebelum siapa pun menyentuhnya. Hampir setiap masalah preflight yang layak di-debug bisa dilacak kembali ke satu input tertentu, dan tim yang menyimpan input-input itu memperbaiki kekambuhannya dalam satu jam, bukan menunggunya muncul kembali di produksi. Property kepatuhan dan Direct File API yang ditunjukkan di sini adalah bagian dari HotPDF Delphi Component untuk Delphi dan C++Builder, yang dokumentasinya membahas setiap pemanggilan secara menyeluruh