Tehnički članak

Ugrađivanje AVIF, HEIF i JPEG XL slika u PDF iz Delphija

PDF Library for Delphi prihvata AVIF, HEIF i JPEG XL slike kao ulaz kroz AddModernImageFromFile i njegove varijante za tok i string, čuvajući alfa kanal, ugrađen ICC profil i 16-bitne kanale na putu u objekat slike PDF-a. Detekcija formata se dešava na omeđenom čitanju magičnog broja, a dekodiranje se izvodi kroz zamenljiv backend, tako da se ništa eksterno ne poziva za fajl koji zapravo nije jedan od tih formata

Ovi formati su stigli u tokove rada dokumenata preko telefona. iOS godinama podrazumevano proizvodi HEIC, Android uređaji proizvode AVIF, a terenski tehničar koji fotografiše oštećen deo šalje sliku koju generator PDF izveštaja izgrađen 2015. uopšte ne može da otvori. Generička rezervna putanja, dekodiranje kroz platformsku bitmapu, pouzdano daje 8-bitnu boju i gubi alfa kanal i profil boje usput

Šta moderna putanja slike čuva, a konverzija u bitmapu gubi?

Tri stvari, i svaka ima tok rada koji od nje zavisi. Alfa kanal preživljava, što je bitno za logotipe i izrezane proizvode postavljene preko sadržaja stranice. ICC profil preživljava, što je bitno za sve što će biti štampano ili usklađeno po boji. A 16-bitni kanali preživljavaju, što je bitno za medicinske i naučne slike gde 8-bitna kvantizacija uništava upravo one nijanse zbog kojih je slika snimljena

Prosleđivanje slike kroz platformsku bitmapu gubi sve tri u jednom koraku, i to čini tiho: rezultujući PDF izgleda približno ispravno, a niko to ne primeti dok štampač ne pita zašto je korporativna crvena pogrešna. Vrednost opcije 8 na modernim pozivima slike je zastavica koja drži alfa kanal, ICC i 16-bitne kanale zajedno, i ona je podrazumevana za te pozive

Dodavanje jedne na stranicu

Poziv vraća identifikator slike, koji se zatim bira i crta, ili crta i oslobađa u jednom koraku:

uses
  PDFlibrary, PDFlibModernImage;

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

    // Options = 8 čuva alfa kanal, ICC i 16-bitne kanale
    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;

Detekcija prethodi dekodiranju i namerno je uska. Biblioteka čita omeđeno zaglavlje, prepoznaje ISO bazne brendove medijskih fajl formata koji identifikuju AVIF i HEIF, i prepoznaje i sirove i kontejnerske potpise JPEG XL-a, zatim vraća poziciju toka pozivaoca. Nepoznat ili prerušen ulaz nikada ne stigne do eksternog kodeka, što sprečava da preimenovan izvršni fajl bude predat dekoderu kao da je slika

Gde se dekodiranje zapravo dešava?

Moderni formati slika su veliki, složeni kodeci, a stavljanje jednog unutar PDF biblioteke bio bi čudan dizajnerski izbor. Podrazumevani backend dinamički učitava raspoređujući MagickWand modul u procesu i traži ga po dokumentovanom redosledu: eksplicitan fajl ili direktorijum koji vi podesite, promenljive okruženja, direktorijum izvršnog fajla, i sistemsku putanju pretrage

Aplikacije koje već isporučuju dekoder, ili koje uopšte ne smeju da učitaju eksterni modul, registruju sopstveni povratni poziv umesto toga. Ugovor je mali: pročitaj ulazni tok, upiši PNG u izlazni tok, poštuj traženu orijentaciju:

function MyDecoder(InStream, OutPNG: TStream;
  ImageFormat: TPDFlibModernImageFormat;
  ApplyOrientation: Boolean): Boolean;
begin
  // Dekoduj InStream sopstvenim kodekom i upiši PNG bajtove u OutPNG
  Result := DecodeWithBundledCodec(InStream, OutPNG,
    ImageFormat, ApplyOrientation);
end;

begin
  RegisterModernImageDecoderBackend(MyDecoder);
  // ... dodaj slike ...
  ClearModernImageDecoderBackend;    // nazad na podrazumevani backend
end;

Raspoređivanje dobija jednu pogodnost i jedno namerno suzdržavanje. Ako direktorijum kodeka sadrži poddirektorijum modules\coders, biblioteka popunjava promenljive okruženja kodeka koje takav raspored zahteva, ali samo kada ih aplikacija domaćin još nije postavila. Aplikacija sa sopstvenom strategijom raspoređivanja runtime-a zadržava svoju

Zašto PNG u sredini?

Premošćavanje kroz PNG u memoriji umesto sirovog bafera piksela izgleda kao dodatan korak, a zapravo je najjeftiniji ispravan korak. PNG izražava sve što mora preživeti, alfa kanal, tip boje, dubinu bita i ugrađen ICC profil, a biblioteka već ima zrelu, dobro testiranu putanju iz PNG-a u objekat PDF slike sa ispravnim filterima i prostorom boja. Ponovna upotreba znači da moderni formati nasleđuju godine rada na ispravnosti umesto da dobiju paralelnu implementaciju

Most je u potpunosti u memoriji, tako da se ne stvaraju privremeni fajlovi i nije potrebno čišćenje pri padu. Jedna nabora zahtevala je izričito rukovanje: neke konverzije odbacuju ICC profil pri promeni formata. Backend zato hvata izvorni profil pre prebacivanja formata, komprimuje ga sa Flate, gradi ispravan iCCP segment sa ponovo izračunatim CRC-om, i uklanja svaki sRGB segment koji bi bio u sukobu sa njim. U testiranju, dekodiran AVIF je zadržao 16-bitni RGBA sa 16-bitnim alfa kanalom, a profil izvučen iz rezultujućeg PDF-a se poklopio sa izvornim profilom bajt po bajt na 60.960 bajtova

Praktične napomene pre nego što ga uključite u produkciju

Proverite dostupnost pri pokretanju, a ne pri prvoj fotografiji. ModernImageCodecAvailable prijavljuje da li backend može biti korišćen, a SetModernImageCodecLibrary pokazuje na eksplicitan fajl ili direktorijum kada vaše raspoređivanje smešta kodek negde nestandardno:

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

Pratite veličinu fajla rezultata. 16-bitna RGBA slika sa ugrađenim profilom je velik objekat PDF slike, a izveštaj sa četrdeset njih biće velik. Kada je dokument namenjen prikazu na ekranu, a ne štampi, smanjenje uzorkovanja pre ugrađivanja je pravi kompromis, a opšte poluge veličine su obrađene u optimizaciji veličine PDF fajla

Konačno, odlučite politiku boja namerno. Čuvanje izvornog profila je ispravno za arhivski i štamparski rad; konverzija u prostor na nivou celog dokumenta je ispravna kada mešoviti skup fotografija mora izgledati usklađeno, a putanja konverzije je opisana u promeni boje dokumenta u drugi prostor boja. Ako trebate da potvrdite šta je zapravo završilo u fajlu, putanja inspekcije u izvlačenju teksta, slika i fontova prijavljuje objekte slika koje dokument nosi

Moderni ulaz slika, upravljanje bojama i optimizacija slika su deo iste biblioteke za Delphi, C++Builder i Free Pascal; kompletna lista funkcija je na stranici PDF Library for Delphi