Artículo técnico

Uso de PDFium VCL en Delphi para comparar documentos PDF en paralelo

· Programación PDF

Comparar múltiples documentos PDF uno al lado del otro es esencial para la revisión, el control de calidad y la verificación de documentos. Vista dividida La demostración muestra cómo mostrar dos o tres documentos PDF simultáneamente utilizando PDFium VCL.

Resumen

Esta demostración avanzada muestra múltiples documentos PDF en vistas sincronizadas, lo que permite a los usuarios comparar documentos visualmente. Admite tanto modos de comparación de dos vías como de tres vías, con controles de navegación y zoom independientes para cada vista.

Características principales

  • Modo de dos paneles – Comparar dos documentos uno al lado del otro.
  • Modo de tres paneles. – Compara tres documentos simultáneamente.
  • Navegación independiente. – Navega por cada documento de forma independiente.
  • Zoom sincronizado. – Aplica el zoom a todas las vistas o de forma individual.
  • Selección de texto. – Selecciona y copia texto de cualquier panel.
  • Guardar como imagen – Exportar la vista actual como una imagen
  • Resaltado del panel activo – Indicación visual del panel activo

Requisitos de la DLL PDFium

Antes de ejecutar cualquier aplicación PDFium VCL, asegúrese de que los archivos DLL de PDFium estén instalados:

  • pdfium32.dll / pdfium64.dll – Versiones estándar (~5-6 MB)
  • pdfium32v8.dll / pdfium64v8.dll – Con el motor JavaScript V8 (~23-27 MB)

Instalación: Ejecutar PDFiumVCL\DLLs\CopyDlls.bat como administrador para copiar automáticamente los archivos DLL a los directorios del sistema de Windows.

Configuración de múltiples vistas.

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;

Cambio entre modos de vista.

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;

Abrir archivos PDF en cada 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;

Gestión del panel activo.

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;

Aplicar acciones al panel activo o a todas las vistas.

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;

Navegación de página sincronizada (opcional).

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;

Controles de zoom independientes.

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;

Guardar la vista actual como imagen.

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;

Selección de texto en cada 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;

Casos de uso.

  • Revisión de versiones de documentos. – Comparar documentos originales y revisados.
  • Control de calidad. – Verificar la producción con las plantillas.
  • Revisión legal. – Comparar versiones de contratos.
  • Verificación de la traducción. – Ver documentos originales y traducidos.
  • Documentos multilingües. – Ver el mismo contenido en diferentes idiomas.

Conclusión.

La demostración de la vista dividida muestra la flexibilidad de PDFium VCL para crear herramientas avanzadas de comparación de documentos. Con soporte para múltiples vistas independientes, navegación sincronizada y controles por panel, puede crear aplicaciones de comparación profesionales.

La capacidad de abrir diferentes archivos PDF en cada panel y compararlos visualmente es invaluable para la revisión y el control de calidad.

Cree herramientas de comparación de documentos potentes. con Componente Delphi PDFium VCL..