Teknik Makale

Delphi'den PDF'ye AVIF, HEIF ve JPEG XL Görüntüleri Gömme

PDF Library for Delphi, AddModernImageFromFile ve onun akış ile dize varyantları üzerinden AVIF, HEIF ve JPEG XL görüntülerini girdi olarak kabul eder; PDF görüntü nesnesine giden yolda alfayı, gömülü ICC profilini ve 16 bit kanalları korur. Biçim tespiti sınırlı bir sihirli sayı (magic-number) okumasıyla gerçekleşir ve kod çözme, değiştirilebilir bir arka uç üzerinden çalışır, bu yüzden gerçekte bu biçimlerden biri olmayan bir dosya için hiçbir harici şey çağrılmaz

Bu biçimler, belge iş akışlarına telefonlar üzerinden girdi. iOS yıllardır varsayılan olarak HEIC üretiyor, Android cihazlar AVIF üretiyor ve hasarlı bir parçayı fotoğraflayan bir saha teknisyeni, 2015'te oluşturulmuş bir PDF rapor üretecinin hiç açamadığı bir görüntü gönderiyor. Genel geri düşüş (fallback) yolu — bir platform bitmap'i üzerinden kod çözme — güvenilir bir şekilde 8 bit renk verir ve bu sırada alfayı ve renk profilini kaybeder

Modern görüntü yolu, bir bitmap dönüşümünün kaybettiği neyi korur?

Üç şey ve her birinin buna bağımlı bir iş akışı var. Alfa hayatta kalır; bu, sayfa içeriğinin üzerine bindirilen logolar ve ürün kesitleri için önemlidir. ICC profili hayatta kalır; bu, basılacak veya renk eşleştirilecek her şey için önemlidir. Ve 16 bit kanallar hayatta kalır; bu, 8 bit niceleme (quantisation) görüntünün tam da yakalandığı gradasyonları yok ettiği tıbbi ve bilimsel görüntüler için önemlidir

Bir görüntüyü bir platform bitmap'i üzerinden geçirmek üçünü de tek adımda kaybeder ve bunu sessizce yapar: ortaya çıkan PDF yaklaşık olarak doğru görünür ve bir matbaacı kurumsal kırmızının neden yanlış olduğunu sorana kadar kimse fark etmez. Modern görüntü çağrılarındaki 8 seçenek değeri, alfayı, ICC'yi ve 16 bit kanalları bir arada tutan bayraktır ve bu çağrılar için varsayılandır

Bir sayfaya görüntü eklemek

Çağrı, ardından seçilip çizilen veya tek adımda çizilip serbest bırakılan bir görüntü tanımlayıcısı döndürür:

uses
  PDFlibrary, PDFlibModernImage;

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

    // Options = 8, alfayı, ICC'yi ve 16 bit kanalları korur
    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;

Tespit, kod çözmeden önce gelir ve kasıtlı olarak dardır. Kütüphane, sınırlı bir başlık okur, AVIF ve HEIF'i tanımlayan ISO temel medya dosya biçimi markalarını tanır ve JPEG XL'in hem ham hem de kapsayıcı imzalarını tanır, ardından çağıranın akış konumunu geri yükler. Bilinmeyen veya gizlenmiş bir girdi hiçbir zaman harici kodeğe ulaşmaz; bu, yeniden adlandırılmış bir yürütülebilir dosyanın sanki bir resimmiş gibi bir kod çözücüye teslim edilmesini önler

Kod çözme gerçekte nerede gerçekleşir?

Modern görüntü biçimleri büyük, karmaşık kodeklerdir ve birini bir PDF kütüphanesinin içine koymak tuhaf bir tasarım seçimi olurdu. Varsayılan arka uç, dağıtılabilir bir MagickWand modülünü işlem içinde dinamik olarak yükler ve onu belgelenmiş bir sırada arar: sizin ayarladığınız açık bir dosya veya dizin, ortam değişkenleri, yürütülebilir dosya dizini ve sistem arama yolu

Zaten bir kod çözücü ile gelen veya hiçbir harici modül yüklememesi gereken uygulamalar, bunun yerine kendi geri çağırmalarını (callback) kaydeder. Sözleşme küçüktür: girdi akışını okuyun, çıktı akışına bir PNG yazın, istenen yönlendirmeye (orientation) uyun:

