Kutsut AddText-metodia leimataksesi rivin PDF-sivulle PDFiumPas:lla, sitten kutsut heti FindFirst-metodia vahvistaaksesi, että leima osui, ja haku palautuu tyhjänä. Teksti on sivulla — Acrobat näyttää sen — mutta PDFiumPas:n TPdf-komponentti pitää erillisen välimuistitetun FPDF_TEXTPAGE-rakenteen, jäsennettynä kerran sivun sisältövirrasta, eikä muokkaus päivitä tuota rakennetta takautuvasti itsestään. Kysele sitä ennen kuin se on virkistetty, ja luet sivun täsmälleen sellaisena kuin se näytti ennen muutostasi, ei sen jälkeen
Miksi PDFium palauttaa vanhentunutta tekstiä heti muokkauksen jälkeen?
PDFiumPas kääri Googlen PDFium-renderöintimoottorin Delphille ja C++Builderille, ja sen teksti- ja muokkauskutsut ulottuvat kahteen eri alijärjestelmään tuon moottorin sisällä. FPDF_TEXTPAGE kuuluu lukupuolelle: FPDFText_LoadPage käy sivun sisältövirran läpi kerran ja rakentaa tekstisivun — merkkikoodit, sijainnit, fonttimitat, sanarajat — ja PDFiumPas pitää tuon rakenteen välimuistitettuna niin kauan kuin sivu pysyy ladattuna. Muokkauskutsut kuten FPDFPage_InsertObject tai FPDFPage_GenerateContent toimivat täysin erilaisella esityksellä, sivun olio- ja sisältövirtakaaviolla, eikä PDFium työnnä noita muutoksia jo avoimeen tekstisivuun itsestään. Sen uudelleenrakentaminen jokaisella muokkauksella tekisi erämuokkauksesta kohtuuttoman hitaan, joten suunnittelu vaihtaa tuon kustannuksen säännöksi sen sijaan — kuka tahansa pitää kahvaa hallussaan, sulkee sen sisältöä muuttavan muokkauksen jälkeen, ja seuraava luku rakentaa tuoreen
TPdf:n tekstivälimuistin sisällä: FTextPage, LoadTextPage ja UnloadTextPage
TPdf seuraa välimuistitettua kahvaa yhdessä yksityisessä kentässä, FTextPage, ja kääri sen elinkaaren kahteen metodiin. LoadTextPage tarkistaa, onko FTextPage nil, ja vain siinä tapauksessa kutsuu FPDFText_LoadPage-funktiota nykyistä sivua vasten; jos kahva on jo olemassa, LoadTextPage käyttää sitä uudelleen kysymättä, onko sivu muuttunut sen rakentamisen jälkeen. UnloadTextPage on toinen puolisko: se sulkee natiivin kahvan funktiolla FPDFText_ClosePage, asettaa FTextPage:n takaisin nilliksi, ja pudottaa myös välimuistitetun verkkolinkkilistan ja minkä tahansa kesken olevan hakuistunnon, koska molemmat johdettiin samasta tekstisivusta ja vanhenevat samasta syystä
LoadTextPagen uudelleenkäyttö-tarkistamatta-käytös on juuri se, miksi järjestys on merkityksellinen. Jokainen tekstikysely TPdf:llä — Text, FindFirst, GetWebLinks — ohjautuu ensin LoadTextPage-funktion kautta, joten niin kauan kuin FTextPage yhä pitää muokkausta edeltävää kahvaa, millään noista kutsuista ei ole tapaa tietää, että muutos tapahtui. Sivunavigointi ei koskaan ollut riski tässä: UnloadPage, joka ajetaan sivunvaihdoilla, uudelleenlatauksilla ja asiakirjan sulkemisella, on aina sulkenut tekstisivun sivun itsensä mukana. Avoin kysymys oli aina muokkauksista, jotka sovelletaan sivuun, jolla yhä istut
Mitkä PDFiumPas-metodit virkistävät välimuistin automaattisesti?
TPdf:n omat sivunmuokkausmetodit — AddText, SetText, SetTextPositions, AddPath, RemoveObject ja InsertFormObjectFromXObject — kukin kutsuu UnloadTextPage-funktiota ennen kuin ne kutsuvat UpdatePage-funktiota (PDFiumin FPDFPage_GenerateContent) sarjallistaakseen muutoksen sisältövirtaan. Kutsu mitä tahansa näistä, ja aivan seuraava Text-, FindFirst- tai GetWebLinks-kutsu rakentaa tekstisivun uudelleen sisällöstä sellaisena kuin se nyt on, ilman että puoleltasi vaaditaan mitään ylimääräistä kutsua
var
Pdf: TPdf;
Index: Integer;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := 'invoice.pdf';
Pdf.Active := True;
Pdf.PageNumber := 1;
Pdf.AddText('Reviewed by J. Alvarez', 'Helvetica', 10, 72, 40, clBlack, 255, 0);
// AddText already closed the cached text page, so this FindFirst
// call rebuilds it fresh before it searches
Index := Pdf.FindFirst('Reviewed by J. Alvarez');
if Index >= 0 then
ShowMessage('Stamp confirmed at character ' + IntToStr(Index));
finally
Pdf.Free;
end;
end;
Malli, joka yhä hajoaa: raa'an TextPage-kahvan välimuistittaminen
TPdf paljastaa elävän kahvan vain luku -ominaisuuden TextPage kautta, harvinaista tapausta varten, jossa sinun on kutsuttava FPDFText_*-funktiota, jota PDFiumPas ei ole kääräissyt. Tuo pako-luukku on myös se yksi paikka, jossa automaattinen mitätöinti ei voi auttaa: heti kun kopioit FPDF_TEXTPAGE-arvon ominaisuudesta paikalliseen muuttujaan, PDFiumPas:lla ei ole tapaa tietää, että pidät sitä yhä hallussasi, eikä tapaa päivittää kopiotasi, kun UnloadTextPage ajetaan jossain muualla koodissasi
var
Pdf: TPdf;
RawHandle: FPDF_TEXTPAGE;
StaleCount: Integer;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := 'contract.pdf';
Pdf.Active := True;
Pdf.PageNumber := 1;
RawHandle := Pdf.TextPage; // FPDFText_LoadPage handle, cached in FTextPage
Pdf.SetText(0, 'Amended Clause 4.2');
// SetText already closed RawHandle and set Pdf.TextPage back to nil.
// Calling any FPDFText_* function against the old value now touches a
// handle PDFium has already freed — undefined behavior, not a bug you
// can catch with a nil check
StaleCount := FPDFText_CountChars(RawHandle);
finally
Pdf.Free;
end;
end;
Kahvan käyttäminen sen jälkeen, kun FPDFText_ClosePage on ajettu sille, on määrittelemätöntä käytöstä itse PDFiumissa, ei PDFiumPas-käytäntö, jonka voisit valita ohittaa — se voi palauttaa viimeksi tunnetun datan, palauttaa ei mitään, tai kaataa prosessin, eikä se, mikä näistä tapahtuu tietyssä käännöksessä, ole jotain, mihin sovelluskoodin pitäisi luottaa. Turvallinen sääntö on kapea: lue Pdf.TextPage tuoreena, välittömästi ennen FPDFText_*-kutsua, joka sitä tarvitsee, äläkä koskaan pidä kopiota yli lauseen, joka saattaa muokata sivua
Erä muokkauksesi, sitten kysele kerran
Mikään tästä ei tarkoita, että jokainen AddText- tai RemoveObject-kutsu tarvitsee puolustavan tekstikyselyn heti sen jälkeen tuloksen tarkistamiseksi. Jokainen muokkausmetodi maksaa jo tekstisivun sulkemisen kustannuksen kerran; kysely jokaisen yksittäisen muokkauksen jälkeen silmukan sisällä maksaa tuon kustannuksen uudelleen ilman hyötyä, koska FPDFText_LoadPage käy koko sisältövirran läpi uudelleen joka kerta, kun se ajetaan
var
Pdf: TPdf;
I: Integer;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := 'watermarked.pdf';
Pdf.Active := True;
Pdf.PageNumber := 1;
// Strip every text object that looks like a draft watermark. Each
// RemoveObject call already invalidates the cache on its own, so
// nothing needs refreshing by hand between iterations
for I := Pdf.ObjectCount - 1 downto 0 do
if (Pdf.ObjectType[I] = otText) and (Pdf.ObjectBounds[I].Top > 700) then
Pdf.RemoveObject(I, True);
// Query once, after the whole batch is done, not once per removal
if Pdf.FindFirst('DRAFT') < 0 then
ShowMessage('Watermark cleared');
finally
Pdf.Free;
end;
end;
Sama erittelylogiikka pätee nimenomaan hakutilaan. FindNext ja FindPrevious jatkavat FindFirst-funktion aloittamaa istuntoa, ja tuo istunto puretaan UnloadTextPage-funktiolla kaiken muun mukana, joten FindNext-kutsun kutsuminen uudelleen muokkauksen jälkeen — FindFirst-funktion uudelleenkutsumisen sijaan — nostaa poikkeuksen sen sijaan, että hiljaa jatkaisi hakua sisältöä vastaan, jota ei enää ole olemassa. Kohtele mitä tahansa muokkausta kovana rajana sekä tekstisisällölle että hakupositiolle, ja anna yhden tuoreen FindFirst-kutsun muokkausten toisella puolella poimia haku takaisin
Mihin tämä sopii poiminta- ja annotaatiotyön kanssa
Pelkkä tekstin poiminta — sivun tekstin lukeminen muuttamatta mitään — ei koskaan törmää mihinkään tästä, koska mikään ei mitätöi kahvaa, jota mikään muokkaus ei ole koskettanut. Miten Text, merkkisuorakulmiot ja sanarajat toimivat muokkaamattomalla sivulla, käsitellään artikkelissa rinnakkaisartikkeli tekstin poiminnasta PDFiumPas:lla, joka kattaa tuon maaperän ilman tätä artikkelia, joka lisää tekstisivuvälimuistin elinkaaren päälle
Välimuistin elinkaari on merkityksellisin työnkuluissa, jotka muokkaavat ja sitten välittömästi toimivat tuloksen perusteella: korjauksen leimaaminen ja sen etsiminen, kappaleen redaktointi ja sen katoamisen vahvistaminen, tai lauseen paikantaminen ankkuroidakseen merkintäannotaation heti tekstin lisäämisen jälkeen sen lähelle. Tuo viimeinen tapaus kannattaa merkitä erikseen — quad-point-merkintäannotaatiot sijoitetaan merkkisuorakulmioista, jotka luetaan tekstisivulta, joten ennen muokkausta talteen otetuista koordinaateista rakennettu annotaatio päätyy korostamaan väärää kohtaa heti, kun muokkaus astuu voimaan
TPdf:n muokkaus- ja teksti-API:t ovat osa PDFium-komponenttia Delphille ja C++Builderille, ja tuotesivulla on koko metodiviite tässä käsitellyille muokkaus-, poiminta- ja hakupinnoille