Teknisk artikel

Använda PDFium VCL i Delphi för att jämföra PDF-dokument sida vid sida

· PDF-programmering

Att jämföra flera PDF-dokument sida vid sida är viktigt för revisionsgranskning, kvalitetskontroll och dokumentverifiering. Den Delad vy demo visar hur man visar två eller tre PDF-dokument samtidigt med PDFium VCL.

Översikt

Denna avancerade demo visar flera PDF-dokument i synkroniserade vyer, så att användare kan jämföra dokument visuellt. Den stöder både tvåvägs- och trevägsjämförelselägen, med oberoende navigerings- och zoomkontroller för varje vy.

Nyckelfunktioner

  • Tvåpanelsläge – Jämför två dokument sida vid sida
  • Trepanelsläge – Jämför tre dokument samtidigt
  • Oberoende navigering – Navigera i varje dokument oberoende
  • Synkroniserad zoom – Använd zoom på alla vyer eller individuellt
  • Textval – Välj och kopiera text från valfri panel
  • Spara som bild – Exportera aktuell vy som en bild
  • Aktiv panelmarkering – Visuell indikering av den aktiva panelen

PDFium DLL-krav

Innan du kör ett PDFium VCL-program, se till att PDFium DLL-filerna är installerade:

  • pdfium32.dll / pdfium64.dll – Standardversioner (~5-6 MB)
  • pdfium32v8.dll / pdfium64v8.dll – Med V8 JavaScript-motor (~23-27 MB)

Installation: Kör PDFiumVCL\DLLs\CopyDlls.bat som administratör för att automatiskt kopiera DLL:erna till Windows systemkataloger.

Ställa in flera vyer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
type
  TFormMain = class(TForm)
    // Three PDF components
    Pdf1: TPdf;
    Pdf2: TPdf;
    Pdf3: TPdf;
    
    // Three view components
    PdfView1: TPdfView;
    PdfView2: TPdfView;
    PdfView3: TPdfView;
    
    // Container panels
    ScrollBox1: TScrollBox;
    ScrollBox2: TScrollBox;
    ScrollBox3: TScrollBox;
    
    // Splitters for resizing
    Splitter1: TSplitter;
    Splitter2: TSplitter;
    
  private
    FActivePdfView: TPdfView;  // Currently active view
    FAllViewsMode: Boolean;    // Apply actions to all views
    ThreeViewMode: Boolean;    // Three-panel mode enabled
  end;

Växla mellan visningslägen

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
procedure TFormMain.SpeedButtonThreeViewClick(Sender: TObject);
begin
  ThreeViewMode := not ThreeViewMode;
  SpeedButtonThreeView.Down := ThreeViewMode;
  UpdateLayout;
end;
 
procedure TFormMain.UpdateLayout;
var
  TotalWidth: Integer;
begin
  if ThreeViewMode then
  begin
    // Three view mode: equal thirds
    ScrollBox1.Align := alNone;
    ScrollBox2.Align := alNone;
    ScrollBox3.Align := alNone;
    
    Splitter1.Visible := False;
    Splitter2.Visible := False;
    
    TotalWidth := ClientWidth;
    
    ScrollBox1.Left := 0;
    ScrollBox1.Width := TotalWidth div 3;
    ScrollBox1.Height := ClientHeight - PanelButtons.Height;
    
    ScrollBox2.Left := ScrollBox1.Width;
    ScrollBox2.Width := TotalWidth div 3;
    ScrollBox2.Height := ClientHeight - PanelButtons.Height;
    
    ScrollBox3.Left := ScrollBox2.Left + ScrollBox2.Width;
    ScrollBox3.Width := TotalWidth - ScrollBox3.Left;
    ScrollBox3.Height := ClientHeight - PanelButtons.Height;
    ScrollBox3.Visible := True;
    
    SpeedButtonOpenPdf3.Visible := True;
  end
  else
  begin
    // Two view mode: equal halves
    ScrollBox3.Visible := False;
    Splitter2.Visible := False;
    
    TotalWidth := ClientWidth;
    
    ScrollBox1.Left := 0;
    ScrollBox1.Width := TotalWidth div 2;
    ScrollBox1.Height := ClientHeight - PanelButtons.Height;
    
    ScrollBox2.Left := ScrollBox1.Width;
    ScrollBox2.Width := TotalWidth - ScrollBox2.Left;
    ScrollBox2.Height := ClientHeight - PanelButtons.Height;
    
    SpeedButtonOpenPdf3.Visible := False;
  end;
