기술 문서

Delphi에서 PDF/A 디바이스 색, OutputIntent, 투명성 검증

veraPDF는 RGB를 전혀 그리지 않는 파일에 ISO 19005-1 6.2.3.3을 꽂고, 맨몸 re f를 보정되지 않은 것으로 부르고, 똑같은 페이지 1이 통과하는데 페이지 2를 실패시킵니다. PDF/A는 그 규칙들을 각 페이지가 그리는 것 기준으로 판정합니다. 그래서 Delphi용 PDFium Component PDF/A 검증기는 색과 투명성 판정에 나서기 전에 모든 페이지를 폼과 패턴, 글리프, 어노테이션까지 추적합니다

6.2.3.3과 6.2.4.3이 실제로 요구하는 것

ISO 19005-1 6.2.3.3은 세 개의 독립 규칙을 한 문단에 담습니다. 부합하는 파일은 DeviceRGB나 DeviceCMYK를 쓸 수 있지만 둘을 함께 쓰지 못하고, 보정되지 않은 색상 공간을 하나라도 쓰면 파일이 PDF/A-1 OutputIntent를 담아야 하며, DeviceRGB는 프로파일이 RGB인 인텐트와 함께일 때만, DeviceCMYK는 CMYK인 인텐트와 함께일 때만 허용됩니다. DeviceGray가 그 목록에 없는 이유는 조항이 이어서 어느 인텐트 아래서든 회색을 변환해 쓸 수 있다고 설명하기 때문입니다. 인텐트 자체는 선택입니다. 6.2.2는 파일이 인텐트를 지정해도 된다고 하며, /S /GTS_PDFA1과 /DestOutputProfile의 유효한 ICC 프로파일 스트림을 갖춘 OutputIntents 항목만 인텐트로 셉니다. 그러니 모든 파일에 인텐트를 요구하는 검사기는 디바이스 색을 전혀 그리지 않는 부합 문서들을 거부합니다. Part 1은 DefaultRGB나 DefaultCMYK를 언급하지 않지만, 그것들을 거쳐 재사상된 색은 CIE 기반 공간(ISO 32000-1 §8.6.5.6)에서 렌더링되어 6.2.3.1의 디바이스 독립성 요구를 충족하고, 6.2.3.3의 veraPDF 테스트 스위트는 그것을 보정된 것으로 다루며, PDFium Component도 조항을 같게 읽습니다. 혼합 금지는 별개로 서 있습니다. RGB와 CMYK를 둘 다 그리는 PDF/A-1 파일은 Default 항목이 둘 다를 보정해도 실패합니다. ISO 19005-2 6.2.4.3은 그 금지를 내려놓고 각 공간을 제 조건대로 보정하는데, 아래 표의 오른쪽 열이 보여 주듯, PDFium Component는 파트마다 검사를 한 번씩 돌리고 혼합 점검은 PDF/A-1 선언에만 적용합니다

그려진 디바이스 공간PDF/A-1 (ISO 19005-1 6.2.3.3)PDF/A-2 이후 (ISO 19005-2 6.2.4.3)
DeviceRGB범위 안의 DefaultRGB 또는 RGB 인텐트. DeviceCMYK와 함께는 안 됩니다범위 안의 DefaultRGB, 또는 RGB OutputIntent
DeviceCMYK범위 안의 DefaultCMYK 또는 CMYK 인텐트. DeviceRGB와 함께는 안 됩니다범위 안의 DefaultCMYK, 또는 CMYK OutputIntent
DeviceGray범위 안의 DefaultGray, 또는 임의의 PDF/A-1 OutputIntent범위 안의 DefaultGray, 또는 임의의 PDF/A OutputIntent

무엇이 색상 공간 사용으로 셈되는가?

