기술 문서

HotPDF 및 TPrinter를 사용하여 Delphi에서 로드된 PDF 인쇄

HotPDF는 세 가지 호출을 사용하여 로드된 PDF를 실제 프린터, Windows 디바이스 컨텍스트 또는 클립보드로 인쇄할 수 있습니다: PrintLoadedDocument는 VCL TPrinter를 구동하고, RenderLoadedPageToDC는 페이지를 임의의 HDC에 직접 그리며, RenderLoadedPageToClipboard는 페이지를 비트맵 또는 벡터 메타파일로 클립보드에 복사합니다. HotPDF는 Delphi 및 C++Builder용 네이티브 VCL PDF 컴포넌트이며, v2.331.0에서 이 최고 수준의 인쇄 경로를 추가하고 v2.348.0에서 이를 정제하였습니다. 이로써 비트맵 렌더러 주위에 TPrinter 루프를 수작업으로 직접 구현할 필요가 없어졌습니다. 세 가지 호출 모두 페이지의 벡터 콘텐츠를 대상에 직접 그리므로, 프린터가 인쇄할 수 있는 최고 선명도를 그대로 유지합니다

비트맵 대신 PDF 페이지를 프린터에 직접 그리는 이유는 무엇인가요?

PDF 페이지는 픽셀 그리드가 아니라 ISO 32000-1 그래픽 모델을 기준으로 실행되는 벡터 그리기 연산자(경로, 텍스트 및 이미지)의 프로그램입니다. 페이지를 인쇄하는 가장 직관적인 방법은 페이지를 비트맵으로 래스터화한 뒤 그 비트맵을 프린터 캔버스에 그리는(Blit) 것이며 이 방법도 작동은 하지만, 프린터 고유의 장점을 완전히 상실하게 만듭니다. 최신 레이저 프린터는 600 또는 1200 DPI의 해상도를 갖습니다; 150 또는 300 DPI로 래스터화된 비트맵을 용지 크기에 맞춰 늘리면 거칠고 텍스트 가장자리가 톱니처럼 깨지며 보간 현상이 고스란히 나타납니다. RenderLoadedPageToDC는 더 나은 방식을 취합니다: 페이지의 콘텐츠 스트림을 대상 디바이스 컨텍스트로 직접 출력되는 GDI 호출로 변환하여 재생성하므로, 벡터 텍스트와 라인 아트가 프린터에 벡터 형식 그대로 도달하고 프린터가 가진 하드웨어 해상도에서 최종적으로 단 한 번만 래스터화됩니다

Delphi에서 로드된 PDF를 실제 프린터로 인쇄하려면 어떻게 해야 하나요?

HotPDF는 할당된 VCL TPrinterTHPDFPrintOptions 레코드를 인수로 받아 선택한 페이지를 인쇄하고 전송된 페이지 수를 반환하는 PrintLoadedDocument(Printer, Options)를 통해 로드된 문서를 인쇄합니다. 장치를 선택하기 위해 먼저 Printer.PrinterIndex를 설정하고, 옵션 레코드(THPDFPrintOptions.Default 클래스 함수가 합리적인 기본값을 제공함)를 채운 뒤 호출하면 됩니다. 라이브러리는 Printer.BeginDoc으로 인쇄 작업을 시작하고 페이지 사이사이에 Printer.NewPage를 호출하며 페이지 범위를 순회한 뒤 Printer.EndDoc으로 닫으므로, 개발자가 인쇄 작업의 수명 주기를 수작업으로 관리할 필요가 없습니다

uses Printers;

var
  Pdf: THotPDF;
  Opts: THPDFPrintOptions;
begin
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('invoice.pdf') > 0 then
    begin
      Printer.PrinterIndex := -1;         // -1은 기본 프린터를 선택합니다
      Opts := THPDFPrintOptions.Default;  // 모든 페이지, 300 DPI, FitPage, 컬러
      Opts.PageRange := '1,3-5';          // 1부터 시작합니다. 비어 있으면 모든 페이지를 인쇄합니다
      Opts.Copies := 2;
      Pdf.PrintLoadedDocument(Printer, Opts);
    end;
  finally
    Pdf.Free;
  end;
end;

PageRange 문자열은 1부터 시작하며 인쇄 대화 상자와 같은 방식으로 읽힙니다: '1,3-5'는 1페이지와 3~5페이지를 인쇄하며, 비어 있는 문자열은 문서 전체를 인쇄합니다. CopiesPrinter.Copies에 직접 매핑됩니다. 다만 한 가지만 유념하십시오. VCL은 Delphi 버전에 따라 한 부씩 인쇄(Collate) 설정을 일관되지 않게 공개하므로, HotPDF는 사본 개수만 설정하고 한 부씩 인쇄 여부는 프린터 드라이버 기본값에 위임합니다. 따라서 한 부씩 인쇄 순서가 확실히 보장되어야 하는 경우에는 해당 플래그를 신뢰하기보다 TPrinterSetupDialog를 통해 드라이버 레벨에서 직접 설정하는 것이 좋습니다

DPI와 FitPage가 어떻게 인쇄 비율을 결정하나요?

