기술 문서

Delphi에서 PDFium VCL을 사용하여 PDF 문서에서 이미지 추출하기

· PDF 프로그래밍

PDF 문서에는 종종 귀중한 이미지들이 포함되어 있습니다—사진, 다이어그램, 차트 및 그래픽. 이미지 추출 이 데모는 PDFium VCL을 사용하여 PDF 문서에서 모든 내장 이미지를 추출하고, 각 이미지의 특성에 따라 최적의 형식으로 저장하는 방법을 보여줍니다.

개요

이 데모는 PDF 페이지에서 내장된 이미지(비트맵)를 추출하여 별도의 이미지 파일로 저장합니다. 이미지 미리보기, 형식 감지 및 진행 상황 추적 기능이 있는 일괄 추출 기능을 포함합니다.

주요 기능

  • 모든 이미지 추출 – PDF에서 모든 내장 이미지를 추출합니다.
  • 페이지 범위 선택 – 특정 페이지에서만 추출합니다.
  • 스마트 형식 감지 – 이미지의 특성에 따라 JPEG, PNG 또는 BMP 형식을 자동으로 선택합니다.
  • 이미지 미리보기 – 저장하기 전에 추출된 이미지를 미리 봅니다.
  • 상세 정보 – 크기, 형식 및 파일 크기를 확인합니다.
  • 일괄 처리 – 진행 상황 추적과 함께 여러 이미지를 추출합니다.

PDFium DLL 요구 사항

PDFium VCL 애플리케이션을 실행하기 전에, PDFium DLL 파일이 설치되어 있는지 확인하십시오.

  • pdfium32.dll / pdfium64.dll – 표준 버전 (약 5-6 MB)
  • pdfium32v8.dll / pdfium64v8.dll – V8 JavaScript 엔진 포함 (약 23-27 MB)

설치: 실행 PDFiumVCL\DLLs\CopyDlls.bat 관리자 권한으로 실행하여 DLL 파일을 Windows 시스템 디렉터리에 자동으로 복사합니다.

기본 이미지 추출

내장된 이미지는 다음 속성을 통해 액세스할 수 있습니다: Bitmap 그리고 BitmapCount 속성:

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
procedure ExtractImagesSimple;
var
  Pdf: TPdf;
  I, J: Integer;
  Bitmap: TBitmap;
begin
  Pdf := TPdf.Create(nil);
  try
    Pdf.FileName := 'document.pdf';
    Pdf.Active := True;
    
    // Loop through all pages
    for I := 1 to Pdf.PageCount do
    begin
      Pdf.PageNumber := I;
      
      // Loop through all images on this page
      for J := 0 to Pdf.BitmapCount - 1 do
      begin
        Bitmap := Pdf.Bitmap[J];
        try
          // Save as BMP
          Bitmap.SaveToFile(Format('Page%d_Image%d.bmp', [I, J + 1]));
        finally
          Bitmap.Free;
        end;
      end;
    end;
    
  finally
    Pdf.Active := False;
    Pdf.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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
procedure TFormMain.ButtonExtractClick(Sender: TObject);
var
  I, J, StartPage, EndPage: Integer;
  Bitmap: TBitmap;
  FullFileName, DetectedFormat, ImageExtension: string;
  ImageInfo: TImageInfo;