색상 공간을 쓴다는 것은 리더가 렌더링할 패스 위에서 그것으로 그린다는 뜻입니다. 선언만으로는 부족합니다. veraPDF 스위트는 6.2.3.3 통과 파일로 이 점을 보여 줍니다. 이름 붙은 Form XObject가 K와 k로 CMYK를 설정하고 페이지의 리소스 사전에 앉아 있지만 페이지 콘텐츠에서 결코 참조되지 않으며, 파일의 OutputIntent는 RGB입니다. 디바이스 색 이름의 파일 전체 검색은 그 파일을 실패로 몰고, CMYK 인텐트 아래 DeviceRGB만 그리는 파일은 놓칩니다. 이름 둘이 충돌할 일이 없으니까요. PDFium Component는 대신 그리기 그래프를 순회하는데, 바이트 수준 PDF/A 프리플라이트 스캐너 위에 세워져 있습니다. 각 페이지에서 이 순회가 세는 색은:

  • 페이지 콘텐츠 스트림과 그것들이 Do로 부르는 모든 Form XObject, 중첩된 폼까지
  • scn이나 SCN으로 고른 패턴, 패턴의 자체 Resources로 읽습니다
  • Tf로 고른 Type 3 폰트의 CharProcs
  • 이미지 XObject와 인라인 이미지, 자기 사전이 이름 짓는 색상 공간 기준
  • 어노테이션 외형 스트림, 페이지 위에 덧그려집니다. 위젯의 /AP /N이 상태 사전이면 모든 상태가 셈에 듭니다. 필드를 뒤집으면 /AS가 고르지 않은 상태를 그리기 때문입니다

도달 가능성의 더 미묘한 절반은 콘텐츠가 결코 이름 대지 않는 색입니다. q 0 0 10 10 re f Q에는 색 연산자가 없습니다. 그래도 그립니다. 그래픽스 상태의 초기 색상 공간은 DeviceGray(ISO 32000-1 Table 52)이므로 채움은 DeviceGray 검정이고, PDF/A OutputIntent나 DefaultGray가 없는 한 모든 파트에서 보정되지 않습니다. 그래서 검사는 아직 무언가 색을 골랐는지를 추적합니다. rg, k, g와 그 스트로크 형태들이 디바이스 공간을 고르고, cs와 CS는 이름 짓는 것을 고르며, 어떤 선택보다 먼저 도달한 채움, 스트로크, 텍스트 연산자는 DeviceGray를 기록합니다. /CS0 cs 1 0 0 /P0 scn은 이미 공간을 골랐으므로 그 scn은 회색이 아닙니다

PDFium Component가 Delphi에서 PDF/A 디바이스 색 판정 전에 순회하는 도달 가능한 그리기 경로: 폼, 패턴, Type 3 글리프, 이미지, 어노테이션 외형 스트림
색상 공간을 선언하는 것만으로는 부족합니다 — 순회는 각 페이지가 그리는 것을 셉니다. 맨몸 re f가 초기 상태에서 얻는 디바이스 회색까지

인라인 이미지는 자기 색상 공간과 날샘플을 콘텐츠 스트림 안으로 직접 끌어들이므로, 스캐너는 둘 다 신중히 읽어야 합니다. /CS는 축약형(G, RGB, CMYK, I)일 수도 있고 [/Indexed /DeviceRGB 255 13 0 R]로 해석되는 리소스 이름일 수도 있는데, 그 베이스가 셈에 듭니다. 그리고 ID와 EI 사이의 바이트는 임의의 이진 데이터이므로, EI는 공백 사이에서만 이미지를 끝냅니다. 그렇지 않으면 압축된 샘플 안의 rg가 유령 연산자가 됩니다

% 페이지 1: DefaultRGB가 범위 안, 그리고 아무도 부르지 않는 XObject
4 0 obj << /Type /Page /Parent 2 0 R /Contents 5 0 R
           /Resources << /ColorSpace << /DefaultRGB 9 0 R >>
                         /XObject << /Fm0 6 0 R >> >> >>
endobj
% 페이지 2: 같은 콘텐츠 스트림, ColorSpace 하위 사전 없음
7 0 obj << /Type /Page /Parent 2 0 R /Contents 5 0 R /Resources << >> >>
endobj
5 0 obj << /Length 46 >> stream
1 0 0 rg 72 72 200 100 re f
q 0 0 10 10 re f Q
endstream
endobj
6 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 50 50] /Length 24 >> stream
0 0 0 1 k 0 0 50 50 re f
endstream
endobj
9 0 obj [/ICCBased 10 0 R]
endobj

