HotPDF는 RenderLoadedPageToBitmap(PageIndex, DPI) 호출 한 번으로 로드된 PDF 페이지를 Delphi TBitmap으로 렌더링해 줍니다. 이 함수는 페이지의 콘텐츠 스트림을 해석하여 지정된 해상도의 호출자 소유 24비트 RGB 비트맵을 반환합니다. 이는 썸네일 스트립, 인쇄 미리보기 또는 PDF-to-image 내보내기 파이프라인에서 필요로 하는 기능입니다. 본 문서에서는 이 API를 살펴본 뒤, 단순한 기능 위주의 뷰어 수준을 넘어선 제대로 된 렌더러의 차별점인, 유사한 시스템 글꼴 대신 내장된 글꼴 프로그램 자체에서 텍스트를 드로잉하는 메커니즘을 상세히 분석합니다
PDF 페이지는 그림이 아니라 일종의 프로그램입니다. 즉, ISO 32000-1 §8 규격에 정의된 그래픽 모델에 따라 경로를 설정하고, 글꼴을 지정하며, 색상을 조절하고, 글자 모양(glyph)을 배치하는 연속적인 연산자 스트림 프로그램입니다. PDF 파일 자체에는 특정 픽셀이 어떤 형태로 그려져야 하는지 정의되어 있지 않습니다. 비트맵 이미지를 생성하려면 해당 프로그램을 실행해야 합니다. 즉, 현재의 변환 매트릭스, q/Q에 대한 그래픽 상태 스택, 클리핑 경로, 채우기(fill) 및 선 그리기(stroke) 색상 공간 등을 메모리 상에서 제어하면서 그 실행 결과를 래스터화(rasterize)하는 일련의 처리가 수반됩니다. '3페이지를 이미지로 표시한다'는 작업이 파일 형식 변환이 아닌, 콘텐츠 스트림 인터프리터를 구현하는 기술인 이유가 여기에 있습니다
로드된 페이지를 TBitmap으로 렌더링하기
RenderLoadedPageToBitmap 함수는 0부터 시작하는 페이지 인덱스와 DPI 값을 인수로 받습니다. 이때 72 DPI는 PDF 사용자 공간의 1단위를 1픽셀로 변환 매핑합니다. 인덱스 범위 초과나 필요한 리소스 누락 등의 원인으로 실패하는 경우, 예외를 일으키는 대신 nil을 반환하여 뷰어 애플리케이션이 손상된 페이지를 건너뛰고 나머지 페이지들을 정상적으로 출력할 수 있도록 예외 처리를 지원합니다. 반환된 비트맵은 호출자가 소유권을 가지며 사용이 끝난 후 직접 해제해야 합니다
var
Pdf: THotPDF;
Bmp: TBitmap;
begin
Pdf := THotPDF.Create(nil);
try
if Pdf.LoadFromFile('report.pdf') > 0 then
begin
Bmp := Pdf.RenderLoadedPageToBitmap(0, 144); // page 1 at 144 DPI
if Bmp <> nil then
try
Image1.Picture.Assign(Bmp);
finally
Bmp.Free; // caller owns the bitmap
end;
end;
finally
Pdf.Free;
end;
end;
DPI 인수를 활용하면 다양한 스케일링 요구 시나리오에 손쉽게 대처할 수 있습니다. 썸네일 스트립은 36 또는 48 DPI 수준으로 렌더링하여 용량이 작고 생성이 빠른 비트맵을 확보하며, 화면 미리보기는 일반적인 디스플레이 밀도에 맞추어 96 또는 144 DPI로 렌더링하고, 파일 내보내기는 고품질 인쇄 규격에 맞추어 300 DPI로 출력합니다. /Rotate 속성에 따른 페이지 회전과 /MediaBox 원점 반전(PDF는 원점이 좌측 하단인 반면 GDI는 좌측 상단임)은 페이지-디바이스 변환 매트릭스 내부에서 안전하게 정렬되므로, 72 DPI 기준의 US Letter 크기 페이지를 호출하면 정확히 612×792 픽셀의 올바른 정방향 이미지를 리턴해 줍니다
왜 렌더링된 PDF 썸네일에서 잘못된 글자가 보일까요?
렌더링된 PDF 썸네일 이미지에 엉뚱한 모양의 글자가 나타나는 원인은 대개 렌더러가 문서 파일에 내장된 글꼴 정보 대신 뷰어 시스템의 대체 시스템 글꼴을 사용하여 그렸기 때문입니다. 초기 버전의 HotPDF 렌더러가 바로 이 방식을 사용했습니다. /BaseFont 이름에서 ABCDEF+Arial과 같은 서브셋 접두사를 제거하여 Arial로 가공한 후 GDI 엔진에 해당 이름의 시스템 폰트를 호출하고, 이를 사용해 화면에 텍스트를 그렸습니다. 표준 인코딩 기반의 Arial이나 Times New Roman 글꼴을 사용하는 문서라면 임시방편으로 비슷하게 그려집니다. 하지만 이는 대략적인 묘사에 불과하며 특정 조건에서는 완전히 깨지게 됩니다
가장 곤란한 경우는 서브셋(subset) 글꼴을 사용하는 문서입니다. 서브셋 글꼴은 문서 생성기에 의해 해당 문서에서 사용되는 단 40여 개의 글자 모양만을 압축해 포함하며, 문자 코드가 문서 파일 내의 자체적인 전용 순서로 배치됩니다(예컨대 코드 1은 'T', 코드 2는 'h' 등으로 매핑됨). 일반적인 시스템 글꼴은 이러한 비표준 전용 매핑 규칙을 알 수 없으므로, 텍스트가 화면에서 완전히 소멸되거나 전혀 다른 이상한 문자들로 표시됩니다. 사용자 지정 인코딩, 기호 글꼴, 바코드 글꼴, 그리고 렌더링 시스템에 설치되지 않은 특수 글꼴도 마찬가지로 오류를 일으킵니다. 시스템 글꼴 대체 방식으로 처리되는 렌더러는 일반 문서에 대해서는 그럭저럭 썸네일을 렌더링하지만, 폰트 내장이 필수적인 특수 글꼴을 사용한 페이지를 마주하면 한계를 보이고 마는 것입니다
내장 글자 모양 렌더링: 글꼴 프로그램 자체에서 그리기
HotPDF는 5개 버전(v2.268.0~v2.272.0)에 걸친 개선 과정을 통해 내장된 글꼴 프로그램을 직접 해석하고 각 문자의 외곽선 정보를 분석하여 채워진 GDI 벡터 경로로 드로잉함으로써 이 간극을 극복했습니다. 이제 렌더링된 페이지의 텍스트는 표준 PDF 뷰어와 동일하게 글꼴 프로그램의 원시 벡터 외곽선 데이터를 사용해 표현되므로, 서브셋 글꼴, 사용자 지정 인코딩 및 미설치 특수 글꼴까지 원본과 완전히 동일한 모양으로 그려집니다. 지원되는 글꼴 유형은 다음과 같이 보강되었습니다
내장 TrueType 프로그램(FontFile2)이 포함된 Type0/CIDFontType2 글꼴의 경우, 렌더러가 glyf 및 loca 테이블을 직접 구문 분석합니다. 2차(quadratic) 윤곽선 데이터를 GDI가 해석할 수 있는 3차(cubic) 베지에 곡선으로 변환하고, 연속된 오프커브(off-curve) 포인트 사이에 생략된 온커브(on-curve) 포인트를 재구성하며, 복합 문자 구조를 재귀적으로 분석해 재현합니다. Identity 방식 및 명시적 스트림 기반 CIDToGIDMap 레이아웃을 모두 지원하며, 문자 배치 너비(advance)는 /W 및 /DW 항목 설정을 그대로 준수하므로 2바이트 규격의 Identity-H 텍스트도 간격 조절이 흐트러지지 않고 올바르게 드로잉됩니다
CFF 프로그램(CIDFontType0C, Type1C 또는 OpenType 래퍼 형식의 FontFile3)은 선, 곡선, 플렉스 패밀리, 힌트 마스크, 서브루틴 오프셋 바이어스가 교정된 로컬/글로벌 서브루틴 호출 등을 모두 제어하는 완전한 Type 2 charstring 인터프리터를 탑재하여 지원합니다. CID 키 방식의 CFF 프로그램은 글꼴 문자 세트(charset)를 통해 코드를 매핑하므로, 글자 모양 배치 순서가 표준 CID와 다른 서브셋 글꼴도 안전하게 소화하며, FDArray/FDSelect에 따른 글자별 font-DICT 바인딩 정보를 준수합니다. 단순(non-CID) TrueType 글꼴은 유니코드 형식 4 및 12를 기본으로 하고 사용자 정의 영역인 F000 기호 테이블과 구형 Macintosh 형식까지 대조하는 다중 서브테이블 체인을 활용해 내장 글꼴의 cmap 테이블에서 1바이트 문자 코드를 올바르게 매핑하며, 단순 Type1 글꼴은 CFF 프로그램 내장 인코딩 정보를 역추적해 글자 위치를 잡아냅니다
렌더러의 완성도를 높이는 두 가지 세부 처리 규칙이 있습니다. 첫째, 단순 글꼴의 /Encoding 사전은 ISO 32000-1 §9.6.6 규정 우선순위에 따라 해석됩니다. 즉, /Differences 배열 설정이 최우선이고 그 다음으로 기본 인코딩 테이블, 최종적으로 폰트 자체의 매핑 맵이 적용됩니다. 이는 TeX 및 PostScript 기반의 저작 도구들이 의존하는 흐름으로, 어도비 글자 이름 테이블(Adobe Glyph List)이나 CFF charset, TrueType cmap 정보를 활용해 문자 이름을 추적하여 매핑합니다. 둘째, 개별 문자 정의 자체가 미니 콘텐츠 스트림 형태로 기록되는 Type3 글꼴의 경우, 폰트 매트릭스, 폰트 크기, 텍스트 변환 매트릭스를 모두 결합하여 렌더러를 통해 재현합니다. 문자 공간 /Widths 배열은 ISO 32000-1 §9.6.5 스펙 요구에 맞춰 /FontMatrix를 기준으로 변환 적용되며, d1 지시어로 문자 경계 박스 크기를 지정한 문자 드로잉 프로시저는 해당 격자판 범위 밖으로 묘사 정보가 침범하지 않도록 엄격하게 클리핑 필터 처리합니다. 이를 통해 오작동하는 특수 바코드 문자가 지정 공간 밖으로 삐져나가는 현상을 사전에 방지합니다. 간혹 프로그램 손상 등으로 문자 매핑에 완전히 실패한 경우에는 해당 문자가 아예 생략되는 텍스트 누락 사고를 방지하기 위해 임시방편으로 시스템 글꼴 대체 드로잉을 최종 수단으로 이행해 대처합니다
반복적인 렌더링 속도를 어떻게 향상시키나요?
HotPDF가 제시하는 해법은 최근 사용된 페이지 기반 캐시(MRU Cache)입니다. RenderLoadedPageToBitmapCached는 페이지 인덱스 및 DPI 값을 키로 삼아 최대 RenderCacheCapacity개(기본값 8)의 렌더링이 완료된 페이지 비트맵 정보를 메모리에 관리합니다. 동일한 요청이 접수되면 콘텐츠 스트림을 다시 해석하지 않고 파싱이 완료된 비트맵의 사본을 즉시 반환하여, 매 페이지를 처음부터 재해석하는 것보다 통상 수천 배 이상 빠르게 렌더링을 마칩니다. 이 방식은 사용자가 두 페이지 사이를 번갈아 오가거나 뷰어 창 크기 조절로 인해 동일 페이지를 같은 DPI로 재차 요청하는 그래픽 뷰어 시나리오에 완벽한 시너지 효과를 냅니다
// Thumbnail strip: first pass renders, scrolling back hits the cache
for I := 0 to ThumbCount - 1 do
begin
Bmp := Pdf.RenderLoadedPageToBitmapCached(I, 48);
if Bmp <> nil then
try
ThumbList.AddThumbnail(I, Bmp);
finally
Bmp.Free;
end;
end;
// After editing a loaded page in place:
Pdf.InvalidateRenderedPageCache; // next render reflects the change
캐시 최대 수치를 늘리기 전에 메모리 리소스 점유 예산을 점검해 보는 것이 좋습니다. 300 DPI 규격의 US Letter 크기 페이지 하나는 2550×3300 픽셀 규모로 24비트 비트맵 기준 약 25 MB의 메모리를 점유합니다. 300 DPI 고해상도 이미지를 8장 캐싱해 두면 약 200 MB의 메모리를 사용하게 됩니다. 반면 저해상도 썸네일의 경우 동일한 8개 항목의 점유량이 1메가바이트 미만에 불과합니다. 따라서 실무에서 주로 사용하는 목표 해상도 범위에 맞춰 RenderCacheCapacity 한도를 지정하고, 로드된 원본 문서 정보를 중간에 가공 및 편집한 후에는 InvalidateRenderedPageCache를 호출해 기존 캐시를 명시적으로 비워 주십시오. 캐시는 오직 페이지 인덱스와 DPI 정보만을 키값으로 삼아 판단하기 때문에 백그라운드 원본 콘텐츠가 수정된 상황을 스스로 감지하지 못합니다. 새로운 문서 파일을 다시 로드하면 캐시는 자동으로 리셋됩니다
페이지 캐시 하단에서는 또 다른 이미지 캐시가 이중으로 작동합니다. 디코딩이 완료된 이미지 XObject 자원들은 ImageCacheMaxBytes(기본값 32 MB) 용량 한도로 관리되며 마찬가지로 최근 사용량 기준(LRU) 알고리즘에 따라 초과분이 삭제됩니다. 모든 페이지에 반복 출현하는 회사 로고나 배경 양식 이미지를 매 페이지마다 새로 파싱하지 않고 문서당 최초 1회만 디코딩해 재활용하므로, 공통 이미지가 포함된 다량의 페이지 렌더링 처리 속도가 대폭 증가하며 다중 페이지 TIFF 파일 내보내기 성능 역시 크게 향상됩니다. InvalidateRenderedPageCache 함수를 실행하면 이 이미지 캐시 역시 함께 초기화됩니다
아직 완벽한 드로잉을 지원하지 않는 제한 영역
본 렌더링 라이브러리는 일반적인 사무용 비즈니스 PDF 규격을 타겟으로 설계되었으므로, 구조적 렌더링 지원 한계를 사전에 숙지해 둘 필요가 있습니다. CalRGB, Lab 및 ICC 기반 색상 공간 정보는 색상 프로파일 엔진을 직접 구동하지 않고 대략적인 대체 색상으로 변환 처리됩니다. 기본적인 디바이스 색상 공간, 인덱스 팔레트 및 샘플링된 Type 0 함수 색상 룩업(Color LUT) 등은 정상 지원하지만, 정교한 ICC 렌더링 의도를 요구하는 전문 인쇄용 인쇄 데이터의 색감은 완벽히 일치하지 않을 수 있습니다. 단순 투명도 처리를 넘어서는 그라데이션 패턴(sh) 및 특수 혼합 모드(blend mode)는 드로잉 처리 범위를 벗어나며, 무한 루프 에러를 방지하기 위해 Form XObject의 재귀 호출 깊이도 필터 제한되어 있습니다. 인보이스, 보고서, 계약서, 서식 파일처럼 텍스트, 선 경로, 이미지 기반의 일반 페이지는 완벽한 화질을 보증하지만, 그라데이션과 투명 레이어가 가득한 고난도 디자인 증명 파일의 비비드 색상은 최종 인쇄 인쇄 결과용이 아닌 화면 미리보기용 수준으로 접근해 대처하는 것이 안전합니다
실무 요약: 구축 중인 처리 시스템이 HotPDF를 사용해 문서를 작성하거나 일반적인 비즈니스용 문서를 로드해 소비하는 형태라면, RenderLoadedPageToBitmap은 내장된 글꼴 글자 모양 벡터, 정확한 CID 진행 폭, 그리고 정확한 페이지 치수를 그대로 보존하여 완벽한 화질로 이미지 렌더링을 완수합니다. 앞선 한계 사양들은 일반적인 비즈니스 문서에서는 출현 빈도가 극히 낮은 매우 독특한 그래픽 규격 영역에만 국한되는 사항들입니다
RenderLoadedPageToBitmap과 그 캐시 래핑 기능 및 내장 글자 모양 벡터 드로잉 라이브러리는 모두 Delphi 및 C++Builder용 HotPDF Component에 포함되어 배포됩니다. 외부 DLL 없이 Delphi만으로 구성된 VCL 라이브러리로, PDF 생성, 편집, 텍스트 추출 및 화면 이미지 렌더링에 이르는 포괄적인 기능들을 단 하나의 단일 패키지로 제공합니다