Searchable OCR Text Layers

HotPDF는 애플리케이션이 공급한 OCR 엔진용으로 선택된 로드 페이지를 렌더링하고, 인식된 각 단어에 맞춰진 검색 가능한 보이지 않는 Unicode 텍스트를 원자적으로 추가할 수 있습니다

SearchableOCR 콘솔 demo는 바로 실행해 볼 수 있는 워크플로를 제공합니다. --create-sample로 세 페이지짜리 이미지 전용 샘플을 만들고, 내장 OCR, RapidOCR, Tesseract DLL/CLI 인식 중에 고르고, 페이지를 선택하고, 신뢰도와 리소스 한도를 설정한 뒤 변환 통계와 함께 검색 가능한 사본을 저장합니다

Engine integration

애플리케이션이 쓸 수 있는 어떤 동기 OCR provider로도 IHPDFOCREngine을 구현할 수 있습니다

엔진은 빌린 TBitmap, 요청 DPI, 정규화 페이지 회전, media box 좌표, 남은 단어/UTF-16 예산, 실효 취소 token을 THPDFOCRRequest로 받습니다

단어 박스와 선택적 baseline은 왼쪽 위 bitmap 픽셀 좌표를 쓰고, 엔진은 Recognize가 반환한 뒤 빌린 bitmap을 보유하거나 해제하면 안 됩니다

선택적 로컬 엔진

버전 2.754.0은 Windows에서 IHPDFOCREngine을 반환하는 명시적 Tesseract/RapidOCR 팩토리를 추가합니다. 엔진 없는 overload는 여전히 기존 내장 엔진을 고릅니다

선택한 엔진을 어댑터를 만들기 전에 로컬에 설치·준비한 뒤 그 어댑터를 ApplyLoadedOCRTextLayer의 엔진 overload로 전달하십시오. 실행 파일, Python 패키지, OCR 모델은 선택적 외부 의존성이며 HotPDF에 번들되지 않습니다

Tesseract

선택적 네이티브 Tesseract DLL 어댑터는 HPDFCreateTesseractDLLOCREngine과 THPDFTesseractOptions로 구성 가능한 페이지 분할과 engine mode, 다국어 인식, 네이티브 단어 baseline을 더합니다

function HPDFCreateTesseractOCREngine(const ExecutablePath,
  TessDataDirectory, Language: string;
  TimeoutMilliseconds: Cardinal = 60000): IHPDFOCREngine; overload;
function HPDFCreateTesseractOCREngine(const ExecutablePath,
  TessDataDirectory, Language: string;
  const Options: THPDFTesseractOptions): IHPDFOCREngine; overload;

선언은 HPDFTesseractRecognition에 있습니다. TSV 출력이 가능한 Tesseract 실행 파일과 요청 언어 모델(chi_sim용 chi_sim.traineddata 등)이 담긴 데이터 디렉터리를 준비하십시오

options overload는 명시적인 page segmentation, 인식 engine mode, 타임아웃, 입력 픽셀 한도를 갖춘 THPDFTesseractOptions.Default를 받습니다. 입력 레이아웃에 맞춰 tpsSingleLine, tpsSingleWord, tpsSparseText 중에서 고르면 되며 Tesseract OCR Adapters에 예제가 있습니다

이 예제는 실행 파일과 데이터가 표시된 경로에 이미 설치됐고 PDF가 로드된 THotPDF 인스턴스라고 가정합니다

uses SysUtils, HPDFDoc, HPDFTesseractRecognition;

procedure AddTesseractText(PDF: THotPDF);
var
  Engine: IHPDFOCREngine;
  Options: THPDFOCRTextLayerOptions;
  Info: THPDFOCRTextLayerInfo;
begin
  Engine := HPDFCreateTesseractOCREngine(
    'C:\OCR\Tesseract\tesseract.exe',
    'C:\OCR\Tesseract\tessdata', 'chi_sim', 60000);
  Options := THPDFOCRTextLayerOptions.Default;
  if not PDF.ApplyLoadedOCRTextLayer([0], Engine, Options, Info) then
    raise Exception.Create('OCR text layer was not added');
end;

RapidOCR

네이티브 RapidOCR DLL 어댑터는 HPDFCreateRapidOCRDLLOCREngine으로 지속적인 in-process CPU ONNX 모델로 메모리 스냅샷을 인식하며, Delphi, C++Builder, Windows FPC/Lazarus 빌드에서 선택적 angle classification과 협력적 취소를 제공합니다

RapidOCR 로컬 모델 어댑터는 Delphi, C++Builder, FPC/Lazarus 빌드에서 명시적인 ONNX 모델 경로, 선택적 angle classification, 로컬 문자 사전·폰트, CPU 스레드 한도, 입력 픽셀 예산용 THPDFRapidOCROptions overload도 제공합니다

function HPDFCreateRapidOCREngine(const PythonExecutable, BridgeScript,
  ModelDirectory: string; TimeoutMilliseconds: Cardinal = 60000): IHPDFOCREngine;