도입부의 각 증상이 이 조각에서 나옵니다. /Fm0은 Do를 만날 일이 없으므로 그 k는 무관합니다. 두 페이지의 맨몸 re f는 보정할 것이 아무것도 없는 DeviceGray입니다. 페이지 1의 rg는 페이지 1이 함께 그리는 리소스의 DefaultRGB가 덮고, 페이지 2는 같은 스트림을 그 맵이 없는 리소스로 돌리므로 같은 바이트가 거기서는 보정되지 않습니다. PDF/A-1b 선언에 기대되는 것: 페이지 2의 RGB와 두 페이지의 회색에 기인한 pvaiMissingOutputIntent와 pvaiMissingIccProfile입니다. 폼은 아무것도 더하지 않습니다. 불리면 그 CMYK가 PDF/A-1 혼합 금지를 그 위에 얹습니다

기본 색상 공간은 그리는 리소스 사전의 것입니다

Default 맵은 현재 리소스 사전의 ColorSpace 하위 사전에서 찾습니다(ISO 32000-1 §8.6.5.6). 그래서 리소스 자체만큼 지역적입니다. 문서에는 전역 기본이 없습니다. 이미지 XObject는 자체 Resources가 없으므로, 사전이 /ColorSpace /DeviceCMYK라고 말하는 이미지는 그것을 그리는 페이지나 폼의 DefaultCMYK가 보정하고, 두 곳에서 그려지는 같은 이미지는 한쪽에서만 보정될 수 있습니다. Form XObject와 타일링 패턴, Type 3 글리프 프로시저는 자체 Resources를 지니므로, 페이지의 DefaultCMYK는 그 안쪽에 닿지 않고 자기 사전의 맵은 닿습니다. PDFium Component는 맵을 같게 범위 묶습니다. 판정은 TPdfAValidationResult 레코드로 돌아옵니다. 탐지된 Conformance에 Issues 세트가 더해진 꼴입니다. 폴더 하나를 선별하기엔 충분합니다

uses
  System.SysUtils, System.Classes, System.TypInfo, FPdfPdfa;

procedure ReportColorFindings(const FileName: string; Log: TStrings);
const
  ColorRules: TPdfAValidationIssues = [pvaiMissingOutputIntent,
    pvaiMissingIccProfile, pvaiMixedDeviceColorSpaces, pvaiBlendSpaceUndefined];
var
  Source: TFileStream;
  Res: TPdfAValidationResult;
  Found: TPdfAValidationIssues;
  Issue: TPdfAValidationIssue;
begin
  Source := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
  try
    Res := ValidatePdfACompliance(Source);   // 위치 0부터 읽습니다
  finally
    Source.Free;
  end;
  Log.Add(ExtractFileName(FileName) + ': ' +
    GetEnumName(TypeInfo(TPdfAConformance), Ord(Res.Conformance)));
  Found := Res.Issues * ColorRules;
  for Issue in Found do
    case Issue of
      pvaiMissingOutputIntent:
        Log.Add('  reachable uncalibrated device color, no PDF/A OutputIntent');
      pvaiMissingIccProfile:
        Log.Add('  no OutputIntent with a DestOutputProfile ICC stream');
      pvaiMixedDeviceColorSpaces:
        Log.Add('  RGB/CMYK use disagrees with the intent, or PDF/A-1 paints both');
      pvaiBlendSpaceUndefined:
        Log.Add('  transparent page without a blending color space');
    end;
  if Found = [] then
    Log.Add('  device color and blending rules satisfied');
end;

pvaiMissingOutputIntent와 pvaiMissingIccProfile는 순회가 보정되지 않은 디바이스 색에 도달하고 PDF/A OutputIntent가 없을 때 함께 나타납니다. pvaiMissingIccProfile 홀로는 인텐트가 있으되 프로파일을 싣지 않은 뜻이며, 6.2.2는 그것을 PDF/A 인텐트로 받아들이지 않습니다. pvaiMixedDeviceColorSpaces는 PDF/A-1 혼합 금지와 컴포넌트 불일치를 모두 커버합니다. 네 컴포넌트 인텐트 아래의 보정되지 않은 DeviceRGB, 혹은 세 컴포넌트 인텐트 아래의 DeviceCMYK입니다. 세트는 페이지가 아니라 규칙의 이름을 말하므로, 길거나 병합된 문서에서는 어느 페이지가 Default 항목을 선언하고 어느 페이지가 안 하는지 비교하세요

