Tehnicki clanak

Dodavanje JPEG 2000 slika u PDF-ove u Delphi-ju pomocu HotPDF-a

Skenirani medicinski preparat, aerofotogrametrijska ploca, filmski kadar arhiviran sa punim dinamickim opsegom. To su slike koje stizu u JPEG 2000 formatu, i stizu tako iz razloga. Format cuva 12 ili 16 bita po kanalu, kompresuje wavelet transformacijom umesto blok DCT koji JPEG koristi, i moze kodirati istu sliku bez gubitaka ili sa gubicima iz jednog codestream-a. Kada dokument izgraden od tih izvora mora postati PDF, slika mora proci kroz filter koji PDF specifikacija rezervise upravo za ovaj kodek

HotPDF v2.228.0 obnovio je funkcionalni JPEG 2000 decode engine za tu putanju. Ranija verzija isporucila je jedinicu sa stub funkcijama koje su vracale nil, pa je API postojao ali nista nije dekodirao. Trenutni engine vezuje OpenJPEG 2.5.4 staticno i pretvara JP2 ili J2K izvor u piksele koje HotPDF moze postaviti na stranicu

JPXDecode filter u PDF-u

ISO 32000-1 definise JPXDecode filter u paragraf 7.4.9. PDF image XObject imenuje svoju kompresiju u unosu /Filter recnika toka, a JPXDecode je vrednost koja govori da su podaci toka JPEG 2000 codestream, a ne baseline JPEG koji nosi /DCTDecode. Filter je ono sto omogucava PDF-u da cuva wavelet-kompresovane podatke slike sa visokim bit-depth-om, i prihvata i lossless i lossy rezime kodeka, jer je rezim svojstvo samog codestream-a, a ne omotaca oko njega

Ta poslednja tacka je vredna pamcenja. JPEG 2000 je jedan algoritam sa lossless posebnim slucajem, a ne dva odvojena formata. Reverzibilni 5/3 wavelet rekonstruise originalne uzorke tacno; ireverzibilni 9/7 wavelet trguje tu tacnost za manju datoteku. Dekoder oba tretira na isti nacin pri citanju, sto je razlog zasto HotPDF treba samo jednu putanju dekodiranja da prihvati sta god mu JPXDecode tok donese

Sta dekoder radi sa pikselima

PDF image XObject-i u uobicajenom slucaju ocekuju 8 bita po komponenti u DeviceGray ili DeviceRGB. JPEG 2000 to rutinski premashuje, a njegov model komponenti je opstiji od pakovanog rastera, pa dekoder ima tri posla da obavi pre nego sto podaci budu upotrebljivi kao normalna slika

Prvo, komponente visokog bit-depth-a ponovo se uzorkuju na 8 bita. Uzorak od 12 ili 16 bita skalira se na opseg 0 do 255 da bi rezultat bio obicni 8-bitni raster. Potpisane komponente se prethodno pomeraju u nepotpisani opseg. Detalj je vazan jer je sam po sebi sa gubicima: 16-bitni sivi sken gubi svoju duboku tonsku skalu cim postane 8-bitna PDF slika, sto je ispravan kompromis za prikaz na ekranu i stampanje, ali ne i za ponovnu arhivaciju

Drugo, YCbCr (kodek to naziva SYCC) prostor boja konvertuje se u RGB. JPEG 2000 cesto cuva boje u prostoru luma-hroma radi efikasnosti kompresije, ista ideja kao kod baseline JPEG-a, i dekoder primenjuje standardnu inverznu transformaciju da stranica dobije pravi RGB

Trece, poduzorkovane komponente uzorkuju se naviše metodom replikacije najblizeg suseda. Hroma kanali se cesto cuvaju na polovicnoj rezoluciji, pa dekoder cita svaku komponentu na njenim dimenzijama i njenim faktorom uzorkovanja, a zatim replicira uzorke da sve kanale dovede na punu velicinu slike pre isprepletanja. Najblizi sused drzi taj korak jeftinim; hroma koja se popunjava bila je niske frekvencije od pocetka, pa je vidljivi trosak mali

JP2 kutije nasuprot sirovog J2K codestream-a

JPEG 2000 datoteka dolazi u dva oblika, i HotPDF otkriva koji cita na osnovu prvih bajtova, a ne na osnovu ekstenzije datoteke. JP2 datoteka je kontejner strukturiran kutijama: otvara se dvanaestbajtnom kutijom potpisa 00 00 00 0C 6A 50 20 20 i obmotava codestream pored kutija koje opisuju prostor boja, rezoluciju i metapodatke. Sirovi J2K codestream ne nosi nikakav kontejner i pocinje SOC markerom FF 4F FF 51. Dekoder cita te pocetne bajtove, prepoznaje potpis i bira odgovarajuci OpenJPEG kodek za svaki slucaj

Oba oblika su podrzana jer se oba pojavljuju u praksi. Uredaji za snimanje i arhive kojima su potrebni pratedeci metapodaci emituju JP2; alati koji zele najmanji moguc teret emituju goli codestream. Tip formata je modeliran kao enum TJpeg2000FileType sa clanovima jtInvalid, jtJP2, jtJ2K i jtJPT. Clan JPT imenuje JPIP streaming varijantu; detektor bajt-potpisa razresava dva oblika koja moze da dekodira, JP2 i J2K, a sve ostalo prijavljuje kao jtInvalid pa nepodrzani ulaz ne uspeva cisto umesto da proizvodi smece

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;

