접근성: 태그 지정 기본 요소와 PDF/UA-2 구조 모델
한눈에 보기
섹션 제목: “한눈에 보기”NextPDF Core는 접근 가능한 문서 작성을 지원하는 기본 요소를 제공합니다. 논리 구조 트리, 표준 역할 매핑, 표시 콘텐츠 태그 지정, 그리고 ISO 14289-2(PDF/UA-2)와 ISO 32000-2 §14.7에 정의된 구조 트리 모델에 맞춘 BCP-47 언어 속성입니다. 생성된 파일의 적합성은 최종 문서, 작성자의 콘텐츠 선택, 외부 검사기에 의해 결정되는 속성이며, 라이브러리가 사용자를 대신하여 주장하는 보증이 아닙니다.
composer require nextpdf/core개념 개요
섹션 제목: “개념 개요”태그가 지정된 PDF는 루트에 단일 Document 구조 요소를 두는 논리 구조 트리를 포함합니다. 보조 기술은 이 트리를 읽고 시각적 레이아웃과 독립적인 의미 있는 읽기 순서를 도출합니다(ISO 32000-2 §14.7.2; ISO 14289-2 §8.2.5.2). NextPDF는 NextPDF\Accessibility 네임스페이스에서 서로 협력하는 세 가지 타입으로 이를 모델링합니다.
StructureTree는 계층 구조를 소유하고, 페이지별 표시 콘텐츠 식별자를 할당하며, 상위 및 하위 중첩을 추적합니다. ISO 32000-2 §14.7에 따라 구조 트리 루트, 구조 요소, 상위 트리, 역할 맵, 그리고 PDF 2.0 표준 구조 네임스페이스를 직렬화합니다. createRoot()는 필수인 단일 Document 요소를 언어 속성과 함께 초기화합니다. addElement()는 지정된 구조 유형의 하위 요소를 연결합니다. hasRoot()와 rootHasChildren()은 트리 존재 여부와 하위 항목 존재 여부를 보고합니다.
StructureElement는 하나의 구조 요소 딕셔너리에 대한 값 객체입니다. 표준 구조 유형(H1부터 H6까지, P, L, LI, Table, Figure, Link와 같은 표 368의 이름), 표시 콘텐츠 식별자 항목, 그리고 대체 텍스트, 대체용 텍스트, 제목, 언어에 대한 선택적 접근성 속성을 캡처합니다. 단일 요소는 여러 페이지에 걸쳐 있을 수 있으며, 페이지마다 하나의 식별자 항목을 누적하므로 kids 배열은 페이지 경계를 넘어 표시 콘텐츠를 참조합니다.
TaggedContentEmitter는 HTML 파이프라인을 구조 트리에 연결합니다. Document::enableTaggedPdf()가 활성화되면 HTML 렌더러는 이미터를 연결해 블록 수준 요소가 해당 구조 요소 노드와 대응되는 표시 콘텐츠 연산자를 생성하도록 합니다. HtmlToStructureMap은 HTML 태그에서 PDF 구조 유형으로 변환하는 테이블 기반 매핑을 제공합니다(ISO 14289-2 §8). 이미터는 HTML 머리글 및 바닥글 영역과 같은 장식용 러닝 콘텐츠를 아티팩트로 라우팅하여 읽기 순서에서 제외합니다.
언어 태그 지정은 Bcp47Validator(RFC 5646)가 검증합니다. 올바른 형식 여부에 대한 구문 검사와 레지스트리 기반 유효성 검사를 제공합니다. 엄격 모드(ConformancePolicy::strictUa2())는 잘못된 형식의 태그를 쓰기 시점에 자동으로 삭제하는 대신 API 경계에서 거부합니다. 이는 카탈로그 언어 항목이 특정 언어로 결정되어야 한다는 ISO 14289-2 §8.4.4 요구 사항과 일치합니다.
API 표면
섹션 제목: “API 표면”| 기호 | 종류 | 요약 |
|---|---|---|
Document::enableTaggedPdf(string $lang = 'en', ?ConformancePolicy $policy = null): static | 메서드 | 구조 트리와 HTML 브리지를 활성화하고, 마크 정보 및 카탈로그 언어 항목을 설정합니다. |
Document::setLanguage(string $lang): static | 메서드 | 문서 수준의 자연어를 설정합니다(BCP-47). |
Document::isTaggedPdfEnabled(): bool | 메서드 | 활성 적합성 모드가 구조적 태그 지정을 의무화하는지 반환합니다. |
StructureTree::createRoot(string $lang = 'en'): int | 메서드 | 필수인 단일 Document 루트 요소를 만듭니다. |
StructureTree::addElement(int $parentIndex, string $type, int $pageIndex, ...): int | 메서드 | 지정된 구조 유형의 하위 구조 요소를 연결합니다. |
StructureTree::hasRoot(): bool 및 rootHasChildren(): bool | 메서드 | 트리와 하위 항목의 존재 여부를 검사합니다. |
StructureElement | final class | 하나의 구조 요소에 대한 값 객체입니다(대체 텍스트, 대체용 텍스트, 제목, 언어, 식별자). |
RoleMap::standard(): array<string,string> | static | 표준 구조 유형 어휘(ISO 32000-2 표 368과 PDF 2.0 유형). |
Bcp47Validator::isWellFormed/isValid/validate/normalise | 메서드 | RFC 5646 구문 및 레지스트리 기반 언어 태그 검증을 수행합니다. |
AccessibilityAutoFixerRegistry | final class | 휴리스틱 구조 픽서를 위한 옵트인 PSR-11 스타일 레지스트리입니다. |
코드 샘플 — 빠른 시작
섹션 제목: “코드 샘플 — 빠른 시작”<?php
declare(strict_types=1);
use NextPDF\Core\Document;
$doc = Document::createStandalone();
// The BCP-47 tag drives the catalog language entry and the// structure-tree root language attribute.$doc->enableTaggedPdf(lang: 'en');$doc->setTitle('Tagged accessibility demo');$doc->addPage();
// Semantic HTML maps to structure elements: h1 to /H1, p to /P,// ul and li to /L plus /LI. Text runs are wrapped in// marked-content operators with stable identifiers.$doc->writeHtml('<h1>Document title</h1><p>Body paragraph.</p>');
$doc->save(__DIR__ . '/output/tagged.pdf');코드 샘플 — 프로덕션
섹션 제목: “코드 샘플 — 프로덕션”<?php
declare(strict_types=1);
use NextPDF\Conformance\ConformancePolicy;use NextPDF\Core\Document;use NextPDF\Exception\InvalidConfigException;use Psr\Log\LoggerInterface;
final class AccessibleReportWriter{ public function __construct(private readonly LoggerInterface $logger) { }
public function render(string $html, string $bcp47Lang, string $outPath): void { $doc = Document::createStandalone();
try { // strictUa2() rejects malformed BCP-47 tags at the API // boundary (ISO 14289-2 §8.4.4) instead of dropping silently. $doc->enableTaggedPdf($bcp47Lang, ConformancePolicy::strictUa2()); } catch (InvalidConfigException $e) { $this->logger->error('Rejected language tag for tagged PDF', [ 'lang' => $bcp47Lang, 'reason' => $e->getMessage(), ]);
throw $e; }
$doc->setTitle('Quarterly accessibility report') ->setLanguage($bcp47Lang) ->addPage();
$doc->writeHtml($html);
// The engine emits a Degraded / ComplianceRisk advisory directing // the caller to validate externally; surface it to operators // rather than treating tagged output as certified. foreach ($doc->getWarnings() as $warning) { $this->logger->warning('Tagged-PDF advisory', [ 'code' => $warning->code->value, 'message' => $warning->message, ]); }
$doc->save($outPath); }}엣지 케이스 및 주의 사항
섹션 제목: “엣지 케이스 및 주의 사항”- 호출 순서.
enableTaggedPdf()를writeHtml()전에 호출하세요. HTML 파이프라인은 파서 생성 시점에 적합성 모드를 확인하며, 이미 렌더링된 콘텐츠에 대해서는 이미터를 소급하여 연결하지 않습니다. - 빈 구조 트리.
enableTaggedPdf()가 적용되었지만 연결된 구조 하위 항목이 없는 문서는 메타데이터에서 PDF/UA-2를 광고하지 않습니다. 게시 게이트는rootHasChildren()이며,hasRoot()가 아닙니다. 빈 구조 트리로 PDF/UA-2를 주장하는 파일은 검증기가 거부하기 때문입니다(ISO 14289-2 §5;EmptyTaggedPdfDoesNotAdvertisePdfUa2Test에 의해 검증됨). - 적합성 모드 붕괴. 동일한 문서에서
enablePdfA()와enableTaggedPdf()를 호출하면 단일 값 적합성 판별자는 마지막 호출이 우선하는 방식으로 붕괴됩니다. 부작용(구조 트리, 마크 정보)은 누적된 상태로 유지되며, 붕괴를 관찰할 수 있도록CONFORMANCE_MODE_CLOBBERED경고가 발생합니다. - 자동 픽서는 자동이 아닙니다. 기본 제공 픽서(
EmptyTagStripper,LegacyLangNormaliser,RootLangFallback)는NextPDF\Accessibility\AutoFixer\*아래에 제공되지만 자동으로 등록되지는 않습니다. 소비자는AccessibilityAutoFixerRegistry에 이를 명시적으로 등록해야 합니다.
알려진 제한 사항
섹션 제목: “알려진 제한 사항”NextPDF는 PDF/UA-2 구조 트리 모델과 일치하는 구조를 내보내지만, 추론할 수 없는 의미 정보를 자동으로 작성하지는 않습니다. 다음 항목은 작성자가 제공하는 마크업 또는 속성이 필요하며 자동으로 생성되지 않습니다.
- 이미지 및 기타 비텍스트 콘텐츠에 대한 대체 텍스트;
- HTML 마크업이 표현하는 범위를 넘어서는 표 머리글 범위와 머리글-셀 연결;
- 표시되는 링크 텍스트가 자체적으로 설명되지 않는 경우의 링크 목적 텍스트;
- 목록 마크업 없이 시각적으로만 목록처럼 배치된 콘텐츠에 대한 목록 의미;
- 소스 순서가 의도된 읽기 순서와 다를 때 수정된 읽기 순서;
- 모호한 콘텐츠가 장식적인지 의미가 있는지에 대한 분류.
이 라이브러리는 엔드 투 엔드 PDF/UA-2 검증을 수행하지 않습니다. 런타임 자체가 Degraded / ComplianceRisk 권고(PDFUA2_FOUNDATIONAL)를 내보내어, 프로덕션 승인을 위해 외부 검사기로 출력을 검증하도록 호출자에게 안내합니다. PDF/UA 검사기(예: veraPDF)로 검증하세요. NextPDF는 사용자를 대신하여 적합성을 주장하지 않습니다. 최종 문서의 적합성은 API 호출이 아니라 작성자의 선택과 검증기에 따라 결정됩니다.
구조 트리 구성은 구조 요소 수에 선형으로 비례합니다. 식별자 할당은 표시 콘텐츠 시퀀스마다 상각된 상수 시간입니다. 직렬화는 요소 집합을 한 번 선형으로 순회합니다. HTML 기반 태그 지정의 주요 비용은 태그 발생이 아니라 HTML 파이프라인 자체입니다. performance_budget에 선언된 레시피별 상한(벽시계 시간 1500 ms, 피크 64 MB)은 일반적인 다중 페이지 의미 문서에 적용됩니다. 대용량 문서는 페이지 수가 아니라 요소 수에 따라 선형적으로 확장됩니다.
보안 참고 사항
섹션 제목: “보안 참고 사항”언어 태그와 접근성 속성은 PDF 이름 및 문자열 객체로 유입됩니다. NextPDF는 PdfStringEscaper를 통해 이를 이스케이프하므로, 잘못된 형식이거나 악의적인 언어 태그, 대체 텍스트, 대체용 텍스트, 제목 값이 PDF 객체 컨텍스트를 벗어날 수 없습니다. 엄격 모드는 추가로 등록되지 않은 BCP-47 태그를 API 경계에서 거부하여, 라이터에 도달하기 전에 입력 표면을 좁힙니다. 접근성 속성은 작성자가 제공하는 자유 텍스트를 포함할 수 있습니다. 이를 신뢰할 수 없는 출력으로 취급하고, 다른 문서 콘텐츠에 적용하는 것과 동일한 검토를 적용하세요. 프로필 검사기 동작에 대해서는 Conformance 모듈을 참조하세요.
적합성
섹션 제목: “적합성”이 페이지는 라이브러리 동작을 절 식별자에 매핑합니다. 사용자의 출력이 적합하다고 주장하지 않습니다. 인용된 절은 직접 인용이 아니라 의역입니다. 절 수준 표와 명시적인 비적용 범위에 대해서는 PDF/UA-2 사양 매핑을 참조하세요. 인용 청크 해시는 docs/public/modules/core/_normative-evidence-a11y.md에 기록됩니다.