Tekninen artikkeli

Hahmonna (Render PDF Pages to JPEG Images in Delphi with PDFium Component) PDF-sivut JPEG-kuviksi Delphissä PDFium Component -komponentilla

PDF-sivun hahmontaminen (Rendering a PDF page to a JPEG is two operations that people tend to run together and then) JPEG-kuvaksi koostuu kahdesta toiminnosta (operations that people tend to run together and then), jotka ihmisillä on tapana ajaa yhdessä ja sitten (run together and then debug separately. First) virheenkorjata erikseen (debug separately. First). Ensin (First you rasterize the) rasteroit sivun (rasterize the page into a pixel bitmap at a) pikselibittikartaksi (pixel bitmap at a resolution you) valitsemallasi resoluutiolla (resolution you choose. Then). Sitten luovutat kyseisen bittikartan JPEG-kooderille (hand that bitmap to a JPEG encoder and) ja (and pick a) valitset (pick a quality. PDFium) laadun (quality. PDFium). PDFium Component omistaa (owns the first) ensimmäisen puoliskon RenderPage-kutsun (RenderPage; the) kautta (through RenderPage; the); toinen puolisko on (second half is plain) puhdasta VCL:ää, (VCL, TJPEGImage from) TJPEGImage Vcl.Imaging.jpeg-yksiköstä. Sauma näiden (seam between them is) välillä (between them is where the) on paikka, jossa mielenkiintoiset päätökset (where the interesting decisions live, because) piilevät, koska hahmonnuspuolella (because the resolution you pick on the render side and) valitsemasi resoluutio ja (resolution you pick on the render side and the) koodauspuolella (encode side trade off against each) valitsemasi laatu tekevät kauppoja (trade off against each other and) toisiaan vastaan (against each other and against file) ja (and against file size in) tiedostokokoa (file size in ways that) vastaan (against file size in ways that) tavoilla, joissa (ways that are easy to) on (are easy to get wrong) helppo tehdä virheitä (get wrong)

Asia, joka on (thing to internalize before) sisäistettävä (internalize before any) ennen (before any code: a) koodausta (code: a PDF page): PDF-sivulla ei (PDF page has no) ole pikseleitä (has no pixels. It). Se (It is described in) on (is described in points, where) kuvattu (described in points, where) pisteissä (points, where one), joissa yksi piste (one point is 1/72 inch, and) on 1/72 tuumaa, ja sivu (inch, and the page is a) on niissä (page is a vector) pisteissä (points. When) mitattu vektoripiirros (vector drawing measured in those points. When). Kun pyydät PDFiumia hahmontamaan (ask PDFium to render, you), valitset kuinka (are choosing how) monelle pikselille (many pixels to) projisoit tuon piirroksen (project that drawing onto, and), ja (and that) tuo (that choice is the) valinta on (choice is the DPI. Get) DPI. Laske väärin (Get the arithmetic wrong and), ja (and you either) joko hahmonnat sumean (render a blurry) pikkukuvan, kun halusit tulostusmestarin (thumbnail when you wanted a print master, or), tai (or you allocate a) varaat 200 megapikselin bittikartan jollekin (megapixel bitmap for something destined to), jonka on (destined to be a 120-pixel) tarkoitus olla (be a 120-pixel preview) 120 pikselin esikatselu (preview)

DPI:stä (From DPI to pixel) pikselimittoihin (pixel dimensions)

