Tehnični članak

Vzporedna primerjava PDF v Delphiju s PDFium Component

Dva dokumenta, odprta hkrati, ista številka strani, vsak v svoji drsni plošči: to je jedro pregledovalnika za primerjavo. PDFium Component to omogoča z neposrednim objektnim modelom, kjer je TPdf lastnik datoteke, TPdfView pa lastnik prikaza. En dokument, en TPdf, en TPdfView. Če želite tri plošče, imate tri pare. Težki deli niso klici vmesnika; težka sta računanje postavitve ob spremembi velikosti okna in logika usklajevanja strani, ko se odločate, kateri pogled naj sledi kateremu

Postavitev obrazca

Obrazec VCL nosi tri vsebnike TScrollBox drug ob drugem, vsak z TPdfView v sebi in poravnan na alClient, tako da zapolni polje. Med polji sedita dve komponenti TSplitter, da lahko uporabnik med izvajanjem prilagaja širine stolpcev. Orodna vrstica nad ploščami nosi gumbe za odpiranje, kontrolnike povečave in preklop med dvema in tremi pogledi

Način s tremi pogledi je logična vrednost, ki jo obrazec vodi interno. Ko se preklopi, preračunate širine ter tretji stolpec pokažete ali skrijete. Najpreprostejši pristop je počistiti vse lastnosti Align, skriti razdelilnike in nato nastaviti absolutne položaje:

Diagram postavitve obrazca vzporednega pregledovalnika za primerjavo PDF v Delphiju, zgrajenega s PDFium Component, z orodno vrstico, tremi drsnimi polji s ploščami TPdfView in razdelilniki v načinu z dvema in tremi pogledi
Vsaka plošča je drsno polje s komponento TPdfView v sebi, preklop med dvema in tremi pogledi pa je le drugačen nabor dodelitev širin
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;
    // Isto vrednost (ClientHeight - višina orodne vrstice) dodelite vsem trem 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;

Nastavitev Align := alNone na vseh treh poljih pred celoštevilskim računanjem prepreči, da bi se pogon omejitev VCL prepiral z vašimi dodelitvami. Po postavitvi razdelilnike znova prikažite, če želite v načinu z dvema pogledoma vlečenje za spreminjanje velikosti

Višina vsakega drsnega polja je odjemalčevo področje minus višina plošče z orodno vrstico. Ker je orodna vrstica zasidrana na vrhu z alTop, vam ClientHeight - PanelButtons.Height da uporaben navpični prostor. To dodelite vsem trem poljem znotraj istega klica UpdateLayout, tako da ni nikoli sličice, v kateri bi bilo eno polje višje od drugih in bi povzročilo utripanje postavitve

Odpiranje dokumenta

Vsak par plošč potrebuje svoj postopek odpiranja. Vzorec je kratek: komponento deaktivirajte, nastavite ime datoteke, aktivirajte in nato preverite Active; če je ostal False, povprašajte po geslu in poskusite znova. Upoštevajte, da izrisovanje krmili TPdfView.Active, datoteko pa dejansko odpre TPdf.Active; sta neodvisna. Nastavitev PdfView.Active := True, kadar povezani TPdf še ni dejaven, ni škodljiva, a ne prikaže ničesar

Diagram poteka odpiranja dokumenta PDF s PDFium Component v Delphiju, s tihim preverjanjem Active, enim ponovnim poskusom z geslom in pogovornim oknom z napako za poškodovane ali z geslom zaščitene datoteke
Neuspelo nalaganje pusti Active na False brez izjeme, zato potek to preveri, enkrat poskusi znova z geslom in na koncu težavo sporoči, namesto da bi kazal prazno ploščo
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;

  // Odpovedi nalaganja so tihe: Active ostane False, izjeme ni.
  if not PdfComponent.Active then
  begin
    // Najverjetneje datoteka, zaščitena z geslom; dajte uporabniku en poskus.
    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 dodelitvi vedno preverite PdfComponent.Active; poškodovana datoteka ali napačno geslo povzročita, da nalaganje na privzeti poti tiho odpove brez sprožitve izjeme. Izrecna nastavitev PdfViewComponent.PageNumber := 1 po uspešnem odpiranju prepreči zastarelo številko strani iz prejšnjega dokumenta

Pogovorno okno s sporočilom na koncu je namerno: želite, da se pokvarjene ali nepodprte datoteke pokažejo takoj, namesto da bi jih pogoltnila tiha prazna plošča. Uporabnik, ki ne vidi ničesar, nima pojma, ali se je datoteka naložila in je preprosto prazna ali pa jo je komponenta zavrnila. Poročanje o odpovedi napako ohrani vidno

Sledenje dejavni plošči

Ko uporabnik klikne v ploščo, ta postane dejavna. Obrazec vodi zasebno polje FActivePdfView: TPdfView. Vizualna povratna informacija je sprememba barve obrobe na vsebujočem TScrollBox: za dejavnega jo nastavite na clHighlight, za druge pa na clWindow. To priklopite na vsak TPdfView.OnClick in na postopek odpiranja, tako da fokus sledi dokumentu, ki ste ga pravkar odprli

Nekatere operacije veljajo za vse vidne plošče in ne le za dejavno. To vejo poganja logična vrednost FAllViewsMode na obrazcu. Ko je resnična, se spremembe povečave in navigacija po straneh razširijo na vsako ploščo, ki ima dejaven 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;

Usklajena navigacija po straneh

