تقسيم ملف PDF كبير إلى ملفات أصغر أمر ضروري لتوزيع المستندات وأرشفتها ومعالجتها. Split PDF يوضح العرض التوضيحي كيفية تقسيم مستندات PDF باستخدام طرق مختلفة مع PDFium VCL في Delphi.
نظرة عامة
يوفر هذا العرض التوضيحي الشامل ثلاثة أوضاع للتقسيم: الصفحات الفردية، ونطاقات الصفحات، وعبر الإشارات المرجعية. يتضمن تتبع التقدم، وتسجيلًا تفصيليًا، وتسمية ملفات الإخراج القابلة للتخصيص.
أوضاع التقسيم
- الصفحات الفردية - إنشاء ملف PDF منفصل لكل صفحة.
- نطاقات الصفحات. تقسيم حسب نطاقات الصفحات المخصصة (مثل 1-5، 6-10).
- حسب الإشارات المرجعية. التقسيم عند حدود الإشارات المرجعية للأقسام المنطقية.
متطلبات ملف PDFium DLL.
قبل تشغيل أي تطبيق PDFium VCL، تأكد من تثبيت ملفات PDFium DLL:
pdfium32.dll/pdfium64.dll– الإصدارات القياسية (حوالي 5-6 ميجابايت).pdfium32v8.dll/pdfium64v8.dll– مع محرك JavaScript V8 (حوالي 23-27 ميجابايت).
التثبيت: تشغيل PDFiumVCL\DLLs\CopyDlls.bat بصلاحيات المسؤول لنسخ ملفات DLL تلقائيًا إلى مجلدات نظام Windows.
التقسيم إلى صفحات فردية.
|
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; |
التقسيم حسب نطاقات الصفحات.
|
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; |
تحليل نطاقات الصفحات.
|
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; |
التقسيم حسب الإشارات المرجعية.
|
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; |
أسماء ملفات إخراج قابلة للتخصيص.
|
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; |
تحديثات التقدم والحالة.
|
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; |
دعم الإلغاء.
|
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; |
ملخص الإكمال.
|
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; |
حالات الاستخدام.
- استخراج الفصول. - قسّم الكتب أو الأدلة إلى فصول باستخدام الإشارات.
- توزيع الصفحات. - امنح أعضاء الفريق المختلفين نطاقات صفحات مختلفة.
- الأرشفة حسب القسم. - قم بتنظيم المستندات الكبيرة إلى ملفات أصغر وأكثر قابلية للإدارة.
- استخراج الصفحات. استخراج صفحات محددة للمشاركة أو المراجعة.
الخلاصة.
يوضح نموذج "Split PDF" مرونة مكتبة PDFium VCL في معالجة المستندات. سواء كان التقسيم يتم حسب الصفحات أو النطاقات أو الأقسام المنطقية المحددة بواسطة الإشارات المرجعية، فإن العملية بسيطة وفعالة.
بالاقتران مع تسمية الإخراج القابلة للتخصيص وتتبع التقدم، يمكنك إنشاء أدوات تقسيم مستندات احترافية لأي سير عمل.
تنزيل. مكون PDFium VCL. من loslab.com، وتحكم في مستندات PDF الخاصة بك.