begin
  FCancelled := False;
  FProcessedImages := 0;
  FTotalImages := 0;
  
  ClearExtractedImages;
  EnableControls(False);
  
  try
    Pdf.FileName := EditPdfFile.Text;
    Pdf.PageNumber := 0;
    Pdf.Active := True;
    
    ParsePageRange(EditPageRange.Text, StartPage, EndPage);
    if EndPage = -1 then
      EndPage := Pdf.PageCount;
      
    // Calculate total images for progress
    for I := StartPage to EndPage do
    begin
      Pdf.PageNumber := I;
      FTotalImages := FTotalImages + Pdf.BitmapCount;
    end;
    
    ProgressBar.Max := FTotalImages;
    
    // Extract images
    for I := StartPage to EndPage do
    begin
      if FCancelled then
        Break;
        
      Pdf.PageNumber := I;
      
      for J := 0 to Pdf.BitmapCount - 1 do
      begin
        if FCancelled then
          Break;
          
        Bitmap := Pdf.Bitmap[J];
        if Assigned(Bitmap) then
        begin
          try
            // Detect optimal format
            DetectedFormat := DetectImageFormat(Bitmap);
            ImageExtension := GetExtensionForFormat(DetectedFormat);
            
            FullFileName := Format('%s\Page%d_Image%d%s',
              [FCurrentOutputDir, I, J + 1, ImageExtension]);
              
            SaveBitmapInOptimalFormat(Bitmap, FullFileName);
            
            // Store image info for preview
            ImageInfo.FileName := FullFileName;
            ImageInfo.PageNumber := I;
            ImageInfo.ImageIndex := J + 1;
            ImageInfo.Width := Bitmap.Width;
            ImageInfo.Height := Bitmap.Height;
            ImageInfo.Format := DetectedFormat;
            ImageInfo.Bitmap := TBitmap.Create;
            ImageInfo.Bitmap.Assign(Bitmap);
            
            AddImageInfo(ImageInfo);
            
            Inc(FProcessedImages);
            ProgressBar.Position := FProcessedImages;
            
          finally
            Bitmap.Free;
          end;
        end;
      end;
    end;
    
    UpdateImageList;
    
  finally
    Pdf.Active := False;
    EnableControls(True);
  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
function TFormMain.DetectImageFormat(ABitmap: TBitmap): string;
begin
  // Check if image has transparency (alpha channel)
  if ABitmap.PixelFormat = pf32bit then
  begin
    // PNG for transparency support
    Result := 'PNG';
  end
  // Check if it's likely a photographic image
  else if (ABitmap.Width * ABitmap.Height > 100000) and
          (ABitmap.PixelFormat in [pf24bit, pf32bit]) then
  begin
    // Large, complex image - use JPEG for smaller file size
    Result := 'JPEG';
  end
  else
  begin
    // Small or simple image - preserve quality with BMP
    Result := 'BMP';
  end;
end;
 
function TFormMain.GetExtensionForFormat(const AFormat: string): string;
begin
  case UpperCase(AFormat)[1] of
    'J': Result := '.jpg';
    'P': Result := '.png';
    'B': Result := '.bmp';
  else
    Result := '.bmp';
  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
procedure TFormMain.SaveBitmapInOptimalFormat(ABitmap: TBitmap;
  const AFileName: string);
var
  JpegImg: TJPEGImage;
  FileExt: string;
begin
  FileExt := UpperCase(ExtractFileExt(AFileName));
  
  if FileExt = '.JPG' then
  begin
    // Save as JPEG with good quality
    JpegImg := TJPEGImage.Create;
    try
      JpegImg.Assign(ABitmap);
      JpegImg.CompressionQuality := 85; // Good quality/size balance
      JpegImg.SaveToFile(AFileName);
    finally
      JpegImg.Free;
    end;
  end
  else if FileExt = '.PNG' then
  begin
    // PNG would require additional library
    // Fall back to BMP for compatibility
    ABitmap.SaveToFile(ChangeFileExt(AFileName, '.bmp'));
  end
  else
  begin
    // BMP - lossless quality
    ABitmap.SaveToFile(AFileName);
  end;
end;

TPdfImage를 사용하여 원시 이미지 데이터에 접근합니다.

고급 사용 사례의 경우, 원시 이미지 데이터에 접근할 수 있습니다.

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 ProcessRawImageData;
var
  Pdf: TPdf;
  I: Integer;
  PdfImage: TPdfImage;
