Artikel Teknis

Menyematkan Gambar AVIF, HEIF, dan JPEG XL ke PDF dari Delphi

PDF Library for Delphi menerima gambar AVIF, HEIF, dan JPEG XL sebagai input melalui AddModernImageFromFile serta varian stream dan string-nya, mempertahankan alpha, profil ICC yang disematkan, dan channel 16-bit saat masuk ke objek gambar PDF. Deteksi format terjadi pada pembacaan magic-number yang dibatasi, dan decoding berjalan melalui backend yang dapat diganti, sehingga tidak ada apa pun yang dipanggil secara eksternal untuk sebuah berkas yang sebenarnya bukan salah satu format tersebut

Format-format ini masuk ke dalam alur kerja dokumen lewat ponsel. iOS telah menghasilkan HEIC secara default selama bertahun-tahun, perangkat Android menghasilkan AVIF, dan seorang teknisi lapangan yang memotret sebuah komponen rusak mengirimkan gambar yang sama sekali tidak dapat dibuka generator laporan PDF yang dibangun tahun 2015. Jalur fallback generik, decoding melalui bitmap platform, secara andal menghasilkan warna 8-bit dan kehilangan alpha serta profil warna di sepanjang jalan

Apa yang dipertahankan jalur gambar modern yang hilang akibat konversi bitmap?

Tiga hal, dan masing-masing memiliki alur kerja yang bergantung padanya. Alpha bertahan, yang penting untuk logo dan cutout produk yang dikomposit di atas konten halaman. Profil ICC bertahan, yang penting untuk apa pun yang akan dicetak atau dicocokkan warnanya. Dan channel 16-bit bertahan, yang penting untuk citra medis dan ilmiah di mana kuantisasi 8-bit menghancurkan gradasi yang justru menjadi alasan gambar itu diambil

Melewatkan sebuah gambar melalui bitmap platform menghilangkan ketiganya dalam satu langkah, dan itu terjadi secara diam-diam: PDF yang dihasilkan tampak kurang lebih benar, dan tidak ada yang menyadarinya sampai seorang operator printer bertanya mengapa warna merah korporat menjadi salah. Nilai opsi 8 pada panggilan gambar modern adalah flag yang mempertahankan alpha, ICC, dan channel 16-bit bersama-sama, dan itulah default untuk panggilan tersebut

Menambahkan satu ke sebuah halaman

Panggilan tersebut mengembalikan sebuah identifier gambar, yang kemudian dipilih dan digambar, atau digambar dan dilepaskan dalam satu langkah:

uses
  PDFlibrary, PDFlibModernImage;

var
  Lib: TPDFlib;
  ImageID: Integer;
begin
  Lib := TPDFlib.Create;
  try
    Lib.NewDocument;
    Lib.SetPageSize('A4');
    Lib.NewPage;

    // Options = 8 mempertahankan alpha, ICC, dan channel 16-bit
    ImageID := Lib.AddModernImageFromFile('site-photo.heic', 8);
    if ImageID > 0 then
      Lib.DrawImageAndRelease(ImageID, 40, 40, 515, 340)
    else
      Lib.DrawText(40, 40, 'image could not be decoded');

    Lib.SaveToFile('inspection-report.pdf');
  finally
    Lib.Free;
  end;
end;

Deteksi mendahului decoding dan dengan sengaja dibuat sempit. Library membaca sebuah header yang dibatasi, mengenali brand format berbasis media file ISO yang mengidentifikasi AVIF dan HEIF, serta mengenali baik signature mentah maupun container dari JPEG XL, lalu memulihkan posisi stream pemanggil. Input yang tidak dikenal atau tersamar tidak pernah mencapai codec eksternal, yang mencegah executable yang berganti nama diserahkan ke sebuah decoder seolah-olah ia sebuah gambar

Di mana sebenarnya decoding berlangsung?

Format gambar modern adalah codec besar dan kompleks, dan menempatkan salah satunya di dalam sebuah library PDF akan menjadi pilihan desain yang aneh. Backend default memuat modul MagickWand yang dapat dideploy secara dinamis in-process dan mencarinya dalam urutan yang terdokumentasi: berkas atau direktori eksplisit yang Anda atur, environment variable, direktori executable, dan search path sistem

