Техническа статия

Вграждане на изображения AVIF, HEIF и JPEG XL в PDF от Delphi

PDF Library for Delphi приема изображения AVIF, HEIF и JPEG XL като вход чрез AddModernImageFromFile и неговите варианти за поток и низ, запазвайки алфа канала, вградения ICC профил и 16-битовите канали по пътя навътре в обекта на изображение на PDF. Разпознаването на формата се извършва чрез ограничено четене на магическо число, а декодирането преминава през заменяема бекенд реализация, така че нищо външно не се извиква за файл, който всъщност не е един от тези формати

Тези формати навлязоха в работни процеси с документи чрез телефони. iOS произвежда HEIC по подразбиране от години, Android устройствата произвеждат AVIF, а полеви техник, снимащ повредена част, изпраща изображение, което генератор на PDF отчети, изграден през 2015 г., изобщо не може да отвори. Общият резервен път — декодиране през платформено растерно изображение — надеждно дава 8-битов цвят и губи алфа канала и цветовия профил по пътя

Какво запазва пътят за модерни изображения, което конвертиране в растерно изображение губи?

Три неща, и всяко има работен процес, който зависи от него. Алфа каналът оцелява, което има значение за лога и изрязани продуктови изображения, композирани върху съдържанието на страницата. ICC профилът оцелява, което има значение за всичко, което ще бъде отпечатано или цветово съгласувано. А 16-битовите канали оцеляват, което има значение за медицински и научни изображения, където 8-битовото квантуване унищожава точно градациите, заради които изображението е било заснето

Прекарването на изображение през платформено растерно изображение губи и трите наведнъж, и го прави тихо: получаваният PDF изглежда приблизително правилно, и никой не забелязва, докато принтер не попита защо корпоративното червено е грешно. Стойност на опция 8 при извикванията за модерни изображения е флагът, който пази алфа, ICC и 16-битовите канали заедно, и е стойността по подразбиране за тези извиквания

Добавяне на изображение към страница

Извикването връща идентификатор на изображение, който след това се избира и изчертава, или се изчертава и освобождава в една стъпка:

uses
  PDFlibrary, PDFlibModernImage;

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

    // Options = 8 пази алфа, ICC и 16-битовите канали
    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;

Разпознаването предхожда декодирането и е съзнателно тясно. Библиотеката чете ограничена заглавка, разпознава марките на формата ISO base media file, идентифициращи AVIF и HEIF, и разпознава както суровите, така и контейнерните сигнатури на JPEG XL, след което възстановява позицията в потока на извикващия. Непознат или прикрит вход никога не достига до външния кодек, което пази преименуван изпълним файл от предаване на декодер, сякаш е снимка

Къде всъщност се извършва декодирането?

Модерните формати на изображения са големи, сложни кодеци, а поставянето на такъв вътре в PDF библиотека би било странен дизайнерски избор. Бекендът по подразбиране динамично зарежда разгръщаем модул MagickWand в процеса и го търси в документиран ред: изричен файл или директория, зададени от вас, променливи на средата, директорията на изпълнимия файл и системния път за търсене

Приложения, които вече доставят декодер, или които изобщо не трябва да зареждат външен модул, регистрират собствено обратно извикване вместо това. Договорът е малък: прочети входния поток, запиши PNG в изходния поток, зачети заявената ориентация:

function MyDecoder(InStream, OutPNG: TStream;
  ImageFormat: TPDFlibModernImageFormat;
  ApplyOrientation: Boolean): Boolean;
begin
  // Декодирайте InStream със собствен кодек и запишете PNG байтове в OutPNG
  Result := DecodeWithBundledCodec(InStream, OutPNG,
    ImageFormat, ApplyOrientation);
end;

begin
  RegisterModernImageDecoderBackend(MyDecoder);
  // ... добавяне на изображения ...
  ClearModernImageDecoderBackend;    // обратно към бекенда по подразбиране
end;

Разгръщането получава едно удобство и една съзнателна въздържаност. Ако директорията на кодека съдържа поддиректория modules\coders, библиотеката попълва променливите на средата за кодека, от които такова оформление се нуждае, но само когато хостовото приложение вече не ги е задало. Приложение със своя собствена стратегия за разгръщане на средата за изпълнение я запазва

Защо PNG по средата?

Свързването през PNG в паметта, вместо чрез сурова буферна памет с пиксели, изглежда като допълнителна стъпка, а всъщност е най-евтината правилна такава. PNG изразява всичко, което трябва да оцелее — алфа канал, тип цвят, битова дълбочина и вграден ICC профил — а библиотеката вече има зрял, добре тестван път от PNG в обект на изображение на PDF с правилните филтри и цветово пространство. Повторното му използване означава, че модерните формати наследяват години коректностна работа, вместо да получат паралелна реализация

Мостът е изцяло в паметта, така че не се създават временни файлове и не е нужно почистване при срив. Една подробност изискваше изрична обработка: някои преобразувания изпускат ICC профила при смяна на формата. Затова бекендът улавя изходния профил преди смяната на формата, компресира го с Flate, изгражда валиден блок iCCP с преизчислена CRC, и премахва всеки блок sRGB, който би влязъл в конфликт с него. При тестване декодиран AVIF запази 16-битов RGBA с 16-битов алфа канал, а профилът, извлечен от получения PDF, съвпадна с изходния профил байт по байт при 60 960 байта

Практически бележки, преди да го включите в продукция

Проверете наличността при стартиране, а не при първата снимка. ModernImageCodecAvailable отчита дали може да се използва бекенд, а SetModernImageCodecLibrary сочи към изричен файл или директория, когато разгръщането ви поставя кодека на нестандартно място:

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

Следете размера на файла на резултата. 16-битово RGBA изображение с вграден профил е голям обект на изображение в PDF, а отчет с четиридесет такива ще бъде голям. Когато документът е предназначен за преглед на екран, а не за печат, намаляването на резолюцията преди вграждане е правилният компромис, а общите лостове за размер са разгледани в оптимизация на размера на PDF файл

Накрая, решете политиката за цвят съзнателно. Запазването на изходния профил е правилно за архивна и печатна работа; преобразуването в пространство за целия документ е правилно, когато смесен набор от снимки трябва да изглежда последователно, а маршрутът на преобразуване е описан в прецветяване на документ в друго цветово пространство. Ако трябва да потвърдите какво всъщност е попаднало във файла, пътят за инспекция в извличане на текст, изображения и шрифтове отчита обектите на изображения, които документ носи

Вход за модерни изображения, управление на цвета и оптимизация на изображения са част от една и съща библиотека за Delphi, C++Builder и Free Pascal; пълният списък с функции е на страницата на PDF Library for Delphi