실제 배포하기 전에 FitPageDPI가 상호 작용하는 방식을 이해해 두어야 합니다. FitPage가 True(기본값)인 경우 HotPDF는 각 페이지의 MediaBox를 읽고 가로세로 비율을 유지하면서 Printer.PageWidthPrinter.PageHeight 크기에 맞춰 조정하며, 페이지가 종이에 가득 차도록 배율을 적용해 렌더링합니다. 이 모드에서는 출력이 프린터의 물리적 용지 치수에 맞춰져야 하므로 Options.DPI가 실제 맞춤 배율에 의해 덮어씌워집니다. 반면 FitPage가 False인 경우 HotPDF는 72 PDF 단위를 DPI 장치 픽셀에 매핑하여 각 페이지를 1:1 원본 비율로 Options.DPI에 정확히 맞춰 렌더링합니다. 이는 원본 페이지와 용지 크기가 이미 일치하고 정확한 해상도가 중요할 때 유용합니다. 원본 페이지 크기와 공급 트레이 크기가 다를 때는 FitPage를 사용하고, 용지 크기가 일치하며 결정론적인 배율이 필요할 때는 1:1 방식을 사용하십시오

v2.348.0에 추가된 두 가지 옵션은 거의 잘 나오는 것 같지만 미세하게 어긋나는 인쇄 문제를 해결해 줍니다. 모든 실제 프린터에는 물리적 한계로 잉크가 닿지 않는 인쇄 불가 영역(하드 마진)이 있으며, 기본적으로 페이지 원점은 이 마진 안쪽에 위치하므로 여백 없이 가득 찬 페이지는 두 모서리 부근이 약간 잘리게 됩니다. IgnoreHardMargin을 True로 설정하면 HotPDF는 프린터의 PHYSICALOFFSETXPHYSICALOFFSETY 값을 조회하고 디바이스 원점을 이동시켜 해당 오프셋을 상쇄하므로, 페이지 원점이 실제 종이 모서리와 정확히 매핑됩니다. 두 번째 옵션인 AutoRotate는 기본적으로 활성화되어 있습니다: 이는 각 페이지의 MediaBox를 읽고 가로가 세로보다 넓은 경우 프린터 방향을 가로(Landscape)로 전환하여 넓은 페이지가 세로 레이아웃에 맞춰 잘리지 않고 올바르게 인쇄되도록 합니다. AutoRotate는 개발자가 Orientation을 명시적으로 설정하는 즉시 비활성화되므로, 의도적인 방향 선택이 항상 우선권을 갖습니다

임의의 디바이스 컨텍스트에 PDF 페이지를 렌더링하려면 어떻게 해야 하나요?

RenderLoadedPageToDC(PageIndex, DC, DPI, W, H)는 인쇄 루프 하부의 기초 메서드이며 그 자체로도 매우 유용합니다. PrintLoadedDocument는 프린터 캔버스를 대상으로 페이지당 한 번씩 이 메서드를 호출하지만, 대상은 오프스크린 메모리 DC, 커스텀 뷰어 내부의 컨트롤 캔버스, 인쇄 미리보기 화면 등 모든 Windows HDC가 될 수 있습니다. PageIndex는 0부터 시작하고, WH는 대상 표면의 장치 단위 해상도이며, 렌더러는 페이지의 /Contents를 순회하며 지정한 DC에 GDI 호출을 보냅니다. 한 가지 유념해야 할 동작이 있습니다: 이 메서드는 백그라운드 채우기를 수행하지 않습니다. 표면의 소유권은 호출자에게 있으므로, 페이지 뒤에 흰색 종이 배경을 표시하려면 렌더링 전에 DC를 직접 배경색으로 채워두어야 합니다. 덕분에 개발자가 원하는 경우 기존 캔버스 위에 PDF 페이지를 겹쳐서 그리는(Composite) 작업이 가능합니다

// 150 DPI의 오프스크린 24비트 표면에 1페이지를 그립니다
var
  Surface: TBitmap;
begin
  Surface := TBitmap.Create;
  try
    Surface.PixelFormat := pf24bit;
    Surface.SetSize(1275, 1650);           // 150 DPI 기준 8.5 x 11 인치
    Surface.Canvas.Brush.Color := clWhite;
    Surface.Canvas.FillRect(Surface.Canvas.ClipRect);  // 호출자가 배경을 칠합니다
    Pdf.RenderLoadedPageToDC(0, Surface.Canvas.Handle, 150, Surface.Width, Surface.Height);
    // Surface가 이제 겹쳐진 페이지를 보유하므로 전송(Blit)하거나 저장할 준비가 되었습니다
  finally
    Surface.Free;
  end;
end;

