Сканиран медицински препарат, аерофотоснимка за геодезия, кадър от филм, архивиран с пълен динамичен диапазон. Това са изображенията, пристигащи като JPEG 2000, и причината да бъдат такива е основателна. Форматът запазва 12 или 16 бита на канал, компресира с уейвлет трансформация вместо блоковия DCT, използван от JPEG, и може да кодира едно и също изображение или без загуби, или с загуби от един кодов поток. Когато документ, изграден от тези източници, трябва да стане PDF, изображението трябва да премине през филтър, запазен от PDF спецификацията именно за този кодек
HotPDF v2.228.0 възстанови работещ JPEG 2000 декодиращ двигател за този path. По-ранна версия беше доставила модула с stub функции, връщащи nil, така че API-то съществуваше, но не декодираше нищо. Текущият двигател статично свързва OpenJPEG 2.5.4 и превръща JP2 или J2K источник в пиксели, които HotPDF може да постави на страница
Филтърът JPXDecode в PDF
ISO 32000-1 дефинира филтъра JPXDecode в §7.4.9. Image XObject в PDF посочва компресията си в записа /Filter на речника на потока, а JPXDecode е стойността, указваща, че данните в потока са JPEG 2000 кодов поток, а не базовото JPEG, пренасяно от /DCTDecode. Филтърът позволява на PDF да съдържа уейвлет-компресирани данни на изображения с висока битова дълбочина и приема и двата режима на кодека без загуби и с загуби, тъй като режимът е свойство на самия кодов поток, а не на обвивката около него
Последната точка е тази, която трябва да запомните. JPEG 2000 е единствен алгоритъм с частен случай без загуби, а не два отделни формата. Обратимото уейвлет 5/3 пресъздава оригиналните стойности точно; необратимото уейвлет 9/7 разменя тази точност срещу по-малък файл. Декодерът третира двата по еднакъв начин при четене, затова HotPDF се нуждае само от един декодиращ path, за да приема всичко, което JPXDecode поток може да предложи
Какво прави декодерът с пикселите
PDF image XObject обектите в обичайния случай очакват 8 бита на компонент в DeviceGray или DeviceRGB. JPEG 2000 редовно надхвърля това, а моделът му на компоненти е по-общ от опакован растер, затова декодерът трябва да извърши три операции, преди данните да могат да се използват като нормално изображение
Първо, компонентите с висока битова дълбочина се преизчисляват до 8 бита. Стойност от 12 или 16 бита се мащабира до диапазона от 0 до 255, така че резултатът да е обикновен 8-битов растер. Знаковите компоненти първо се прехвърлят в беззнаков диапазон. Детайлът е важен, защото сам по себе си представлява загуба: 16-битово сканиране в сива скала губи дълбокия си тонален диапазон в момента, в който стане 8-битово PDF изображение, което е правилната размяна за показване на екран и печат, но не и за повторно архивиране
Второ, цветовото пространство YCbCr (кодекът го нарича SYCC) се преобразува в RGB. JPEG 2000 често съхранява цвят в пространство яркост-цветност за ефективност на компресията, същата идея, използвана от базовото JPEG, и декодерът прилага стандартната обратна трансформация, за да получи страницата истинско RGB
Трето, субдискретизираните компоненти се интерполират чрез репликация на най-близкия съсед. Цветностните канали често се съхраняват с половин резолюция, затова декодерът чете всеки компонент с неговите размери и неговия коефициент на дискретизация, след което репликира стойности, за да доведе всеки канал до пълния размер на изображението преди комбиниране. Методът на най-близкия съсед поддържа операцията евтина; цветността, която се запълва, е нискочестотна по природа, така че видимата цена е малка
JP2 кутии срещу необработен J2K кодов поток
JPEG 2000 файл съществува в два варианта, а HotPDF установява кой чете от първите байтове, а не от разширението на файла. JP2 файлът е контейнер с кутийна структура: отваря се с 12-байтова кутия с подпис 00 00 00 0C 6A 50 20 20 и обгражда кодовия поток заедно с кутии, описващи цветово пространство, резолюция и метаданни. Необработеният J2K кодов поток не съдържа никакъв контейнер и започва с маркера SOC FF 4F FF 51. Декодерът чете тези начални байтове, разпознава подписа и избира съответния OpenJPEG кодек за всеки случай
И двата варианта са поддържани, тъй като и двата се срещат на практика. Устройства за заснемане и архиви, нуждаещи се от страничните метаданни, генерират JP2; инструменти, искащи минимален товар, генерират необработения кодов поток. Типът на формата е моделиран като изброен тип TJpeg2000FileType с членовете jtInvalid, jtJP2, jtJ2K и jtJPT. Членът JPT обозначава вариант за поточно предаване JPIP; детекторът на байтови подписи разрешава двата варианта, които може да декодира, JP2 и J2K, и докладва всичко останало като jtInvalid, така че неподдържан вход се проваля чисто, вместо да произвежда безсмислен резултат
uses
HPDFJpeg2000;
var
Decoder: THPDFJpeg2000Decoder;
Pixels: TJpeg2000ByteArray;
begin
Decoder := THPDFJpeg2000Decoder.Create;
try
if Decoder.LoadFromStream(Input) then // JP2 or J2K, auto-detected
if Decoder.GetImageData(Pixels) then
// Pixels is 8-bit interleaved, ColorComponents channels wide,
// row-major top to bottom: ready for a DeviceGray/DeviceRGB XObject.
ProcessRaster(Decoder.Width, Decoder.Height,
Decoder.ColorComponents, Pixels);
finally
Decoder.Free;
end;
end;
Без загуби и с загуби при кодиране
Декодерът чете и двата режима, без да му се казва кой е. Изборът се превръща в параметър само когато вървите в обратна посока и създавате JPEG 2000 файл, което HotPDF може да прави и чрез класа TJpeg2000Bitmap, наследник на TBitmap, зареждащ и записващ растерни данни като JP2. Два атрибута управляват изхода. LosslessCompression е булева стойност, която при True избира обратимото уейвлет; CompressionQuality е TJpeg2000QualityRange, цяло число от 1 до 100, където 1 е малко и грозно, а 100 е голямо и вярно. Стойностите по подразбиране са в именувани константи: Jpeg2000DefaultLosslessCompression е False, а Jpeg2000DefaultLossyQuality е 80
Изборът е решение за съдържанието. Компресията без загуби подхожда за мастер копие, медицинско или правно сканиране, всичко, което може да бъде прекодирано по-късно и не трябва да натрупва поколенчески загуби. Компресия с загуби при качество 80 подхожда за изображение, предназначено за екран или печат, където плавната деградация на уейвлета дава забележимо по-малък файл без артефакти, видими за читателя. Има едно предупреждение за CMYK: битмапът предоставя SetCMYK, за да маркира четириканалните данни като CMYK, а не RGBA, което е от значение за печатни тръбопроводи, запазващи цветовите разделения непокътнати
uses
HPDFJpeg2000;
var
Bmp: TJpeg2000Bitmap;
begin
Bmp := TJpeg2000Bitmap.Create;
try
Bmp.LoadFromStream(Source); // decode an existing JP2/J2K
Bmp.LosslessCompression := True; // reversible 5/3 wavelet
// or, for a smaller lossy file:
// Bmp.LosslessCompression := False;
// Bmp.CompressionQuality := 80; // matches the default
Bmp.SaveToStream(Output); // always writes a JP2 file
finally
Bmp.Free;
end;
end;
Защо не съществува филтърен pipeline за декодиране при зареждане
Един архитектурен факт определя начина на използване на всичко това и лесно може да се предположи обратното. HotPDF няма общ филтър за декодиране на изображения при зареждане. Когато отворите PDF, вече съдържащ JPXDecode изображение, двигателят не декодира този поток. Той запазва JPEG 2000 байтовете точно такива, каквито са, така че копирането на страница или обединяването на документи пренася изображението непокътнато, байт по байт. Декодерът има единствена входна точка и тя е от страната на създаването: файловият AddImage, разпределян по разширение на файла за обработка на източници .jp2, .j2k, .jpt и .jpc
Това разделяне е правилният дизайн, а не ограничение. Декодирането на вграден JPX поток при зареждане, само за да бъде прекодиран при запис, би превърнало архивирано изображение без загуби в такова с загуби и би раздуло всяко обединяване, и всичко това за изображение, което само сте искали да преместите от един PDF в друг. Пропускането на потока буква по буква е операция без загуби и бърза. Декодирането се отлага за единствения момент, в който е наистина необходимо: когато предадете на двигателя JPEG 2000 файл от диск и поискате да растеризира изображението за поставяне на нова страница. В този момент файлът трябва да стане пиксели и декодерът се изпълнява
Регистриране на поддръжка и поставяне на изображение
Регистрирането на JPEG 2000 изображения е по избор чрез компилационния превключвател HPDF_REGISTER_JPEG2000_PICTURE, изключен по подразбиране. Причината е реален конфликт, а не предпазливост: глобалното регистриране на файловите формати jp2, j2k и jpc с TPicture може да попречи на BLOB формат детекцията, на която разчита TppDBImage на ReportBuilder. Дефинирайте превключвателя, когато тази интеграция не е активна, и файловите формати се регистрират, така че TPicture да ги разпознава; оставете го недефиниран и разпределянето по разширение на AddImage все още декодира JPEG 2000 файлове директно, тъй като този path изобщо не минава през TPicture
Като се разбере това, поставянето на JPEG 2000 изображение следва същия ритъм от три повиквания като при всяко друго изображение в HotPDF. Предайте на AddImage path до .jp2 файл и тип компресия за начина, по който изображението да се съхрани в изхода, след което позиционирайте върнатия индекс на изображението на страницата с ShowImage
var
Pdf: THotPDF;
ImgIndex: Integer;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.BeginDoc;
Pdf.AddPage;
// The .jp2 source is decoded through the OpenJPEG backend, then
// re-embedded with the compression you request here.
ImgIndex := Pdf.AddImage('Scan_16bit.jp2', icJpeg);
// x, y, width, height in points; final 0 is the rotation angle.
Pdf.ShowImage(ImgIndex, 72, 72, 400, 300, 0);
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
Компресията, която предавате на AddImage, контролира как декодираното изображение се съхранява отново, а не как е прочетено. JPEG 2000 файл, декодиран до битмап, може да бъде записан обратно като DCTDecode JPEG, Flate растер или друг поддържан филтър, в зависимост от нуждите на документа. Декодирането от JP2 или J2K се случва първо във всеки случай, така че същото повикване приема уейвлет-компресиран источник и го вгражда в каквато форма останалата ви тръба очаква
За по-широка представа как изображенията и шрифтовете попадат в генерирания изход вижте нашите бележки за изходни данни на отчети с шрифтове и изображения. Когато документът, който сглобявате, използва повторно съдържание от съществуващи PDF файлове, поведението на преминаване, описано тук, се съчетава с механиките за обединяване и ревизия в обектни потоци и инкрементални актуализации. JPEG 2000 декодиращият двигател се доставя като част от HotPDF Component за Delphi и C++Builder, наред с API-тата за изображения, шрифтове и документи, разгледани другаде в този блог