html Dzielenie dokumentów PDF na wiele plików za pomocą PDFium Delphi | losLab Software Development Blog

Artykuł techniczny

Dzielenie dokumentów PDF na wiele plików za pomocą PDFium Delphi

· Programowanie PDF

Podział dużego PDF na mniejsze pliki jest niezbędny do dystrybucji, archiwizowania i przetwarzania dokumentów. The Podział PDF pokazuje, jak dzielić dokumenty PDF przy użyciu różnych metod z PDFium VCL w Delphi.

Przegląd

To wszechstronne demo oferuje trzy tryby podziału: poszczególne strony, zakresy stron i według zakładek. Obejmuje śledzenie postępu, szczegółowe rejestrowanie i konfigurowalne nazewnictwo plików wyjściowych.

Tryby podziału

  • Poszczególne strony – Utwórz osobny PDF dla każdej strony
  • Zakresy stron – Podziel według niestandardowych zakresów stron (e.g., 1-5, 6-10)
  • Według zakładek – Podziel na granicach zakładek dla sekcji logicznych

PDFium Wymagania DLL

Przed uruchomieniem jakiejkolwiek aplikacji PDFium VCL upewnij się, że są zainstalowane pliki DLL PDFium:

  • pdfium32.dll / pdfium64.dll – Wersje standardowe (~5-6 MB)
  • pdfium32v8.dll / pdfium64v8.dll – Z silnikiem V8 JavaScript (~23-27 MB)

Instalacja: Uruchom PDFiumVCL\DLLs\CopyDlls.bat jako Administrator, aby automatycznie kopiować biblioteki DLL do katalogów systemu Windows.

Podział na pojedyncze strony

Zakreślacz składni Urvanov v2.9.1
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
procedure TFormMain.ProcessIndividualPages;
var
  I: Integer;
  OutputFile: string;
  OutputDir: string;
  PdfNew: TPdf;
begin
  OutputDir := GetOutputDirectory;
  UpdateProgress('Splitting into individual pages...', 0, Pdf.PageCount);
  
  PdfNew := TPdf.Create(nil);
  try
    for I := 1 to Pdf.PageCount do
    begin
      if FCancelled then
        Break;
        
      // Create new document for this page
      PdfNew.CreateDocument;
      
      // Import single page
      PdfNew.ImportPages(Pdf, IntToStr(I), 1);
      
      // Generate output filename
      OutputFile := GenerateOutputFileName(
        edtFilePattern.Text, Pdf.FileName, I);
      OutputFile := OutputDir + '\' + OutputFile;
      
      // Save the single-page PDF
      if PdfNew.SaveAs(OutputFile) then
      begin
        LogMessage(Format('Created: %s', [ExtractFileName(OutputFile)]));
        Inc(FSplitCount);
      end
      else
        LogMessage(Format('Failed to create: %s', [OutputFile]), LOG_ERROR);
        
      PdfNew.Active := False;
      
      UpdateProgress('Processing...', I, Pdf.PageCount);
    end;
  finally
    PdfNew.Free;
  end;
end;
[Czas formatu: 0,0010 sekundy]

Podział według zakresów stron

Zakreślacz składni Urvanov v2.9.1
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.ProcessPageRanges;
var
  Ranges: TPageRanges;
  I: Integer;
  OutputFile: string;
  OutputDir: string;
  PageList: string;
  PdfNew: TPdf;
begin
  Ranges := ParsePageRanges(edtPageRanges.Text);
  if Length(Ranges) = 0 then
  begin
    LogMessage('No valid page ranges specified', LOG_ERROR);
    Exit;
  end;
  
  OutputDir := GetOutputDirectory;
  UpdateProgress('Splitting by page ranges...', 0, Length(Ranges));
  
  PdfNew := TPdf.Create(nil);
  try
    for I := 0 to High(Ranges) do
    begin
      if FCancelled then
        Break;
        
      PdfNew.CreateDocument;
      
      // Build page range string
      PageList := Format('%d-%d', [Ranges[I].StartPage, Ranges[I].EndPage]);
      
      // Import the range
      PdfNew.ImportPages(Pdf, PageList, 1);
      
      // Generate output filename
      OutputFile := Format('%s\%s_pages_%d-%d.pdf', [
        OutputDir,
        ChangeFileExt(ExtractFileName(Pdf.FileName), ''),
        Ranges[I].StartPage,
        Ranges[I].EndPage
      ]);
      
      if PdfNew.SaveAs(OutputFile) then
      begin
        LogMessage(Format('Created: %s (pages %s)',
          [ExtractFileName(OutputFile), PageList]));
        Inc(FSplitCount);
      end;
      
      PdfNew.Active := False;
      
      UpdateProgress('Processing...', I + 1, Length(Ranges));
    end;
  finally
    PdfNew.Free;
  end;
