PDF-sivun hahmontaminen JPEG-kuvaksi koostuu kahdesta toiminnosta, joita ihmisillä on tapana ajaa yhdessä ja sitten virheenkorjata erikseen. Ensin rasteroit sivun pikselibittikartaksi valitsemallasi resoluutiolla. Sitten luovutat kyseisen bittikartan JPEG-kooderille ja valitset laadun. PDFium Component omistaa ensimmäisen puoliskon RenderPage-kutsun kautta; toinen puolisko on puhdasta VCL:ää, TJPEGImage Vcl.Imaging.jpeg-yksiköstä. Sauma niiden välillä on paikka, jossa mielenkiintoiset päätökset piilevät, koska hahmonnuspuolella valitsemasi resoluutio ja koodauspuolella valitsemasi laatu tekevät kauppoja toisiaan vastaan ja tiedostokokoa vastaan tavoilla, joissa on helppo tehdä virheitä
Asia, joka on sisäistettävä ennen mitään koodia: PDF-sivulla ei ole pikseleitä. Se on kuvattu pisteissä, joissa yksi piste on 1/72 tuumaa, ja sivu on niissä pisteissä mitattu vektoripiirros. Kun pyydät PDFiumia hahmontamaan, valitset, kuinka monelle pikselille projisoit tuon piirroksen, ja tuo valinta on DPI. Laske väärin, ja joko hahmonnat sumean pikkukuvan, kun halusit tulostusmestarin, tai varaat 200 megapikselin bittikartan jollekin, jonka on tarkoitus olla 120 pikselin esikatselu
DPI:stä pikselimittoihin
RenderPage haluaa kokonaislukupikseliset Width- ja Height-arvot, ei DPI:tä. Joten ensimmäinen tehtävä on muuntaminen. Sivu ilmoittaa kokonsa pisteinä PageWidth- ja PageHeight-ominaisuuksien kautta (molemmat Double-tyyppiä), ja muunnos on sama, jota jokainen rasteroija käyttää: pikselit ovat yhtä kuin pisteet kertaa kohde-DPI jaettuna 72:lla. Yhdysvaltalainen Letter-sivu on 612 kertaa 792 pistettä. 150 DPI:llä siitä tulee 1275 kertaa 1650 pikseliä; 72 DPI:llä se pysyy arvossa 612 kertaa 792, yksi pikseli pistettä kohden, mikä on se tapaus, jonka ihmiset unohtavat olevan pelkkä identiteetti
// Pdf.PageNumber-arvon on jo osoitettava haluamaasi sivuun.
PixelW := Round(Pdf.PageWidth * Dpi / 72);
PixelH := Round(Pdf.PageHeight * Dpi / 72);
Bitmap := Pdf.RenderPage(0, 0, PixelW, PixelH, ro0, [], clWhite);
// ... käytä Bitmap-muuttujaa ...
Bitmap.Free; // funktiomuotoinen RenderPage antaa omistajuuden sinulle
Kaksi yksityiskohtaa noilla neljällä rivillä ratkaisevat, onko koodi oikein. Ensimmäinen on se, että RenderPage-kutsun funktiomuoto palauttaa TBitmap-objektin, jonka sinä omistat. PDFium varasi sen ja käveli pois; jos et vapauta sitä Free-kutsulla jokaisella iteraatiolla, muutaman sadan sivun erä vuotaa muutaman sadan bittikartan verran, ja prosessi paisuu, kunnes jokin kaatuu. Toinen on Color-argumentti, tässä clWhite. PDF-sivut piirretään yleensä olettaen läpinäkymättömän valkoisen alustan, ja läpinäkyvyyttä sisältävä sivu, joka hahmonnetaan väärälle taustavärille, tuottaa mutaisia reunoja tai satunnaisia tummia haloja. Valkoinen on oikea oletus lähes jokaiselle asiakirjalle; parametri on olemassa niitä harvinaisia tapauksia varten, joissa se ei ole
Kohteet 0, 0 ovat Left- ja Top-poikkeamat sivulle skaalatussa koordinaattiavaruudessa, ja jätät ne nollaan, ellet ole rajaamassa. ro0 on kierto: jätä se nollaan, ja PDFium kunnioittaa mitä tahansa kiertoa, jonka sivu jo ilmoittaa /Rotate-merkinnässään, joten vaakasuuntaiseksi tehty sivu tulee ulos vaakasuuntaisena ilman että teet mitään
Bittikartan koodaaminen JPEG-muotoon
Kun bittikartta on olemassa, JPEG on helppo osa, ja se on puhdasta Delphiä. TJPEGImage.Assign kopioi bittikartan sisään, CompressionQuality asettaa laadun asteikolla 1–100, ja SaveToFile kirjoittaa tiedoston. Ainoa järjestyssääntö on, että laatu on asetettava ennen tallennusta, koska se ohjaa koodausta, jonka SaveToFile laukaisee
uses
Vcl.Graphics, Vcl.Imaging.jpeg, PDFium;
procedure SavePageAsJpeg(Pdf: TPdf; PageNumber, Dpi, Quality: Integer;
const FileName: string);
var
Bitmap: TBitmap;
Jpeg: TJPEGImage;
begin
Pdf.PageNumber := PageNumber;
Bitmap := Pdf.RenderPage(0, 0,
Round(Pdf.PageWidth * Dpi / 72),
Round(Pdf.PageHeight * Dpi / 72),
ro0, [], clWhite);
try
Jpeg := TJPEGImage.Create;
try
Jpeg.Assign(Bitmap);
Jpeg.CompressionQuality := Quality; // 1..100
Jpeg.SaveToFile(FileName);
finally
Jpeg.Free;
end;
finally
Bitmap.Free;
end;
end;
Tuo sisäkkäinen try/finally näyttää pikkutarkalta yksisivuiselle apulaiselle, ja se on täsmälleen oikein eräajolle. Sisempi lohko vapauttaa kooderin, ulompi lohko vapauttaa bittikartan, ja kumpi tahansa niistä laukeaa poikkeuksessa ja vapauttaa silti sen, mitä se omistaa. Kutista ne yhdeksi, ja koodauksen aikainen poikkeus voi jättää bittikartan orvoksi. Pitkässä juoksussa tuo on ero sellaisen muuntimen, joka valmistuu, ja sellaisen välillä, joka kuolee sivulla 300 vioittuneen tiedoston ja muistin loppumisesta kertovan valintaikkunan kera
DPI:n ja laadun valitseminen yhdessä
Nämä kaksi säädintä eivät ole riippumattomia tulosteen käyttötarkoituksesta, ja yleinen virhe on vääntää molempia ylöspäin varovaisuudesta. 300 DPI:llä hahmonnettu ja laadulla 95 tallennettu verkkopikkukuva on useiden satojen kilotavujen kokoinen tiedosto, joka teeskentelee olevansa 120 pikselin kuva; selain heittää lähes kaiken siitä menemään pienentäessään kokoa. Sovita resoluutio pikseleihin, joita tuloste todella tarvitsee, ja valitse sitten laatu, joka selviytyy JPEG:n häviöllisestä pakkaamisesta ilman näkyviä virheitä
| Tuloste | DPI | JPEG-laatu |
|---|---|---|
| Luettelon pikkukuva | 72 | 60-70 |
| Esikatselu näytöllä | 96-150 | 80-85 |
| Yksityiskohtainen katselu | 200-300 | 85-95 |
| Tulostuksen alkuperäiskappale | 300-600 | 90-100 |
JPEG-laatu ansaitsee oman varoituksensa. Se ei ole lineaarinen säädin. Hyppy 70:stä 85:een ostaa todellisen visuaalisen parannuksen kohtuullisella tiedoston kasvulla; hyppy 95:stä 100:aan kaksinkertaistaa tiedoston koon suunnilleen erolla, jota tuskin kukaan huomaa, koska laatu 100 ei silti ole häviötön, se vain lakkaa hylkäämästä paljoakaan. Paljon tekstiä sisältävillä sivuilla JPEG:n lohkopohjainen pakkaus tuhrii glyyfien terävät reunat haaleaksi soimiseksi, minkä vuoksi alle noin 80:n laatu tekee skannatun näköistä tekstiä tulosteeseen, jonka pitäisi olla terävä. Jos sivut ovat enimmäkseen tekstiä ja voit vaihtaa muotoa, PNG hahmontaa tuon tekstin ilman soimista; JPEG ansaitsee paikkansa valokuvamaisessa ja sekasisällössä, jossa sen pakkaus on aidosti pienempi
Nopeammat, pienemmät pikkukuvat
Kun kohteena on pikkukuva uskollisen toisinnon sijaan, voit kertoa hahmontajalle, että sen tulee tehdä vähemmän työtä. Options-parametri ottaa joukon TRenderOption-lippuja, ja muutama niistä vaihtaa uskollisuutta nopeuteen täsmälleen sillä tavalla, jolla pieni esikatselu haluaa. reGrayscale pudottaa värit, mikä sekä hahmontaa nopeammin että tuottaa pienemmän bittikartan koodattavaksi. reNoSmoothImage ja reNoSmoothPath ohittavat reunanpehmennyksen, joka on joka tapauksessa näkymätön pikkukuvakoossa
function RenderThumbnail(Pdf: TPdf; PageNumber, MaxW, MaxH: Integer): TBitmap;
var
Scale: Double;
begin
Pdf.PageNumber := PageNumber;
// Sovita sivu kokoon MaxW x MaxH säilyttäen kuvasuhde.
Scale := Min(MaxW / Pdf.PageWidth, MaxH / Pdf.PageHeight);
Result := Pdf.RenderPage(0, 0,
Round(Pdf.PageWidth * Scale),
Round(Pdf.PageHeight * Scale),
ro0, [reGrayscale, reNoSmoothImage], clWhite);
end;
Pikkukuvatapaus osoittaa myös puhtaamman tavan ajatella kokoa. Sen sijaan, että mennään DPI:n kautta, lasketaan yksi skaalakerroin, joka sovittaa sivun rajauslaatikon sisään ja säilyttää kuvasuhteen, mikä on se, mitä näiden kahden suhdeluvun Min tekee. Sekä pystysuuntainen että vaakasuuntainen sivu päätyvät saman laatikon sisään ilman vääristymiä, eikä sinun tarvitse koskaan miettiä, mikä DPI vastaa arvoa "sovita 200 kertaa 280". Yksi varoitus koskien reGrayscale-lippua: se muuntaa rasterikuvien sisällön harmaaksi, mutta vektoritäytöt ja teksti pitävät väriarvonsa moottorissa, joten sivu, joka on enimmäkseen vektoritaidetta, voi tulla takaisin vähemmän yksivärisenä kuin lipun nimi antaa ymmärtää. Todelliseen, täysin harmaasävyiseen tulokseen hahmonnetun bittikartan muuntaminen GrayscalePdfBitmap-funktiolla on luotettava polku
Koko asiakirjan eräajo
Sen kokoaminen kokonaista asiakirjaa varten on silmukka PageCount-ominaisuuden yli, jolloin PageNumber liikkuu yhden sivun kerrallaan. Sivut ovat 1-pohjaisia: sivu yksi on PageNumber := 1, ja silmukka suoritetaan PageCount-arvoon asti mukaan lukien, ei arvoon PageCount - 1. Toinen asia, jota eräajon on kunnioitettava, on hiljaisen latauksen sopimus. Active := True-arvon asettaminen ei koskaan nosta virhettä vaurioituneesta tiedostosta tai väärästä salasanasta; se vain jättää Active-tilan arvoon False. Tarkista se ennen kuin hahmonnat yhtäkään sivua, tai ensimmäinen RenderPage-kutsu toimii asiakirjaa vastaan, jota ei koskaan avattu
procedure ExportAllPages(const PdfPath, OutDir: string; Dpi, Quality: Integer);
var
Pdf: TPdf;
I, Digits: Integer;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := PdfPath;
Pdf.Active := True;
if not Pdf.Active then
raise Exception.Create('Could not open ' + PdfPath);
Digits := Length(IntToStr(Pdf.PageCount)); // nollatäyttö, jotta tiedostot lajittuvat oikein
for I := 1 to Pdf.PageCount do
SavePageAsJpeg(Pdf, I, Dpi, Quality,
Format('%s\page_%.*d.jpg', [OutDir, Digits, I]));
finally
Pdf.Active := False;
Pdf.Free;
end;
end;
Nollatäyttö Digits-muuttujan kautta on pieni asia, joka säästää iltapäivän myöhemmin. Nimeä tiedostot väliltä page_1.jpg–page_10.jpg, ja mikä tahansa työkalu, joka lajittelee ne merkkijonoina, laittaa tiedoston page_10 aivan tiedoston page_1 perään, sekoittaen järjestyksen. Täyttäminen suurimman sivunumeron leveyteen, jolloin 300-sivuinen asiakirja tuottaa tiedoston page_001.jpg, pitää leksikaalisen järjestyksen ja sivujärjestyksen identtisenä kaikkialla myöhemmin
Asiakirjoille, jotka ovat riittävän suuria, jotta muuntaminen vie huomattavasti aikaa, aja se käyttöliittymäsäikeen ulkopuolella tai pumppaa viestejä sivujen välillä, jotta sovellus pysyy vastaavana, ja anna käyttäjälle tapa pysäyttää se. Jos hahmonnat erittäin suuria sivuja ja haluat peruutuksen, joka puree kesken sivun eikä vain sivujen välillä, PDFium Component -komponentilla on progressiivinen hahmonnuspolku peruutustunnuksella; se on raskaampi mekanismi kuin useimmat eräviennit tarvitsevat, mutta se on olemassa, kun yksittäinen sivu 600 DPI:llä on itsessään riittävän hidas estääkseen toiminnan
Yksi viimeinen pariliitos, joka on hyvä tietää. Sivun rasterointi hylkää sen tekstikerroksen: JPEG on pikseleitä, eivätkä sen sisällä olevat sanat ole enää valittavissa tai haettavissa. Kun tarvitset sekä kuvan että sen alla olevan tekstin, hahmonna kuva ja vedä teksti erikseen, mitä kumppaniartikkeli tekstin purkaminen PDF-asiakirjoista PDFium Component -komponentilla käsittelee. Tässä esitetyt RenderPage-ylikuormitukset ja hahmonnusvaihtoehdot ovat osa PDFium Component -komponenttia Delphille ja C++Builderille