Delphi에서 두 리소스 사전으로 그려지는 하나의 DeviceCMYK 이미지: 한 페이지에서는 DefaultCMYK가 보정하고 다른 페이지에서는 보정되지 않음, PDFium Component의 보고 기준
기본 색상 공간은 그리는 리소스 사전의 것입니다. 그래서 같은 이미지가 어떤 페이지가 그릴 때는 보정되고 폼이 그릴 때는 보정되지 않을 수 있습니다

투명한 페이지는 언제 자기 블렌딩 공간이 필요한가?

투명한 페이지가 자기 블렌딩 색상 공간을 필요로 하는 것은 문서에 PDF/A OutputIntent가 없을 때뿐입니다. ISO 19005-2 6.2.10(PDF/A-4에서는 6.2.9)이 인텐트를 ISO 32000-1 §11.3.4가 말하는 기본 블렌딩 색상 공간으로 만듭니다. 인텐트가 없으면 투명성을 담은 모든 페이지가 속성 사전(ISO 32000-1 Table 147)에 CS를 넣은 Group을 싣아야 합니다. 그 CS도 6.2.4의 검사를 받으므로, sRGB 인텐트 아래의 /DeviceCMYK 페이지 그룹은 없는 것처럼 보고되고, PDFium Component는 둘 다에 pvaiBlendSpaceUndefined를 듭니다. CalRGB나 ICCBased 그룹 공간에는 그런 의존이 없습니다. PDF/A-1은 이 질문에 닿지 않습니다. ISO 19005-1 6.4가 투명성을 아예 배제하기 때문입니다

어려운 부분은 투명성을 포함이라는 구절입니다. ISO 19005-2의 부속서 A는 규범적이고 페이지 바깥쪽부터 검사합니다. /SMask 키나 /ca 값의 파일 전체 셈은 다른 질문에 답합니다. 바이트 검색은 다른 곳의 투명성 구문과도 부딪힙니다. 금지된 전환 액션인 /S /Trans는 모든 /S /Transparency 그룹의 접두어이고, /Screen은 금지된 어노테이션 서브타입이자 표준 블렌드 모드이므로, 이름은 자기 키와 짝을 이루기 전까지는 아무 뜻이 없습니다. 부속서 A를 따라, PDFium Component는 이들 가운데 하나라도 페이지에서 도달하면 그 페이지를 투명한 것으로 다룹니다:

  • 콘텐츠가 gs로 고르고 소프트 마스크 사전을 갖거나 1 미만의 ca나 CA를 갖거나 Normal 이외의 블렌드 모드를 갖는 ExtGState. 선언만 되고 골라진 적 없는 것은 셈에 안 듭니다
  • Do로 불리는 Form XObject 중 /Group이 /S /Transparency를 갖거나 자기 콘텐츠가 이 조건 중 하나를 충족하는 것. 타일링 패턴은 폼처럼 판정합니다
  • SMask 스트림을 갖거나 0 위의 SMaskInData 값을 갖는 이미지 XObject
  • 페이지가 텍스트를 보여 주는 Type 3 폰트의 글리프 기술, 폼처럼 판정합니다
  • 어노테이션 외형 스트림, 모든 위젯 상태 포함, 그리고 어노테이션 사전 자체의 블렌드 모드

그룹은 디바이스 색 규칙으로도 되먹입니다. 이 지점은 코퍼스가 우리를 바로잡은 대목입니다. 6.2.4.3의 veraPDF 스위트는 어떤 OutputIntent도 없이 디바이스 RGB를 그리면서 통과가 기대되는 PDF/A-4 파일들을 갖고 있는데, 각 페이지의 /Group이 보정된 CS를 이름 대기 때문입니다. 우리는 고립된 그룹만 보정할 수 있다고 여겼습니다. 고립되지 않은 그룹은 배경 위로 합성되니까요. 그것은 페이지 그룹에서는 틀린 생각이었습니다. Table 147은 출력 매체에 곧장 놓이는 페이지는 I와 무관하게 사실상 고립된다고 적어 두어, 그 CS가 존중됩니다. Form XObject나 어노테이션 외형에서는 그 플래그가 실제로 판가름합니다. 스위트에는 /I true만 다른 통과 파일과 실패 파일이 있습니다. DeviceGray는 그룹에서 보정을 받지 않습니다. 6.2.4.3은 DefaultGray나 인텐트를 요구하고, CS가 디바이스 공간인 그룹은 제 몸이 보정을 필요로 하기 때문입니다. PDFium Component는 고로 페이지 그룹이 /I가 무엇을 말든 보정하게 두고, 폼이나 외형 그룹은 고립됐을 때만 보정하게 두며, 회색은 그룹 보정 밖에 두고, 그룹이 이름 대는 디바이스 공간은 여전히 검사합니다