end;
[Czas formatowania: 0,0008 sekundy]

Analizowanie zakresów stron

Zakreślacz składni Urvanov v2.9.1
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
function TFormMain.ParsePageRanges(const RangeStr: string): TPageRanges;
var
  Parts: TStringList;
  I: Integer;
  Part: string;
  DashPos: Integer;
  StartPage, EndPage: Integer;
  Range: TPageRange;
begin
  SetLength(Result, 0);
  
  if Trim(RangeStr) = '' then
    Exit;
    
  Parts := TStringList.Create;
  try
    Parts.Delimiter := ',';
    Parts.DelimitedText := RangeStr;
    
    for I := 0 to Parts.Count - 1 do
    begin
      Part := Trim(Parts[I]);
      if Part = '' then
        Continue;
        
      DashPos := Pos('-', Part);
      if DashPos > 0 then
      begin
        // Range: "1-5"
        StartPage := StrToIntDef(Trim(Copy(Part, 1, DashPos - 1)), 0);
        EndPage := StrToIntDef(Trim(Copy(Part, DashPos + 1, Length(Part))), 0);
      end
      else
      begin
        // Single page: "3"
        StartPage := StrToIntDef(Part, 0);
        EndPage := StartPage;
      end;
      
      if (StartPage > 0) and (EndPage >= StartPage) and
         (EndPage <= Pdf.PageCount) then
      begin
        Range.StartPage := StartPage;
        Range.EndPage := EndPage;
        SetLength(Result, Length(Result) + 1);
        Result[High(Result)] := Range;
      end;
    end;
  finally
    Parts.Free;
  end;
end;
[Czas formatowania: 0,0008 sekundy]

Dzielenie według zakładek

Zakreślacz składni Urvanov v2.9.1
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
58
59
60
61
62
63
64
65
66
67
68
procedure TFormMain.ProcessBookmarks;
var
  Bookmarks: TBookmarks;
  I: Integer;
  StartPage, EndPage: Integer;
  OutputFile: string;
  OutputDir: string;
  BookmarkTitle: string;
  PdfNew: TPdf;
