Artikel Teknis

Validasi PDF/X di Delphi dengan PDFium Component

PDFium Component untuk Delphi memvalidasi dokumen PDF/X siap cetak melalui TPdf.ValidatePdfX, yang mengimplementasikan pemeriksaan ISO 15930 dalam dua lapisan: delapan pemeriksaan konten tingkat bita (kompresi LZW terlarang, JavaScript, bidang formulir, referensi OPI, TrimBox yang hilang, kunci Trapped yang tidak disetel, dan banyak lagi) ditambah lintasan model-objek PDFium yang menggunakan FPDFFont_GetIsEmbedded untuk memverifikasi penyematan font pada setiap objek teks di setiap halaman. Hasilnya adalah catatan TPdfXValidationResult yang menyebutkan tingkat kesesuaian yang terdeteksi dan mencantumkan setiap pelanggaran sebagai enum bertipe, sehingga aplikasi Delphi Anda dapat memberi tahu pelanggan dengan tepat mengapa file akan ditolak di toko percetakan sebelum ada yang mencetak pelat

Jika Anda pernah mengirimkan pekerjaan ke percetakan komersial dan menerimanya kembali dengan penolakan satu baris — "tidak ada TrimBox", "font tidak disematkan", "Trapped tidak disetel" — Anda tahu biaya yang harus dibayar karena terlambat mengetahuinya. PDF/X adalah rekan pracetak untuk PDF/A: di mana arsip PDF/A menjamin dokumen dirender secara identik beberapa dekade dari sekarang, PDF/X menjamin dokumen dipisahkan, dicitrakan, dan dipotong secara identik pada RIP (Raster Image Processor) orang lain besok pagi. Kedua standar tersebut berbagi mesin (identifikasi XMP, OutputIntents, profil ICC tersemat) tetapi menjawab pertanyaan yang berbeda, itulah sebabnya komponen mengirimkan validator terpisah untuk masing-masing — sisi PDF/A dibahas dalam validasi pra-penerbangan PDF/A dengan PDFium Component

Apa yang sebenarnya disyaratkan ISO 15930 dari PDF siap cetak?

ISO 15930 ada untuk memungkinkan terjadinya blind exchange (pertukaran buta): seorang desainer menyerahkan file ke printer yang belum pernah mereka ajak bicara, dan percetakan tersebut dapat menghasilkan output yang benar tanpa panggilan telepon, tanpa email kehilangan font, dan tanpa gambar tertaut yang tertinggal di laptop desainer. Setiap aturan dalam standar melayani tujuan itu. Font harus disematkan karena RIP penerima tidak dapat diasumsikan memilikinya. Referensi eksternal dilarang karena file tersebut harus lengkap di dalamnya sendiri. Fitur interaktif dilarang karena tinta tidak memiliki penangan onclick

PDFium Component mengenali tiga keluarga kesesuaian dan melaporkannya melalui enum TPdfXConformance dalam hasil validasi: pxc1a untuk PDF/X-1a:2001 (ISO 15930-1, garis dasar CMYK-plus-spot yang ketat pada PDF 1.3/1.4), pxc3 untuk PDF/X-3:2002 (ISO 15930-3, yang menerima warna terkelola RGB, Lab, dan ICC), dan pxc4 untuk PDF/X-4:2010 (ISO 15930-7, yang akhirnya memungkinkan transparansi hidup dan lapisan pada basis PDF 1.6). File yang tidak membawa identifikasi PDF/X sama sekali kembali sebagai pxcNone, yang merupakan jawaban yang berguna: dokumen tersebut tidak pernah diklaim siap cetak, dan hal-hal lain yang dilaporkan validator menjelaskan apa yang diperlukan untuk mencapainya

Larangan tersebut masuk akal setelah Anda berpikir seperti vendor RIP. /LZWDecode dilarang di setiap varian PDF/X sehingga konsumen yang patuh tidak pernah bergantung pada filter dengan riwayat kompatibilitas dan lisensi; Flate melakukan pekerjaan yang sama tanpa beban tersebut. JavaScript, bidang AcroForm, dan kamus tindakan tambahan /AA dilarang karena file cetak harus berupa deskripsi tetap dari tanda di atas kertas — apa pun yang dapat mengubah tampilan pada saat dibuka akan merusak jaminan bahwa apa yang terbukti adalah apa yang dicetak. Penampung OPI (Open Prepress Interface) dilarang karena, secara desain, mereka merupakan referensi ke gambar resolusi tinggi yang disimpan di tempat lain, dan "tempat lain" adalah tepat apa yang dilarang oleh pertukaran buta (blind exchange)

Mengapa toko percetakan menolak PDF tanpa TrimBox?

