Korvauskäsittelytiimillä (claims-processing team had thirty years of) oli (had thirty years of) kolmenkymmenen (thirty years of) vuoden edestä paperikansioita, jotka (paper files going through a) menivät arkkisyöttöisen (going through a sheet-fed) skannerin (scanner. The) läpi. Skanneri (scanner spat out one) sylkäisi ulos (spat out one) yhden (one) JPEG-kuvan per sivu (JPEG per page into a) kansioon (folder, named), nimettynä (named) 0001.jpg, 0002.jpg, ja (and so on. What) niin edelleen (so on. What). Mitä (What) arkisto (archive actually needed was one) todella (actually needed was one) tarvitsi, oli (needed was one) yksi PDF per tapauskansio (case file, with the), sivut (pages in order, so) järjestyksessä (in order, so), jotta arvioija (reviewer could open a) voisi (could open a) avata (open a) yhden asiakirjan (single document instead of) sadoista (hundred image thumbnails. That) kuvapikkukuvista (image thumbnails. That) läpiklikkailun sijaan (clicking through a hundred image thumbnails. That). Tuo viimeinen (last step, turning a) vaihe (step, turning a), numeroidun (numbered pile of) skannauspinon (scans into a) muuttaminen (turning a numbered pile of scans into a) yhdeksi (single ordered) järjestetyksi (ordered) PDF-tiedostoksi, on työ (job here) tässä (here)
PDFium Component käsittelee sen (handles it directly. Beyond) suoraan (directly. Beyond). Hahmontamisen ja (rendering and text) tekstin (text extraction, the) purkamisen (extraction, the) lisäksi (Beyond rendering and text extraction, the) komponentti (component can build a) voi rakentaa (can build a) PDF:n alusta (PDF from scratch: create) alkaen: luoda (create an) tyhjän (empty document, add) asiakirjan (document, add), lisätä (add a) tyhjän (blank page sized however) sivun halutun kokoisena (sized however you like, drop), pudottaa (drop an) kuvan (image onto that) kyseiselle (that page in) sivulle käyttäjätilan koordinaateissa (user-space coordinates, then), ja sitten (then save. The) tallentaa (save. The). Koko (whole pipeline lives on the) liukuhihna (pipeline lives on the) asuu (lives on the) TPdf-komponentissa, joten (so a batch converter is a) erämuunnin on silmukka (loop over filenames plus) tiedostonimien (filenames plus a) yli (over filenames plus a) sekä kourallinen (plus a handful of) kutsuja (calls)
Muunnoksen (shape of the) muoto (shape of the conversion)
Kolme asiaa on (Three things have to) tapahduttava (happen for each) jokaiselle skannaukselle (each scan. You). Päätät sivukoon (decide the page size, you), sijoitat (place the image inside the) kuvan (image inside the) sivun (page leaving a) sisälle jättäen marginaalin (leaving a margin, and), ja (and you advance to the) siirryt (advance to the) seuraavalle (next page. PDFium) sivulle (page. PDFium). PDFium Component antaa (gives you one) sinulle yhden metodin jokaiselle (method for each: AddPage): AddPage luo (creates a) tyhjän sivun (blank page at a) tietyssä koossa (given size, AddImage), AddImage (tai (or AddPicture if) AddPicture, jos (if you already hold a) sinulla (you already hold a) on jo (already hold a) TPicture) piirtää (draws the bitmap into the) bittikartan nykyiselle (current page, and) sivulle, ja (and PageNumber tells) PageNumber kertoo komponentille (tells the component which), mihin sivulle (which page subsequent) myöhemmät piirtokutsut (draw calls target) kohdistuvat (target)
Yksi yksityiskohta (One detail that trips) joka yllättää ihmisiä (trips people up is the) on koordinaattijärjestelmä (coordinate system. PDF). PDF:n käyttäjätila (user space puts the) asettaa origon (puts the origin at the) sivun (page, with) vasempaan (lower-left corner of the) alakulmaan (corner of the page, with), jolloin (with Y increasing) Y kasvaa ylöspäin (increasing upward, the), toisin (opposite of the) kuin (opposite of the) ne (screen coordinates Delphi) näyttökoordinaatit (screen coordinates Delphi), joihin Delphi-kehittäjät kurottavat refleksein (developers reach for by reflex. The). AddImage-metodille välittämäsi (pass to AddImage is the) X, Y on kuvasuorakulmion (image rectangle, and) vasen (lower-left corner of the) alakulma (corner of the image rectangle, and), ja (and Width, Height) Width, Height ovat asetuskoon (placement size in) mittoja pisteinä (points, not), eivät (not the) lähdetiedoston pikselikokona (pixel size of the source file. Get). Tee (Get that backwards and) se (that backwards and) väärinpäin (backwards and your), ja skannauksesi (scans land off the) laskeutuvat sivun ulkopuolelle (land off the page or) tai (or upside down relative) ylösalaisin suhteessa siihen (relative to where), minne odotit (expected them) niiden tulevan
Asiakirjan ja (Creating the document and a) yhden (a page per) sivun luominen per skannaus (page per scan)
Aloita (Start with an) tyhjällä (empty document. CreateDocument) asiakirjalla (document. CreateDocument). CreateDocument varaa (allocates a fresh) uuden (fresh PDF and) PDF:n ja (and leaves the) jättää komponentin (component active, so) aktiiviseksi, joten (so there is no) erillistä avausvaihetta ei (separate open step. From) ole (is no separate open step. From). Sieltä käsin käyt läpi (walk the list of) skannattujen (scanned files, and) tiedostojen (files, and for) luettelon (list of scanned files, and), ja jokaiselle niistä lisäät (for each one you add a) sivun, teet siitä (make it current, and) nykyisen, ja sijoitat kuvan (place the image. Page). Sivun (Page dimensions here) mitat (dimensions here are) ovat (are A4 in) tässä A4 pisteinä (points (595), arkistoidun (archived correspondence) kirjeenvaihdon (correspondence) standardi (standard sheet size for) arkkikoko (sheet size for)
procedure TArchiveForm.ScansToPdf(const Files: TStrings; const OutputPath: string);
const
PageW = 595.0; // A4 width in points
PageH = 842.0; // A4 height in points
Margin = 36.0; // half-inch border around each scan
var
I: Integer;
Pdf: TPdf;
begin
Pdf := TPdf.Create(nil);
try
Pdf.CreateDocument; // new, empty, already active
for I := 0 to Files.Count - 1 do
begin
Pdf.AddPage(I + 1, PageW, PageH); // 1-based page index
Pdf.PageNumber := I + 1; // make the new page current
PlaceScan(Pdf, Files[I], PageW, PageH, Margin);
end;
Pdf.SaveAs(OutputPath);
finally
Pdf.Free;
end;
end;
Jokainen iteraatio (Each iteration creates a) luo (creates a page and) sivun ja (and immediately sets) asettaa PageNumber-ominaisuuden välittömästi (immediately sets PageNumber to) siihen (it. That). Tuo (That second line matters: AddPage) toinen (second line matters: AddPage) rivi merkitsee (matters: AddPage inserts): AddPage lisää (inserts the page but) sivun, mutta piirtometodit vaikuttavat (draw methods act on) siihen sivuun, joka (whichever page is) sattuu olemaan nykyinen (current, so), joten PageNumber-ominaisuuden asettaminen kohdistaa (setting PageNumber is what aims) AddImage-kutsun juuri tekemääsi sivuun (aims AddImage at the page you just made. Skip). Ohita se (Skip it and), ja (and your) kuvasi pinoituvat sille sivulle, joka (images stack onto whatever page happened) sattui (happened to) olemaan ladattuna aiemmin (be loaded before)
Yksi oletus (One assumption hides in) piiloutuu tuohon (hides in that loop: the) silmukkaan: Files-luettelon (order of Files. A) järjestys (order of Files. A). Skanneri nimeää (scanner names pages) sivut (pages 0001.jpg) 0001.jpg:stä 0100.jpg:iin, mutta hakemiston (directory enumeration does) luettelointi (enumeration does not) ei koskaan palauta (always return them) niitä lajiteltuna, ja sillä hetkellä (moment you hit) kun osut (hit page9.jpg) page9.jpg:iin vieressä (next to page10.jpg) page10.jpg:tä, yksinkertainen merkkijonolajittelu (plain string sort puts) laittaa (puts page 10 before) sivun 10 ennen (before page 9. Sort) sivua 9. Lajittele luettelo nimenomaisesti ennen (list explicitly before the) silmukkaa, ja suosi (prefer zero-padded) nollatäytettyjä nimitapoja (names at scan) skannaushetkellä (scan time so), jotta leksikaalinen järjestys (lexical order matches) vastaa sivujärjestystä (matches page order. Page). Sivujen järjestys (sequence is the) on se yksi asia (one thing a), jonka (which a) arvioija huomaa (reviewer notices immediately, and) välittömästi (immediately, and it), ja (and it is the) se on celkein (cheapest mistake to) estettävissä (prevent) oleva (prevent) virhe (mistake to)
Skannauksen (Placing a scan and) sijoittaminen (Placing a scan and) ja sen (and keeping its) kuvasuhteen (aspect ratio) säilyttäminen (keeping its aspect ratio)
Skannaus on (scan is rarely the) harvoin samanmuotoinen kuin (same shape as the) sivu (page. If). Jos venytät (If you stretch it to) sen (it to fill the) täyttämään (fill the sheet you) arkin, vääristät (distort the text; if) tekstiä (text; if you); jos (if you place it at) sijoitat sen täydessä (place it at full pixel) pikselikoossa, se pursuaa (size it overflows. The) yli (overflows. The). Ratkaisu (fix is to) on (is to scale by) skaalata (scale by the) pienemmällä näistä (smaller of the two) kahdesta (two ratios, width-fit) suhteesta, leveyden sovitus (width-fit or height-fit, and) tai korkeuden sovitus, ja keskittää ylijäävä osuus (center what is left over. Because). Koska origo on (origin sits at the) alhaalla vasemmalla (lower-left, centering), keskittäminen tarkoittaa jäännöstilan (centering means splitting the leftover) jakamista (splitting the leftover space evenly) tasan ja (and adding it to) sen lisäämistä (adding it to both) sekä X:ään (both X and) että (and Y) Y:hyn
procedure TArchiveForm.PlaceScan(Pdf: TPdf; const FileName: string;
PageW, PageH, Margin: Double);
var
Pic: TPicture;
AvailW, AvailH, Scale, DrawW, DrawH, X, Y: Double;
begin
Pic := TPicture.Create;
try
Pic.LoadFromFile(FileName); // BMP, JPG, PNG, etc. via the VCL graphics units
AvailW := PageW - 2 * Margin;
AvailH := PageH - 2 * Margin;
// Fit inside the margins without distorting the scan.
Scale := Min(AvailW / Pic.Width, AvailH / Pic.Height);
DrawW := Pic.Width * Scale;
DrawH := Pic.Height * Scale;
// Center: leftover space split evenly. Y measured from the page bottom.
X := (PageW - DrawW) / 2;
Y := (PageH - DrawH) / 2;
Pdf.AddImage(FileName, X, Y, DrawW, DrawH);
finally
Pic.Free;
end;
end;
Tämä (This loads the) lataa tiedoston (file once to) kerran (once to read its) lukeakseen sen pikselimitat (pixel dimensions, computes a), laskee (computes a single) yhden yhtenäisen (single uniform scale, and) skaalan ja (passes the placement) välittää (passes the placement rectangle to) asettelusuorakulmion AddImage-kutsulle. AddImage hyväksyy (accepts a file) tiedostopolun suoraan ja (path directly and) reitittää (routes it through the) sen saman kuvaliukuhihnan (same image pipeline as) kautta (through the same image pipeline as) kuin (as AddPicture, so) AddPicture, joten mikä tahansa (any format the) muoto, jonka VCL-grafiikkayksiköt tunnistavat (VCL graphics units recognize works), toimii ilman erikoistapauksia (without special-casing. If). Jos (If you already) sinulla on (have the image) kuva jo (already have the image decoded in) purettuna (decoded in a) TPicture-objektissa esikatseluruudusta (preview pane, call), kutsu AddPicture(Pic, X, Y, DrawW, DrawH) samalla (same rectangle and) suorakulmiolla ja (rectangle and skip the) ohita toinen (skip the second file) tiedostonluku (file read)
Purun (Skipping the decode for) ohittaminen (Skipping the decode for) JPEG-skannauksissa (JPEG scans)
Skannerit tuottavat lähes (Scanners almost always emit) aina JPEG-muotoa (JPEG. Loading). JPEG:n lataaminen (Loading a JPEG into) TPicture-objektiin (TPicture decodes it) purkaa sen (decodes it to a) bittikartaksi, ja sitten (bitmap, and then) PDFium koodaa sen uudelleen (re-encodes it on) tallennettaessa, kaksi (save, two lossy) häviöllistä (lossy round trips you) edestakaista matkaa (round trips you do), joita et tarvitse (do not need. AddJpegImage). AddJpegImage upottaa alkuperäiset (embeds the original) pakatut tavut (compressed bytes straight) suoraan sivulle (straight into the) virrasta, mikä on sekä nopeampaa että (which is both faster and visually) visuaalisesti siistimpää (cleaner for a) suuren volyymin (high-volume batch) eräajossa (batch)
var
Stream: TFileStream;
begin
// ... after AddPage + PageNumber for the current page ...
Stream := TFileStream.Create(FileName, fmOpenRead);
try
// Embeds the JPEG bytes as-is; no decode/re-encode cycle.
Pdf.AddJpegImage(Stream, X, Y, DrawW, DrawH);
finally
Stream.Free;
end;
end;
Lasket silti (You still compute X) X-, (Y, DrawW) Y-, (and DrawH the) DrawW- ja (same way, since) DrawH-arvot samalla (way, since you) tavalla, koska tarvitset pikselimitat skaalausta (pixel dimensions to) varten (scale. Read). Lue ne tiedostosta tai (file or a) nopeasta otsikon jäsennyksestä (quick header parse, then), ja anna sitten (hand the raw) raaka (raw stream to) virta AddJpegImage-kutsulle. PNG- (For PNG or) tai (or TIFF scans the) TIFF-skannauksille (TIFF scans the AddImage) AddImage-polku on oikea (path is the right); varaa (one; reserve the) JPEG-pikakuvake sille muodolle (JPEG shortcut for the), johon se (format it actually) todella soveltuu (applies to)
Jokaisen sivun merkitseminen (Labeling each page)
Arkistoituja skannauksia on (Archived scans are easier to) helpompi (easier to audit when) auditoida, kun jokainen (each page carries its) sivu kantaa (carries its source) lähdetiedostonsa nimeä (filename. AddText). AddText piirtää merkkijonon käyttäjätilan koordinaattiin (string at a user-space coordinate, so), joten kuvateksti asettuu (caption sits just) aivan (just under the) kuvan alapuolelle (under the image. Remember). Muista käännetty (Remember the inverted) Y-akseli: asettaaksesi otsikon skannauksen (label below the scan, you) alle, vähennät kuvan alareunasta (subtract from the image's bottom) etkä (edge rather than) lisää (add to it) siihen
// Caption below the scan: Y decreases toward the page bottom.
Pdf.AddText('File: ' + ExtractFileName(FileName), 'Helvetica', 9,
X, Y - 14, clGray);
Yksi viimeinen (One last point about) huomio tallentamisesta (saving. SaveAs). SaveAs on funktio, joka palauttaa Boolen arvon (function that returns a Boolean, so), joten tuotantokoodissa tarkista sen tulos (in production code check its result rather) sen sijaan, että olettaisit kirjoituksen (than assuming the write succeeded; a) onnistuneen; täysi (full disk or) levy tai lukittu tulostepolku (locked output path fails) epäonnistuu (fails quietly otherwise. Once) muuten hiljaisesti (quietly otherwise. Once the). Kun silmukka (loop finishes and) päättyy ja (and the file is) tiedosto on kirjoitettu (written, you), sinulla on (have exactly what) täsmälleen se mitä (what the archive needed: one) arkisto tarvitsi: yksi järjestetty (ordered PDF per) PDF per (case file, pages) tapauskansio, sivut skaalattuna sopiviksi (scaled to fit, ready), valmiina luettavaksi missä tahansa katseluohjelmassa (ready to read in any viewer)
Samat rakennuspalikat kattavat (same building blocks cover) vastaavia töitä (related jobs. Swap). Vaihda (Swap the per-page) sivukohtainen mitoitussääntö (sizing rule and) ja (and you get a) saat (get a photo) valokuvakirjan (book with one), jossa on (image per sheet; keep) yksi kuva per arkki; pidä silmukka (keep the loop but), mutta lue monisivuisesta (read from a TIFF multi-page source and) TIFF-lähteestä, ja sinulla on faksiarkiston muunnin (fax-archive converter. If). Jos (If you want the) haluat (want the wider) laajemman kuvan PDF-tiedostojen (picture of building PDFs programmatically, see) rakentamisesta ohjelmallisesti (programmatically, see creating), katso (see creating PDF) PDF-asiakirjojen (PDF documents from scratch with PDFium Component) luominen (creating PDF documents from scratch with PDFium Component) tyhjästä PDFium Component -komponentilla (PDF documents from scratch with PDFium Component); hahmontaaksesi (to render the) tuloksen takaisin (result back to) näytölle (screen later, see) myöhemmin (later, see converting), katso (see converting PDF) PDF-sivujen muuntaminen (converting PDF pages to JPEG images with PDFium Component) JPEG-kuviksi PDFium Component -komponentilla (JPEG images with PDFium Component)
PDFium Component osoitteesta (from loslab.com bundles the) loslab.com (bundles the document-creation, rendering, and) niputtaa koko tässä sarjassa (used throughout this) käytetyt asiakirjan luonti-, hahmonnus- (document-creation, rendering, and) ja (and text APIs used) teksti-API:t yhteen (APIs used throughout this series)