Tekninen artikkeli

JPEG 2000 -kuvien lisääminen PDF-tiedostoihin Delphissä HotPDF:n avulla

Skannattu lääketieteellinen dia, ilmakuvausruutu, filmiruutu arkistoituna koko dynaamiselle alueelle. Nämä ovat kuvia, jotka saapuvat JPEG 2000:na, ja ne saapuvat siihen suuntaan syystä. Muoto säilyttää 12 tai 16 bittiä kanavaa kohti, pakkaa aallokemuunnoksella JPEG:n käyttämän lohko DCT:n sijaan ja pystyy koodaamaan saman kuvan joko häviöttömänä tai häviöllisenä yhdestä koodivirrasta. Kun niistä lähteistä rakennetusta asiakirjasta tulee PDF, kuvan on kuljettava suodattimen läpi, jonka PDF-määritys varaa juuri tätä koodekkia varten

HotPDF v2.228.0 palautti toimivan JPEG 2000 -purkumoottorin kyseiselle tielle. Aiemmassa koontiversiossa yksikkö toimitettiin tynkätoiminnoilla, jotka palauttivat koodin nil, joten API 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-muodossa

ISO 32000-1 määrittelee JPXDecode-suodattimen kohdassa 7.4.9. PDF-kuvan XObject nimeää pakkauksensa virtasanakirjan /Filter-kohteessa, ja JPXDecode on arvo, joka sanoo, että virran data on JPEG 2000 -koodivirta pikemminkin kuin perusviivan JPEG, jota /DCTDecode sisältää. Suodatin on se, mikä sallii PDF:n säilyttää aallokepakattua kuvadataa, jolla on suuri bittisyvyys, ja se sallii sekä koodekin häviöttömän että häviöllisen tilan, koska tila on itse koodivirran, ei sen ympärillä olevan kääreen ominaisuus

Se viimeinen seikka on pitämisen arvoinen. JPEG 2000 on yksi algoritmi häviöttömällä erikoistapauksella, ei kahta erillistä muotoa. Käännettävä 5/3 aalloke rekonstruoi alkuperäiset näytteet tarkalleen; peruuttamaton 9/7-aalloke vaihtaa kyseisen tarkkuuden pienempään tiedostoon. Dekooderi käsittelee molempia samalla tavalla lukuhetkellä, minkä vuoksi HotPDF tarvitsee vain yhden purkupolut hyväksyäkseen sen, mitä tahansa JPXDecode-virta heittääkään siihen

Mitä dekooderi tekee pikseleille

PDF-kuvan XObjects odottavat tavallisesti 8 bittiä per komponentti DeviceGray:ssä tai DeviceRGB:ssä. JPEG 2000 ylittää säännöllisesti sen, ja sen komponenttimalli on yleisempi kuin pakattu rasteri, joten dekooderilla on kolme työtä tehtävänä, ennen kuin data on käytettävissä normaalikuvana

Ensin korkean bittisyvyyden komponentit otetaan uudelleen 8 bittiin. 12- tai 16-bittinen näyte pienennetään alueelle 0-255 siten, että tuloksena on tavallinen 8-bittinen rasteri. Allekirjoitetut komponentit siirretään ensin allekirjoittamattomalle alueelle. Yksityiskohdalla on merkitystä, koska se itsessään on häviöllinen: 16-bittinen harmaasävyskannaus menettää syvän sävyalueensa heti, kun siitä tulee 8-bittinen PDF-kuva, mikä on oikea kompromissi näytön ja tulostuksen suhteen, mutta ei uudelleen arkistoinnille

Toiseksi YCbCr (koodekki kutsuu sitä nimellä SYCC) -väriavaruus muunnetaan RGB:ksi. JPEG 2000 tallentaa usein värit luminanssiväriavaruuteen pakkauksen tehostamiseksi. Tämä on sama ajatus, jota perus-JPEG käyttää, ja dekooderi soveltaa standardia käänteistä muunnosta, jotta sivu saa aidon RGB:n

Kolmanneksi alinäytteenotetuista komponenteista otetaan näyte lähimmän naapurin replikaatiolla. Kromakanavat tallennetaan usein puolet tarkkuudella, joten dekooderi lukee jokaisen komponentin sen omilla mitoilla ja omalla näytteenottokertoimellaan ja kopioi sitten näytteitä tuodakseen jokaisen kanavan täyteen kuvan kokoon ennen lomitusta. Lähin naapuri pitää askeleen halpana; kromi, jota se täytti, oli alun alkaen matalataajuista, joten näkyvät kustannukset ovat pienet

JP2-laatikot verrattuna raaka-J2K-koodivirtaan

