losLab PDF Library는 한 번의 호출로 이미 로드된 PDF의 누락된 글꼴 프로그램을 내장할 수 있습니다. EmbedMissingFonts는 문서의 모든 글꼴 사전을 순회하고, BaseFont 이름으로 일치하는 설치된 시스템 글꼴을 찾아 글꼴 프로그램을 파일에 다시 작성합니다. 글꼴 내장 문제로 PDF/A 검증에 실패한 서드파티 문서를 복구하는 개발 팀에게 이 기능은 프리플라이트(preflight) 오류 00030을 해결하는 확실한 해결책입니다
이러한 시나리오는 매우 흔하게 발생합니다. 아카이브 수집 파이프라인이 공급업체, 고객 또는 스캔 대행업체로부터 PDF를 전달받습니다. 이 문서들은 사내의 모든 PC에서 정상적으로 렌더링되지만, PDF/A 검증기는 파일당 한 번씩 동일한 경고를 반복하며 전체 배치를 거부합니다. 즉, 최소 하나 이상의 글꼴이 내장되지 않았다는 오류입니다. 업스트림의 누구도 파일을 다시 생성해주지 않으므로, 파이프라인에서 이를 직접 복구해야 합니다. 이 글에서는 이 복구 경로를 다룹니다. 이 글은 PDF/A 및 PDF/UA 위반 감지를 다루는 프리플라이트 문서의 동반 기사로, 이전 글이 어떤 문서가 손상되었는지 알려준다면 이번 글은 가장 빈번하게 발생하는 손상 원인을 해결하는 방법을 설명합니다
왜 PDF/A는 모든 글꼴이 내장되도록 요구할까요?
ISO 19005-1 §6.3.4는 표준 준수 문서에 사용된 모든 글꼴이 파일 내에 글꼴 프로그램을 포함해야 한다고 요구합니다. PDF/A의 핵심 약속은 재현성(reproducibility)이기 때문입니다. 즉, 현재 문서를 생성한 장치와 글꼴을 공유하지 않는 50년 후의 기기에서도 문서가 완전히 동일하게 렌더링되어야 합니다. 내장되지 않은 글꼴은 뷰어 시스템 어딘가에서 Arial을 찾아보라는 명령과 같으며, 표준 규격에서는 '뷰어 시스템 어딘가'라는 조건이 아카이브 보존성을 보장하지 않는다고 봅니다. 대체 글꼴이 어떤 글자 모양(glyph), 메트릭 및 범위를 가지고 있든 독자는 그대로 보게 되며, 이는 원래 작성자가 의도한 모습과 다를 수 있습니다
역사적 주범은 Standard 14 관례입니다. PDF 1.0은 모든 뷰어가 Helvetica, Times, Courier, Symbol, ZapfDingbats를 제공할 것을 보장했기 때문에, 생성기들은 글꼴을 내장하지 않고 이름으로만 참조하도록 설계되었으며, 지난 30년간의 툴들도 여전히 이 방식을 따르고 있습니다. losLab PDF Library는 이 요구사항을 매우 엄격하게 다룹니다. PDF/A 생성 모드에서 AddStandardFont는 의도적으로 아무 동작도 하지 않도록 설계되었습니다. 라이브러리는 Standard 14 글꼴 프로그램을 내장하고 있지 않으므로 가지고 있지 않은 것을 내장할 수 없고, 표준 준수를 선언한 문서에 내장되지 않은 참조를 쓰는 것을 거부합니다. 이 메서드는 글꼴을 선택하지 않고 0을 반환하므로, PDF/A 문서는 대신 글꼴이 내장된 AddTrueTypeFont를 사용해야 하며, PDF/A 모드가 활성화되어 있는 동안 Embed=0 요청은 내부적으로 Embed=1로 자동 승격됩니다. 이것이 작성(writer) 측의 원칙입니다. 더 어려운 문제는 읽기(reader) 측으로, 다른 사람이 이미 작성하여 사용자가 직접 만들지 않은 글꼴 사전으로 가득 찬 문서입니다
EmbedMissingFonts는 로드된 문서를 어떻게 복구하나요?
losLab PDF Library는 글꼴을 재구축하는 대신 기존 위치에서 직접 복구합니다. PDF 생성기가 내장되지 않은 TrueType 글꼴을 작성할 때 생성되는 FontDescriptor 사전은 FontName, FontBBox, Flags, Ascent, Descent, StemV 등을 이미 모두 포함하고 있어 구조적으로 완전합니다. 내장된 글꼴과 내장되지 않은 글꼴의 유일한 차이점은 실제 글꼴 프로그램을 담고 있는 /FontFile2 스트림 참조 항목의 누락 여부입니다. 따라서 EmbedMissingFonts는 글꼴 사전, 인코딩, 너비 배열(widths array) 또는 리소스 이름으로 글꼴을 참조하는 콘텐츠 스트림을 건드리지 않습니다. 시스템에서 일치하는 글꼴 프로그램을 읽어 새로운 스트림 객체로 압축한 다음, 이미 존재하는 FontDescriptor에 단 하나의 /FontFile2 참조(CIDFontType0 글꼴의 경우 /FontFile3 참조)를 추가할 뿐입니다. 문서 페이지가 가리키는 모든 요소가 원래 위치에 그대로 유지되므로, 사용자가 직접 제어하지 않는 파일에서도 안전하게 작업을 실행할 수 있습니다
지원 범위에는 실제 환경에서 접하게 되는 두 가지 글꼴 아키텍처인 단순 TrueType 글꼴과 한중일(CJK) 텍스트 및 최신 유니코드 출력을 위해 생성되는 복합 Type0/CID 글꼴이 모두 포함됩니다. 탐색 과정에서 페이지별 리소스 조사에 의존하는 대신 문서 개체 트리 전체의 모든 Font 사전을 명시적으로 열거하므로, 주석(annotation)에서 참조되거나 여러 페이지에서 공유되는 글꼴까지 모두 찾아낼 수 있습니다. API는 로드된 문서에 대해 단 한 번만 호출하면 됩니다
var
PDF: TPDFlib;
Repaired: Integer;
begin
PDF := TPDFlib.Create;
try
if PDF.LoadFromFile('supplier-invoice.pdf', '') <> 1 then
raise Exception.Create('Could not load PDF');
// Walks every Font dictionary; returns how many fonts
// gained a font program. Fonts whose program cannot be
// found on the system are skipped, not failed.
Repaired := PDF.EmbedMissingFonts;
Writeln(Format('%d font program(s) embedded', [Repaired]));
PDF.SaveToFile('supplier-invoice-repaired.pdf');
finally
PDF.Free;
end;
end;
단순히 문자열을 비교하는 것보다 이름 매칭이 훨씬 더 효과적으로 작동하는 이유를 설명하는 한 가지 중요한 세부 정보는 라이브러리가 조회를 수행하기 전에 BaseFont 이름을 정규화한다는 점입니다. 서브셋 접두사(여섯 개의 대문자와 더하기 기호로 구성된 ABCDEF+ 패턴)는 제거되고, ArialMT와 같은 PostScript 스타일 접미사는 Arial로 변환되며, TrueType 컬렉션(.ttc) 파일은 감지 및 압축 해제되어 .ttc 내부에 존재하는 글꼴 페이스도 올바르게 내장됩니다
프리플라이트 보고서로 복구 결과 검증하기
CreatePreflightReport는 검증 단계에 해당하며, 복구 프로세스는 닫힌 루프 형태를 띱니다. 즉, 파일 검증을 실패하게 만든 검사 항목을 그대로 사용해 복구 완료를 확인해야 합니다. 오류 코드 00030은 '최소 하나 이상의 글꼴이 내장되지 않았음(FontFile/FontFile2/FontFile3 누락)'이라는 PDF/A 정밀 감사 결과이며, 파일 전체를 대상으로 보고되므로 단 하나의 글꼴만 누락되어도 계속 오류로 남게 됩니다. 원본 파일에서 보고서를 실행하고, 복구 및 저장한 후, 출력 파일에 대해 다시 보고서를 실행해 보십시오
function HasFontEmbeddingViolation(PDF: TPDFlib;
const FileName: string): Boolean;
var
Report: string;
begin
// ComplianceTests = 1 selects the PDF/A checks
Report := PDF.CreatePreflightReport(FileName, '', 1, 0);
Result := Pos('00030', Report) > 0;
end;
파일 전체에 대한 결과 대신 개별 글꼴의 상태를 확인하려면, 복구된 문서를 다시 로드한 후 열거하면 됩니다. FindFonts에 이어 SelectFont와 GetFontIsEmbedded를 호출하면 각 글꼴의 내장 상태를 개별적으로 알려주며, 일괄 처리 작업 중에 어떤 파일의 어떤 글꼴 페이스를 복구하지 못했는지 정확히 기록할 때 유용하게 쓰입니다. 동일한 열거 패턴은 로드된 PDF에서 텍스트, 이미지 및 글꼴을 추출하는 방법을 다룬 기사에서도 등장하며, 해당 문서에서는 복구 대신 추출 작업을 위해 이 패턴을 활용합니다
글꼴이 시스템에 설치되어 있지 않으면 어떻게 되나요?
EmbedMissingFonts는 프로그램을 찾을 수 없는 글꼴은 모두 건너뛰고, 반환 값을 통해 이 사실을 보고합니다. 반환된 개수가 사용자가 파악한 내장되지 않은 글꼴 수보다 작다면, 그 차이만큼의 글꼴이 시스템에 부재하다는 의미입니다. 이는 예외적인 실패 모드로, 문서에 지정된 글꼴을 대체하기 위한 임의의 프로그램을 임의로 생성하여 내장하는 것보다 훨씬 안전합니다. 대체 글꼴 프로그램을 임의로 생성하면 원래의 렌더링 결과가 보존되지 않으며, 이는 아카이브 복구 시 절대로 일어나서는 안 되기 때문입니다. 이러한 상황을 위해 losLab PDF Library는 호출자가 제공한 .ttf 또는 .otf를 지정된 글꼴에 내장하는 EmbedFontProgramFromFile을 제공합니다. 이를 통해 파이프라인 프로세스에 예상되는 기업용 글꼴을 미리 포함해 두고 필요한 경우 이를 대체 글꼴로 사용하도록 구현할 수 있습니다
var
I, FontID: Integer;
begin
PDF.FindFonts;
for I := 1 to PDF.FontCount do
begin
FontID := PDF.GetFontID(I);
if (FontID > 0) and (PDF.SelectFont(FontID) = 1) then
if PDF.GetFontIsEmbedded = 0 then
// Try the installed system font first, then fall back
// to a font file shipped alongside the application
if PDF.EmbedFontProgram(PDF.FontName) = 0 then
PDF.EmbedFontProgramFromFile(PDF.FontName,
'fonts\CorporateSans.ttf');
end;
end;
두 가지 명확한 제한 사항이 있습니다. 첫째, 현재 구현에서는 Type1 글꼴을 복구하지 않습니다. 이 글꼴의 /FontFile 항목에는 명시적인 길이 키를 포함하는 3세그먼트 PFB 구조가 필요한데, 잘못된 형식의 스트림을 생성하기보다는 라이브러리가 복구를 아예 건너뛰도록 처리합니다. 최신 문서에서는 흔치 않지만 오래된 아카이브에서는 발견될 수 있습니다. 둘째, 글꼴을 내장하는 행위는 라이선스 동의가 필요한 작업입니다. TrueType 글꼴의 내장 권한은 해당 글꼴을 개발한 파운드리(foundry)에 있으며, 라이선스가 부여된 글꼴 프로그램을 삽입하여 사외로 나가는 문서를 복구할 때는 실제로 글꼴 라이선스 조건이 이를 허용하는지 확인해야 합니다. 라이브러리는 지시한 동작을 그대로 수행할 뿐이며, 라이선스 허용 여부는 컴파일러가 아닌 법무 부서에 문의해야 합니다
글꼴 내장은 필수 조건이지만 충분 조건은 아닙니다
글꼴을 복구하는 것은 오직 오류 00030만을 해결해 줍니다. 암호화, 누락된 XMP 메타데이터, OutputIntent가 없는 장치 의존적 색상 공간, 혹은 ToUnicode 맵 부재 등으로 인해 PDF/A 표준을 준수하지 못하는 문서는 글꼴을 내장한 후에도 여전히 검증에 실패합니다. 따라서 단독으로 처리하기보다 프리플라이트 기반 루프의 일환으로 이 복구 프로세스를 실행해야 합니다. 전체 보고서를 실행하고 지적된 문제를 수정하며 최종 검증 결과를 보고서로 다시 확인해 보십시오. 또한 파일 크기 문제도 고려해야 합니다. 한중일(CJK) 글꼴 프로그램은 파일 크기가 수 메가바이트에 달할 수 있어, 여러 개를 내장하면 원래 작았던 문서가 크게 부풀어 오를 수 있습니다. 이에 대한 대안은 PDF 파일 크기 최적화 및 글꼴 서브셋 분석에서 다루는 서브셋(subsetting) 기법으로, 내장된 글꼴 프로그램을 실제 문서 렌더링에 사용된 문자 모양으로만 제한하여 크기를 줄일 수 있습니다
새 문서의 품질 저하 방지하기
SetEmbedAllFonts는 동일한 기능의 예방 조치에 해당합니다. 즉, 작성 측의 가드를 통해 생성하는 코드에서 이 기사에서 복구하려는 부류의 결함이 있는 문서가 생성되는 것을 사전에 방지합니다. SetEmbedAllFonts(1)을 활성화하면 이후 Embed=0을 요청하는 모든 AddTrueTypeFont 호출이 글꼴 내장 참조로 승격되며, 이는 이미 PDF/A 모드에서 강제하는 모든 문서에 대한 보장을 동일하게 제공합니다. 이 설정은 로드된 파일 내의 기존 글꼴이 아니라 호출 이후 추가되는 글꼴에만 적용되므로 작업 영역이 명확히 나뉩니다. 직접 만드는 새 문서에는 SetEmbedAllFonts를 적용하고, 외부에서 유입되는 기존 문서에는 EmbedMissingFonts를 사용하여 대처합니다
PDF.NewDocument;
PDF.SetEmbedAllFonts(1);
// From here on, AddTrueTypeFont(Name, 0) behaves
// like AddTrueTypeFont(Name, 1): no non-embedded
// reference can reach the output file
작성자 측 가드와 '로드-복구-저장' 방식 모두 결과를 검증하는 프리플라이트 엔진과 더불어 Delphi, C# 및 VB.NET을 위한 losLab PDF Library의 일부로 포함되어 있습니다. 제품 페이지에서 개별 글꼴 내장 및 서브셋 호출을 포함한 완전한 글꼴 API 참조서를 확인하실 수 있습니다