end;

Öppna PDF-filer i varje panel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
procedure TFormMain.OpenPdfFile(PdfComponent: TPdf;
  PdfViewComponent: TPdfView; const Title: string);
var
  Password: string;
begin
  if OpenDialog.Execute then
  begin
    PdfComponent.Active := False;
    PdfComponent.FileName := OpenDialog.FileName;
    PdfComponent.Password := '';
    
    try
      PdfViewComponent.Active := True;
    except
      on Error: EPdfError do
        if Error.Message = 'Password required or incorrect password' then
        begin
          if InputQuery('Enter Password', 'Password: ', Password) then
          begin
            PdfComponent.Password := Password;
            PdfViewComponent.Active := True;
          end
          else
            raise;
        end
        else
          raise;
    end;
    
    SetActivePdfView(PdfViewComponent);
    UpdateControlsState;
  end;
end;
 
procedure TFormMain.SpeedButtonOpenPdf1Click(Sender: TObject);
begin
  OpenPdfFile(Pdf1, PdfView1, 'PDF 1');
end;
 
procedure TFormMain.SpeedButtonOpenPdf2Click(Sender: TObject);
begin
  OpenPdfFile(Pdf2, PdfView2, 'PDF 2');
end;
 
procedure TFormMain.SpeedButtonOpenPdf3Click(Sender: TObject);
begin
  OpenPdfFile(Pdf3, PdfView3, 'PDF 3');
end;

Hantera Active Panel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
procedure TFormMain.SetActivePdfView(PdfView: TPdfView);
begin
  FActivePdfView := PdfView;
  
  // Visual feedback for active panel
  if PdfView = PdfView1 then
  begin
    ScrollBox1.Color := clHighlight;
    ScrollBox2.Color := clWindow;
    ScrollBox3.Color := clWindow;
  end
  else if PdfView = PdfView2 then
  begin
    ScrollBox1.Color := clWindow;
    ScrollBox2.Color := clHighlight;
    ScrollBox3.Color := clWindow;
  end
  else if PdfView = PdfView3 then
  begin
    ScrollBox1.Color := clWindow;
    ScrollBox2.Color := clWindow;
    ScrollBox3.Color := clHighlight;
  end;
  
  UpdateControlsState;
end;
 
procedure TFormMain.PdfView1Click(Sender: TObject);
begin
  SetActivePdfView(PdfView1);
end;
 
procedure TFormMain.PdfView2Click(Sender: TObject);
begin
  SetActivePdfView(PdfView2);
end;
 
procedure TFormMain.PdfView3Click(Sender: TObject);
begin
  SetActivePdfView(PdfView3);
end;

Tillämpa åtgärder på aktiva eller alla vyer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
procedure TFormMain.ApplyToAllViews(const Operation: string);
begin
  if FAllViewsMode then
  begin
    // Apply to all active views
    if PdfView1.Active then
      ApplyOperation(PdfView1, Operation);
    if PdfView2.Active then
      ApplyOperation(PdfView2, Operation);
    if PdfView3.Active and ThreeViewMode then
      ApplyOperation(PdfView3, Operation);
  end
  else
  begin
    // Apply only to active view
    if Assigned(FActivePdfView) then
      ApplyOperation(FActivePdfView, Operation);
  end;
end;
 
procedure TFormMain.SpeedButtonZoomInClick(Sender: TObject);
begin
  ApplyToAllViews('ZoomIn');
end;
 
procedure TFormMain.SpeedButtonZoomOutClick(Sender: TObject);
begin
  ApplyToAllViews('ZoomOut');
end;

Synkroniserad sidnavigering (valfritt)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
procedure TFormMain.SynchronizePages(SourceView: TPdfView);
var
  PageNum: Integer;
begin
  if not chkSynchronize.Checked then
    Exit;
    
  PageNum := SourceView.PageNumber;
  
  // Apply to other views
  if (SourceView <> PdfView1) and PdfView1.Active then
    if PageNum <= PdfView1.PageCount then
      PdfView1.PageNumber := PageNum;
      
  if (SourceView <> PdfView2) and PdfView2.Active then
    if PageNum <= PdfView2.PageCount then
      PdfView2.PageNumber := PageNum;
      
  if (SourceView <> PdfView3) and PdfView3.Active and ThreeViewMode then
    if PageNum <= PdfView3.PageCount then
      PdfView3.PageNumber := PageNum;