JPEG 2000 -tiedosto on kahdessa muodossa, ja HotPDF havaitsee kumpaa se lukee ensimmäisistä tavuista tiedostopäätteen sijaan. JP2-tiedosto on laatikkostrukturoitu säiliö: se avautuu kahdentoista tavun allekirjoituslaatikolla 00 00 00 0C 6A 50 20 20 ja käärii koodivirran laatikoiden rinnalle, jotka kuvaavat väriavaruutta, resoluutiota ja metadataa. Raaka J2K-koodivirta ei sisällä ollenkaan konttia, ja alkaa SOC-merkillä FF 4F FF 51. Dekooderi lukee nuo etutavut, tunnistaa allekirjoituksen ja valitsee kussakin tapauksessa vastaavan OpenJPEG-koodekin

Molemmat muodot käsitellään, koska molempia esiintyy luonnossa. Kaappaa laitteet ja arkistot, jotka tarvitsevat sivumetatietoja lähettävät JP2:n; työkalut, jotka haluavat pienimmän mahdollisen hyötykuorman, lähettävät paljaan koodivirran. Muototyyppi on mallinnettu enumina, TJpeg2000FileType, ja siinä on jäsenet jtInvalid, jtJP2, jtJ2K ja jtJPT. JPT-jäsen nimeää JPIP-suoratoistoversion; tavuallekirjoitusilmaisin ratkaisee kaksi sen purkamaa muotoa, JP2:n ja J2K:n, ja raportoi kaiken muun kuin jtInvalid, jotta ei-tuettu syöte epäonnistuu puhtaasti roskan tuottamisen sijaan

uses
  HPDFJpeg2000;

var
  Decoder: THPDFJpeg2000Decoder;
  Pixels: TJpeg2000ByteArray;
begin
  Decoder := THPDFJpeg2000Decoder.Create;
  try
    if Decoder.LoadFromStream(Input) then          // JP2 tai J2K, automaattisesti tunnistettu
      if Decoder.GetImageData(Pixels) then
        // Pixels on 8-bittinen lomitettu, ColorComponents -kanavien leveä,
        // rivitason tärkeimmät ylhäältä alas: valmiina DeviceGray/DeviceRGB XObjectille.
        ProcessRaster(Decoder.Width, Decoder.Height,
                      Decoder.ColorComponents, Pixels);
  finally
    Decoder.Free;
  end;
end;

Häviötön ja häviöllinen koodauspuolella

Dekooderi lukee molemmat tilat kertomatta kumpi on. Valinta muodostuu vain parametriksi, kun menet toiseen suuntaan ja tuotat JPEG 2000 -tiedoston, jonka HotPDF voi tehdä myös TJpeg2000Bitmap-luokan kautta, joka on TBitmap-jälkeläinen, joka lataa ja tallentaa rasteritiedot JP2:na. Kaksi ominaisuutta ohjaa tulostetta. LosslessCompression on boolen arvo, joka valitsee palautuvan aallon, kun se on tosi; CompressionQuality on koodi TJpeg2000QualityRange, kokonaisluku väliltä 1-100, jossa 1 on pieni ja ruma ja 100 on suuri ja uskollinen. Oletukset asuvat nimetyissä vakioissa: Jpeg2000DefaultLosslessCompression on False ja Jpeg2000DefaultLossyQuality on 80

Päätös on sisältöpäätös. Lossless sopii pääkopioon, lääketieteelliseen tai juridiseen skannaukseen, mihin tahansa sellaiseen, joka voidaan koodata myöhemmin uudelleen ja joka ei saa kerääntyä sukupolvitappiota. Häviöllinen laatuluokassa 80 sopii kuvalle suunnatulle ruudulle tai tulostukselle, jossa aallokkeen siro huonontuminen tuottaa huomattavasti pienemmän tiedoston ilman artefakteja, jotka lukija huomaisi. Varoituksena on yksi CMYK-varoitus: bittikartta paljastaa komennon SetCMYK, joka merkitsee nelikanavaisen datan CMYK:ksi RGBA:n sijaan, jolla on merkitystä painoputkissa, jotka pitävät erottelut ennallaan

uses
  HPDFJpeg2000;

var
  Bmp: TJpeg2000Bitmap;
begin
  Bmp := TJpeg2000Bitmap.Create;
  try
    Bmp.LoadFromStream(Source);              // pura olemassa oleva JP2/J2K
    Bmp.LosslessCompression := True;         // palautuva 5/3 aalloke
    // tai pienempi häviöllinen tiedosto:
    // Bmp.LosslessCompression := False;
    // Bmp.CompressionQuality := 80;         // vastaa oletusasetusta
    Bmp.SaveToStream(Output);                // kirjoittaa aina JP2-tiedoston
  finally
    Bmp.Free;
  end;
end;

Miksi latauksella purkavaa suodatinputkistoa ei ole

