Technisch artikel

AVIF-, HEIF- en JPEG XL-afbeeldingen insluiten in PDF vanuit Delphi

PDF Library for Delphi accepteert AVIF-, HEIF- en JPEG XL-afbeeldingen als invoer via AddModernImageFromFile en de stream- en stringvarianten daarvan, met behoud van alfa, het ingesloten ICC-profiel en 16-bits kanalen op weg naar het PDF-afbeeldingsobject. Formaatdetectie gebeurt via een begrensde magic-number-lezing, en decodering verloopt via een vervangbare backend, zodat niets externs wordt aangeroepen voor een bestand dat niet daadwerkelijk een van die formaten is

Deze formaten zijn documentworkflows binnengekomen via telefoons. iOS produceert al jaren standaard HEIC, Android-toestellen produceren AVIF, en een veldtechnicus die een beschadigd onderdeel fotografeert, stuurt een afbeelding die een PDF-rapportgenerator uit 2015 helemaal niet kan openen. Het generieke fallbackpad, decoderen via een platformbitmap, levert betrouwbaar 8-bits kleur op en verliest onderweg alfa en het kleurprofiel

Wat behoudt het moderne-afbeeldingspad dat een bitmapconversie verliest?

Drie dingen, en elk daarvan heeft een workflow die ervan afhankelijk is. Alfa blijft behouden, wat ertoe doet voor logo's en productuitsnedes die over pagina-inhoud worden gecomponeerd. Het ICC-profiel blijft behouden, wat ertoe doet voor alles wat wordt afgedrukt of kleurgematcht. En 16-bits kanalen blijven behouden, wat ertoe doet voor medische en wetenschappelijke beeldvorming waar 8-bits kwantisering precies de gradaties vernietigt waarvoor de afbeelding is vastgelegd

Een afbeelding door een platformbitmap laten gaan, verliest alle drie in één stap, en dat gebeurt stilzwijgend: de resulterende PDF ziet er ongeveer goed uit, en niemand merkt het totdat een drukker vraagt waarom het bedrijfsrood niet klopt. Optiewaarde 8 op de moderne-afbeeldingsaanroepen is de vlag die alfa, ICC en 16-bits kanalen samen behoudt, en het is de standaard voor die aanroepen

Er een aan een pagina toevoegen

De aanroep retourneert een afbeeldings-ID, die vervolgens wordt geselecteerd en getekend, of in één stap getekend en vrijgegeven:

uses
  PDFlibrary, PDFlibModernImage;

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

    // Options = 8 behoudt alfa, ICC en 16-bits kanalen
    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;

Detectie gaat aan decodering vooraf en is bewust smal. De bibliotheek leest een begrensde header, herkent de ISO-basismediabestandsformaat-merken die AVIF en HEIF identificeren, en herkent zowel de ruwe als de containersignaturen van JPEG XL, en herstelt vervolgens de streampositie van de aanroeper. Een onbekende of vermomde invoer bereikt de externe codec nooit, wat voorkomt dat een hernoemd uitvoerbaar bestand aan een decoder wordt gegeven alsof het een afbeelding was

Waar vindt de decodering eigenlijk plaats?

Moderne afbeeldingsformaten zijn grote, complexe codecs, en er een in een PDF-bibliotheek stoppen zou een vreemde ontwerpkeuze zijn. De standaardbackend laadt dynamisch een implementeerbare MagickWand-module in-process en zoekt deze in een gedocumenteerde volgorde: een expliciet bestand of directory die u instelt, omgevingsvariabelen, de directory van het uitvoerbare bestand, en het systeemzoekpad

Toepassingen die al een decoder meeleveren, of die helemaal geen externe module mogen laden, registreren in plaats daarvan hun eigen callback. Het contract is klein: lees de invoerstream, schrijf een PNG naar de uitvoerstream, respecteer de gevraagde oriëntatie:

function MyDecoder(InStream, OutPNG: TStream;
  ImageFormat: TPDFlibModernImageFormat;
  ApplyOrientation: Boolean): Boolean;
begin
  // Decodeer InStream met uw eigen codec en schrijf PNG-bytes naar OutPNG
  Result := DecodeWithBundledCodec(InStream, OutPNG,
    ImageFormat, ApplyOrientation);
end;

begin
  RegisterModernImageDecoderBackend(MyDecoder);
  // ... afbeeldingen toevoegen ...
  ClearModernImageDecoderBackend;    // terug naar de standaardbackend
end;

Deployment krijgt één gemak en één bewuste terughoudendheid. Als de codecdirectory een submap modules\coders bevat, vult de bibliotheek de codec-omgevingsvariabelen in die zo'n indeling nodig heeft, maar alleen wanneer de hosttoepassing die nog niet heeft ingesteld. Een toepassing met haar eigen runtime-deploymentstrategie behoudt die

Waarom PNG in het midden?

Overbruggen via een PNG in het geheugen in plaats van een ruwe pixelbuffer lijkt een extra stap en is eigenlijk de goedkoopste correcte optie. PNG drukt alles uit wat moet overleven: alfa, kleurtype, bitdiepte en een ingesloten ICC-profiel, en de bibliotheek heeft al een volwassen, goed geteste route van PNG naar een PDF-afbeeldingsobject met de juiste filters en kleurruimte. Die hergebruiken betekent dat moderne formaten jaren aan correctheidswerk erven in plaats van een parallelle implementatie te krijgen

De brug bevindt zich volledig in het geheugen, dus er worden geen tijdelijke bestanden aangemaakt en is geen opruiming nodig bij een crash. Eén complicatie vereiste expliciete afhandeling: sommige conversies laten het ICC-profiel vallen bij het wisselen van formaat. De backend legt daarom het bronprofiel vast vóór de formaatwisseling, comprimeert het met Flate, bouwt een geldig iCCP-chunk met een herberekende CRC, en verwijdert elk sRGB-chunk dat ermee zou botsen. Bij testen behield een gedecodeerde AVIF 16-bits RGBA met 16-bits alfa, en het profiel geëxtraheerd uit de resulterende PDF kwam byte voor byte overeen met het bronprofiel, bij 60.960 bytes

Praktische opmerkingen voordat u dit in productie inschakelt

Controleer beschikbaarheid bij het opstarten in plaats van bij de eerste foto. ModernImageCodecAvailable rapporteert of een backend kan worden gebruikt, en SetModernImageCodecLibrary wijst naar een expliciet bestand of directory wanneer uw deployment de codec ergens niet-standaard plaatst:

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

Houd de bestandsgrootte van het resultaat in de gaten. Een 16-bits RGBA-afbeelding met een ingesloten profiel is een groot PDF-afbeeldingsobject, en een rapport met veertig ervan wordt groot. Wanneer het document bestemd is voor schermweergave in plaats van afdrukken, is downsampling vóór het insluiten de juiste afweging, en de algemene groottehendels worden behandeld in PDF-bestandsgrootte-optimalisatie

Bepaal ten slotte bewust het kleurbeleid. Het bronprofiel behouden is correct voor archief- en drukwerk; converteren naar een documentbrede ruimte is correct wanneer een gemengde set foto's er consistent moet uitzien, en de conversieroute wordt beschreven in een document herkleuren naar een andere kleurruimte. Als u moet bevestigen wat daadwerkelijk in het bestand terechtkwam, rapporteert het inspectiepad in tekst-, afbeeldings- en lettertype-extractie de afbeeldingsobjecten die een document draagt

Moderne-afbeeldingsinvoer, kleurbeheer en afbeeldingsoptimalisatie maken deel uit van dezelfde bibliotheek voor Delphi, C++Builder en Free Pascal; de volledige functielijst staat op de PDF Library for Delphi-pagina