RenderPage haluaa (wants integer) kokonaislukupikseli-Width ja Height-arvot, ei DPI:tä. Joten (So the first) ensimmäinen tehtävä on (job is converting. A) muuntaminen (converting. A). Sivu ilmoittaa (page reports its) kokonsa pisteinä (size in points through PageWidth) PageWidth- (PageWidth and PageHeight (both) ja (and PageHeight (both Double), and) PageHeight-ominaisuuksien (ominaisuuksien) kautta (through PageWidth and PageHeight (both Double), and the) (molemmat (both Double), and the) Double-tyyppiä), ja (and the conversion is the) muunnos (conversion is the same one) on (is the same one every) sama (same one every rasterizer uses: pixels), jota (every rasterizer uses: pixels equal) jokainen (every rasterizer uses: pixels equal) rasteroija käyttää (rasterizer uses: pixels equal points): pikselit (pixels equal points times) ovat (equal points times target) yhtä (equal points times target) kuin (times target DPI divided) pisteet kertaa kohde-DPI (target DPI divided by) jaettuna 72:lla. Yhdysvaltalainen Letter-sivu on 612 kertaa (by 792 points. At) 792 pistettä. 150 DPI:llä siitä (At 150 DPI that becomes 1275) tulee 1275 kertaa (by 1650 pixels; at) 1650 pikseliä; 72 DPI:llä se (at 72 DPI it stays 612) pysyy (stays 612 by) arvossa 612 kertaa 792, yksi pikseli pistettä kohden (one pixel per point, which), mikä (which is the) on se (is the case people) tapaus, jonka (case people forget is) ihmiset (people forget is just) unohtavat olevan pelkkä (forget is just the identity) identiteetti (identity)

// Pdf.PageNumber must already point at the page you want.
PixelW := Round(Pdf.PageWidth  * Dpi / 72);
PixelH := Round(Pdf.PageHeight * Dpi / 72);
Bitmap := Pdf.RenderPage(0, 0, PixelW, PixelH, ro0, [], clWhite);
// ... use Bitmap ...
Bitmap.Free;   // the function-form RenderPage hands you ownership

Kaksi yksityiskohtaa noilla (Two details in those) neljällä rivillä (four lines decide whether) ratkaisevat (decide whether the) onko koodi oikea (code is correct. The). Ensimmäinen on, että (first is that the) RenderPage-kutsun funktio-muoto (function form of RenderPage returns) palauttaa (returns a TBitmap) TBitmap-objektin, jonka sinä omistat (that *you* own. PDFium). PDFium varasi sen ja (allocated it and walked) käveli pois (walked away; if); jos et (if you do not Free) vapauta (Free it on) sitä (it on every) Free-kutsulla jokaisella (every iteration, a) iteraatiolla, muutaman (batch over a) sadan sivun erä vuotaa muutaman (hundred pages leaks a) sadan (hundred bitmaps and) bittikartan verran ja (bitmaps and the) prosessi paisuu, kunnes jotain kaatuu (process bloats until something falls over. The). Toinen (second is the Color) on Color-argumentti, tässä clWhite. PDF-sivut piirretään (PDF pages are usually) yleensä (usually drawn assuming) olettaen, että alusta (drawn assuming an) on läpinäkymättömän valkoinen (opaque white substrate, and), ja läpinäkyvyyttä (and a page) sisältävä (with transparency rendered) sivu (page with transparency rendered onto), joka (with transparency rendered onto the) on hahmonnettu väärälle (rendered onto the wrong) taustavärille, tuottaa mutaisia reunoja (background color produces muddy edges or) tai (or stray dark) satunnaisia tummia (stray dark halos. White) haloja (halos. White is). Valkoinen on oikea (White is the right) oletus lähes jokaiselle (default for almost every) asiakirjalle; parametri (document; the parameter exists) on olemassa (exists for the) niitä (the rare) harvinaisia tapauksia varten (rare case where it is), joissa se (where it is not) ei ole (not)

