PDF/A 검증
PDF/A(ISO 19005)는 전자 문서를 장기 보존하기 위한 국제 표준입니다. PDF Oxide는 주요 PDF/A 레벨을 모두 검증하며, 준수하지 않는 문서를 준수 상태로 변환할 수도 있습니다.
바인딩 지원 현황. PDF/A 검증은 Python(
doc.validate_pdf_a(level)), Rust(validate_pdf_a+PdfAValidator빌더), WASM(doc.validatePdfA(level)), Go(doc.ValidatePdfA(level))에서 사용할 수 있습니다. 공개된 C# 래퍼는 아직 제공되지 않습니다. Rust CLI(pdf-oxide validate --pdfa 2b doc.pdf)를 사용하거나 지원되는 바인딩 중 하나를 통해 호출하세요. PDF/A 변환(PdfAConverter)은 현재 Rust와 Python에서만 공개되어 있습니다.
지원 레벨
| 레벨 | 표준 | 구조 | Unicode | 투명도 | 임베디드 파일 |
|---|---|---|---|---|---|
| 1a | ISO 19005-1 | 필수 | 필수 | 불가 | 불가 |
| 1b | ISO 19005-1 | 불필요 | 불필요 | 불가 | 불가 |
| 2a | ISO 19005-2 | 필수 | 필수 | 가능 | 불가 |
| 2b | ISO 19005-2 | 불필요 | 불필요 | 가능 | 불가 |
| 2u | ISO 19005-2 | 불필요 | 필수 | 가능 | 불가 |
| 3a | ISO 19005-3 | 필수 | 필수 | 가능 | 가능 |
| 3b | ISO 19005-3 | 불필요 | 불필요 | 가능 | 가능 |
| 3u | ISO 19005-3 | 불필요 | 필수 | 가능 | 가능 |
레벨 “a”(접근성)는 태그가 지정된 구조 트리와 Unicode 문자 매핑을 요구합니다. 레벨 “b”(기본)는 시각적 재현성만 요구합니다. 레벨 “u”(Unicode)는 전체 구조 트리 없이 Unicode 텍스트 매핑을 요구합니다.
빠른 검증
한 번의 호출로 확인하려면 편의 함수를 사용하세요.
from pdf_oxide import PdfDocument
doc = PdfDocument("document.pdf")
result = doc.validate_pdf_a("2b")
print(f"Valid: {result.valid}")
print(f"Level: {result.level}")
for error in result.errors:
print(f" Error: {error}")
const doc = new WasmPdfDocument(bytes);
const result = doc.validatePdfA("2b");
console.log(`Valid: ${result.valid}`);
console.log(`Errors: ${result.errors.length}`);
doc.free();
use pdf_oxide::PdfDocument;
use pdf_oxide::compliance::{validate_pdf_a, PdfALevel};
let mut doc = PdfDocument::open("archive.pdf")?;
let result = validate_pdf_a(&mut doc, PdfALevel::A1b)?;
if result.has_errors() {
println!("Not PDF/A-1b compliant:");
for error in &result.errors {
println!(" [{}] {} (clause {})",
error.code, error.message,
error.clause.as_deref().unwrap_or("n/a"));
}
} else {
println!("Document is PDF/A-1b compliant");
}
package main
import (
"fmt"
"log"
pdfoxide "github.com/yfedoseev/pdf_oxide/go"
)
func main() {
doc, err := pdfoxide.Open("archive.pdf")
if err != nil { log.Fatal(err) }
defer doc.Close()
// Level encoding: 0 = 1b, 1 = 1a, 2 = 2b, 3 = 2a, 4 = 2u, 5 = 3b, 6 = 3a, 7 = 3u
result, err := doc.ValidatePdfA(0) // PDF/A-1b
if err != nil { log.Fatal(err) }
if result.Valid {
fmt.Println("Document is PDF/A-1b compliant")
} else {
fmt.Println("Not PDF/A-1b compliant:")
for _, e := range result.Errors {
fmt.Printf(" %s\n", e)
}
}
}
검증기 API
PdfAValidator는 세밀한 제어를 위한 빌더 패턴을 제공합니다.
use pdf_oxide::PdfDocument;
use pdf_oxide::compliance::{PdfAValidator, PdfALevel};
let mut doc = PdfDocument::open("report.pdf")?;
let result = PdfAValidator::new()
.stop_on_first_error(false)
.include_warnings(true)
.validate(&mut doc, PdfALevel::A2b)?;
println!("Errors: {}", result.errors.len());
println!("Warnings: {}", result.warnings.len());
개별 검사
전체 스위트 대신 개별 검증 범주를 실행합니다.
use pdf_oxide::PdfDocument;
use pdf_oxide::compliance::{PdfAValidator, PdfALevel};
let mut doc = PdfDocument::open("report.pdf")?;
let validator = PdfAValidator::new();
// Check only metadata
let result = validator.check_metadata(&mut doc, PdfALevel::A1b)?;
// Check only fonts
let result = validator.check_fonts(&mut doc, PdfALevel::A1b)?;
// Check only color spaces
let result = validator.check_colors(&mut doc, PdfALevel::A1b)?;
// Check only transparency
let result = validator.check_transparency(&mut doc, PdfALevel::A2b)?;
// Check only structure tags
let result = validator.check_structure(&mut doc, PdfALevel::A1a)?;
독립 실행형 검증기
최대한의 유연성을 위해 각 검증 범주는 독립 실행형 함수로도 제공됩니다.
use pdf_oxide::PdfDocument;
use pdf_oxide::compliance::validators::*;
use pdf_oxide::compliance::{PdfALevel, ValidationResult};
let mut doc = PdfDocument::open("document.pdf")?;
let mut result = ValidationResult::new(PdfALevel::A1b);
// Run each validator independently
validate_xmp_metadata(&mut doc, PdfALevel::A1b, &mut result)?;
validate_fonts(&mut doc, PdfALevel::A1b, &mut result)?;
validate_colors(&mut doc, PdfALevel::A1b, &mut result)?;
validate_encryption(&mut doc, PdfALevel::A1b, &mut result)?;
validate_transparency(&mut doc, PdfALevel::A1b, &mut result)?;
validate_structure(&mut doc, PdfALevel::A1b, &mut result)?;
validate_javascript(&mut doc, PdfALevel::A1b, &mut result)?;
validate_embedded_files(&mut doc, PdfALevel::A1b, &mut result)?;
validate_annotations(&mut doc, PdfALevel::A1b, &mut result)?;
println!("Total errors: {}", result.errors.len());
검증기 요약
| 함수 | 검사 내용 |
|---|---|
validate_xmp_metadata() |
XMP 스트림 존재 여부, pdfaid:part 및 pdfaid:conformance 항목 존재 여부, 메타데이터 일관성 |
validate_fonts() |
모든 글꼴 임베딩 여부, 글리프 폭 존재 여부, Unicode 매핑 사용 가능 여부(레벨 “a” 및 “u”용) |
validate_colors() |
output intent 없이 장치 종속 색상 연산자(rg, RG, k, K, g, G)를 사용하지 않음 |
validate_encryption() |
PDF/A 문서에서는 암호화가 허용되지 않음 |
validate_transparency() |
PDF/A-1에서는 투명도 불가, PDF/A-2 이상에서는 허용 |
validate_structure() |
유효한 역할 매핑을 갖춘 태그된 구조 트리 존재(레벨 “a”에서 필수) |
validate_javascript() |
JavaScript 동작이나 트리거가 존재하지 않음 |
validate_embedded_files() |
PDF/A-1 및 PDF/A-2에서는 허용되지 않음, PDF/A-3은 각 파일 사양에 AFRelationship 키 필요 |
validate_annotations() |
해당 ISO 19005 파트에 따라 주석 유형이 제한됨 |
ValidationResult
ValidationResult 구조체는 검증 실행의 전체 결과를 담고 있습니다.
pub struct ValidationResult {
pub level: PdfALevel,
pub errors: Vec<ComplianceError>,
pub warnings: Vec<ComplianceWarning>,
pub stats: ValidationStats,
}
| 필드 | 타입 | 설명 |
|---|---|---|
level |
PdfALevel |
대상 준수 레벨 |
errors |
Vec<ComplianceError> |
준수를 가로막는 차단성 위반 |
warnings |
Vec<ComplianceWarning> |
품질에 영향을 줄 수 있는 비차단성 문제 |
stats |
ValidationStats |
검사한 페이지, 글꼴, 객체의 수 |
ComplianceError
pub struct ComplianceError {
pub code: ErrorCode,
pub message: String,
pub location: Option<String>,
pub clause: Option<String>,
}
code 필드는 MissingXmpMetadata, FontNotEmbedded, DeviceDependentColor, EncryptionPresent, TransparencyNotAllowed, MissingStructureTree, JavaScriptPresent, InvalidEmbeddedFile와 같은 범주를 가진 ErrorCode 열거형을 사용합니다.
ComplianceWarning
pub struct ComplianceWarning {
pub code: WarningCode,
pub message: String,
pub location: Option<String>,
}
PDF/A 변환
준수하지 않는 문서를 PDF/A 준수 상태로 변환합니다.
use pdf_oxide::PdfDocument;
use pdf_oxide::compliance::{convert_to_pdf_a, PdfALevel};
let mut doc = PdfDocument::open("input.pdf")?;
let result = convert_to_pdf_a(&mut doc, PdfALevel::A1b)?;
println!("Conversion actions taken:");
for action in &result.actions {
println!(" - {}: {}", action.action_type, action.description);
}
if result.remaining_errors.is_empty() {
println!("Document is now PDF/A-1b compliant");
} else {
println!("{} issues could not be resolved automatically",
result.remaining_errors.len());
}
변환 구성
변환 과정을 세밀하게 조정합니다.
use pdf_oxide::PdfDocument;
use pdf_oxide::compliance::{PdfAConverter, PdfALevel, ConversionConfig};
let mut doc = PdfDocument::open("input.pdf")?;
let config = ConversionConfig::new()
.embed_fonts(true)
.remove_javascript(true)
.flatten_transparency(true)
.add_structure(true);
let result = PdfAConverter::new(PdfALevel::A2b)
.with_config(config)
.convert(&mut doc)?;
변환기는 다음 작업을 자동으로 수행합니다.
- XMP 메타데이터 주입 –
pdfaid:part및pdfaid:conformance항목을 추가합니다 - 글꼴 임베딩 – 참조되었지만 임베디드되지 않은 글꼴을 임베딩합니다
- JavaScript 제거 – JavaScript 동작과 트리거를 제거합니다
- 투명도 평탄화 – 투명 요소를 불투명하게 렌더링합니다(PDF/A-1 전용)
- ICC 프로파일 변환 – 장치 종속 색상을 ICC 기반 색 공간으로 변환합니다
- 구조 태깅 – 기본 구조 태그를 추가합니다(레벨 “a” 대상)
워크플로: 검증, 수정, 재검증
일반적인 보존 워크플로는 검증을 수행하고, 자동 변환을 시도한 뒤, 다시 검증합니다.
use pdf_oxide::PdfDocument;
use pdf_oxide::compliance::{validate_pdf_a, convert_to_pdf_a, PdfALevel};
let level = PdfALevel::A2b;
let mut doc = PdfDocument::open("input.pdf")?;
// Step 1: Initial validation
let result = validate_pdf_a(&mut doc, level)?;
if !result.has_errors() {
println!("Already compliant");
return Ok(());
}
println!("{} errors found, attempting conversion...", result.errors.len());
// Step 2: Automatic conversion
let conversion = convert_to_pdf_a(&mut doc, level)?;
println!("{} actions taken", conversion.actions.len());
// Step 3: Re-validate
let result = validate_pdf_a(&mut doc, level)?;
if result.has_errors() {
println!("{} errors remain after conversion:", result.errors.len());
for e in &result.errors {
println!(" {} -- {}", e.code, e.message);
}
} else {
println!("Document is now PDF/A-2b compliant");
}
PdfALevel 메서드
PdfALevel 열거형에는 레벨 기능을 조회하기 위한 도우미 메서드가 포함되어 있습니다.
| 메서드 | 반환값 | 설명 |
|---|---|---|
part() |
PdfAPart |
ISO 19005 파트(Part1, Part2, Part3) |
conformance() |
char |
적합성 문자(‘a’, ‘b’ 또는 ‘u’) |
requires_structure() |
bool |
태그된 구조 트리가 필수인지 여부 |
requires_unicode() |
bool |
Unicode 매핑이 필수인지 여부 |
allows_transparency() |
bool |
투명도 허용 여부 |
allows_jpeg2000() |
bool |
JPEG 2000 이미지 허용 여부 |
allows_embedded_files() |
bool |
파일 첨부 허용 여부 |
xmp_part() |
&str |
XMP pdfaid:part 값 |
xmp_conformance() |
&str |
XMP pdfaid:conformance 값 |
from_xmp(part, conformance) |
Option<Self> |
XMP 메타데이터 값에서 레벨 파싱 |
다음 단계
- PDF/UA 접근성 – 접근성 검증
- PDF/X 인쇄 제작 – 인쇄 제작 검증
- API 레퍼런스 – 전체 Rust API