Lossless i lossy na strani enkodera

Dekoder cita oba rezima bez da mu se kaze koji je. Izbor postaje parametar tek kada idete u suprotnom smeru i pravite JPEG 2000 datoteku, sto HotPDF moze da uradi i putem klase TJpeg2000Bitmap, naslednika TBitmap koji ucitava i cuvaju rasterske podatke kao JP2. Dva svojstva upravljaju izlazom. LosslessCompression je boolean koji bira reverzibilni wavelet kada je tacno; CompressionQuality je TJpeg2000QualityRange, celi broj od 1 do 100 gde je 1 mali i ruzan a 100 veliki i veran. Podrazumevane vrednosti zive u imenovanim konstantama: Jpeg2000DefaultLosslessCompression je False a Jpeg2000DefaultLossyQuality je 80

Odluka je odluka o sadrzaju. Lossless odgovara matnoj kopiji, medicinskom ili pravnom skenu, svemu sto moze biti ponovo kodirano kasnije i ne sme akumulirati generacijski gubitak. Lossy na kvalitetu 80 odgovara slici namenjenoj ekranu ili stampi, gde graciozan pad wavelet kodeka daje primetno manju datoteku bez artefakta koji bi citaoc primetio. Postoji jedna CMYK napomena vredna isticanja: bitmap izlaze SetCMYK za oznacavanje cetvorookanalnih podataka kao CMYK umesto RGBA, sto je vazno za stamparske tokove koji cuvaju separacije netaknutima

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;

Zasto ne postoji filter za dekodiranje pri ucitavanju

Jedna arhitektonska cinjenica oblikuje kako koristite sve ovo, i lako je pretpostaviti suprotno. HotPDF nema opsti filter za dekodiranje slika pri ucitavanju. Kada otvorite PDF koji vec sadrzi JPXDecode sliku, engine ne dekodira taj tok. Cuva JPEG 2000 bajtove tacno onako kako jesu, pa kopija stranice ili spajanje dokumenata prenosi sliku netaknutu, bajt po bajt. Dekoder ima jednu ulaznu tacku, i ona je na strani kreiranja: AddImage koji prima datoteku, preusmeren prema ekstenziji datoteke da obradi izvore .jp2, .j2k, .jpt i .jpc

To razdvajanje je ispravan dizajn, a ne ogranicenje. Dekodiranje ugradenog JPX toka pri ucitavanju, samo da bi ga se ponovo kodiralo pri cuvanju, pretvorilo bi lossless arhivsku sliku u lossy i nadulo bi svako spajanje, sve za sliku koju ste samo nameravali premestiti iz jednog PDF-a u drugi. Prosledivanje toka verbatim je lossless operacija i brza. Dekodiranje se odlaze do jednog trenutka kada je zaista potrebno: kada engine predate JPEG 2000 datoteku sa diska i zatrazite da rasterizuje tu sliku za postavljanje na novu stranicu. U tom trenutku datoteka mora postati pikseli, i dekoder se pokrace

Registrovanje podrske i postavljanje slike

Registracija JPEG 2000 slika je opt-in iza switch za kompajliranje HPDF_REGISTER_JPEG2000_PICTURE, koji je podrazumevano iskljucen. Razlog je stvarni sukob, a ne oprez: globalno registrovanje formata datoteka jp2, j2k i jpc sa TPicture moze ometati detekciju BLOB formata na koji se oslanja TppDBImage iz ReportBuilder-a. Definisajte switch kada ta integracija nije u upotrebi, i formati datoteka se registruju pa ih TPicture prepoznaje; ostavite ga nedefinisanim i dispatch prema ekstenziji u AddImage jos uvek direktno dekodira JPEG 2000 datoteke, jer ta putanja uopste ne prolazi kroz TPicture

S tim razumevanjem, postavljanje JPEG 2000 slike je isti ritam tri poziva kao i za svaku drugu sliku u HotPDF-u. Predate AddImage putanju .jp2 i tip kompresije za nacin cuvanja slike u izlazu, zatim pozicionirate vraceni indeks slike na stranicu sa 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;

Kompresija koju prosledujete u AddImage kontrolise kako se dekodirana slika ponovo cuva, a ne kako je procitana. JPEG 2000 datoteka dekodirana u bitmap moze izaci kao DCTDecode JPEG, Flate raster, ili drugi podrzani filter, koji god odgovara dokumentu. Dekodiranje iz JP2 ili J2K dogada se prvo bez obzira, pa isti poziv prihvata wavelet-kompresovani izvor i ugraduje ga u koji god oblik ostatak vaseg toka rada ocekuje

Za siru sliku toga kako slike i fontovi dospevaju u generisani izlaz, pogledajte nase beleske o izlazu izvestaja sa fontovima i slikama. Kada dokument koji sastavljate ponovo koristi sadrzaj iz postojecih PDF-ova, ponasanje prosledivanja opisano ovde ide zajedno sa mehanikom spajanja i revizija u objektnim tokovima i inkrementalnim azuriranjima. JPEG 2000 decode engine isporucuje se kao deo HotPDF Component za Delphi i C++Builder, zajedno sa API-jima za slike, fontove i dokumente obradenim drugde na ovom blogu