Dividir un PDF grande en archivos más pequeños es esencial para la distribución, el archivado y el procesamiento de documentos. Demostración de "Split PDF". La demostración muestra cómo dividir documentos PDF utilizando varios métodos con PDFium VCL en Delphi.
Resumen
Esta demostración completa ofrece tres modos de división: páginas individuales, rangos de páginas y por marcadores. Incluye seguimiento del progreso, registro detallado y nombres de archivo de salida personalizables.
Modos de división.
- Páginas individuales. – Crea un PDF separado para cada página.
- Rangos de páginas. – Dividir por rangos de página personalizados (por ejemplo, 1-5, 6-10).
- Por Marcadores. – Dividir en los límites de los marcadores para secciones lógicas.
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.
Dividir en páginas individuales.
|
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; |
Dividir por rangos de página.
|
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; |
Análisis de rangos de páginas:
|
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; |
Dividir por marcadores.
|
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; |
Nombres de archivo de salida personalizables.
|
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; |
Actualizaciones de progreso y estado.
|
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; |
Soporte para cancelación.
|
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; |
Resumen de finalización.
|
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; |
Casos de uso.
- Extraer capítulos. – Dividir libros o manuales por capítulo utilizando marcadores.
- Distribuir páginas. – Asignar diferentes rangos de páginas a diferentes miembros del equipo.
- Archivar por sección. – Organizar documentos grandes en archivos más pequeños y manejables.
- Extracción de páginas. – Extrae páginas específicas para compartir o revisar.
Conclusión.
La demostración de división de PDF muestra la flexibilidad de PDFium VCL para la manipulación de documentos. Ya sea que se divida por páginas, rangos o secciones lógicas definidas por marcadores, el proceso es sencillo y eficiente.
Combinado con nombres de salida personalizables y seguimiento del progreso, puede crear herramientas profesionales de división de documentos para cualquier flujo de trabajo.
Descargar Componente PDFium VCL de loslab.com y toma el control de tus documentos PDF.