선언은 HPDFRapidOCRRecognition에 있습니다. rapidocr과 onnxruntime이 설치된 Python, 제공된 tools/OCR/rapidocr_tsv.py bridge, 이 세 로컬 모델을 준비하십시오

bridge는 RapidOCR 결과 컨테이너용 %WINDIR%\Fonts\arial.ttf도 요구하고, 자동 다운로드를 끄며, 설정된 실행 풀마다 ONNX 스레드 하나를 씁니다. 모델, 패키지, 로컬 폰트가 없으면 인식이 실패합니다

현재 bridge는 간체 중국어 모델 구성을 쓰고, 전각/반각 치환 없이 인식된 문점부호를 보존합니다

uses SysUtils, HPDFDoc, HPDFRapidOCRRecognition;

procedure AddRapidOCRText(PDF: THotPDF);
var
  Engine: IHPDFOCREngine;
  Options: THPDFOCRTextLayerOptions;
  Info: THPDFOCRTextLayerInfo;
begin
  Engine := HPDFCreateRapidOCREngine(
    'C:\OCR\Python\python.exe',
    'C:\HotPDF\tools\OCR\rapidocr_tsv.py',
    'C:\OCR\RapidOCR\models', 60000);
  Options := THPDFOCRTextLayerOptions.Default;
  if not PDF.ApplyLoadedOCRTextLayer([0], Engine, Options, Info) then
    raise Exception.Create('OCR text layer was not added');
end;

두 팩토리는 존재하는 실행 파일·데이터 경로를 검증하고 1~3,600,000밀리초(기본 60,000) 타임아웃을 받습니다. 잘못된 구성은 EArgumentException을 던집니다

공유 어댑터는 따옴표로 묶인 경로와 제한된 상속 handle로 숨은 로컬 프로세스를 띄우고, 25밀리초마다 취소·타임아웃·출력 크기를 폴링하며, 실패 시 임시 파일 정리 전에 프로세스를 종료합니다

TSV 출력은 64MiB, 진단 파일 출력은 1MiB로 제한되고 반환 진단은 4,096자로 잘립니다. 인식된 단어는 요청의 단어·UTF-16 예산과 유효 bitmap 바운드에도 맞아야 합니다

TSV 인식 출력은 유효한 UTF-8이어야 하고 인식된 단어 안에 NUL 바이트나 C0/C1 제어 문자가 있어서는 안 됩니다. 정상 단어 뒤에 malformed 출력이 이어지면 유효한 단어가 앞서 있더라도 전체 인식 요청이 실패합니다

이는 출력·요청 한도이지 외부 엔진 메모리 사용의 hard cap이 아닙니다. 취소와 엔진 실패는 부분 페이지를 공개하지 않고 text-layer 상태로 반환됩니다

인식 근거와 한계

로컬 RapidOCR 3.8.4 베이스라인은 다섯 고정 중국어 스캔 영역(300 DPI 선명 영역 2개, 150 DPI 저해상도 압박 영역 3개)에서 15회 반복 모두를 통과했고, 현재 참조 전사본 기준 문자 오류율 최대 5%, 삭제율 최대 2%로 평가됐습니다

모든 반복이 읽기 순서 검사, 총 5,190회 단어/문자 좌표 검사, 72 DPI 가시 픽셀 동등성을 통과했고, 두 선명 영역은 해당 참조 대비 문자 오류가 0이었습니다

두 차례의 AI 시각 리뷰가 중국어 텍스트와 숫자에는 일치하지만, 래스터의 일부 문점부호 code point는 여전히 모호하고 사람 판정이 남아 있습니다. 문점부호 차이도 여전히 오류로 치며, 이 결과는 corpus 근거이지 일반 정확도 보장이 아닙니다

지오메트리와 검색 텍스트

HotPDF는 렌더러 페이지 transform을 역산해 0/90/180/270도 회전 페이지에서도 단어 baseline이 정렬된 채 유지됩니다

승인된 각 단어는 텍스트 렌더링 모드 3 Tr, 맞춤 가로 텍스트 스케일, 회전 인식 텍스트 행렬로 기록되어 페이지 래스터는 그대로 두면서 선택 가능한 콘텐츠 순서를 유지합니다

공유 Type 0 Identity-H 폰트는 Unicode scalar에 상한 문서 로컬 CID를 부여하고, 보충 문자용 UTF-16 surrogate 대상을 포함한 완전한 ToUnicode 맵을 기록합니다

같은 baseline 위의 인접한 Latin·키릴 단어는 지오메트리가 단어 간격을 가리킬 때 명시적인 Unicode 공백을 받습니다. 인접한 CJK 단어는 공백을 끼워 넣지 않고 원본 텍스트를 유지합니다

스캔 PDF 처리

