Skannattu lääketieteellinen leike, ilmakuvauksen ruutu, täydellä dynaamisella alueella arkistoitu filmiruutu. Nämä ovat kuvia, jotka saapuvat JPEG 2000 -muodossa, ja ne saapuvat sellaisina syystä. Muoto säilyttää 12 tai 16 bittiä kanavaa kohti, pakkaa aallokemuunnoksella (wavelet transform) JPEG:n käyttämän lohko-DCT:n sijaan, ja voi koodata saman kuvan joko häviöttömästi tai häviöllisesti yhdestä koodivirrasta. Kun näistä lähteistä rakennetun asiakirjan on muututtava PDF:ksi, kuvan on kuljettava suodattimen läpi, jonka PDF-määrittely varaa juuri tätä koodekkia varten
HotPDF v2.228.0 palautti toimivan JPEG 2000 -purkumoottorin kyseiselle polulle. Aiempi koontiversio oli toimittanut yksikön tynkäfunktioilla, jotka palauttivat nil, joten ohjelmointirajapinta oli olemassa mutta ei purkanut mitään. Nykyinen moottori sitoo OpenJPEG 2.5.4:n staattisesti ja muuttaa JP2- tai J2K-lähteen pikseleiksi, jotka HotPDF voi sijoittaa sivulle
JPXDecode-suodatin PDF:ssä
ISO 32000-1 määrittelee JPXDecode-suodattimen kohdassa 7.4.9. PDF:n kuva-XObject nimeää pakkauksensa virtasanakirjan /Filter-merkinnässä, ja JPXDecode on arvo, joka kertoo virtadatan olevan JPEG 2000 -koodivirta perus-JPEG:n sijaan, jota /DCTDecode kantaa. Tämä suodatin sallii PDF:n sisältää aallokepakattua kuvadataa suurella bittisyvyydellä, ja se hyväksyy koodekin sekä häviöttömän että häviöllisen tilan, koska tila on itse koodivirran ominaisuus eikä sen ympärillä olevan kääreen
Tuo viimeinen kohta on syytä pitää mielessä. JPEG 2000 on yksittäinen algoritmi, jolla on häviötön erikoistapaus, ei kaksi erillistä muotoa. Käännettävä 5/3-aalloke rekonstruoi alkuperäiset näytteet tarkasti; peruuttamaton 9/7-aalloke vaihtaa tuon tarkkuuden pienempään tiedostoon. Purkaja käsittelee molempia lukuhetkellä samalla tavalla, minkä vuoksi HotPDF tarvitsee vain yhden purkupolun hyväksyäkseen kaiken, mitä JPXDecode-virta sille heittää
Mitä purkaja tekee pikseleille
PDF:n kuva-XObjectit odottavat yleisessä tapauksessa 8 bittiä komponenttia kohti DeviceGray- tai DeviceRGB-väriavaruuksissa. JPEG 2000 ylittää tämän rutiininomaisesti, ja sen komponenttimalli on yleisempi kuin pakatun rasterin, joten purkajalla on kolme tehtävää ennen kuin data on käyttökelpoista normaalina kuvana
Ensinnäkin, suuren bittisyvyyden komponentit uudelleennäytteistetään 8 bittiin. 12-bittinen tai 16-bittinen näyte skaalataan alaspäin välille 0–255, jotta tulos on tavallinen 8-bittinen rasteri. Etumerkilliset komponentit siirretään ensin etumerkittömälle alueelle. Tällä yksityiskohdalla on merkitystä, koska se on jo itsessään häviöllinen: 16-bittinen harmaasävyskannaus menettää syvän sävyalueensa heti, kun siitä tulee 8-bittinen PDF-kuva, mikä on oikea kompromissi ruutu- ja tulostuskäytössä mutta ei uudelleenarkistoinnissa
Toiseksi, YCbCr-väriavaruus (koodekki kutsuu sitä SYCC:ksi) muunnetaan RGB:ksi. JPEG 2000 tallentaa värin usein luma-kroma-avaruuteen (luma-chroma) pakkaustehokkuuden vuoksi – sama idea, jota perus-JPEG käyttää – ja purkaja soveltaa standardia käänteismuunnosta, jotta sivu saa aitoa RGB:tä
Kolmanneksi, alinäytteistetyt komponentit ylinäytteistetään lähimmän naapurin toistolla (nearest-neighbor replication). Kromakanavat tallennetaan usein puolella resoluutiolla, joten purkaja lukee jokaisen komponentin sen omilla mitoilla ja omalla näytteenottokertoimella, ja toistaa sitten näytteitä tuodakseen jokaisen kanavan täyteen kuvakokoon ennen lomitusta. Lähimmän naapurin menetelmä pitää askeleen kevyenä; sen täyttämä kroma oli alun perinkin matalataajuista, joten visuaalinen hinta on pieni
JP2-laatikot vastaan raaka J2K-koodivirta
JPEG 2000 -tiedostoa on kahta muotoa, ja HotPDF tunnistaa luettavan muodon ensimmäisistä tavuista eikä tiedostotunnisteesta. JP2-tiedosto on laatikkopohjainen säiliö: se alkaa kaksitoistatavuisella allekirjoituslaatikolla 00 00 00 0C 6A 50 20 20 ja käärii koodivirran laatikoiden rinnalle, jotka kuvaavat väriavaruutta, resoluutiota ja metatietoja. Raaka J2K-koodivirta ei sisällä lainkaan säiliötä ja alkaa SOC-merkillä FF 4F FF 51. Purkaja lukee nämä alkutavut, tunnistaa allekirjoituksen ja valitsee sopivan OpenJPEG-koodekin kullekin tapaukselle
Molemmat muodot käsitellään, koska molempia esiintyy luonnossa. Kaappauslaitteet ja arkistot, jotka tarvitsevat oheismetatietoja, tuottavat JP2:ta; työkalut, jotka haluavat pienimmän mahdollisen hyötykuorman, tuottavat paljaan koodivirran. Muototyyppi on mallinnettu enumina, TJpeg2000FileType, jonka jäsenet ovat jtInvalid, jtJP2, jtJ2K ja jtJPT. JPT-jäsen nimeää JPIP-suoratoistomuunnoksen; tavuallekirjoituksen tunnistin ratkaisee ne kaksi muotoa, jotka se pystyy purkamaan (JP2 ja J2K), ja raportoi kaiken muun tyyppinä jtInvalid, jotta tukematon syöte epäonnistuu siististi sen sijaan, että se tuottaisi roskaa
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;
Häviötön ja häviöllinen koodauspuolella
Purkaja lukee molempia tiloja ilman, että sille kerrotaan kumpi se on. Valinnasta tulee parametri vasta, kun menet toiseen suuntaan ja tuotat JPEG 2000 -tiedoston, minkä HotPDF voi myös tehdä TJpeg2000Bitmap-luokan kautta. Se on TBitmap-jälkeläinen, joka lataa ja tallentaa rasteridataa JP2-muodossa. Kaksi ominaisuutta ohjaa tulostetta. LosslessCompression on totuusarvo, joka valitsee käännettävän aallokkeen ollessaan tosi; CompressionQuality on TJpeg2000QualityRange, kokonaisluku 1:stä 100:aan, missä 1 on pieni ja ruma ja 100 on suuri ja uskollinen. Oletukset sijaitsevat nimetyissä vakioissa: Jpeg2000DefaultLosslessCompression on False ja Jpeg2000DefaultLossyQuality on 80
Päätös on sisältöön liittyvä päätös. Häviötön sopii isäntäkopioon (master copy), lääketieteelliseen tai juridiseen skannaukseen, kaikkeen mitä voidaan joutua koodaamaan uudelleen myöhemmin ja johon ei saa kertyä sukupolvien yli tapahtuvaa laadun heikkenemistä. Häviöllinen laadulla 80 sopii ruudulle tai tulostukseen menevään kuvaan, jossa aallokkeen siro heikkeneminen tuottaa huomattavasti pienemmän tiedoston ilman artefakteja, joita lukija huomaisi. Yksi CMYK-varoitus on nostettava esiin: bittikartta tarjoaa SetCMYK-kutsun nelikanavaisen datan merkitsemiseen CMYK:ksi RGBA:n sijaan. Tällä on merkitystä tulostusputkille, jotka pitävät erottelut ehjinä
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;
Miksi latauksessa tapahtuvaa purkuputkea ei ole
Yksi arkkitehtuurinen tosiasia muokkaa sitä, miten käytät mitään tästä, ja on helppo olettaa päinvastoin. HotPDF:ssä ei ole yleistä lataushetkellä tapahtuvaa kuvien purkusuodatinta (decode-on-load). Kun avaat PDF:n, joka sisältää jo JPXDecode-kuvan, moottori ei pura tuota virtaa. Se pitää JPEG 2000 -tavut täsmälleen sellaisina kuin ne ovat, joten sivun kopiointi tai asiakirjan yhdistäminen vie kuvan läpi koskemattomana, tavu tavulta. Purkajalla on yksittäinen aloituspiste, ja se on luomispuolella: tiedostopohjainen AddImage, joka ohjataan tiedostotunnisteen perusteella käsittelemään .jp2-, .j2k-, .jpt- ja .jpc-lähteitä
Tämä jako on oikea rakenne eikä rajoitus. Upotetun JPX-virran purkaminen ladattaessa vain sen uudelleenkoodaamiseksi tallennettaessa muuttaisi häviöttömästi arkistoidun kuvan häviölliseksi ja paisuttaisi jokaista yhdistämistä, vain siksi, että halusit siirtää kuvan yhdestä PDF:stä toiseen. Virran läpivienti sellaisenaan on häviötön ja nopea toimenpide. Purkaminen lykätään ainoaan hetkeen, jolloin sitä todella vaaditaan: kun ojennat moottorille JPEG 2000 -tiedoston levyltä ja pyydät sitä rasteroimaan kyseisen kuvan uudelle sivulle sijoittamista varten. Tässä vaiheessa tiedoston on muututtava pikseleiksi, ja purkaja käynnistyy
Tuen rekisteröinti ja kuvan sijoittaminen
JPEG 2000 -kuvien rekisteröinti on vapaaehtoinen (opt-in) ominaisuus HPDF_REGISTER_JPEG2000_PICTURE -käännöskytkimen takana, joka on oletuksena pois päältä. Syynä on todellinen konflikti, ei varovaisuus: jp2-, j2k- ja jpc-tiedostomuotojen rekisteröiminen globaalisti TPicture-luokalle voi häiritä ReportBuilderin TppDBImage:n luottamaa BLOB-muodon tunnistusta. Määrittele kytkin silloin, kun tuo integraatio ei ole käytössä, ja tiedostomuodot rekisteröidään niin, että TPicture tunnistaa ne; jätä se määrittelemättä ja AddImage:n tunnistepohjainen ohjaus purkaa silti JPEG 2000 -tiedostoja suoraan, koska se polku ei mene TPicture:n kautta ollenkaan
Kun tämä on ymmärretty, JPEG 2000 -kuvan sijoittaminen noudattaa samaa kolmen kutsun rytmiä kuin minkä tahansa muun HotPDF-kuvan kohdalla. Anna AddImage-kutsulle .jp2-polku ja pakkaustyyppi, joka määrittää, miten kuva tulisi tallentaa tulosteeseen, ja aseta palautettu kuvaindeksi sitten sivulle ShowImage-kutsulla
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;
Pakkaus, jonka välität AddImage-kutsulle, ohjaa sitä, miten purettu kuva tallennetaan uudelleen, ei sitä, miten se luettiin. Bittikartaksi purettu JPEG 2000 -tiedosto voi palata ulos DCTDecode JPEG:nä, Flate-rasterina tai muuna tuettuna suodattimena – mikä tahansa asiakirjaan sopiikin. Purkaminen JP2:sta tai J2K:sta tapahtuu ensin joka tapauksessa, joten sama kutsu hyväksyy aallokepakatun lähteen ja upottaa sen missä tahansa muodossa, jota putkesi loppuosa odottaa
Jos haluat laajemman kuvan siitä, kuinka kuvat ja fontit päätyvät luotuun tulosteeseen, katso huomiomme raporttien tulostuksesta fonttien ja kuvien kera. Kun kokoamasi asiakirja käyttää uudelleen sisältöä olemassa olevista PDF-tiedostoista, tässä kuvattu läpivientikäyttäytyminen (passthrough) yhdistyy artikkelissa objektivirrat ja inkrementaaliset päivitykset kuvattuihin yhdistämis- ja versiomekaniikkoihin. JPEG 2000 -purkumoottori toimitetaan osana HotPDF-komponenttia Delphille ja C++Builderille, yhdessä kuva-, fontti- ja asiakirjaohjelmointirajapintojen kanssa, joita käsitellään muualla tässä blogissa