0, 0 ovat Left- ja (and Top offsets) Top-poikkeamat (offsets into the) sivulle (into the page, in), skaalatussa koordinaattiavaruudessa (scaled coordinate space, and), ja (and you leave) jätät ne (leave them at) nollaan, ellet (zero unless you) ole (are cropping. The) rajaamassa (cropping. The ro0). ro0 on kierto (is rotation: leave): jätä se nollaan (leave it at) ja (and PDFium honors) PDFium kunnioittaa mitä (honors whatever rotation) tahansa (whatever rotation the) kiertoa, jonka sivu (rotation the page already) jo (already declares in) ilmoittaa /Rotate-merkinnässään, joten vaakasuuntaiseksi tehty (entry, so a) sivu (page authored landscape) tulee (comes out landscape) ulos vaakasuuntaisena ilman (landscape without you), että (without you doing) teet (doing anything) mitään (anything)

Bittikartan (Encoding the bitmap as) koodaaminen (Encoding the bitmap as) JPEG-muotoon (JPEG)

Kun bittikartta (Once the bitmap exists) on olemassa (exists, JPEG), JPEG on helppo (is the easy) osa, ja se (part, and it) on puhdasta (is pure Delphi. TJPEGImage) Delphiä. TJPEGImage.Assign kopioi bittikartan sisään (copies the bitmap in, CompressionQuality), CompressionQuality asettaa (sets the quality) laadun (quality on a) asteikolla 1-100 (scale, and), ja (and SaveToFile) SaveToFile kirjoittaa (writes the file. The) tiedoston (file. The only). Ainoa järjestyssääntö on (only ordering rule is), että laatu on (that quality has) asetettava ennen tallennusta (to be set before), koska se ohjaa koodausta (you save, because), jonka SaveToFile laukaisee (it governs the encode that SaveToFile triggers)

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ää (looks fussy for) pikkutarkalta yksisivuiselle apulaiselle (fussy for a one-page helper, and), ja se on (and it is exactly) täsmälleen (exactly right for) oikein (right for a) eräajolle (batch. The). Sisempi lohko vapauttaa (inner block frees the) kooderin, ulompi lohko (encoder, the outer) vapauttaa bittikartan (block frees the), ja kumman tahansa bittikartan (bitmap, and either) laukeaminen poikkeuksessa vapauttaa (one firing on an exception still releases) silti sen (releases what it), mitä (what it owns. Collapse) se (it owns. Collapse) omistaa (owns. Collapse them). Kutista ne (Collapse them into) yhdeksi, ja koodauksen (one and an) aikainen (exception during encoding) poikkeus voi jättää bittikartan orvoksi (can strand the). Pitkässä juoksussa (bitmap. Over a) tuo on ero (long run that) sellaisen muuntimen välillä (is the difference between), joka (a converter that finishes) päättyy, ja sellaisen (and one that) välillä, joka (dies on page) kuolee (dies on page 300) sivulla 300 vioittuneen tiedoston ja (with a corrupt) muistin loppumisesta (file and an) kertovan (out-of-memory dialog) valintaikkunan kera

DPI:n ja laadun (Choosing DPI and quality) valitseminen yhdessä (together)

Kaksi säädintä eivät (Two knobs are not) ole riippumattomia (independent of the) tulosteen käyttötarkoituksesta (output's purpose, and), ja (and the common) yleinen (common mistake is) virhe on (mistake is turning) vääntää molempia (turning both up) ylöspäin (up out of) varovaisuudesta (caution. A). 300 DPI:llä hahmonnettu (web thumbnail rendered) ja laadulla 95 tallennettu verkkopikkukuva on (at 300 DPI and saved) useiden (at quality 95 is) satojen kilotavujen (several hundred kilobytes pretending) kokoinen tiedosto, joka (pretending to be) teeskentelee (to be a) olevansa 120 pikselin (120-pixel image; the) kuva; selain heittää (browser throws away) niistä lähes kaiken menemään pienentäessään (almost all of) kokoa (it on the downscale. Match). Sovita (Match the resolution) resoluutio (resolution to the) pikseleihin, joita (pixels the output) tuloste todella tarvitsee (actually needs, then), ja valitse sitten laatu (pick a quality), joka selviytyy (that survives JPEG's) JPEG:n häviöllisestä (lossy compression without) pakkaamisesta (compression without visible) ilman (without visible artifacts) näkyviä virheitä (artifacts)