begin
  Pdf := TPdf.Create(nil);
  try
    Pdf.FileName := 'document.pdf';
    Pdf.Active := True;
    Pdf.PageNumber := 1;
    
    for I := 0 to Pdf.ImageCount - 1 do
    begin
      PdfImage := Pdf.Image[I];
      
      // Access raw image properties
      ShowMessage(Format('Image %d: %d x %d, %d bytes',
        [I, PdfImage.Width, PdfImage.Height, Length(PdfImage.Data)]));
        
      // PdfImage.Data contains raw pixel data
    end;
    
  finally
    Pdf.Active := False;
    Pdf.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
procedure TFormMain.UpdatePreview(Index: Integer);
var
  Info: TImageInfo;
begin
  if (Index >= 0) and (Index < Length(FExtractedImages)) then
  begin
    Info := FExtractedImages[Index];
    
    // Update preview
    if Assigned(Info.Bitmap) then
      ImagePreview.Picture.Assign(Info.Bitmap);
      
    // Update info display
    MemoInfo.Lines.Clear;
    MemoInfo.Lines.Add('File: ' + ExtractFileName(Info.FileName));
    MemoInfo.Lines.Add('Page: ' + IntToStr(Info.PageNumber));
    MemoInfo.Lines.Add('Dimensions: ' + IntToStr(Info.Width) +
                       ' x ' + IntToStr(Info.Height));
    MemoInfo.Lines.Add('Format: ' + Info.Format);
    if Info.Size > 0 then
      MemoInfo.Lines.Add('Size: ' + FormatFloat('#,##0', Info.Size) + ' bytes');
  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
procedure TFormMain.ParsePageRange(const ARange: string;
  var AStartPage, AEndPage: Integer);
var
  RangeStr: string;
  DashPos: Integer;
begin
  RangeStr := Trim(ARange);
  AStartPage := 1;
  AEndPage := -1; // -1 means extract to end
  
  if (RangeStr = '') or (UpperCase(RangeStr) = 'ALL') then
    Exit;
    
  DashPos := Pos('-', RangeStr);
  if DashPos > 0 then
  begin
    // Range format: start-end
    AStartPage := StrToIntDef(Trim(Copy(RangeStr, 1, DashPos - 1)), 1);
    AEndPage := StrToIntDef(Trim(Copy(RangeStr, DashPos + 1, Length(RangeStr))), -1);
  end
  else
  begin
    // Single page
    AStartPage := StrToIntDef(RangeStr, 1);
    AEndPage := AStartPage;
  end;
end;

추출된 이미지 폴더 열기.

1
2
3
4
5
6
7
procedure TFormMain.ButtonOpenFolderClick(Sender: TObject);
begin
  if DirectoryExists(FCurrentOutputDir) then
    ShellExecute(Handle, 'open', PChar(FCurrentOutputDir), nil, nil, SW_SHOWNORMAL)
  else
    ShowMessage('Output directory does not exist.');
end;

사용 사례

  • 디지털 자산 추출. – 마케팅 자료에서 사진 및 그래픽을 추출합니다.
  • 문서 변환. – 웹 또는 기타 형식에 사용할 이미지를 준비합니다.
  • 아카이브 처리 – 스캔 문서 아카이브에서 이미지를 추출합니다.
  • 콘텐츠 분석 – 머신러닝 또는 분석을 위한 이미지를 추출합니다.

결론

"이미지 추출" 데모는 PDFium VCL을 사용하여 PDF 문서에서 내장된 이미지를 추출하는 것이 얼마나 쉬운지 보여줍니다. 이 구성 요소는 복잡한 PDF 구문 분석을 처리하고, 사용자는 추출된 이미지를 애플리케이션에서 사용하는 방법을 중심으로 작업합니다.

지능형 형식 감지와 결합하여, 모든 사용 사례에 대해 최적화된 출력을 생성하는 전문적인 이미지 추출 도구를 만들 수 있습니다.

자세히 알아보기 PDFium 컴포넌트 방문하여 loslab.com에서 PDF 문서의 내용을 잠금 해제하세요.