Aplikasi yang sudah mengirimkan sebuah decoder, atau yang sama sekali tidak boleh memuat modul eksternal, mendaftarkan callback-nya sendiri sebagai gantinya. Kontraknya kecil: baca stream input, tulis PNG ke stream output, hormati orientasi yang diminta:

function MyDecoder(InStream, OutPNG: TStream;
  ImageFormat: TPDFlibModernImageFormat;
  ApplyOrientation: Boolean): Boolean;
begin
  // Dekode InStream dengan codec Anda sendiri dan tulis byte PNG ke OutPNG
  Result := DecodeWithBundledCodec(InStream, OutPNG,
    ImageFormat, ApplyOrientation);
end;

begin
  RegisterModernImageDecoderBackend(MyDecoder);
  // ... tambahkan gambar ...
  ClearModernImageDecoderBackend;    // kembali ke backend default
end;

Deployment mendapat satu kemudahan dan satu penahanan diri yang disengaja. Jika direktori codec berisi subdirektori modules\coders, library akan mengisi environment variable codec yang dibutuhkan layout semacam itu, tetapi hanya ketika aplikasi host belum mengaturnya sendiri. Aplikasi dengan strategi deployment runtime-nya sendiri mempertahankan strateginya

Mengapa PNG di tengah?

Menjembatani lewat sebuah PNG in-memory alih-alih buffer piksel mentah tampak seperti langkah tambahan dan sebenarnya adalah langkah termurah yang benar. PNG menyatakan segala sesuatu yang harus bertahan, alpha, tipe warna, bit depth, dan profil ICC yang disematkan, dan library ini sudah memiliki jalur yang matang dan teruji dengan baik dari PNG ke objek gambar PDF dengan filter dan color space yang tepat. Menggunakan kembali jalur itu berarti format modern mewarisi bertahun-tahun kerja koreksi alih-alih mendapatkan implementasi paralel

Jembatan ini sepenuhnya berada di memori, sehingga tidak ada berkas sementara yang dibuat dan tidak ada pembersihan yang diperlukan saat crash. Ada satu kerutan yang memerlukan penanganan eksplisit: sebagian konversi membuang profil ICC saat mengganti format. Backend karena itu menangkap profil sumber sebelum pergantian format, mengompresnya dengan Flate, membangun chunk iCCP yang valid dengan CRC yang dihitung ulang, dan menghapus chunk sRGB apa pun yang akan bertentangan dengannya. Dalam pengujian, sebuah AVIF yang didekode mempertahankan RGBA 16-bit dengan alpha 16-bit, dan profil yang diekstraksi dari PDF hasilnya cocok dengan profil sumber byte demi byte pada 60.960 byte

Catatan praktis sebelum Anda mengaktifkannya di produksi

Periksa ketersediaan saat startup, bukan pada foto pertama. ModernImageCodecAvailable melaporkan apakah sebuah backend dapat digunakan, dan SetModernImageCodecLibrary menunjuk ke berkas atau direktori eksplisit ketika deployment Anda menempatkan codec-nya di lokasi non-standar:

Lib.SetModernImageCodecLibrary('C:\MyApp\codecs');
if Lib.ModernImageCodecAvailable = 0 then
  Log('modern image input unavailable - HEIC and AVIF will be refused');

Perhatikan ukuran berkas hasilnya. Gambar RGBA 16-bit dengan profil yang disematkan adalah objek gambar PDF yang besar, dan sebuah laporan dengan empat puluh di antaranya akan besar. Ketika dokumen ditujukan untuk tampilan layar alih-alih cetak, downsampling sebelum penyematan adalah trade-off yang tepat, dan tuas ukuran umum dibahas dalam optimisasi ukuran berkas PDF

Terakhir, putuskan kebijakan warna dengan sengaja. Mempertahankan profil sumber benar untuk pekerjaan arsip dan cetak; mengonversi ke ruang seluruh dokumen benar ketika sekumpulan foto yang campur aduk harus tampak konsisten, dan jalur konversinya dijelaskan dalam mewarnai ulang dokumen ke color space lain. Jika Anda perlu mengonfirmasi apa yang sebenarnya masuk ke dalam berkasnya, jalur inspeksi dalam ekstraksi teks, gambar, dan font melaporkan objek gambar yang dibawa sebuah dokumen

Input gambar modern, manajemen warna, dan optimisasi gambar adalah bagian dari library yang sama untuk Delphi, C++Builder, dan Free Pascal; daftar fitur lengkapnya ada di halaman PDF Library for Delphi