Tuloste (Output)DPIJPEG-laatu (JPEG quality)
Luettelon pikkukuva (List thumbnail)7260-70
Esikatselu näytöllä (On-screen preview)96-15080-85
Yksityiskohtainen katselu (High-detail viewing)200-30085-95
Tulostuksen alkuperäiskappale (Print master)300-60090-100

JPEG-laatu on oman varoituksen sanansa (worth a word) arvoinen (of caution on). Se ei ole (is not a) lineaarinen (linear dial. The) säädin (dial. The jump). Hyppy (jump from 70) 70:stä 85:een ostaa todellisen (to 85 buys a) visuaalisen parannuksen modestilla tiedoston kasvamisella (real visual improvement for); hyppy (modest file growth; the) 95:stä 100:aan karkeasti ottaen (jump from 95) kaksinkertaistaa tiedoston (to 100 roughly) koon (doubles the file) erolla, jota lähes kukaan ei (for a difference) näe, koska (almost nobody can) laatu (see, because quality) 100 ei (100 still is) siltikään (is not lossless) ole (not lossless, it) häviötön (lossless, it just), se (it just stops) vain lakkaa (stops discarding much) hylkäämästä paljoakaan (discarding much. For). Paljon tekstiä (text-heavy pages, JPEG's) sisältävillä sivuilla JPEG:n lohkopohjainen (block-based compression smears) pakkaus (compression smears the) tuhrii (smears the sharp) glyyfien (edges of glyphs) terävät (sharp edges of) reunat haileaksi (into faint ringing) soimiseksi (ringing, which), mistä (which is why) syystä alle (quality below about) 80:n (80 makes scanned-looking) laatu (quality below about 80 makes scanned-looking text) tekee skannatun näköistä tekstiä (scanned-looking text on) tulosteeseen (what should be), jonka (what should be crisp) tulisi (should be crisp output. If) olla (be crisp output. If) terävä (crisp output. If the). Jos (If the pages) sivut ovat (are mostly text) enimmäkseen tekstiä ja voit (and you can) vaihtaa (change formats, PNG) muotoja, PNG hahmontaa tuon tekstin ilman soimista (renders that text without); JPEG (the ringing; JPEG) ansaitsee (earns its place) paikkansa valokuvamaisessa (on photographic and) ja (and mixed content) sekasisällössä (mixed content where), jossa sen (where its compression) pakkaus (compression is genuinely) on (is genuinely smaller) aidosti pienempi (smaller)

Nopeammat, pienemmät pikkukuvat (Faster, smaller thumbnails)

Kun kohteena on (When the target) pikkukuva uskollisen toisinnon sijaan (is a thumbnail rather), voit kertoa (than a faithful) hahmontajalle, että (reproduction, you can) sen tulee tehdä vähemmän (tell the renderer to) työtä (do less work. The). Options-parametri ottaa sarjan (parameter takes a set of) TRenderOption-lippuja (TRenderOption flags, and), ja muutama niistä vaihtaa (a few of them) uskollisuutta nopeuteen täsmälleen (trade fidelity for) sillä tavalla, jolla pieni esikatselu (speed in exactly) haluaa (the way a small preview wants. reGrayscale). reGrayscale pudottaa värit (drops color, which), mikä sekä hahmonnetaan (both renders faster) nopeammin että tuottaa (and produces a) pienemmän bittikartan koodattavaksi (smaller bitmap to). reNoSmoothImage ja (encode. reNoSmoothImage and) reNoSmoothPath ohittavat reunanpehmennyksen (reNoSmoothPath skip anti-aliasing), joka on (that is invisible) näkymätön (invisible at thumbnail) pikkukuvakoossa (scale anyway) joka tapauksessa (anyway)

function RenderThumbnail(Pdf: TPdf; PageNumber, MaxW, MaxH: Integer): TBitmap;
var
  Scale: Double;
begin
  Pdf.PageNumber := PageNumber;
  // Fit the page inside MaxW x MaxH while preserving aspect ratio.
  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 (thumbnail case also) myös puhtaamman (shows the cleaner) tavan (way to think) ajatella kokoa (about sizing. Instead). Sen (Instead of going) sijaan, että (of going through) mentäisiin (going through DPI) DPI:n kautta, lasketaan yksi skaalakerroin, joka (compute a single) sovittaa sivun rajauslaatikon sisään ja (scale factor that) säilyttää kuvasuhteen (fits the page), mikä (inside a bounding) on (box and preserves) se mitä näiden kahden suhdeluvun (the aspect ratio, which is what the Min of the two ratios does. A) Min (Min of the two ratios does. A portrait) tekee (does. A portrait page). Sekä pystysuuntainen että (portrait page and) vaakasuuntainen (a landscape page) sivu (page both end) päätyvät (end up inside) saman laatikon (the same box) sisään ilman vääristymiä (without distortion, and), eikä sinun tarvitse koskaan miettiä (you never have), mikä (to reason about) DPI vastaa (what DPI corresponds) arvoa "sovita 200 x (to "fit in) 280". Yksi (200 by 280." One) varoitus (caveat with reGrayscale): reGrayscale (reGrayscale: it converts) muuntaa (converts raster image) rasterikuvien (raster image content) sisällön harmaaksi (to gray, but), mutta vektoritäytöt (vector fills and) ja teksti (text keep their) pitävät (keep their color) väriarvonsa (color values in) moottorissa (the engine, so), joten sivu, joka (so a page) on enimmäkseen (that is mostly) vektoritaidetta, voi tulla (vector art may) takaisin vähemmän (come back less) yksivärisenä kuin lipun nimi antaa (monochrome than the) ymmärtää (flag's name suggests. For). Todenmukaiseen (true full-grayscale result), täysin harmaasävyiseen tulokseen, hahmonnetun bittikartan muuntaminen (converting the rendered) GrayscalePdfBitmap-funktiolla on luotettava polku (bitmap with GrayscalePdfBitmap is the reliable path)

Koko asiakirjan (Batching a whole document) eräajo (Batching a whole document)

Sen (Putting it together) kokoaminen kokonaista asiakirjaa varten on silmukka (for a full) PageCount-ominaisuuden yli (document is a), jolloin (loop over PageCount) PageNumber (with PageNumber moved) liikkuu yhden (moved one page) sivun (at a time. Pages) kerrallaan (at a time. Pages are). Sivut (Pages are 1-based) ovat 1-pohjaisia (1-based: page): sivu yksi on (one is PageNumber) PageNumber := 1, ja silmukka suoritetaan (and the loop runs to) PageCount:iin (PageCount inclusive, not) asti (inclusive, not PageCount) (mukaan lukien), ei PageCount - 1. Toinen asia (The other thing), jota (the batch must) eräajon (batch must respect) on kunnioitettava (respect is the), on (is the silent-load) hiljaisen latauksen sopimus (silent-load contract. Setting). Active := True -arvon (Setting Active := True never) asettaminen (Setting Active := True never raises) ei (never raises on) koskaan (never raises on a) nosta (raises on a damaged) virhettä vaurioituneesta (damaged file or) tiedostosta tai väärästä (a wrong password) salasanasta; se jättää vain Active-tilan (it just leaves) arvoon (Active at False) False. Tarkista se (Check it before) ennen kuin hahmonnat (you render a) yhtäkään (single page, or) sivua, tai ensimmäinen (first RenderPage works) RenderPage-kutsu (RenderPage works against) toimii asiakirjaa (a document that) vastaan (against a document that was), jota ei (was never opened) 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));   // zero-pad so files sort right
    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ö (zero-padding through Digits) Digits-muuttujan kautta on pieni asia, joka säästää (is a small) iltapäivän myöhemmin (thing that saves). Nimeä tiedostot page_1.jpg:stä (an afternoon later. Name) page_10.jpg:iin, ja (the files page_1) mikä tahansa työkalu (jpg through page_10), joka (jpg and any) lajittelee (tool that sorts) ne (them as strings) merkkijonoina (puts page_10 right), laittaa (puts page_10 right after) page_10-tiedoston aivan (after page_1, scrambling) page_1-tiedoston (page_1, scrambling the) perään, sekoittaen (order. Padding to) järjestyksen (order. Padding to the). Täyttäminen (Padding to the width) suurimman (of the highest) sivunumeron (page number, so) leveyteen (width of the), jolloin 300-sivuinen asiakirja tuottaa (a 300-page document) page_001.jpg-tiedoston, pitää leksikaalisen järjestyksen (yields page_001.jpg) ja sivujärjestyksen identtisenä kaikkialla (keeps lexical order) myöhemmin (and page order). (identical everywhere downstream)