Demo/Delphi/SearchableOCR/SearchableOCR.dpr 콘솔 예제는 스캔된 PDF를 로드하고, 명시적인 로컬 언어 프로파일로 네이티브 RapidOCR을 실행하며, 대상이 되는 모든 페이지에 보이지 않는 Unicode 텍스트를 공개하고, viewer를 열지 않고 새 PDF를 저장합니다

SearchableOCR.exe scan.pdf searchable.pdf --dll C:\HotPDF\Lib\Native\RapidOCR\Win64\HotPDFRapidOCR.dll --models C:\HotPDF\Lib\Native\RapidOCR\Models --language ru --dpi 300

간체 중국어에는 --language ch, 번체 중국어에는 --language chinese_cht를 씁니다. DLL은 실행 파일 아키텍처와 맞아야 하고 선택한 로컬 모델 패키지가 설치돼 있어야 합니다

예제는 기존 출력 파일을 덮어쓰지 않으며, 마킹된 HotPDF OCR 레이어를 업데이트할 때는 --replace-ocr를 받습니다

Windows FPC JPEG 스캔 디코딩은 인식 전에 최종 bitmap 픽셀 형식으로 그려서 LCL 형식 변환이 디코딩된 이미지를 유지하게 합니다

기존 OCR 레이어 업데이트

THPDFOCRTextLayerOptions.ReplaceExistingOCRTextLayer를 True로 설정하면 인식된 페이지에서 이전에 생성된 마킹된 HotPDF OCR stream을 새 텍스트와 같은 트랜잭션으로 교체합니다

이 옵션은 마킹된 페이지에서만 SkipPagesWithText를 건너뛰고 저장 후 다시 로드해도 동작합니다. 교체된 페이지 수는 THPDFOCRTextLayerInfo.ReplacedPageCount가 보고합니다

인식 실패와 승인된 단어가 없는 페이지는 기존 text layer를 유지합니다. 서드파티 OCR과 이전 HotPDF 릴리스가 만든 레이어를 포함한 마킹되지 않은 stream은 보존됩니다

교체는 기존 OCR content stream의 연결을 끊을 뿐, 다른 곳에서 여전히 참조될 수 있는 폰트 리소스나 optional-content group은 제거하지 않습니다. 증분 저장 시 이전 revision의 대체된 객체가 남을 수 있습니다

기본값은 여전히 추출 가능한 텍스트가 있는 페이지를 모두 건너뛰는 것이며, 스캔 위의 페이지 번호나 헤더도 여기에 듭니다. SkipPagesWithText를 끄면 페이지 전체를 인식해 기존 네이티브 텍스트가 중복될 수 있으므로, 혼합 페이지는 애플리케이션이 처리를 선택해야 합니다

바운드, 취소, 원자성

THPDFOCRTextLayerOptions.Default는 300 DPI 인식을 켜고, 이미 텍스트를 노출하는 페이지는 건너뛰며, 페이지 수, 픽셀, 단어, UTF-16 unit, 생성 콘텐츠 바이트에 한도를 둡니다

HotPDF는 엔진 결과를 모두 검증하고 copy-on-write 그래프 트랜잭션 하나를 시작하기 전에 페이지 콘텐츠를 전부 만들므로, 엔진 실패, 잘못된 지오메트리, 예산 소진, 취소, 커밋 오류가 로드된 객체 그래프를 그대로 둡니다

빈 페이지 인덱스 배열은 로드된 모든 페이지를 선택하고, 중복 페이지 인덱스는 처음 본 순서로 한 번만 인식됩니다

MaxTotalWords는 나중에 버려지는 낮은 신뢰도·잘못된 단어를 포함해 받은 단어를 모두 세며, 페이지 요청마다 남은 허용량만 받습니다

단어나 UTF-16 예산이 소진되고 처리 대상 페이지가 더 남아 있으면, 그 페이지를 렌더링하거나 인식하기 전에 otlsBudgetExceeded를 반환하며 계획된 text layer를 하나도 공개하지 않습니다. 기존 텍스트 때문에 건너뛴 페이지는 남은 인식 예산을 요구하지 않습니다

optional-content 그룹화

모든 생성 텍스트를 각 페이지 Resources/Properties 딕셔너리를 통해 하나의 이름 있는 layer에 묶으려면 UseOptionalContentGroup을 설정합니다

이 옵션은 PDF 1.5를 요구하고 StrictVersionLock을 따릅니다. 기본은 최대 호환을 위해 보이지 않는 텍스트를 optional-content group 밖에 둡니다

Conformance note

생성된 검색 layer는 렌더링 모드 3이 glyph을 도색하지 않기 때문에 의도적으로 미내장 합성 폰트를 씁니다

이 API만으로 PDF/A 준수 OCR 출력이 만들어지지 않으므로, PDF/A 워크플로는 내장 폰트 text-layer 경로를 쓰고 공개 전에 요청된 conformance 검증을 돌려야 합니다

주요 API

Progressive 렌더링과 취소 · ExtractLoadedPageText Method