TrimBox adalah halaman jadi — persegi panjang yang tersisa setelah pemotongan guillotine. MediaBox, yang dimiliki setiap halaman PDF, hanyalah lembaran: mencakup bleed, tanda potong (crop marks), target pendaftaran, dan bilah warna. Perangkat lunak imposisi memosisikan halaman pada lembaran pers berdasarkan TrimBox mereka; tanpa itu, operator harus menebak di mana kartu nama Anda sebenarnya berakhir, dan tebakan yang salah akan memotong bleed Anda atau menyisakan celah putih di satu sisi. Itulah mengapa ISO 15930 memerlukan TrimBox (atau ArtBox) pada setiap halaman, dan mengapa ValidatePdfX memunculkan pvxiMissingTrimBox ketika tidak ada kunci /TrimBox yang ditemukan di halaman mana pun dari dokumen

Kunci /Trapped menjawab pertanyaan produksi yang berbeda. Trapping adalah teknik pracetak yang sedikit menumpang-tindihkan warna yang berdekatan sehingga misregistrasi pers yang kecil tidak membuka celah putih di antara mereka. Percetakan perlu tahu apakah pekerjaan itu sudah dilakukan: trapping pada file yang sudah di-trapping akan melipatgandakan tumpang tindih, dan melewatkan trapping pada file yang tidak di-trapping berisiko memunculkan celah yang terlihat. Oleh karena itu, PDF/X mengharuskan kamus Info untuk menyatakan /Trapped /True atau /Trapped /False secara eksplisit — kunci yang hilang atau /Unknown memaksa manusia untuk memeriksa file tersebut, yang merupakan percakapan yang ingin dihilangkan oleh pertukaran buta. Komponen menandai ini sebagai pvxiTrappedNotSet

Menjalankan validasi dua lapisan dengan TPdf.ValidatePdfX

TPdf.ValidatePdfX mengambil no argumen dan mengembalikan catatan TPdfXValidationResult dengan tiga anggota: Conformance (varian PDF/X yang terdeteksi), Issues (set Pascal dari nilai-nilai TPdfXValidationIssue), dan pembantu IsCompliant. Secara internal, ia menyerialkan dokumen yang dimuat ke aliran memori, menjalankan inspektur tingkat bita di atasnya, dan kemudian berjalan melintasi model objek PDFium untuk pemeriksaan penyematan per font. Gerbang pra-penerbangan minimal tampak seperti ini:

uses PDFium, FPdfPdfx;

procedure CheckPrintReadiness(const FileName: string);
var
  Pdf: TPdf;
  Res: TPdfXValidationResult;
begin
  Pdf := TPdf.Create(nil);
  try
    Pdf.FileName := FileName;
    Pdf.Active := True;

    Res := Pdf.ValidatePdfX;
    Writeln('Detected conformance: ',
      Ord(Res.Conformance)); // pxc1a, pxc3, pxc4, pxcNone...

    if Res.IsCompliant then
      Writeln('PDF/X checks passed')
    else
    begin
      if pvxiMissingTrimBox in Res.Issues then
        Writeln('REJECT: tidak ada /TrimBox pada halaman');
      if pvxiTrappedNotSet in Res.Issues then
        Writeln('REJECT: /Trapped hilang atau /Unknown');
      if pvxiPdfiumFontNotEmbedded in Res.Issues then
        Writeln('REJECT: halaman menggunakan font yang tidak disematkan');
      if pvxiLzwForbidden in Res.Issues then
        Writeln('REJECT: filter LZWDecode ada');
    end;
  finally
    Pdf.Free;
  end;
end;

Karena Issues adalah set Pascal biasa, Anda dapat mempartisinya sesuai kebutuhan alur kerja Anda — memperlakukan masalah struktural sebagai penolakan keras, memperlakukan pvxiMissingTitle (sebuah SHOULD dalam standar, bukan MUST) sebagai peringatan, dan mencatat sisanya. Jenis rekaman yang sama juga memberi makan generator laporan komponen, jadi jika Anda lebih suka memancarkan dokumen yang dapat dibaca manusia daripada bercabang pada enum, pola dalam membangun CLI laporan pra-penerbangan batch dengan PDFium Component berlaku untuk PDF/X tanpa perubahan

Apa yang ditangkap oleh lapisan tingkat bita — dan apa yang terlewatkan

Pemindaian bita cepat dan tidak memerlukan mesin rendering, tetapi memiliki titik buta bawaan pada font: pada tingkat itu inspektur hanya dapat menerapkan heuristik kasar — ia menandai dokumen ketika ia tidak menemukan program font tersemat sama sekali. File dengan sembilan font tersemat dan satu font sistem yang diselipkan terlihat baik-baik saja pada pemindaian bita. Kesenjangan tunggal itulah mengapa lapisan kedua ada

  • pvxiLzwForbidden — filter /LZWDecode muncul di mana saja dalam file (dilarang di semua varian PDF/X)
  • pvxiJavaScriptForbidden — tindakan atau pohon nama /JavaScript hadir
  • pvxiFormFieldsForbidden — kamus /AcroForm atau entri /XFA ada
  • pvxiAdditionalActions — kamus tindakan tambahan /AA ada
  • pvxiEmbeddedFilesForbidden/EmbeddedFiles atau anotasi /FileAttachment ada
  • pvxiOpiForbidden — entri /OPI atau /Alternates merujuk ke konten gambar yang dapat diganti
  • pvxiMissingTrimBox — tidak ada /TrimBox ditemukan di halaman mana pun
  • pvxiTrappedNotSet/Trapped absen atau disetel ke /Unknown

