PDF tallentaa kuvat ensiluokkaisina objekteina sisältövirtojensa sisällä Kun sivu viittaa valokuvaan, skannaukseen tai kaavioon, pikselidata sijaitsee XObject-sanakirjassa sivun geometrian rinnalla PDFium Component tuo tämän esiin kahden TPdf-ominaisuuden kautta: BitmapCount, joka palauttaa nykyiselle sivulle upotettujen bittikarttojen lukumäärän, ja Bitmap[Index], joka purkaa yhden niistä TBitmap-objektiksi, jonka omistus siirtyy kutsujalle ja joka on vapautettava Siinä koko purkumalli Silmukka on nelirivinen; harkintaa vaatii ympäröivä putkitus
Asiakirjan avaaminen
Ensimmäinen asia, joka TPdf-komponentista kannattaa tietää, on se, ettei Active := True koskaan nosta poikkeusta Latausvirheet, väärät salasanat, vioittuneet tiedostot: kaikki nämä niellään sisäisesti, ja komponentti jää yksinkertaisesti passiiviseksi Lippu on tarkistettava itse sijoituksen jälkeen, tai muuten päädytään sivusilmukkaan, jossa PageCount palauttaa nollan, ja jäädään ihmettelemään, miksi mitään ei purettu
var
Pdf: TPdf;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := 'report.pdf';
Pdf.Active := True;
if not Pdf.Active then
begin
Writeln('Failed to open: ', Pdf.FileName);
Exit;
end;
Writeln(Pdf.PageCount, ' pages');
// jatka purkamiseen
finally
Pdf.Free;
end;
end;
Salasanasuojatut tiedostot toimivat samalla tavalla: aseta Pdf.Password ennen kuin asetat Active := True Jos salasana on väärä, Active jää arvoon False, eikä poikkeusta ole tarttumassa Satojen tiedostojen eräajossa tuo hiljainen käytös on itse asiassa hyödyllinen: virheet kerätään listaan sen sijaan, että kutsupinoa purettaisiin jokaisen kohdalla erikseen
Sivujen läpikäynti ja bittikarttojen nouto
BitmapCount on sivukohtainen, joten Pdf.PageNumber on asetettava ennen sen lukemista Sivunumerointi alkaa ykkösestä; oletusarvo on 0, mikä tarkoittaa, ettei sivua ole ladattu Bitmap[Index]-ominaisuus on nollapohjainen ja palauttaa kutsujan omistukseen siirtyvän TBitmap-objektin Se on vapautettava Jos vapautus unohtuu pitkässä silmukassa suuren asiakirjan yli, muistinkäyttö kasvaa nopeasti, koska yksi bittikartta voi olla useita megatavuja raakaa pikselidataa ennen mitään pakkausta
procedure ExtractAllImages(Pdf: TPdf; const OutputDir: string);
var
Page, Idx: Integer;
Bmp: TBitmap;
OutPath: string;
begin
for Page := 1 to Pdf.PageCount do
begin
Pdf.PageNumber := Page;
for Idx := 0 to Pdf.BitmapCount - 1 do
begin
Bmp := Pdf.Bitmap[Idx];
if not Assigned(Bmp) then
Continue;
try
OutPath := Format('%s\p%d_img%d.bmp', [OutputDir, Page, Idx + 1]);
Bmp.SaveToFile(OutPath);
finally
Bmp.Free;
end;
end;
end;
end;
Assigned-tarkistuksella on merkitystä Pieni osa PDF-generaattoreista kirjoittaa kuva-XObjecteja, joiden pikselimitat ovat nolla tai joiden data on muuten virheellinen; näissä tapauksissa komponentti palauttaa nil-arvon tyhjän bittikartan sijaan nil-paluuarvon käsitteleminen virheenä ja purkamisen pysäyttäminen on väärä refleksi: ohita se, kirjaa sivu ja indeksi lokiin, jos tarvitset jäljitysketjun, ja jatka Loppu sivusta voi silti tuottaa kelvollisia kuvia
Huomaa, että ulompi silmukka asettaa Pdf.PageNumber-arvon jokaisella kierroksella Juuri tuo sijoitus lataa sivun komponentin sisäiseen tilaan ja tekee BitmapCount-arvosta merkityksellisen Jätä se väliin, ja lukemasi määrä koskee samaa sivua toistuvasti Kuvio tuntuu kirjoitettaessa toistolta, mutta se on rajapinnan suunnittelutapa: sivu on kursori, ei kokoelma
Tulostusmuodon valinta
BMP on häviötön ja aina käytettävissä ilman lisäyksiköitä, mikä tekee siitä järkevän oletuksen silloin, kun kuvan sisältöä ei vielä tunneta Kun tiedostokoko on tärkeä, palautetun TBitmap-objektin pikselimuoto kertoo, mikä koodekki sopii 32-bittinen bittikartta sisältää alfakanavan; PNG säilyttää sen häviöttömästi Suuri 24-bittinen kuva jatkuvalla sävyllä on JPEG-ehdokas Pienemmät kuvat tai rajoitetulla paletilla piirretyt kannattaa yleensä jättää BMP-muotoon JPEG-muunnoksen sijaan, sillä se lisää lohkoartefakteja alhaisilla laatuasetuksilla eikä säästä juuri mitään korkeilla
procedure SaveBitmap(Bmp: TBitmap; const FileName: string);
var
Jpg: TJPEGImage;
begin
case UpperCase(ExtractFileExt(FileName)) of
'.JPG', '.JPEG':
begin
Jpg := TJPEGImage.Create;
try
Jpg.Assign(Bmp);
Jpg.CompressionQuality := 85;
Jpg.SaveToFile(FileName);
finally
Jpg.Free;
end;
end;
else
Bmp.SaveToFile(FileName); // BMP: häviötön, ei lisäyksiköitä
end;
end;
Käytännössä muodon valinta perustuu Bmp.PixelFormat-arvoon ja mittoihin Jos PixelFormat = pf32bit, tarvitaan muoto, joka kantaa alfakanavaa; PNG on ilmeinen valinta, vaikka se vaatii vanhemmissa Delphi-versioissa PNGImage-yksikön Noin 300 pikseliä leveämmillä 24-bittisillä kuvilla JPEG laadulla 85 antaa noin kolmasosan koon BMP:hen verrattuna ilman havaittavaa laadun heikkenemistä useimmissa valokuvamaisissa sisällöissä Tuon kynnyksen alapuolella BMP on kooltaan verrattavissa ja välttää laatupäätöksen kokonaan
Mitä BitmapCount laskee ja mitä ei
PDF erottaa kuva-XObjectit ja polkuoperaattoreilla piirretyt vektorigrafiikat toisistaan Visuaalisesti monimutkaiselta näyttävä sivu voi palauttaa BitmapCount-arvon nolla, jos jokainen elementti on vektorimuotoinen Skannatut sivut palauttavat lähes aina tasan yhden: skanneri kirjoittaa koko skannauksen yhtenä koko sivun kuva-XObjectina sillä resoluutiolla, johon skanneri oli asetettu Sivut, joissa ladottu teksti sekoittuu upotettuihin valokuviin, palauttavat yhden merkinnän kutakin valokuvaa kohden Koristeelliset viivat, sävytetyt taustat ja taulukoiden reunaviivat eivät yleensä näy bittikarttalaskennassa lainkaan
Laskenta ei myöskään sisällä upotettuja kuvia (inline images), harvoin käytettyä PDF-rakennetta, jossa kuvadata upotetaan suoraan sivun sisältövirtaan nimetyn XObjectin sijaan Ne jäävät tämän rajapinnan ulottumattomiin; ne ovat todellisissa asiakirjoissa niin harvinaisia, ettei useimpia purkutyökaluja ole rakennettu käsittelemään niitä
Yksi asia kannattaa pitää mielessä: luettu BitmapCount koskee nykyistä sivua sellaisena kuin se oli viimeisimmän PageNumber-sijoituksen hetkellä Jos koodi haarautuu tai kutsuu jotain funktiota, joka muuttaa PageNumber-arvoa laskennan ja noudon välissä, saatetaan lukea vähemmän kuvia kuin mille varattiin tilaa, tai indeksoida loppupisteen ohi Pidä laskennan luku ja Bitmap[]-silmukka samalla sivulla koskematta PageNumber-arvoon niiden välissä
TPdfView-komponentin käyttö lomakesovelluksessa
TPdfView-komponentti tarjoaa samat BitmapCount- ja Bitmap[]-ominaisuudet, mutta sen sivu, jolta se lukee, on näkymän parhaillaan näyttämä sivu, ei TPdf.PageNumber Kaksi sivuosoitinta ovat toisistaan riippumattomia; toisen asettaminen ei siirrä toista VCL-lomakesovelluksessa, jossa on elävä katseluohjelma, voit kutsua Pdf.PageNumber := N ohjataksesi purkamista TPdf:n kautta, kun taas katseluohjelma pysyy sivulla, jonne käyttäjä viimeksi vieritti Tuo erotus on tarkoituksellinen ja pitää katseluohjelman näyttötilan siistinä taustalla käynnissä olevan purkamisen aikana
Muisti ja suorituskyky eräajoissa
Laajan arkiston yli muistibudjetti on tärkein tarkkailtava asia Jokainen Bitmap[]-kutsu varaa uuden TBitmap-objektin keosta, ja 300 DPI:n resoluutiolla skannatulla sivulla se on helposti 25 Mt raakaa pikselidataa ennen mitään koodausta Jos sivuja käsitellään tiiviissä silmukassa vapauttamatta iteraatioiden välissä, työskentelyjoukko kasvaa lineaarisesti kuvien määrän mukana Oikea kaava on aina: hae yksi bittikartta, tee tarvittava, vapauta se, hae seuraava Jos tarvitset viittauksia useisiin bittikarttoihin samanaikaisesti vertailuvaihetta varten, laske ne ensin BitmapCount-arvolla ja varaa säiliö sen mukaisesti, ja vapauta sitten jokainen heti, kun se ei enää ole tarpeen, sen sijaan että siirtäisit siivouksen asiakirjan loppuun 500 skannatun sivun asiakirjalla tuo ero voi tarkoittaa 25 Mt:n ja 12 Gt:n huippumuistinkäytön välistä eroa
Tässä esitellyt BitmapCount- ja Bitmap[]-ominaisuudet kuuluvat Delphille ja C++Builderille tarkoitettuun PDFium Component -kirjastoon