Dva dokumenty otvorené súčasne, rovnaké číslo stránky, každý vo vlastnom rolovateľnom paneli: to je základ porovnávacieho prehliadača. PDFium Component to poskytuje prostredníctvom priameho objektového modelu, kde TPdf vlastní súbor a TPdfView riadi zobrazenie. Jeden dokument, jeden TPdf, jeden TPdfView. Ak chcete tri panely, máte tri páry. Tými náročnejšími časťami nie sú volania API, ale matematika rozloženia pri zmene veľkosti okna a logika synchronizácie stránok, keď určujete, ktoré zobrazenie má nasledovať ktoré
Rozloženie formulára
Formulár VCL obsahuje tri kontajnery TScrollBox vedľa seba, z ktorých každý má vo vnútri komponent TPdfView zarovnaný na alClient, takže vypĺňa celý box. Dva komponenty TSplitter sú umiestnené medzi boxmi, aby používateľ mohol počas prevádzky upravovať šírku stĺpcov. Panel nástrojov nad panelmi obsahuje tlačidlá na otvorenie, ovládacie prvky priblíženia a prepínač medzi zobrazením dvoch alebo troch panelov
Režim troch zobrazení je hodnota typu Boolean, ktorú formulár sleduje interne. Pri jej prepnutí prepočítate šírky a zobrazíte alebo skryjete tretí stĺpec. Najjednoduchším prístupom je zrušiť všetky vlastnosti Align, skryť splittery a potom nastaviť absolútne pozície:
procedure TFormMain.UpdateLayout;
var
TotalWidth: Integer;
begin
TotalWidth := ClientWidth;
if ThreeViewMode then
begin
ScrollBox3.Visible := True;
ScrollBox1.Left := 0;
ScrollBox1.Width := TotalWidth div 3;
ScrollBox2.Left := ScrollBox1.Width;
ScrollBox2.Width := TotalWidth div 3;
ScrollBox3.Left := ScrollBox2.Left + ScrollBox2.Width;
ScrollBox3.Width := TotalWidth - ScrollBox3.Left;
// Apply the same (ClientHeight - toolbar height) to all three Height values
end
else
begin
ScrollBox3.Visible := False;
ScrollBox1.Left := 0;
ScrollBox1.Width := TotalWidth div 2;
ScrollBox2.Left := ScrollBox1.Width;
ScrollBox2.Width := TotalWidth - ScrollBox2.Left;
end;
end;
Nastavenie Align := alNone pre všetky tri boxy pred celočíselnou matematikou zabráni tomu, aby mechanizmus obmedzení VCL bojoval s vašimi priradeniami. Po umiestnení obnovte viditeľnosť splitterov, ak chcete povoliť zmenu veľkosti ťahaním v režime dvoch zobrazení
Výška každého scroll boxu je výška klientskej oblasti mínus výška panela nástrojov. Keďže panel nástrojov je ukotvený navrchu pomocou alTop, ClientHeight - PanelButtons.Height vám poskytne využiteľný vertikálny priestor. Priraďte túto hodnotu všetkým trom boxom v rámci rovnakého volania UpdateLayout, aby nikdy nenastal moment, kedy je jeden box vyšší ako ostatné, čo by spôsobilo blikanie rozloženia
Otvorenie dokumentu
Každý pár panelov potrebuje vlastnú procedúru otvorenia. Vzor je stručný: deaktivujte komponent, nastavte názov súboru, pokúste sa o aktiváciu a zachyťte EPdfError, ak súbor vyžaduje heslo. Všimnite si, že TPdfView.Active riadi vykresľovanie, ale TPdf.Active v skutočnosti otvára súbor – tieto vlastnosti sú nezávislé. Nastavenie PdfView.Active := True, keď jeho prepojený TPdf ešte nie je aktívny, je neškodné, ale nič nezobrazí
procedure TFormMain.OpenPdfFile(PdfComponent: TPdf;
PdfViewComponent: TPdfView);
var
Password: string;
begin
if not OpenDialog.Execute then
Exit;
PdfComponent.Active := False;
PdfComponent.FileName := OpenDialog.FileName;
PdfComponent.Password := '';
try
PdfComponent.Active := True;
except
on E: EPdfError do
begin
if InputQuery('Password', 'Enter document password:', Password) then
begin
PdfComponent.Password := Password;
PdfComponent.Active := True;
end
else
raise;
end;
end;
if PdfComponent.Active then
begin
PdfViewComponent.PageNumber := 1;
SetActivePdfView(PdfViewComponent);
end;
end;
Po priradení vždy skontrolujte PdfComponent.Active; poškodený súbor alebo nesprávne heslo spôsobí, že načítanie v predvolenej ceste zlyhá potichu bez vyvolania výnimky. Explicitné nastavenie PdfViewComponent.PageNumber := 1 po úspešnom otvorení zabráni zobrazeniu neaktuálneho čísla stránky z predchádzajúceho dokumentu
Kód na spracovanie hesla uvedený vyššie vyvolá výnimku pri akejkoľvek inej chybe než pri známej správe o hesle. Je to zámerné: chcete, aby sa poškodené alebo nepodporované súbory prejavili okamžite a neboli potichu prehltnuté ako prázdny panel. Používateľ, ktorý nič nevidí, netuší, či sa súbor načítal a je jednoducho prázdny, alebo či ho komponent odmietol. Vyvolanie výnimky udržiava chybu viditeľnú
Sledovanie aktívneho panela
Keď používateľ klikne do vnútra panela, tento panel sa stane aktívnym. Formulár sleduje súkromné pole FActivePdfView: TPdfView. Vizuálna odozva je realizovaná zmenou farby okraja prislúchajúceho TScrollBox: pre aktívny nastavte farbu na clHighlight a pre ostatné na clWindow. Prepojte to s udalosťou TPdfView.OnClick každého zobrazenia a s procedúrou otvorenia, aby sa zameranie presunulo na dokument, ktorý ste práve otvorili
Niektoré operácie sa vzťahujú na všetky viditeľné panely, nielen na ten aktívny. Prepínač typu Boolean FAllViewsMode na formulári riadi toto vetvenie. Keď je nastavený na hodnotu True, zmeny priblíženia a navigácia po stránkach sa rozšíria na každý panel, ktorý má aktívny dokument:
procedure TFormMain.ApplyZoomToAll(NewZoom: Double);
begin
if PdfView1.Active then PdfView1.Zoom := NewZoom;
if PdfView2.Active then PdfView2.Zoom := NewZoom;
if ThreeViewMode and PdfView3.Active then PdfView3.Zoom := NewZoom;
end;
Synchronizovaná navigácia stránok
Synchronizovaná navigácia je voliteľná, ale užitočná pri revízii dokumentov, kde oba súbory pokrývajú rovnaký rozsah stránok. Logika patrí do obsluhy udalosti, ktorá sa spustí po tom, čo používateľ zmení zobrazenie. Keď zdrojové zobrazenie zmení svoje PageNumber, obsluha rozšíri toto číslo do ostatných zobrazení pod jednou podmienkou: cieľové zobrazenie musí mať aspoň toľko stránok, inak sa krok preskočí
Vlastnosti PageNumber pre TPdfView a TPdf sú nezávislé. TPdf.PageNumber sleduje, ktorú stránku považuje komponent dokumentu za aktuálnu; TPdfView.PageNumber sleduje, čo sa zobrazuje na obrazovke. Pre účely navigácie potrebujete vlastnosť zobrazenia (view), nie dokumentu
Začiarkavacie políčko označené napríklad „Synchronizovať stránky“ dáva kontrolu používateľovi. Keď je nezačiarknuté, každý panel sa pohybuje nezávisle a obsluha okamžite skončí. Táto nezávislosť je dôležitá pre prípady, kedy majú dva dokumenty odlišný počet strán, alebo keď chce používateľ nájsť ekvivalentnú pasáž v preklade, ktorý začína na inej stránke. Trvalé vynútenie synchronizácie by robilo nástroj menej praktickým ako jednoduché usporiadanie dvoch okien na ploche
Jedna vec, na ktorú si treba dať pozor: programové nastavenie PdfView.PageNumber vo vnútri obsluhy synchronizácie samo osebe spustí udalosť zmeny na danom zobrazení. Zabráňte nekonečnej rekurzii pomocou príznaku Boolean, ktorý nastavíte pred priradením a vymažete ihneď po ňom. Tento príznak je na úrovni formulára, nie zobrazenia, keďže všetky tri zobrazenia zdieľajú rovnakú obsluhu
Priblíženie na panel
Každý TPdfView má vlastnú vlastnosť Zoom, typ Double v percentách, kde 1.0 znamená 100%. Jej nastavenie prepíše akýkoľvek aktívny FitMode. Pre tlačidlo „prispôsobiť šírke“ na aktívnom paneli prečítajte zoom prispôsobenia z PdfView.PageWidthZoom[PdfView.PageNumber] a priraďte ho. Pre prispôsobenie na celú stránku použite PageZoom[PageNumber]. Obe sú indexované vlastnosti poľa začínajúce od 1, preto pred prístupom k nim skontrolujte, či číslo stránky nie je nula
Keď exportujete aktuálnu stránku do obrázka, prečítajte otočenie zo zobrazenia, ale zavolajte RenderPage na komponente TPdf, nie na zobrazení. Bitová mapa metódy TPdf.RenderPage preberá explicitné rozmery v pixeloch, hodnotu TRotation a sadu možností TRenderOptions. Variant funkcie vracia TBitmap vlastnenú volajúcim, ktorú po uložení sami uvoľníte:
procedure TFormMain.SaveActiveViewAsImage;
var
Pdf: TPdf;
Bmp: TBitmap;
Jpeg: TJpegImage;
begin
if not Assigned(FActivePdfView) or not FActivePdfView.Active then
Exit;
Pdf := FActivePdfView.Pdf;
Pdf.PageNumber := FActivePdfView.PageNumber;
Bmp := Pdf.RenderPage(
0, 0,
Round(Pdf.PageWidth * 2),
Round(Pdf.PageHeight * 2),
FActivePdfView.Rotation, [], clWhite);
try
if SavePictureDialog.Execute then
begin
Jpeg := TJpegImage.Create;
try
Jpeg.Assign(Bmp);
Jpeg.CompressionQuality := 90;
Jpeg.SaveToFile(SavePictureDialog.FileName);
finally
Jpeg.Free;
end;
end;
finally
Bmp.Free;
end;
end;
Násobiteľ 2x pre šírku a výšku poskytuje ostrejší výstup pre dokumenty s jemným textom. Konštrukcia try/finally okolo uvoľnenia bitovej mapy nie je voliteľná; zrušenie dialógu TSaveDialog stále zasiahne blok finally a chcete, aby sa bitová mapa uvoľnila bez ohľadu na to, čo používateľ urobil
Požiadavky na DLL
PDFium Component obaluje natívnu knižnicu pdfium. 32-bitový hostiteľský proces vyžaduje pdfium32.dll, 64-bitový vyžaduje pdfium64.dll. Varianty s JavaScript engine V8 pridávajú príponu v8 s veľkosťou približne 23 – 27 MB v porovnaní s 5 – 6 MB štandardných zostáv. Pre porovnávací prehliadač, ktorý zakazuje vypĺňanie formulárov (Pdf.FormFill := False), postačuje štandardná zostava bez V8 a distribúcia zostáva menšia
Umiestnite DLL do rovnakého adresára ako spustiteľný súbor alebo do akéhokoľvek adresára v systémovej ceste PATH. Komponent ju načíta na požiadanie, keď sa aktivuje prvý TPdf, takže chýbajúca DLL sa prejaví v tomto bode a nie pri spustení aplikácie. Ak dodávate inštalátor, najspoľahlivejším prístupom je skopírovať DLL do priečinka aplikácie počas inštalácie, namiesto spoliehania sa na systémový adresár, ktorý môže správca neskôr vyčistiť
Zostavy s V8 sú užitočné predovšetkým vtedy, keď potrebujete pracovať s akciami JavaScriptu v PDF, napríklad na spúšťanie výpočtových polí alebo odosielacích skriptov. Pasívny porovnávací prehliadač nemá dôvod spúšťať JavaScript; nastavenie Pdf.FormFill := False pred Active := True úplne preskočí prostredie vypĺňania formulárov, čo tiež znamená, že sa neinicializuje žiadny engine JS, aj keď sa použije štandardná zostava. To je správna predvolená možnosť pre prehliadač určený len na čítanie bez ohlladu na to, ktorú verziu DLL dodávate
Ďalšie podrobnosti o komponente PDFium Component a jeho kompletnom API nájdete na produktovej stránke Delphi PDFium Component