function MyDecoder(InStream, OutPNG: TStream;
  ImageFormat: TPDFlibModernImageFormat;
  ApplyOrientation: Boolean): Boolean;
begin
  // InStream'i kendi kodeğinizle çözün ve PNG baytlarını OutPNG'ye yazın
  Result := DecodeWithBundledCodec(InStream, OutPNG,
    ImageFormat, ApplyOrientation);
end;

begin
  RegisterModernImageDecoderBackend(MyDecoder);
  // ... add images ...
  ClearModernImageDecoderBackend;    // varsayılan arka uca geri dön
end;

Dağıtım bir kolaylık ve bir kasıtlı kısıtlama alır. Kodek dizini bir modules\coders alt dizini içeriyorsa, kütüphane böyle bir düzenin ihtiyaç duyduğu kodek ortam değişkenlerini doldurur, ama yalnızca ana bilgisayar uygulaması bunları zaten ayarlamamışsa. Kendi çalışma zamanı dağıtım stratejisi olan bir uygulama bunu korur

Neden ortada PNG?

Ham bir piksel arabelleği yerine bellek içi bir PNG üzerinden köprülemek fazladan bir adım gibi görünür ve aslında en ucuz doğru olanıdır. PNG, hayatta kalması gereken her şeyi — alfayı, renk türünü, bit derinliğini ve gömülü bir ICC profilini — ifade eder ve kütüphanenin PNG'den doğru filtreler ve renk uzayıyla bir PDF görüntü nesnesine giden olgun, iyi test edilmiş bir yolu zaten vardır. Bunu yeniden kullanmak, modern biçimlerin paralel bir uygulama almak yerine yıllar süren doğruluk çalışmasını devralması anlamına gelir

Köprü tamamen bellek içindedir, bu yüzden hiçbir geçici dosya oluşturulmaz ve bir çökme durumunda hiçbir temizlik gerekmez. Bir pürüz açık ele alma gerektirdi: bazı dönüşümler, biçim değiştirirken ICC profilini düşürür. Bu yüzden arka uç, biçim değişiminden önce kaynak profili yakalar, onu Flate ile sıkıştırır, yeniden hesaplanmış bir CRC ile geçerli bir iCCP parçası (chunk) oluşturur ve onunla çakışacak herhangi bir sRGB parçasını kaldırır. Testlerde, çözülen bir AVIF, 16 bit alfa ile 16 bit RGBA'yı korudu ve ortaya çıkan PDF'den çıkarılan profil, 60.960 baytta kaynak profille bayt bayt eşleşti

Üretimde etkinleştirmeden önce pratik notlar

Kullanılabilirliği ilk fotoğrafta değil başlangıçta kontrol edin. ModernImageCodecAvailable, bir arka ucun kullanılıp kullanılamayacağını bildirir ve dağıtımınız kodeği standart olmayan bir yere yerleştirdiğinde SetModernImageCodecLibrary, açık bir dosyaya veya dizine işaret eder:

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

Sonucun dosya boyutunu izleyin. Gömülü bir profile sahip 16 bit RGBA görüntü, büyük bir PDF görüntü nesnesidir ve bunlardan kırk tanesi olan bir rapor büyük olacaktır. Belge, baskı yerine ekranda görüntülenmek üzereyse, gömmeden önce alt örnekleme (downsampling) yapmak doğru tercihtir ve genel boyut kolları PDF dosya boyutu optimizasyonu yazısında ele alınmıştır

Son olarak, renk ilkesine bilinçli olarak karar verin. Kaynak profili korumak, arşivleme ve baskı işi için doğrudur; karışık bir fotoğraf kümesinin tutarlı görünmesi gerektiğinde belge geneli bir uzaya dönüştürmek doğrudur ve dönüşüm yolu bir belgeyi başka bir renk uzayına yeniden renklendirme yazısında anlatılmıştır. Dosyaya gerçekte neyin indiğini doğrulamanız gerekiyorsa, metin, görüntü ve yazı tipi çıkarma yazısındaki inceleme yolu, bir belgenin taşıdığı görüntü nesnelerini bildirir

Modern görüntü girdisi, renk yönetimi ve görüntü optimizasyonu, Delphi, C++Builder ve Free Pascal için aynı kütüphanenin parçasıdır; eksiksiz özellik listesi Delphi için PDF Library sayfasındadır