Penyematan per font melalui model objek PDFium

Lapisan model objek PDFium Component menjawab pertanyaan font dengan tepat. Setelah lintasan tingkat bita, TPdf.ValidatePdfX melakukan iterasi di setiap halaman, meminta daftar objek dari FPDFPage_CountObjects, dan untuk setiap objek teks menyelesaikan handel font via FPDFTextObj_GetFont dan menanyakan FPDFFont_GetIsEmbedded. Satu font yang tidak disematkan di mana saja dalam dokumen menambahkan pvxiPdfiumFontNotEmbedded ke set masalah. Penelusuran melakukan hubungan singkat (short-circuit) pada dua tingkat — ia berhenti memindai objek pada suatu halaman, dan berhenti memuat halaman berikutnya, saat masalah dikonfirmasi — sehingga pada katalog 300 halaman yang melanggar, putusan sering kali tiba setelah halaman pertama

Dua catatan batas yang patut diketahui. Pertama, lapisan ini memerlukan pustaka PDFium dimuat dan memerlukan build yang mengekspor FPDFFont_GetIsEmbedded; ketika ekspor tidak ada, pemeriksaan dilewati alih-alih gagal, sehingga DLL lama tidak pernah menghasilkan penolakan semu (phantom). Kedua, pemeriksaan menjawab "disematkan atau tidak" dan tidak lebih dari itu — ia tidak membedakan penyematan penuh dari subsetting, juga tidak memeriksa cakupan glyph. Ketika file gagal dan Anda perlu tahu font mana pada halaman mana, teknik enumerasi dalam menganalisis properti font PDF dengan PDFium di Delphi mengambil alih tepat di mana boolean validator berakhir

Memvalidasi aliran tanpa memuat dokumen — atau DLL

Inspektur tingkat bita juga diekspos sebagai fungsi mandiri, ValidatePdfXCompliance(Source: TStream) di unit FPdfPdfx, dan ini adalah Object Pascal murni tanpa ketergantungan pada PDFium DLL. Hal itu membuatnya dapat diterapkan di tempat-tempat di mana mesin rendering tidak diinginkan: gerbang unggahan ringan di server web, pekerjaan CI yang memeriksa karya seni yang dihasilkan, atau layanan Lazarus di platform di mana Anda memilih untuk tidak mengirimkan biner asli. Beri makan aliran apa pun yang dapat dicari (seekable stream):

uses Classes, FPdfPdfx;

function QuickPdfXGate(const FileName: string): Boolean;
var
  Fs: TFileStream;
  Res: TPdfXValidationResult;
begin
  Fs := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
  try
    Res := ValidatePdfXCompliance(Fs);
    Result := Res.IsCompliant and (Res.Conformance <> pxcNone);
  finally
    Fs.Free;
  end;
end;

Pertukarannya sangat jelas: jalur mandiri (standalone path) menjalankan pemeriksaan penanda dan delapan pemeriksaan konten, tetapi tidak untuk lapisan PDFium per-font, sehingga putusan font-nya kembali ke heuristik kasar. Arsitektur yang bijaksana menggunakan ValidatePdfXCompliance sebagai gerbang pertama yang murah dan mencadangkan TPdf.ValidatePdfX lengkap untuk file yang lolos darinya

Di mana validator ini berakhir dan pra-penerbangan penuh dimulai

Kejujuran penting dalam alat pra-penerbangan, jadi inilah batasannya. ValidatePdfX memverifikasi penanda identifikasi, larangan struktural, kunci geometri halaman, deklarasi Trapped, dan penyematan font hingga ke objek teks individu. Ini tidak mengukur cakupan tinta total, memvalidasi bahwa setiap ruang warna sah untuk varian yang diklaim (misalnya aturan hanya CMYK dari X-1a), memeriksa resolusi gambar terhadap layar garis, atau mengevaluasi perilaku cetak tindih (overprint) dan perataan transparansi — itu memerlukan mesin pra-penerbangan dengan warna terkelola, dan dokumentasi unit sendiri menyarankan untuk memasangkannya dengan mesin tersebut untuk sertifikasi akhir. Apa yang diberikan oleh pemeriksaan dua lapisan ini adalah 80% penolakan yang bersifat struktural dan terdeteksi lebih awal, tertangkap dalam hitungan milidetik di dalam kode Delphi Anda sendiri alih-alih dalam email besok dari percetakan

Kedua lapisan validasi, API injeksi penanda PDF/X untuk menghasilkan output yang patuh, serta validator PDF/A, PDF/UA, PDF/E, dan PDF/VT yang berbagi arsitektur yang sama dikirimkan dalam PDFium Component untuk Delphi dan C++Builder — satu komponen, dari rendering hingga gerbang pracetak