단순히 완성된 TBitmap(섬네일, 이미지 내보내기, 캐싱할 미리보기 화면)이 필요한 경우에는 이와 대조되는 비트맵에 PDF 페이지 렌더링하기에서 다루는 RenderLoadedPageToBitmap을 대신 호출하십시오. 차이점은 표면의 소유자입니다. 비트맵 호출은 픽셀 버퍼를 할당하여 반환하는 반면, RenderLoadedPageToDC는 프린터 캔버스나 페인트 핸들러가 넘겨주는 이미 보유 중인 디바이스 컨텍스트에 직접 픽셀을 채웁니다. 두 메서드 모두 동일한 콘텐츠 스트림 인터프리터와 임베디드 글리프 엔진을 공유하므로 어느 경로를 택하든 텍스트 외곽선이 완벽하게 출력됩니다

PDF 페이지를 Word 또는 이미지 편집기에 붙여넣으려면 어떻게 해야 하나요?

RenderLoadedPageToClipboard(PageIndex, DPI, AsMetafile)는 하나의 페이지를 Windows 클립보드에 복사하여 Word, PowerPoint, 이메일 또는 이미지 편집기에 즉시 붙여넣을 수 있게 해줍니다. AsMetafile 플래그는 복사할 포맷을 지정하며, 이 선택은 보기보다 훨씬 중요합니다: False를 전달하면 HotPDF는 지정한 DPI로 렌더링된 24비트 장치 비트맵(CF_BITMAP)을 클립보드에 할당합니다. 이는 어디에나 붙여넣을 수 있는 고정 픽셀 그리드이지만 수신자가 크기를 늘리면 계단 현상이 나타납니다. True를 전달하면 향상된 메타파일(CF_ENHMETAFILE)을 클립보드에 할당하여 페이지의 텍스트와 벡터 아트가 GDI 그리기 명령어로 전송되므로, 붙여넣은 결과가 어떠한 확대 배율에서도 선명하게 유지되며 대상 문서가 부여한 크기에 맞춰 유연하게 리플로우됩니다

// Word에 붙여넣기 위해 크기 조절이 가능한 벡터 메타파일로 2페이지를 복사합니다
Pdf.RenderLoadedPageToClipboard(1, 300, True);

// 대신 동일한 페이지를 300 DPI의 고정 비트맵으로 복사합니다
Pdf.RenderLoadedPageToClipboard(1, 300, False);

판단 요령은 매우 간단합니다. 사용자가 문서를 복사하여 보고서 내부의 다이어그램이나 계약서 초안의 구절처럼 크기 조절을 해야 하는 경우 벡터 텍스트의 크기 조절 및 인쇄 품질이 우수한 메타파일을 사용하십시오. 대상 프로그램이 래스터 데이터만 인식하거나, 특정 해상도로 고정된 스냅샷이 필요한 경우에만 비트맵을 사용하십시오. 단순한 이미지 캡처가 아닌 본문 텍스트의 문자 정보를 추출해야 하는 경우에는 문자 및 좌표 데이터를 제공하는 텍스트 추출 API를 사용하는 전혀 다른 접근이 요구됩니다

인쇄 경로의 한계

이 페이지에 설명된 모든 기능은 Windows 전용이며, 이를 명확히 짚어두어야 합니다. PrintLoadedDocument, RenderLoadedPageToDC, RenderLoadedPageToClipboardTPrinter, GDI 디바이스 컨텍스트 모델, Windows 클립보드, 고급 메타파일 등 모두 Win32 및 Win64 구조를 기반으로 설계되었습니다. 타겟 플랫폼이 다른 경우 HotPDF의 나머지 기능들로 PDF를 생성, 편집 및 조회할 수 있지만, GDI 기반의 이 인쇄 및 클립보드 기능은 지원되지 않습니다. 또한 렌더러는 텍스트, 경로, 이미지 등의 일반적인 문서 하위 세트를 대상으로 하므로, 그라데이션이 많이 들어간 설계 도면이나 ICC 관리 프로필 컬러는 비색계(Colorimetric) 증명 인쇄가 아닌 충실한 일반 프리뷰 형태로 인쇄되며, 이는 비트맵 렌더러와 동일한 한계입니다

여러 파일에 대해 배치 인쇄를 수행하는 경우 각 문서를 차례로 로드하여 인쇄하고 메모리 상태를 지속적으로 모니터링해야 합니다: PrintLoadedDocument는 한 번에 한 페이지씩 렌더링하지만 로드된 문서 개체 그래프 자체는 인쇄 작업 전반에 걸쳐 메모리에 유지되기 때문입니다. 수백 개의 대용량 파일에 대해 인쇄 대기열을 처리해야 하는 경우, 대용량 PDF 워크플로우를 위한 스트리밍 직접 파일 API를 인쇄 경로와 병용하는 것이 효과적입니다: 디스크 레벨에서 필요한 페이지만 먼저 분할, 병합 또는 선택한 뒤 슬림해진 결과물만 메모리에 로드하여 인쇄하십시오. 이렇게 PrintLoadedDocument, RenderLoadedPageToDC, RenderLoadedPageToClipboard는 Delphi 및 C++Builder용 HotPDF 컴포넌트의 일부로 제공됩니다. 외부 DLL 종속성이 없고 PDF 생성, 편집, 텍스트 추출, 렌더링 및 TPrinter, 디바이스 컨텍스트, 클립보드로의 인쇄를 지원하는 네이티브 VCL 라이브러리입니다