Examples / pdf_to_text / delphi

Pdf To Text

A complete, runnable delphi program — 607 lines, shipped in your download.

Demonstrates Text

Same example, other languages: activex_cpp c cpp cpp_linux csharp python vbnet

examples/delphi/pdf_to_text/Main.pas 607 lines
unit Main;

interface

uses
  Windows, SysUtils, Classes, Forms, Dialogs, StdCtrls, ShellApi,
  frmProgress, frmDirSelect, frmInfo, LumasPdfApi, pdf_callBack, pdf_text_extraction, FileSearch, Controls,
  ComCtrls, ShellCtrls, ExtCtrls, ToolWin, ImgList, Menus;

type
  TMainForm = class(TForm)
    Panel1: TPanel;
    ShellTreeView1: TShellTreeView;
    Splitter1: TSplitter;
    Panel3: TPanel;
    ToolBar1: TToolBar;
    tbSaveAsText: TToolButton;
    ImageList1: TImageList;
    tbConvertAll: TToolButton;
    SaveDialog1: TSaveDialog;
    ShellListView1: TShellListView;
    StatusBar1: TStatusBar;
    PopupMenu1: TPopupMenu;
    mnuSaveastext: TMenuItem;
    mnuConvertall: TMenuItem;
    Open1: TMenuItem;
    N2: TMenuItem;
    N1: TMenuItem;
    Selectall1: TMenuItem;
    Deselect1: TMenuItem;
    tbInfo: TToolButton;
    procedure tbSaveAsTextClick(Sender: TObject);
    procedure ShellListView1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure tbConvertAllClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure ShellListView1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    procedure Open1Click(Sender: TObject);
    procedure Deselect1Click(Sender: TObject);
    procedure ShellListView1Click(Sender: TObject);
    procedure ShellTreeView1Click(Sender: TObject);
    procedure Selectall1Click(Sender: TObject);
    procedure tbInfoClick(Sender: TObject);
  private
    FCurrent:    String;
    FFileSearch: CFileSearch;
    FHaveError:  Boolean;
    FMaxCount:   Integer;
    FPDF:        TPDF;
    FSelCount:   Integer;
    function  ConvertFile(var Stack: TPDFParseInterface; TextStack: CPDFToText; const TopDir, InFile: String; PathFromDlg: Boolean): Boolean;
    procedure ConvertFiles(var Stack: TPDFParseInterface; TextStack: CPDFToText; const TopDir, SubDir: String);
    procedure FinishSearch(Sender: TObject);
    procedure GetSelCount(Recursive: Boolean; CreateThread: Boolean);
    procedure GetFileCount(const Path: String; CreateThread: Boolean);
    function  GetFileCountEx(const Path: String): Integer;
    { Private-Deklarationen }
  public
    property CurrentFile: String read FCurrent;
    property HaveError: Boolean read FHaveError write FHaveError;
    property MaxCount: Integer read FMaxCount write FMaxCount;
    { Public-Deklarationen }
  end;

var
  MainForm: TMainForm;

implementation

{$R *.dfm}