end;

Oberoende zoomkontroller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
procedure TFormMain.DoZoom1;
begin
  if PdfView1.Active and (PdfView1.PageNumber > 0) then
  begin
    case ComboBoxZoom.ItemIndex of
      0: PdfView1.Zoom := 0.5;
      1: PdfView1.Zoom := 0.75;
      2: PdfView1.Zoom := 1.0;
      3: PdfView1.Zoom := 1.5;
      4: PdfView1.Zoom := 2.0;
      5: PdfView1.Zoom := PdfView1.PageWidthZoom[PdfView1.PageNumber];
      6: PdfView1.Zoom := PdfView1.PageZoom[PdfView1.PageNumber];
    end;
  end;
end;
 
procedure TFormMain.DoZoom2;
begin
  if PdfView2.Active and (PdfView2.PageNumber > 0) then
  begin
    // Same zoom logic for view 2
  end;
end;
 
procedure TFormMain.DoZoom3;
begin
  if PdfView3.Active and (PdfView3.PageNumber > 0) then
  begin
    // Same zoom logic for view 3
  end;
end;

Sparar aktuell vy som bild

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
procedure TFormMain.MenuItemSaveAsImage1Click(Sender: TObject);
begin
  SaveViewAsImage(PdfView1, Pdf1);
end;
 
procedure TFormMain.SaveViewAsImage(PdfView: TPdfView; Pdf: TPdf);
var
  Bitmap: TBitmap;
  JpegImage: TJpegImage;
begin
  if not PdfView.Active then
  begin
    ShowMessage('No document loaded in this view.');
    Exit;
  end;
  
  SavePictureDialog.FileName := 'page_' + IntToStr(PdfView.PageNumber) + '.jpg';
  
  if SavePictureDialog.Execute then
  begin
    Pdf.PageNumber := PdfView.PageNumber;
    
    Bitmap := Pdf.RenderPage(
      0, 0,
      Round(Pdf.PageWidth * 2),  // 2x resolution
      Round(Pdf.PageHeight * 2),
      PdfView.Rotation, [], clWhite
    );
    
    try
      JpegImage := TJpegImage.Create;
      try
        JpegImage.Assign(Bitmap);
        JpegImage.CompressionQuality := 90;
        JpegImage.SaveToFile(SavePictureDialog.FileName);
        ShowMessage('Image saved successfully.');
      finally
        JpegImage.Free;
      end;
    finally
      Bitmap.Free;
    end;
  end;
end;

Textval i varje panel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
procedure TFormMain.PdfView1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  SetActivePdfView(PdfView1);
  
  if Button = mbLeft then
  begin
    Selecting := True;
    SelectionStart := PdfView1.CharacterIndexAtPos(X, Y, 5.0, 5.0);
    SelectionEnd := SelectionStart;
  end;
end;
 
procedure TFormMain.PdfView1MouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: Integer);
begin
  if Selecting then
  begin
    SelectionEnd := PdfView1.CharacterIndexAtPos(X, Y, 5.0, 5.0);
    PdfView1.Invalidate;
  end;
end;
 
procedure TFormMain.PdfView1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  Selecting := False;
end;

Användningsfall

  • Granskning av dokumentrevision – Jämför original och reviderade dokument
  • Kvalitetskontroll – Verifiera produktionen mot mallar
  • Juridisk granskning – Jämför kontraktsversioner
  • Översättningsverifiering – Visa källdokument och översatta dokument
  • Flerspråkiga dokument – Visa samma innehåll på olika språk

Slutsats

Split View-demon visar flexibiliteten hos PDFium VCL för att bygga avancerade verktyg för dokumentjämförelse. Med stöd för flera oberoende vyer, synkroniserad navigering och kontroller per panel kan du skapa professionella jämförelseapplikationer.

Möjligheten att öppna olika PDF-filer i varje panel och jämföra dem visuellt är ovärderlig för revisionsgranskning och arbetsflöden för kvalitetskontroll.

Bygg kraftfulla verktyg för dokumentjämförelse med Delphi PDFium VCL-komponent.