Delphi용 PDF/A 행렬: 투명한 페이지가 자기 블렌딩 CS가 필요한 때와 PDFium Component가 페이지, 폼, 외형 그룹 보정을 판정하는 방식
출력 인텐트가 기본 블렌딩 공간입니다. 페이지 그룹은 아이솔레이션 플래그가 무엇을 말든 디바이스 색을 보정하고, 폼 그룹은 /I true가 필요합니다

모든 페이지의 그룹 대신 OutputIntent 하나

자기 코드가 보관 파일을 쓴다면 문서 수준 PDF/A OutputIntent에서 시작하세요. 카탈로그 항목 하나가 DeviceGray를 도처에서 보정하고 모든 페이지에서 맞는 디바이스 공간을 덮으며 모든 투명 페이지의 기본 블렌딩 공간이 됩니다. 페이지 그룹과 Default 항목은 각자 하나의 리소스 사전에만 범위가 묶이고, 나중의 병합이 그것들 없이 더하는 페이지가 실패하는 페이지입니다. PDF 2.0은 페이지 객체에 OutputIntents를 더했습니다(ISO 32000-2 §7.7.3.3과 §14.11.5). PDFium Component는 카탈로그에 없을 때 PDF/A-4에 한해 그 페이지 수준 인텐트를 받아들이고, PDF 1.4에서 1.7 위에 세워진 파트 1부터 3은 카탈로그만 봅니다. RGB 콘텐츠에는 SaveAsPdfAToStream이 PDF/A 라이터의 포함 sRGB ICC 프로파일 위에 세운 카탈로그 인텐트를 더하고, 출력 검증이 콘텐츠가 실제로 RGB뿐이었는지를 보여 줍니다

uses
  System.SysUtils, System.Classes, PDFium, FPdfPdfa;

function ArchiveWithSrgbIntent(const InFile, OutFile: string;
  out Remaining: TPdfAValidationIssues): Boolean;
var
  Pdf: TPdf;
  Opts: TPdfASaveOptions;
  Output: TMemoryStream;
  Check: TPdfAValidationResult;
begin
  Result := False;
  Remaining := [];
  Pdf := TPdf.Create(nil);
  Output := TMemoryStream.Create;
  try
    Pdf.FileName := InFile;
    Pdf.Active := True;
    if not Pdf.Active then
      Exit;                           // 파일을 열지 못했습니다
    Opts := TPdfASaveOptions.Default;
    Opts.Conformance := pac2b;        // PDF/A-1은 투명성을 아예 금합니다
    // IccProfileData는 비워 둡니다. 내장 sRGB IEC61966-2.1 프로파일을 씁니다
    if not Pdf.SaveAsPdfAToStream(Output, Opts) then
      Exit;
    Check := ValidatePdfACompliance(Output);
    Remaining := Check.Issues;
    // RGB뿐 콘텐츠에 기대되는 결과: pvaiMissingOutputIntent와
    // pvaiBlendSpaceUndefined는 사라집니다. pvaiMixedDeviceColorSpaces는 이제
    // 어떤 DefaultCMYK도 보정하지 않는 DeviceCMYK를 도달 가능한 경로가 그린다는 뜻입니다
    if Check.IsCompliant then
    begin
      Output.SaveToFile(OutFile);
      Result := True;
    end;
  finally
    Output.Free;
    Pdf.Free;
  end;
end;

sRGB 인텐트를 거쳐도 남는 pvaiMixedDeviceColorSpaces는 순회가 도달 가능한 경로의 DeviceCMYK를 보고하는 것이고, 그 문서는 PDFium Component가 PDF/A-2b로 받아들이기 전에 그것을 그리는 페이지들의 DefaultCMYK 맵이나 CMYK 출력 프로파일이 필요합니다