Asiakirjoille, jotka ovat riittävän suuria jotta (For documents large) muuntaminen (enough that the) vie (conversion takes noticeable) huomattavasti (time, run it) aikaa, aja (run it off) se käyttöliittymäsäikeen (the UI thread) ulkopuolella (off the UI) tai (or pump messages) pumppaa (pump messages between) viestejä (messages between pages) sivujen välillä (between pages so), jotta sovellus (so the application) pysyy (stays responsive, and) vastaavana, ja (and give the) anna käyttäjälle (give the user) tapa (a way to) pysäyttää se (stop. If you). Jos (If you are) hahmonnat erittäin (are rendering very) suuria (large pages and) sivuja (pages and want) ja haluat peruutuksen (want cancellation that), joka (that bites mid-page) puree (bites mid-page rather) kesken (mid-page rather than) sivun eikä (rather than only) vain (only between pages) sivujen (between pages, PDFium) välillä, PDFium Component -komponentilla on progressiivinen hahmonnuspolku peruutustunnuksella (Component has a); se on (progressive render path) raskaampi (with a cancellation) mekanismi (token; that is) kuin (a heavier mechanism) mitä (than most batch) useimmat eräviennit (exports need, but) tarvitsevat (need, but it), mutta (but it is) se on (is there when) siellä, kun (when a single) yksittäinen (single page at) sivu 600 DPI:llä (600 DPI is) on itsessään (itself slow enough) riittävän hidas (slow enough to) estääkseen (block) toiminnan

Yksi viimeinen (One last pairing) pariliitos, joka (pairing worth knowing) on (worth knowing. Rasterizing) hyvä tietää. Sivun (Rasterizing a page) rasterointi hylkää (discards its text) sen (its text layer) tekstikerroksen: JPEG on (the JPEG is) pikseleitä (pixels, and the), eivätkä sen (and the words) sisällä (in it are) olevat (are no longer) sanat (words in) ole enää (no longer selectable) valittavissa tai haettavissa (or searchable. When). Kun tarvitset sekä (When you need) kuvan että (both an image) alla (and the underlying) olevan (underlying text, render) tekstin, hahmonna kuva (render for the) ja vedä teksti (image and pull) erikseen, jota kumppaniartikkeli (the text separately), tekstin (which the companion) purkaminen PDF-asiakirjoista (piece on extracting) PDFium Component -komponentilla (text from PDF documents with PDFium Component), käsittelee. Tässä esitetyt RenderPage-ylikuormitukset ja (covers. The RenderPage) hahmonnusvaihtoehdot ovat (overloads and render) osa (options shown here) PDFium Component -komponenttia (are part of the PDFium Component) Delphi- (for Delphi and) ja (and C++Builder) C++Builder-ohjelmointikieliin