Usklajena navigacija ni obvezna, je pa uporabna pri potekih dela z revizijami dokumentov, kjer obe datoteki pokrivata isti obseg strani. Logika sodi v upravljalnik dogodka, ki se sproži, potem ko uporabnik krmari po enem pogledu. Ko izvorni pogled spremeni svojo lastnost PageNumber, upravljalnik to številko razširi na druge poglede, pri čemer velja eno varovalo: ciljni pogled mora imeti vsaj toliko strani, sicer se preskoči

Lastnosti PageNumber na TPdfView in na TPdf sta neodvisni. TPdf.PageNumber sledi temu, katero stran komponenta dokumenta šteje za trenutno; TPdfView.PageNumber sledi temu, kar je prikazano na zaslonu. Za namene navigacije želite lastnost pogleda in ne lastnosti dokumenta

Potrditveno polje z napisom, kot je »Uskladi strani«, uporabniku da nadzor. Ko ni potrjeno, vsaka plošča krmari neodvisno in upravljalnik takoj izstopi. Ta neodvisnost je pomembna za primere uporabe, kjer imata dokumenta različno število strani ali kjer želi uporabnik najti ustrezen odlomek v prevodu, ki se začne na drugi strani. Če bi usklajevanje vedno vsiljevali, bi bilo orodje težje uporabljati kot preprosto razporeditev dveh oken na namizju

Eno stvar je treba paziti: programska nastavitev PdfView.PageNumber znotraj upravljalnika usklajevanja bo tudi sama sprožila dogodek spremembe na tem pogledu. Pred neskončno rekurzijo se zavarujte z logično zastavico, ki jo nastavite pred dodelitvijo in takoj zatem počistite. Zastavica je na obrazec in ne na pogled, ker si vsi trije pogledi delijo isti upravljalnik

Diagram usklajene navigacije po straneh v pregledovalniku za primerjavo PDF v Delphiju s PDFium Component, s potrditvenim poljem za usklajevanje, varovalom števila strani za vsak ciljni pogled in zastavico proti rekurziji
Številka strani potuje iz izvornega pogleda v vsak drug pogled le tedaj, ko je usklajevanje vklopljeno in vsak ciljni pogled to stran res vsebuje

Povečava za vsako ploščo posebej

Vsak TPdfView nosi svojo lastnost Zoom, vrednost tipa Double v odstotkih, kjer Zoom := 100 pomeni dejansko velikost (100 %). Njena nastavitev preglasi vsak dejaven FitMode. Za gumb za prilagoditev širini na dejavni plošči preberite prilagojeno povečavo iz PdfView.PageWidthZoom[PdfView.PageNumber] in jo dodelite. Za prilagoditev strani uporabite PageZoom[PageNumber]. Obe sta poljski lastnosti, indeksirani s številko strani, šteto od 1, zato se pred dostopom zavarujte pred ničelno številko strani

Ko trenutno stran izvozite v sliko, zasuk preberite iz pogleda, RenderPage pa pokličite na komponenti TPdf in ne na pogledu. Bitnoslikovna oblika metode TPdf.RenderPage vzame izrecne mere v slikovnih pikah ter vrednost TRotation in množico TRenderOptions. Funkcijska različica vrne TBitmap, katerega lastnik je klicatelj in ga po shranjevanju sami sprostite:

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;

Množitelj 2x pri širini in višini da ostrejši izhod za dokumente z drobnim besedilom. Blok try/finally okoli sprostitve bitne slike ni neobvezen; preklic pogovornega okna TSaveDialog še vedno zadene blok finally, vi pa želite, da se bitna slika sprosti ne glede na to, kaj je uporabnik storil

Zahteve glede DLL

PDFium Component ovija izvorno knjižnico pdfium. 32-bitni gostiteljski proces potrebuje pdfium32.dll, 64-bitni pa pdfium64.dll. Različice s pogonom JavaScript V8 dodajo pripono v8 in tehtajo približno 23 do 27 MB v primerjavi s standardnimi gradnjami, ki merijo od 5 do 6 MB. Za pregledovalnik za primerjavo, ki izpolnjevanje obrazcev onemogoči (Pdf.FormFill := False), zadošča standardna gradnja brez V8, ki tudi zmanjša velikost razdeljevanja

DLL postavite v isto mapo kot izvršljivo datoteko ali v katero koli mapo v sistemski poti PATH. Komponenta ga naloži po potrebi, ko se aktivira prvi TPdf, zato se manjkajoč DLL pokaže takrat in ne ob zagonu aplikacije. Če odpremite namestitveni program, je najzanesljivejši pristop, da DLL med namestitvijo kopirate v mapo aplikacije, namesto da se zanašate na sistemsko mapo, ki jo skrbnik utegne pozneje počistiti

Gradnje z V8 so v prvi vrsti uporabne, kadar morate sodelovati z dejanji JavaScript v PDF, denimo da sprožite polja z izračuni ali upravljalnike oddaje. Pasiven pregledovalnik za primerjavo nima razloga poganjati JavaScripta; nastavitev Pdf.FormFill := False pred Active := True okolje za izpolnjevanje obrazcev povsem preskoči, kar pomeni tudi, da se pogon JS ne inicializira, tudi če uporabite standardno gradnjo. To je pravilna privzeta izbira za pregledovalnik samo za branje, ne glede na to, katero različico DLL odpremite

Za nadaljnje podrobnosti o PDFium Component in njegovem celotnem vmesniku obiščite stran izdelka Delphi PDFium Component