Techninis straipsnis

AVIF, HEIF ir JPEG XL vaizdų įterpimas į PDF iš Delphi

PDF Library for Delphi priima AVIF, HEIF ir JPEG XL vaizdus kaip įvestį per AddModernImageFromFile bei jos srauto ir eilutės variantus, išsaugodama alfa kanalą, įterptą ICC profilį ir 16 bitų kanalus, kol vaizdas patenka į PDF vaizdo objektą. Formato aptikimas vyksta per apribotą magiško skaičiaus skaitymą, o dekodavimas vyksta per pakeičiamą galinę sistemą (backend), todėl failui, kuris iš tikrųjų nėra vienas iš šių formatų, joks išorinis komponentas nekviečiamas

Šie formatai į dokumentų darbo srautus atkeliavo per telefonus. iOS jau ilgus metus pagal nutylėjimą kuria HEIC, Android įrenginiai kuria AVIF, o lauko technikas, fotografuojantis sugadintą detalę, atsiunčia vaizdą, kurio 2015 metais sukurtas PDF ataskaitų generatorius apskritai negali atidaryti. Bendrasis atsarginis kelias, dekoduojant per platformos bitmap, patikimai duoda 8 bitų spalvą ir pakeliui praranda alfa kanalą bei spalvų profilį

Ką išsaugo šiuolaikinis vaizdų kelias, kurį praranda konvertavimas per bitmap?

Tris dalykus, ir kiekviena iš jų turi darbo srautą, kuris nuo to priklauso. Alfa kanalas išlieka – tai svarbu logotipams ir produktų iškarpoms, komponuojamoms virš puslapio turinio. ICC profilis išlieka – tai svarbu viskam, kas bus spausdinama ar derinama pagal spalvą. Ir 16 bitų kanalai išlieka – tai svarbu medicininiams bei moksliniams vaizdams, kur 8 bitų kvantavimas sunaikina būtent tuos atspalvių niuansus, dėl kurių vaizdas ir buvo užfiksuotas

Vaizdo praleidimas per platformos bitmap vienu žingsniu prarandą visus tris dalykus, ir tai vyksta tyliai: gautas PDF failas atrodo apytiksliai teisingas, ir niekas to nepastebi, kol spaustuvė nepaklausia, kodėl įmonės raudona spalva neteisinga. 8 reikšmės parinktis šiuolaikinių vaizdų iškvietimuose yra vėliavėlė, kuri kartu išsaugo alfa kanalą, ICC profilį ir 16 bitų kanalus, ir tai yra numatytoji šių iškvietimų reikšmė

Vaizdo pridėjimas prie puslapio

Iškvietimas grąžina vaizdo identifikatorių, kuris tada pasirenkamas ir piešiamas, arba piešiamas ir atlaisvinamas vienu žingsniu:

uses
  PDFlibrary, PDFlibModernImage;

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

    // Options = 8 išsaugo alfa kanalą, ICC profilį ir 16 bitų kanalus
    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;

Aptikimas vyksta prieš dekodavimą ir yra sąmoningai siauras. Biblioteka skaito apribotą antraštę, atpažįsta ISO bazinio medijos failo formato prekės ženklus, identifikuojančius AVIF ir HEIF, ir atpažįsta tiek žalias, tiek konteinerines JPEG XL signatūras, tada atkuria kviečiančiojo srauto poziciją. Nežinoma ar užmaskuota įvestis niekada nepasiekia išorinio kodeko, o tai apsaugo, kad pervadintas vykdomasis failas nebūtų perduotas dekoderiui, tarsi tai būtų nuotrauka

Kur iš tikrųjų vyksta dekodavimas?

Šiuolaikiniai vaizdų formatai yra dideli, sudėtingi kodekai, ir vieno iš jų įdėjimas į PDF biblioteką būtų keistas dizaino sprendimas. Numatytoji galinė sistema procese dinamiškai įkelia diegiamą MagickWand modulį ir jo ieško dokumentuota tvarka: aiškiai jūsų nustatytame faile ar kataloge, aplinkos kintamuosiuose, vykdomojo failo kataloge ir sistemos paieškos kelyje

Aplikacijos, kurios jau turi savo dekoderį arba kurioms apskritai negalima įkelti išorinio modulio, vietoj to registruoja savo pačių atgalinį iškvietimą. Sutartis nedidelė: perskaityti įvesties srautą, į išvesties srautą įrašyti PNG, atsižvelgti į prašomą orientaciją:

function MyDecoder(InStream, OutPNG: TStream;
  ImageFormat: TPDFlibModernImageFormat;
  ApplyOrientation: Boolean): Boolean;
begin
  // Dekoduokite InStream savo pačių kodeku ir įrašykite PNG baitus į OutPNG
  Result := DecodeWithBundledCodec(InStream, OutPNG,
    ImageFormat, ApplyOrientation);
end;

begin
  RegisterModernImageDecoderBackend(MyDecoder);
  // ... pridėkite vaizdus ...
  ClearModernImageDecoderBackend;    // grįžti prie numatytosios galinės sistemos
end;

Diegimas gauna vieną patogumą ir vieną sąmoningą santūrumą. Jei kodeko kataloge yra modules\coders pokatalogis, biblioteka užpildo tokiam išdėstymui reikalingus kodeko aplinkos kintamuosius, bet tik tada, kai priimančioji aplikacija jų dar nenustatė pati. Aplikacija su savo pačios vykdymo aplinkos diegimo strategija ją ir išlaiko

Kodėl PNG yra tarpinė grandis?

Tiltas per atminties PNG, o ne per žalią pikselių buferį, atrodo kaip papildomas žingsnis, o iš tikrųjų yra pigiausias teisingas sprendimas. PNG išreiškia viską, kas turi išlikti – alfa kanalą, spalvos tipą, bitų gylį ir įterptą ICC profilį, o biblioteka jau turi subrandintą, gerai išbandytą kelią iš PNG į PDF vaizdo objektą su teisingais filtrais ir spalvų erdve. Jo pakartotinis naudojimas reiškia, kad šiuolaikiniai formatai paveldi metų metus trukusį tikslumo darbą, o ne gauna lygiagrečią realizaciją

Tiltas visiškai vyksta atmintyje, todėl nesukuriami jokie laikinieji failai ir nereikia jokio valymo įvykus gedimui. Vienas dalykas reikalavo aiškaus apdorojimo: kai kurios konversijos keičiant formatą numeta ICC profilį. Todėl galinė sistema užfiksuoja šaltinio profilį prieš formato pakeitimą, suspaudžia jį su Flate, sukuria teisingą iCCP bloką su perskaičiuotu CRC ir pašalina bet kokį sRGB bloką, kuris su juo konfliktuotų. Testuojant dekoduotas AVIF išlaikė 16 bitų RGBA su 16 bitų alfa kanalu, o profilis, ištrauktas iš gauto PDF, sutapo su šaltinio profiliu baitas po baito, sudarydamas 60 960 baitų

Praktinės pastabos prieš įjungiant tai gamyboje

Patikrinkite prieinamumą paleidimo metu, o ne pirmos nuotraukos metu. ModernImageCodecAvailable praneša, ar galima naudoti galinę sistemą, o SetModernImageCodecLibrary nurodo aiškų failą ar katalogą, kai jūsų diegimas kodeką patalpina neįprastoje vietoje:

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

Stebėkite rezultato failo dydį. 16 bitų RGBA vaizdas su įterptu profiliu yra didelis PDF vaizdo objektas, o ataskaita su keturiasdešimčia jų bus didelė. Kai dokumentas skirtas peržiūrai ekrane, o ne spausdinimui, dydžio sumažinimas prieš įterpiant yra teisingas kompromisas, o bendri dydžio valdymo svertai aprašyti straipsnyje PDF failo dydžio optimizavimas

Galiausiai, sąmoningai nuspręskite dėl spalvų politikos. Šaltinio profilio išsaugojimas teisingas archyvavimo ir spaudos darbui; konvertavimas į vieną visam dokumentui bendrą erdvę teisingas, kai mišrus nuotraukų rinkinys turi atrodyti nuosekliai, o konvertavimo kelias aprašytas straipsnyje dokumento perkėlimas į kitą spalvų erdvę. Jei reikia patvirtinti, kas iš tikrųjų atsidūrė faile, tikrinimo kelias straipsnyje teksto, vaizdų ir šriftų ištraukimas praneša, kokius vaizdo objektus neša dokumentas

Šiuolaikinių vaizdų įvestis, spalvų valdymas ir vaizdų optimizavimas yra tos pačios bibliotekos dalys Delphi, C++Builder ir Free Pascal aplinkoms; pilnas funkcijų sąrašas pateikiamas PDF Library for Delphi puslapyje