begin
  Bookmarks := Pdf.Bookmarks;
  
  if Length(Bookmarks) = 0 then
  begin
    LogMessage('No bookmarks found in document', LOG_WARNING);
    Exit;
  end;
  
  OutputDir := GetOutputDirectory;
  UpdateProgress('Splitting by bookmarks...', 0, Length(Bookmarks));
  
  PdfNew := TPdf.Create(nil);
  try
    for I := 0 to High(Bookmarks) do
    begin
      if FCancelled then
        Break;
        
      StartPage := Bookmarks[I].PageNumber;
      
      // End page is start of next bookmark or end of document
      if I < High(Bookmarks) then
        EndPage := Bookmarks[I + 1].PageNumber - 1
      else
        EndPage := Pdf.PageCount;
        
      if (StartPage > 0) and (EndPage >= StartPage) then
      begin
        PdfNew.CreateDocument;
        
        PdfNew.ImportPages(Pdf,
          Format('%d-%d', [StartPage, EndPage]), 1);
          
        // Clean bookmark title for filename
        BookmarkTitle := Bookmarks[I].Title;
        BookmarkTitle := StringReplace(BookmarkTitle, '/', '_', [rfReplaceAll]);
        BookmarkTitle := StringReplace(BookmarkTitle, '\', '_', [rfReplaceAll]);
        BookmarkTitle := StringReplace(BookmarkTitle, ':', '_', [rfReplaceAll]);
        
        OutputFile := Format('%s\%02d_%s.pdf', [
          OutputDir, I + 1, BookmarkTitle]);
          
        if PdfNew.SaveAs(OutputFile) then
        begin
          LogMessage(Format('Created: %s (pages %d-%d)',
            [ExtractFileName(OutputFile), StartPage, EndPage]));
          Inc(FSplitCount);
        end;
        
        PdfNew.Active := False;
      end;
      
      UpdateProgress('Processing...', I + 1, Length(Bookmarks));
    end;
  finally
    PdfNew.Free;
  end;
end;
[Czas formatowania: 0,0009 sekundy]

Konfigurowalne nazwy plików wyjściowych

Zakreślacz składni Urvanov v2.9.1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function TFormMain.GenerateOutputFileName(
  const Pattern, SourceFile: string;
  PageNum: Integer): string;
var
  BaseName, Ext: string;
begin
  BaseName := ChangeFileExt(ExtractFileName(SourceFile), '');
  Ext := ExtractFileExt(SourceFile);
  
  Result := StringReplace(Pattern, '{filename}', BaseName,
    [rfReplaceAll, rfIgnoreCase]);
  Result := StringReplace(Result, '{page}', IntToStr(PageNum),
    [rfReplaceAll, rfIgnoreCase]);
  Result := StringReplace(Result, '{page:000}', Format('%.3d', [PageNum]),
    [rfReplaceAll, rfIgnoreCase]);
    
  // Ensure .pdf extension
  if not EndsText('.pdf', Result) then
    Result := Result + '.pdf';
end;
[Czas formatowania: 0,0004 sekundy]

Aktualizacje postępu i statusu

Zakreślacz składni Urvanov v2.9.1
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
procedure TFormMain.UpdateProgress(const Status: string;
  Current, Total: Integer);
begin
  lblStatus.Caption := Status;
  
  if Total > 0 then
  begin
    prgProgress.Max := Total;
    prgProgress.Position := Current;
    lblProgress.Caption := Format('%d of %d pages', [Current, Total]);
  end
  else
  begin
    prgProgress.Position := 0;
    lblProgress.Caption := 'Initializing...';
  end;
  
  Application.ProcessMessages;
end;
 
procedure TFormMain.LogMessage(const Msg: string;
  const Level: string = 'INFO');
var
  TimeStamp, LogLine: string;
begin
  TimeStamp := FormatDateTime('hh:nn:ss', Now);
  LogLine := Format('[%s] %s: %s', [TimeStamp, Level, Msg]);
  
  mmoLog.Lines.Add(LogLine);
  mmoLog.Perform(WM_VSCROLL, SB_BOTTOM, 0);
  Application.ProcessMessages;
end;
[Czas formatu: 0,0005 sekundy]

Wsparcie w zakresie anulowania

Zakreślacz składni Urvanov v2.9.1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
procedure TFormMain.btnCancelClick(Sender: TObject);
begin
  FCancelled := True;
  LogMessage('Cancellation requested...', LOG_WARNING);
end;
 
procedure TFormMain.SetProcessingState(Processing: Boolean);
begin
  FProcessing := Processing;
  
  btnBrowse.Enabled := not Processing;
  edtPdfFile.Enabled := not Processing;
  grpOptions.Enabled := not Processing;
  btnSplit.Enabled := not Processing;
  btnCancel.Enabled := Processing;
end;
[Czas formatowania: 0,0002 sekundy]

Podsumowanie ukończenia

Zakreślacz składni Urvanov v2.9.1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
procedure TFormMain.ShowCompletionSummary;
var
  ElapsedTime: TDateTime;
  ElapsedStr: string;
begin
  ElapsedTime := Now - FStartTime;
  ElapsedStr := FormatDateTime('nn:ss', ElapsedTime);
  
  if FCancelled then
    LogMessage(Format('Operation cancelled. Created %d files in %s',
      [FSplitCount, ElapsedStr]), LOG_WARNING)
  else
    LogMessage(Format('Split completed. Created %d files in %s',
      [FSplitCount, ElapsedStr]), LOG_SUCCESS);
end;
[Czas formatowania: 0,0002 sekundy]

Przypadki użycia

  • Wyodrębnij rozdziały – Dziel książki lub podręczniki według rozdziałów za pomocą zakładek
  • Rozpowszechniaj strony – Daj różnym członkom zespołu różne zakresy stron
  • Archiwizuj według sekcji – Organizuj duże dokumenty w mniejsze, łatwe w zarządzaniu pliki
  • Ekstrakcja strony – Wyodrębnij określone strony w celu udostępnienia lub przejrzenia

Wniosek

Demo Split PDF demonstruje elastyczność PDFium VCL w zakresie manipulacji dokumentami. Niezależnie od tego, czy dzielisz według stron, zakresów czy sekcji logicznych zdefiniowanych za pomocą zakładek, proces jest prosty i wydajny.

W połączeniu z konfigurowalnym nazewnictwem wyników i śledzeniem postępu możesz tworzyć profesjonalne narzędzia do dzielenia dokumentów dla dowolnego przepływu pracy.

Pobierz PDFium VCL Komponent z losLab.com i przejmij kontrolę nad swoimi dokumentami PDF.