Yksi arkkitehtoninen tosiasia muokkaa sitä, miten käytät mitä tahansa näistä, ja päinvastoin on helppo olettaa. HotPDF:ssä ei ole yleistä lataamalla purettavaa kuvasuodatinta. Kun avaat PDF-tiedoston, joka sisältää jo JPXDecode-kuvan, moottori ei pura kyseistä virtaa. Se pitää JPEG 2000 -tavut täsmälleen sellaisina kuin ne ovat, joten sivu kopio tai dokumentin yhdistäminen kantaa kuvan läpi koskemattomana, tavu tavulta. Dekooderissa on yksi tulopiste, ja se on luomispuolella: tiedostopohjainen koodi AddImage, joka lähetetään tiedostotunnisteen kautta käsittelemään kohteita .jp2, .j2k, .jpt ja .jpc lähdettä

Tuo jako on oikea rakenne rajoituksen sijaan. Upotetun JPX-virran purkaminen latauksen yhteydessä ja sen koodaaminen uudelleen tallennuksen yhteydessä muuttaisi häviöttömän arkistoidun kuvan häviölliseksi ja paisuttaisi jokaisen yhdistämisen, kaikki kuvalle, jonka tarkoituksena oli vain siirtää PDF-tiedostosta toiseen. Virran ohittaminen sellaisenaan on häviötön ja nopea toiminta. Dekoodaus lykätään ainoaan hetkeen, jolloin sitä aidosti tarvitaan: kun ojennat koneelle JPEG 2000 -tiedoston levyltä ja pyydät sitä rasteroimaan kyseisen kuvan uudelle sivulle sijoittamista varten. Tässä vaiheessa tiedostosta on tultava pikseleitä ja dekooderi on käynnissä

Tuen rekisteröiminen ja kuvan sijoittaminen

JPEG 2000 -kuvien rekisteröinti on sallittava kääntökytkimen HPDF_REGISTER_JPEG2000_PICTURE takana, joka on oletuksena pois päältä. Syynä on todellinen konflikti, ei varovaisuus: tiedostomuotojen jp2, j2k ja jpc rekisteröiminen globaalisti komennolla TPicture voi häiritä ReportBuilderin komennon TppDBImage perustuvaa BLOB-muodon tunnistusta. Määritä kytkin, kun tuo integrointi ei ole pelissä, ja tiedostomuodot rekisteröidään niin koodi TPicture tunnistaa ne; jätä se määrittelemättä ja komennon AddImage laajennuksen lähetys purkaa JPEG 2000 -tiedostot suoraan, koska tämä polku ei mene ollenkaan komennon TPicture kautta

Tämän ymmärtäen JPEG 2000 -kuvan sijoittaminen tapahtuu samanlaisella kolmen puhelun rytmillä kuin mikään muukin HotPDF-kuva. Anna parametrille AddImage koodi .jp2-polku ja pakkaustyyppi sen määrittämiseksi, kuinka kuva tallennetaan tulostukseen, ja sijoita sitten palautettu kuvahakemisto sivulle komennolla ShowImage

var
  Pdf: THotPDF;
  ImgIndex: Integer;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.BeginDoc;
    Pdf.AddPage;
    // .jp2-lähde puretaan OpenJPEG-taustaosan kautta, sitten
    // upotettu uudelleen tässä pyytämälläsi pakkauksella.
    ImgIndex := Pdf.AddImage('Scan_16bit.jp2', icJpeg);
    // x, y, leveys, korkeus pisteinä; lopullinen 0 on kiertokulma.
    Pdf.ShowImage(ImgIndex, 72, 72, 400, 300, 0);
    Pdf.EndDoc;
  finally
    Pdf.Free;
  end;
end;

Koodille AddImage antamasi pakkaus ohjaa sitä, kuinka dekoodattu kuva tallennetaan uudelleen, ei sitä, kuinka se on luettu. Bittikartaksi dekoodattu JPEG 2000 -tiedosto voi palata DCTDecode JPEG -muodossa, Flate-rasterina tai muuna tuettuna suodattimena, kumpi tahansa asiakirjaan sopii. Purkaminen koodista JP2 tai J2K tapahtuu kuitenkin ensin, joten sama puhelu hyväksyy aallokepakatun lähteen ja upottaa sen missä tahansa muodossa muu putki odottaa

Saat laajemman kuvan siitä, kuinka kuvat ja fontit osuvat tuotettuihin tulosteisiin, katsomalla muistiinpanomme raportin ulostulosta, jossa on fontteja ja kuvia. Kun kokoamassasi asiakirjassa käytetään uudelleen olemassa olevien PDF-tiedostojen sisältöä, tässä kuvattu läpivientikäyttäytyminen on pariliitos komennon objektivirrat ja inkrementaaliset päivitykset yhdistämis- ja versiomekaniikan kanssa. JPEG 2000 -purkumoottori toimitetaan osana Delphin ja C++Builderin HotPDF Component -osana muualla tässä blogissa käsiteltyjen kuva-, fontti- ja dokumentti-sovellusliittymien ohella