Dva dokumenty otvorené naraz, rovnaké číslo strany, každý vo vlastnom rolovateľnom paneli: to je jadro porovnávacieho zobrazovača. PDFium Component to poskytuje cez priamočiary objektový model, v ktorom TPdf vlastní súbor a TPdfView vlastní zobrazenie. Jeden dokument, jedno TPdf, jedno TPdfView. Ak chcete tri panely, máte tri dvojice. Ťažké časti nie sú volania rozhrania; je to aritmetika rozloženia pri zmene veľkosti okna a logika synchronizácie strán, keď sa rozhodujete, ktorý pohľad má nasledovať ktorý
Rozloženie formulára
Formulár VCL drží tri kontajnery TScrollBox vedľa seba, každý s jedným TPdfView vnútri zarovnaným na alClient, aby vyplnil celý box. Medzi boxmi sedia dva komponenty TSplitter, takže používateľ môže šírky stĺpcov upravovať za behu. Panel nástrojov nad panelmi nesie tlačidlá na otvorenie, ovládanie priblíženia a prepínač medzi dvoma a tromi pohľadmi
Režim troch pohľadov je boolean, ktorý si formulár sleduje interne. Keď sa prepne, prepočítate šírky a tretí stĺpec zobrazíte alebo skryjete. Najjednoduchším prístupom je vyčistiť 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;
// Rovnaké (ClientHeight - výška panela nástrojov) dajte všetkým trom Height
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 na všetkých troch boxoch pred celočíselnou aritmetikou zabráni tomu, aby s vašimi priradeniami zápasil engine obmedzení vo VCL. Ak chcete v režime dvoch pohľadov meniť šírku ťahaním, po umiestnení viditeľnosť splitterov obnovte
Výška každého rolovacieho boxu je klientská oblasť mínus výška panela nástrojov. Keďže panel nástrojov je ukotvený hore cez alTop, ClientHeight - PanelButtons.Height vám dá využiteľný zvislý priestor. Priraďte ju všetkým trom boxom vnútri toho istého volania UpdateLayout, aby nikdy nenastal snímok, v ktorom je jeden box vyšší než ostatné a spôsobí blikanie rozloženia
Otvorenie dokumentu
Každá dvojica panelov potrebuje vlastnú procedúru na otvorenie. Vzor je krátky: deaktivujte komponent, nastavte názov súboru, aktivujte a potom skontrolujte Active; ak zostalo False, vypýtajte si heslo a skúste znovu. Všimnite si, že TPdfView.Active riadi vykresľovanie, ale súbor v skutočnosti otvára TPdf.Active; sú nezávislé. Nastaviť PdfView.Active := True, kým jeho prepojené TPdf ešte aktívne nie je, je neškodné, ale nezobrazí nič
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 := '';
PdfComponent.Active := True;
// Zlyhania načítania sú tiché: Active zostane False namiesto výnimky.
if not PdfComponent.Active then
begin
// Najskôr ide o súbor chránený heslom; dajte používateľovi jeden pokus.
if InputQuery('Password', 'Enter document password:', Password) then
begin
PdfComponent.Password := Password;
PdfComponent.Active := True;
end;
end;
if not PdfComponent.Active then
begin
ShowMessage('Could not open ' + OpenDialog.FileName +
' (damaged file or wrong password)');
Exit;
end;
PdfViewComponent.PageNumber := 1;
SetActivePdfView(PdfViewComponent);
end;
Po priradení vždy skontrolujte PdfComponent.Active; poškodený súbor alebo nesprávne heslo spôsobia, že načítanie v predvolenej ceste zlyhá potichu bez vyvolania výnimky. Explicitné nastavenie PdfViewComponent.PageNumber := 1 po úspešnom otvorení zabráni tomu, aby ostalo staré číslo strany z predchádzajúceho dokumentu
Dialóg so správou na konci je zámerný: chcete, aby sa poškodené alebo nepodporované súbory ozvali okamžite a neboli spolknuté ako tichý prázdny panel. Používateľ, ktorý nevidí nič, netuší, či sa súbor načítal a je len prázdny, alebo či ho komponent odmietol. Ohlásenie zlyhania udrží chybu viditeľnú
Sledovanie aktívneho panela
Keď používateľ klikne dovnútra panela, tento panel sa stane aktívnym. Formulár si sleduje súkromné pole FActivePdfView: TPdfView. Vizuálnou spätnou väzbou je zmena farby okraja obklopujúceho TScrollBox: aktívnemu nastavte clHighlight a ostatným clWindow. Napojte to na každú udalosť TPdfView.OnClick aj na procedúru otvorenia, aby fokus nasledoval dokument, ktorý ste práve otvorili
Niektoré operácie sa vzťahujú na všetky viditeľné panely, nie len na aktívny. Túto vetvu riadi boolean FAllViewsMode na formulári. Keď je true, zmeny priblíženia a navigácia po stranách sa rozvetvia do každého panela, 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 po stranách
Synchronizovaná navigácia je voliteľná, no užitočná pri postupoch s revíziami dokumentov, kde oba súbory pokrývajú rovnaký rozsah strán. Logika patrí do obsluhy udalosti, ktorá sa spustí po tom, čo používateľ zanavigoval v jednom pohľade. Keď zdrojový pohľad zmení svoje PageNumber, obsluha toto číslo rozšíri do ostatných pohľadov s jednou poistkou: cieľový pohľad musí mať aspoň toľko strán, inak sa preskočí
Vlastnosti PageNumber na TPdfView a na TPdf sú nezávislé. TPdf.PageNumber sleduje, ktorú stranu považuje dokumentový komponent za aktuálnu; TPdfView.PageNumber sleduje, čo je zobrazené na obrazovke. Na účely navigácie chcete vlastnosť pohľadu, nie dokumentu
Zaškrtávacie políčko s popisom typu „Synchronizovať strany“ dáva kontrolu používateľovi. Keď nie je zaškrtnuté, každý panel naviguje nezávisle a obsluha okamžite skončí. Táto nezávislosť je dôležitá pre prípady, keď majú oba dokumenty rôzny počet strán alebo keď chce používateľ nájsť rovnocennú pasáž v preklade, ktorý sa začína na inej strane. Vynútená trvalá synchronizácia by nástroj urobila ťažšie použiteľným než jednoduché usporiadanie dvoch okien na ploche
Jedna vec na pozor: nastavenie PdfView.PageNumber programovo vnútri synchronizačnej obsluhy samo spustí na tomto pohľade udalosť zmeny. Proti nekonečnej rekurzii sa bráňte booleovským príznakom, ktorý nastavíte pred priradením a hneď po ňom zmažete. Príznak je na formulár, nie na pohľad, pretože všetky tri pohľady zdieľajú tú istú obsluhu
Priblíženie na každý panel zvlášť
Každé TPdfView nesie vlastnú vlastnosť Zoom, hodnotu typu Double v percentách, kde Zoom := 100 znamená skutočnú veľkosť (100 %). Jej nastavenie prebije akýkoľvek aktívny FitMode. Pre tlačidlo prispôsobenia šírke na aktívnom paneli prečítajte prispôsobené priblíženie z PdfView.PageWidthZoom[PdfView.PageNumber] a priraďte ho. Pre prispôsobenie strane použite PageZoom[PageNumber]. Obe sú poľové vlastnosti indexované číslom strany od jednotky, takže pred prístupom sa poistite proti nulovému číslu strany
Keď aktuálnu stranu exportujete do obrázka, otočenie prečítajte z pohľadu, ale RenderPage zavolajte na komponente TPdf, nie na pohľade. Bitmapová podoba metódy TPdf.RenderPage berie explicitné rozmery v pixeloch plus hodnotu TRotation a množinu TRenderOptions. Funkčný variant 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;
Dvojnásobný násobiteľ šírky a výšky dá ostrejší výstup pri dokumentoch s jemným textom. try/finally okolo uvoľnenia bitmapy nie je voliteľné; zrušenie dialógu TSaveDialog stále prejde blokom finally a bitmapu chcete uvoľniť bez ohľadu na to, čo používateľ urobil
Požiadavky na DLL
PDFium Component obaľuje natívnu knižnicu pdfium. 32-bitový hostiteľský proces potrebuje pdfium32.dll, 64-bitový potrebuje pdfium64.dll. Varianty s JavaScriptovým enginom V8 pridávajú príponu v8 a vážia zhruba 23-27 MB oproti 5-6 MB štandardných buildov. Pre porovnávací zobrazovač, ktorý vypína vypĺňanie formulárov (Pdf.FormFill := False), stačí štandardný build bez V8 a distribúcia zostane menšia
Umiestnite DLL do rovnakého adresára ako spustiteľný súbor alebo do ľubovoľného adresára v systémovej premennej PATH. Komponent ju načíta na požiadanie pri aktivácii prvého TPdf, takže chýbajúca DLL sa ozve až v tej chvíli, nie pri štarte aplikácie. Ak dodávate inštalátor, najspoľahlivejším prístupom je skopírovať DLL počas inštalácie do priečinka aplikácie namiesto spoliehania sa na systémový adresár, ktorý môže správca neskôr vyčistiť
Buildy s V8 sú užitočné najmä vtedy, keď potrebujete pracovať s akciami JavaScriptu v PDF, napríklad spúšťať výpočtové polia alebo obsluhy odoslania. Pasívny porovnávací zobrazovač nemá dôvod spúšťať JavaScript; nastavenie Pdf.FormFill := False pred Active := True úplne preskočí prostredie na vypĺňanie formulárov, čo zároveň znamená, že sa engine JS neinicializuje ani pri použití štandardného buildu. To je správne predvolené nastavenie pre zobrazovač len na čítanie bez ohľadu na to, ktorý variant DLL dodávate
Ďalšie podrobnosti o PDFium Component a jeho úplnom rozhraní nájdete na produktovej stránke Delphi PDFium Component