function ExtractBaseDir(const Path: String):String;
var i: Integer; c: Char;
begin
   i := Length(Path);
   c := AnsiLastChar(Path)^;
   if (c = '/') or (c = '\') then Dec(i);
   Result := Path;
   while i > 0 do begin
      if (Path[i] = '/') or (Path[i] = '\') then begin
         SetLength(Result, i);
         break;
      end;
      Dec(i);
   end;
end;

function ExtractSubDir(const Path: String):String;
var i, j, len: Integer; c: Char;
begin
   i := Length(Path);
   c := AnsiLastChar(Path)^;
   if (c = '/') or (c = '\') then Dec(i);
   while i > 0 do begin
      if (Path[i] = '/') or (Path[i] = '\') then begin
         len := Length(Path) - i;
         SetLength(Result, len);
         Inc(i);
         for j := 1 to len do begin
            Result[j] := Path[i];
            Inc(i);
         end;
         break;
      end;
      Dec(i);
   end;
end;

function CreateSubDir(const TopDir, Path: String):String;
var i, p, len1, len2: Integer; baseDir: String;
begin
   baseDir := ExtractBaseDir(TopDir);
   len1 := Length(baseDir);
   len2 := Length(Path) - len1 - 1;
   Result := TopDir;
   p := Length(TopDir) + 1;
   SetLength(Result, p + len2);
   for i := len1 + 1 to len2 + len1 + 1 do begin
      Result[p] := Path[i];
      Inc(p);
   end;
end;

function pdf_ErrProc(const Data: Pointer; ErrCode: Integer; const ErrMessage: PAnsiChar; ErrType: Integer): Integer; stdcall;
begin
   MainForm.HaveError := true;
   frmConvProgress.AddLine(MainForm.CurrentFile, ErrMessage);
   Result := 0; // we try to continue.
end;

function pdf_InitProgress(const Data: Pointer; ProgType: TProgType; MaxCount: Integer): Integer; stdcall;
begin
   // Only the "Read" case occurs in this example because we do not save the PDF file.
   case ProgType of
      ptImportPage: frmConvProgress.lbState.Caption := 'Read Page';
      ptWritePage:  frmConvProgress.lbState.Caption := 'Write Page'; // Cannot occur
   end;
   frmConvProgress.prgPage.Position := 0;
   frmConvProgress.prgPage.Max      := MaxCount;
   MainForm.MaxCount                := MaxCount;
   Result := 0;
end;

function pdf_Progress(const Data: Pointer; ActivePage: Integer): Integer; stdcall;
begin
   frmConvProgress.lbActivePage.Caption := Format('%d of %d', [ActivePage, MainForm.MaxCount]);
   Result := 0;
   frmConvProgress.prgPage.StepIt;
   Application.ProcessMessages;
end;

procedure TMainForm.FormCreate(Sender: TObject);
begin
   FPDF := TPDF.Create;
   FPDF.SetErrorMode(emNoFuncNames); // Do not print function names in error messages
   // External cmaps should always be loaded when extracting text from PDF files.
   // See the description of ParseContent() for further information.
   FPDF.SetCMapDir(ExpandFileName('../../../Resource/CMap'), lcmRecursive or lcmDelayed);
end;

procedure TMainForm.FormDestroy(Sender: TObject);
begin
   if FPDF <> nil then FPDF.Free;
   if FFileSearch <> nil then begin
      FFileSearch.Terminate;
      FFileSearch.Free;
   end;
end;

function TMainForm.ConvertFile(var Stack: TPDFParseInterface; TextStack: CPDFToText; const TopDir, InFile: String; PathFromDlg: Boolean): Boolean;
var i, count: Integer; fileName, outFile: String;
begin
   Result     := false;
   FHaveError := false;
   FCurrent   := InFile;
   fileName   := ExtractFileName(FCurrent);
   if not PathFromDlg then
      outFile := TopDir + ChangeFileExt(fileName, '.txt')
   else
      outFile := SaveDialog1.FileName;
   frmConvProgress.lbFileName.Caption   := FCurrent;
   frmConvProgress.lbState.Caption      := 'Read document...';
   frmConvProgress.lbActivePage.Caption := '';
   Application.ProcessMessages;

   if not FPDF.CreateNewPDF('') then Exit; // We do not produce a PDF file in this example
   // We import the page contents only. Enything else makes no sense because such things are
   // ignored during conversion to text.
   FPDF.SetImportFlags(ifContentOnly or ifImportAsPage);
   if FPDF.OpenImportFile(FCurrent, ptOpen, '') < 0 then begin
      FPDF.FreePDF;
      frmConvProgress.prgFile.StepIt;
      frmConvProgress.StatusBar1.Panels[3].Text := Format('%d', [frmConvProgress.prgFile.Position]);
      Exit;
   end;
   Application.ProcessMessages;
   if FPDF.ImportPDFFile(1, 1.0, 1.0) < 0 then begin
      FPDF.FreePDF;
      frmConvProgress.prgFile.StepIt;
      frmConvProgress.StatusBar1.Panels[3].Text := Format('%d', [frmConvProgress.prgFile.Position]);
      Exit;
   end;
   FPDF.CloseImportFile;
   if not textStack.OpenEx(outFile) then begin
      frmConvProgress.AddLine(FCurrent, 'Cannot open file!');
      FPDF.FreePDF;
      frmConvProgress.prgFile.StepIt;
      frmConvProgress.StatusBar1.Panels[3].Text := Format('%d', [frmConvProgress.prgFile.Position]);
      Exit;
   end;
   count := FPDF.GetPageCount;
   frmConvProgress.lbState.Caption  := 'Convert page';
   frmConvProgress.prgPage.Position := 0;
   frmConvProgress.prgPage.Max      := count;
   for i := 1 to count do begin
      frmConvProgress.lbActivePage.Caption := Format('%d of %d', [i, count]);
      Application.ProcessMessages;
      if frmConvProgress.Cancel then begin
         FPDF.FreePDF;
         Exit;
      end;
      FPDF.EditPage(i); // Open the page
      textStack.Init;
      textStack.WritePageIdentifier(i);
      FPDF.ParseContent(TextStack, Stack, pfNone);
      FPDF.EndPage; // Close the page
      frmConvProgress.prgPage.StepIt;
   end;
   textStack.Close;
   if not FHaveError then begin
      frmConvProgress.AddLine(fileName, 'OK');
      Result := true;
   end;
   FPDF.FreePDF;
   frmConvProgress.prgFile.StepIt;
   frmConvProgress.StatusBar1.Panels[3].Text := Format('%d', [frmConvProgress.prgFile.Position]);
end;

procedure TMainForm.ConvertFiles(var Stack: TPDFParseInterface; TextStack: CPDFToText; const TopDir, SubDir: String);
var sr: TSearchRec; inDir, outDir: String; haveDir: Boolean;
begin
   inDir   := SubDir;
   outDir  := CreateSubDir(TopDir, SubDir);
   haveDir := false;
   if AnsiLastChar(inDir)^ <> '\' then inDir := inDir + '\';
   if FindFirst(inDir + '*.*', faAnyFile, sr) <> 0 then Exit;
   if AnsiLastChar(outDir)^ <> '\' then outDir := outDir + '\';
   repeat
      if (sr.Attr and faDirectory) <> 0 then begin
         if sr.Name[1] = '.' then continue;
         ConvertFiles(Stack, TextStack, TopDir, inDir + sr.Name);
      end else begin
         if LowerCase(ExtractFileExt(sr.Name)) = '.pdf' then begin
            if not haveDir and not DirectoryExists(outDir) then begin
               if not ForceDirectories(outDir) then begin
                  frmConvProgress.AddLine(inDir, 'Cannot create output directory!');
                  break;
               end;
            end;
            haveDir := true;
            ConvertFile(Stack, TextStack, outDir, inDir + sr.Name, false);
            if frmConvProgress.Cancel then break;
         end;
      end;
   until FindNext(sr) <> 0;
   FindCLose(sr);
end;

procedure TMainForm.FinishSearch(Sender: TObject);
begin
   FSelCount := CFileSearch(Sender).FileCount;
   if FSelCount > 0 then begin
      tbConvertAll.Enabled  := FSelCount > 1;
      tbSaveAsText.Enabled  := FSelCount = 1;
      mnuSaveAsText.Enabled := FSelCount = 1;
      mnuConvertAll.Enabled := FSelCount > 1;
   end else begin
      tbConvertAll.Enabled  := false;
      tbSaveAsText.Enabled  := false;
      mnuSaveAsText.Enabled := false;
      mnuConvertAll.Enabled := false;
   end;
   StatusBar1.Panels[0].Text := 'PDF files found';
   StatusBar1.Panels[1].Text := Format('%d', [FSelCount]);
end;

procedure TMainForm.GetFileCount(const Path: String; CreateThread: Boolean);
begin
   // Make sure that only one thread is executed
   if FFileSearch <> nil then begin
      FFileSearch.Terminate;
      FFileSearch.Free;
      FFileSearch := nil;
   end;
   if CreateThread then begin
      FFileSearch := CFileSearch.Create(Path);
      FFileSearch.OnTerminate     := FinishSearch;
      FFileSearch.FreeOnTerminate := false;
      FFileSearch.Priority        := tpLowest;
      FFileSearch.Resume;
   end else begin
      Inc(FSelCount, GetFileCountEx(Path));
   end;
end;

function TMainForm.GetFileCountEx(const Path: String): Integer;
var sr: TSearchRec; filePath: String;
begin
   Result := 0;
   try
      filePath := Path;
      if AnsiLastChar(Path)^ <> '\' then filePath := Path + '\';
      if FindFirst(filePath + '*.*', faAnyFile, sr) <> 0 then Exit;
   except
      Exit;
   end;
   try
      repeat
         if (sr.Attr and faDirectory) <> 0 then begin
            if sr.Name[1] = '.' then continue;
            inc(Result, GetFileCountEx(filePath + sr.Name));
         end else begin
            if LowerCase(ExtractFileExt(sr.Name)) = '.pdf' then Inc(Result);
         end;
      until FindNext(sr) <> 0;
   finally
      FindCLose(sr);
   end;
end;

procedure TMainForm.GetSelCount(Recursive: Boolean; CreateThread: Boolean);
var i: Integer;
begin
   FSelCount := 0;
   if not Recursive then begin
      for i := 0 to ShellListView1.Items.Count -1 do begin
         if ShellListView1.Items[i].Selected
         and (LowerCase(ExtractFileExt(ShellListView1.Folders[i].PathName)) = '.pdf') then
            Inc(FSelCount);
      end;
   end else begin
      if ShellListView1.SelCount > 1 then CreateThread := false;
      for i := 0 to ShellListView1.Items.Count -1 do begin
         if ShellListView1.Items[i].Selected then begin
            if ShellListView1.Folders[i].IsFolder then begin
               GetFileCount(ShellListView1.Folders[i].PathName, CreateThread);
            end else if (LowerCase(ExtractFileExt(ShellListView1.Folders[i].PathName)) = '.pdf') then
               Inc(FSelCount);
         end;
      end;
      tbConvertAll.Enabled  := FSelCount > 1;
      tbSaveAsText.Enabled  := FSelCount = 1;
      mnuSaveAsText.Enabled := FSelCount = 1;
      mnuConvertAll.Enabled := FSelCount > 1;
      StatusBar1.Panels[0].Text := 'PDF files selected';
      StatusBar1.Panels[1].Text := Format('%d', [FSelCount]);
   end;
end;

procedure TMainForm.tbConvertAllClick(Sender: TObject);
var i: Integer; recursive: Boolean; topDir: String;
stack: TPDFParseInterface; textStack: CPDFToText;
begin
   textStack := nil;
   if ShellListView1.SelCount = 0 then begin
      FSelCount             := 0;
      tbConvertAll.Enabled  := false;
      tbSaveAsText.Enabled  := false;
      mnuSaveAsText.Enabled := false;
      mnuConvertAll.Enabled := false;
      StatusBar1.Panels[0].Text := 'PDF files selected';
      StatusBar1.Panels[1].Text := '0';
      Exit;
   end;
   for i := 0 to ShellListView1.Items.Count -1 do begin
      if ShellListView1.Items[i].Selected then begin
         if ShellListView1.Folders[i].IsFolder then begin
            topDir := ExtractFilePath(ShellListView1.Folders[i].PathName);
            break;
         end else if (LowerCase(ExtractFileExt(ShellListView1.Folders[i].PathName)) = '.pdf') then begin
            topDir := ExtractFilePath(ShellListView1.Folders[i].PathName);
            break;
         end;
      end;
   end;
   frmSelectDir.edtPath.Text := topDir + 'New Files\';
   frmSelectDir.ShowModal;
   if frmSelectDir.ModalResult = mrOK then begin
      recursive := frmSelectDir.chkRecursive.Checked;
      topDir := frmSelectDir.edtPath.Text;
      if topDir = '' then Exit;
      if not DirectoryExists(topDir) then begin
         if MessageDlg('Directory "' + topDir + '" does not exist.'#13'Create it?', mtConfirmation, [mbYes, mbCancel], 0) = mrCancel then
            Exit
         else if not CreateDir(topDir) then begin
            MessageDlg('Directory "' + topDir + '" could not be created!'#13'Please choose another directory name.', mtError, [mbOK], 0);
            Exit;
         end;
      end;
      FPDF.SetProgressProc(nil, @pdf_InitProgress, @pdf_Progress);
      FPDF.SetOnErrorProc(nil, @pdf_ErrProc);
      FillChar(stack, sizeof(stack), 0);
      stack.BeginTemplate       := parseBeginTemplate;
      stack.RestoreGraphicState := parseRestoreGraphicState;
      stack.SaveGraphicState    := parseSaveGraphicState;
      stack.MulMatrix           := parseMulMatrix;
      stack.SetCharSpacing      := parseSetCharSpacing;
      stack.SetFont             := parseSetFont;
      stack.SetTextDrawMode     := parseSetTextDrawMode;
      stack.SetTextScale        := parseSetTextScale;
      stack.SetWordSpacing      := parseSetWordSpacing;
      stack.ShowTextArrayW      := parseShowTextArrayW;
      frmConvProgress.lstErrorLog.Strings.Clear;
      frmConvProgress.prgFile.Position := 0;
      frmConvProgress.Show;
      try
         textStack := CPDFToText.Create(FPDF);
         Application.ProcessMessages;
         if recursive then
            GetSelCount(true, false)
         else
            GetSelCount(false, false);
         frmConvProgress.prgFile.Max := FSelCount;
         frmConvProgress.StatusBar1.Panels[1].Text := Format('%d', [FSelCount]);
         Application.ProcessMessages;
         for i := 0 to ShellListView1.Items.Count -1 do begin
            if ShellListView1.Items[i].Selected then begin
               if ShellListView1.Folders[i].IsFolder then begin
                  if not recursive then continue;
                  ConvertFiles(stack, textStack, topDir, ShellListView1.Folders[i].PathName);
                  if frmConvProgress.Cancel then break;
               end else if (LowerCase(ExtractFileExt(ShellListView1.Folders[i].PathName)) = '.pdf') then begin
                  ConvertFile(stack, textStack, topDir, ShellListView1.Folders[i].PathName, false);
                  if frmConvProgress.Cancel then break;
               end;
            end;
         end;
      except
         on E: Exception do MessageDlg(E.Message, mtError, [mbOK], 0);
      end;
      frmConvProgress.SetFinish;
      Application.ProcessMessages;
      FSelCount             := 0;
      tbConvertAll.Enabled  := false;
      tbSaveAsText.Enabled  := false;
      mnuSaveAsText.Enabled := false;
      mnuConvertAll.Enabled := false;
      ShellTreeView1.Refresh(ShellTreeView1.TopItem);
   end;
   if textStack <> nil then textStack.Free;
end;

procedure TMainForm.tbSaveAsTextClick(Sender: TObject);
var stack: TPDFParseInterface; textStack: CPDFToText; haveFile: Boolean;
begin
   FCurrent := ShellListView1.SelectedFolder.PathName;
   SaveDialog1.FileName := ChangeFileExt(FCurrent, '.txt');
   if not SaveDialog1.Execute then Exit;
   textStack := nil;
   FPDF.SetProgressProc(nil, @pdf_InitProgress, @pdf_Progress);
   FPDF.SetOnErrorProc(nil, @pdf_ErrProc);
   FillChar(stack, sizeof(stack), 0);
   stack.BeginTemplate       := parseBeginTemplate;
   stack.RestoreGraphicState := parseRestoreGraphicState;
   stack.SaveGraphicState    := parseSaveGraphicState;
   stack.MulMatrix           := parseMulMatrix;
   stack.SetCharSpacing      := parseSetCharSpacing;
   stack.SetFont             := parseSetFont;
   stack.SetTextDrawMode     := parseSetTextDrawMode;
   stack.SetTextScale        := parseSetTextScale;
   stack.SetWordSpacing      := parseSetWordSpacing;
   stack.ShowTextArrayW      := parseShowTextArrayW;
   frmConvProgress.lstErrorLog.Strings.Clear;
   frmConvProgress.prgFile.Position := 0;
   frmConvProgress.Show;
   try
      textStack := CPDFToText.Create(FPDF);
      frmConvProgress.prgFile.Max := 1;
      frmConvProgress.StatusBar1.Panels[1].Text := '1';
      Application.ProcessMessages;
      haveFile := ConvertFile(stack, textStack, ExtractFilePath(FCurrent), FCurrent, true);
   except
      on E: Exception do begin
         MessageDlg(E.Message, mtError, [mbOK], 0);
         haveFile := false;
      end;
   end;
   frmConvProgress.SetFinish;
   Application.ProcessMessages;
   FSelCount             := 0;
   tbConvertAll.Enabled  := false;
   tbSaveAsText.Enabled  := false;
   mnuSaveAsText.Enabled := false;
   mnuConvertAll.Enabled := false;
   ShellTreeView1.Refresh(ShellTreeView1.TopItem);
   if textStack <> nil then textStack.Free;
   if haveFile then ShellExecute(Handle, PChar('open'), PChar(SaveDialog1.FileName), nil, nil, SW_SHOWMAXIMIZED);
end;

procedure TMainForm.Selectall1Click(Sender: TObject);
begin
   ShellListView1.SelectAll;
   ShellListView1Click(nil);
end;

procedure TMainForm.ShellListView1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
   if (ssCtrl in Shift) and (Key = 65) then begin
      ShellListView1.SelectAll;
      GetSelCount(true, true);
      tbConvertAll.Enabled  := FSelCount > 1;
      tbSaveAsText.Enabled  := FSelCount = 1;
      mnuSaveAsText.Enabled := FSelCount = 1;
      mnuConvertAll.Enabled := FSelCount > 1;
      StatusBar1.Panels[0].Text := 'PDF files selected';
      StatusBar1.Panels[1].Text := Format('%d', [FSelCount]);
      Exit;
   end;
   if not ((ssRight in Shift) or (ssLeft in Shift)) then Exit;
   if ShellListView1.SelCount < 1 then
      Exit
   else if ShellListView1.SelCount = 1 then begin
      if ShellListView1.SelectedFolder.IsFolder then begin
         GetSelCount(true, false);
      end;
   end else
      GetSelCount(true, false);
end;

procedure TMainForm.ShellListView1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
   if ShellListView1.SelCount < 1 then begin
      StatusBar1.Panels[0].Text := 'PDF files found';
      StatusBar1.Panels[1].Text := '0';
      Exit
   end else if ShellListView1.SelCount = 1 then begin
      if ShellListView1.SelectedFolder.IsFolder then begin
         GetSelCount(true, true);
      end else begin
         if LowerCase(ExtractFileExt(ShellListView1.SelectedFolder.PathName)) = '.pdf' then
            FSelCount := 1
         else
            FSelCount := 0;
      end;
   end else
      GetSelCount(true, true);
end;

procedure TMainForm.Open1Click(Sender: TObject);
begin
   if ShellListView1.SelCount < 1 then Exit;
   ShellExecute(Handle, PChar('open'), PChar(ShellListView1.SelectedFolder.PathName), nil, nil, SW_SHOWMAXIMIZED);
end;

procedure TMainForm.Deselect1Click(Sender: TObject);
var i: Integer;
begin
   for i := 0 to ShellListView1.Items.Count -1 do begin
      ShellListView1.Items[i].Selected := not ShellListView1.Items[i].Selected;
   end;
   ShellListView1.Repaint;
end;

procedure TMainForm.ShellListView1Click(Sender: TObject);
begin
   GetSelCount(Sender = nil, false);
   if FSelCount = 1 then begin
      if not ShellListView1.SelectedFolder.IsFolder then begin
         if LowerCase(ExtractFileExt(ShellListView1.SelectedFolder.PathName)) = '.pdf' then
            FSelCount := 1
         else
            FSelCount := 0;
      end;
   end;
   if (FSelCount > 0) and ShellListView1.SelectedFolder.IsFolder then begin
      tbSaveAsText.Enabled  := false;
      mnuSaveAsText.Enabled := false;
      tbConvertAll.Enabled  := FSelCount > 0;
      mnuConvertAll.Enabled := FSelCount > 0;
   end else begin
      tbSaveAsText.Enabled  := FSelCount = 1;
      mnuSaveAsText.Enabled := FSelCount = 1;
      tbConvertAll.Enabled  := FSelCount > 1;
      mnuConvertAll.Enabled := FSelCount > 1;
   end;
   StatusBar1.Panels[0].Text := 'PDF files selected';
   StatusBar1.Panels[1].Text := Format('%d', [FSelCount]);
end;

procedure TMainForm.ShellTreeView1Click(Sender: TObject);
begin
   FSelCount             := 0;
   tbConvertAll.Enabled  := false;
   tbSaveAsText.Enabled  := false;
   mnuSaveAsText.Enabled := false;
   mnuConvertAll.Enabled := false;
   StatusBar1.Panels[0].Text := 'PDF files selected';
   StatusBar1.Panels[1].Text := '0';
end;

procedure TMainForm.tbInfoClick(Sender: TObject);
begin
   frmProgInfo.ShowModal;
end;

end.

This file is in the SDK at examples/delphi/pdf_to_text/Main.pas. The build fails if this page and that file ever differ.