-
PDF 포맷 분석 정리PDF 2022. 6. 24. 17:33
PDF file format
빈 PDF 파일을 만드려면 두 개의 구조(structure)를 다뤄야 한다.
- File structure
- Document structure
‘파일 구조(file structure)’는 PDF 포맷을 파싱하는데 필요한 모든 데이터를 정의한다. 반면에 ‘문서 구조(document structure)’는 파일 본문(file body)의 내용을 정의한다.
PDF file structure
Overview of file structure
PDF는 4개의 섹션을 포함한다:
- Header: PDF 사양(PDF specification)의 버전을 정의
- Body: 실제 내용을 표시
- Cross-reference table: 다른 오브젝트에 빠르게 액세스하기 위한 PDF 뷰어용 테이블
- Trailer: PDF 파일의 기타 메타 정보를 정의
Figure1: The file structure of PDF file
Explaination of Sample PDF file
%PDF-1.7 1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj 2 0 obj << /Type /Pages /Kids [3 0 R] /Count 1 >> endobj 3 0 obj << /Type /Page /Parent 2 0 R /MediaBox [0 0 600 400] /Resources << >> >> endobj xref 0 4 00000000000 65535 f 00000000010 00000 n 00000000069 00000 n 00000000141 00000 n trailer << /Root 1 0 R /Size 4 >> startxref 249 %%EOF Object Syntax 1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj
위 그림은 하나의 오브젝트다.
- 1, 0 이름은 버전 번호이며, 일반적으로 사용되지 않는다.
- obj와 endobj는 오브젝트의 시작과 끝을 구분한다.
- << >>는 사전 오브젝트(dictionary object)를 정의한다.
syntax에 대한 자세한 내용은 Adobe PDF reference를 참조하면 된다.
주어진 예제의 오브젝트는 1, 2, 3, ...이며, 임의의 이름을 선택할 수 있다.
Header
%PDF-1.7 라인은 헤더이며, 이 파일이 PDF 1.7 사양을 사용하도록 정의한다.
Body
헤더 아래와 xref 라인의 위는 본문(body)이다. PDF를 올바르게 표시하려면, 본문은 문서 구조(documnet struct)로 정의된 구조를 가져야한다(이에 대한 내용은 이후에 다시 다룬다).
Cross-Reference Table
이 부분이 가장 어려운 부분이다. 잘못 설정될 경우, PDF 뷰어에서 오류가 발생한다.
상호 참조 테이블(cross-reference table)은 본문에 나타나는 모든 오브젝트에 빠르게 액세스하는데 사용된다. 따라서 모든 오브젝트에 상호 참조 항목을 제공해야 한다.
xref 0 4 00000000000 65535 f 00000000010 00000 n 00000000069 00000 n 00000000141 00000 n
이러한 상호 참조 테이블은 키워드 xref와 EOL로 시작한다.
그런 다음 시작 객체(starting object)를 나타내는 라인이 나온다: 여기서는 0이고, 4는 본문의 네개의 오브젝트와 상응하는 네 개의 순차적인 엔트리를 뜻한다.
하지만 바디에서는 1, 2, 3의 오브젝트만을 가졌다. 이는 0번째 오브젝트가 본문(Document Catalog와는 다름)의 루트이며, 이는 표시되지 않기 때문이다.
다음으로 여러 항목들이 나타나며, 각 엔트리의 포맷은 다음과 같다.
nnnnnnnnnn ggggg n eol
nnnnnnnnnn은 문서 시작 부분부터 시작하는 오브젝트의 10자리 바이트 오프셋이다.
ggggg는 5자리 세대 숫자이며, 현재 오브젝트가 어떤 세대인지 나타낸다. 오브젝트가 삭제된 다음 재사용 될 때마다 새로운 세대 번호가 부여된다.
엔트리 타입으로, n은 사용 중, f는 free(not used)를 나타낸다.
Unix EOL 포맷의 경우 <space><linefeed>, Windows EOL 포맷의 경우 <carriage return><linefeed>이다.
엔트리는 정확히 총 20바이트를 차지한다.
그래서 우리의 예제에서 엔트리는 다음과 같다.
00000000069 00000 n
이는 세 번째 엔트리인데, (오브젝트 0에서부터 시작하기 때문에)이는 다음의 오브젝트를 나타낸다:
2 0 obj << /Type /Pages /Kids [3 0 R] /Count 1 >> endobj
이 오브젝트의 오프셋은 69이며, 세대 관련 기능은 사용하지 않으며(00000), 이 엔트리는 사용중이다(n).
Trailer
트레일러 섹션은 PDF 문서의 전체 정보를 제공하지만, 이는 사전(dictionary)를 포함해야 하며, 사전은 적어도 두 개의 항목을 가져야 한다: /Root와 /Size
trailer << /Root 1 0 R /Size 4 >> startxref 249 %%EOF
/Root는 본문의 Catalog를 나타낸다. /Size는 파일의 상호 참조 테이블에 있는 총 항목의 수를 나타낸다.
startxref는 숫자가 다음 라인에 따라오며, 상호 참조 테이블의 시작 오프셋을 나타낸다. 즉, 키워드 xref의 오프셋을 뜻한다.
%EOF는 파일의 끝을 나타낸다.
트레일러 섹션의 주요 목적은 뷰어가 파일의 하단 부터 읽을 수 있게 하는 것이다. 그리고:
starxref 부분을 통해 상호 참조 테이블의 오프셋을 찾는다.
trailer 부분의 /Root를 통해 루트 오브젝트를 찾는다.
그런 다음 뷰어는 상호 참조 테이블을 사용하여 오프셋 0000000010의 루트 오브젝트(우리 예제의 1 0 R) 찾을 수 있다. 루트는 /Pages 2 0 R에 쓰여진 대로 오브젝트 (2 0 R)을 포함한다. 따라서 PDF 뷰어는 상호 참조 테이블을 통해 오프셋 0000000069을 찾을 수 있다. 이는 PDF 오브젝트 트리 전체가 파싱될 때까지 계속된다.
Document Structure
PDF 문서는 트리 계층 구조로 구성되어 있다. 트리의 루트를 Documnet Catalog라고 부르며, trailer의 /Root 엔트리에서 정의된다.
여기서는 빈 PDF 문서를 만드는데 도움이 되는 가장 간단한 사례들만 다룬다.
Figure2. PDF Documnet Structure
Documnet Catalog
1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj
[Must] specify the /Type to /Catalog.
[Must] specify the /Pages entry.
Pages
Pages 노드는 페이지 트리의 루트 노드이다. 다음은 페이지 트리 계층의 예시다.
1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj
1. [Must] specify the /Type to /Catalog.
2. [Must] specify the /Pages entry.
Pages
Pages node is the root node of a page tree. Below is an exmple of page tree hierarchy.2 0 obj << /Type /Pages /Kids [ 4 0 R 10 0 R 24 0 R] /Count 3 >> endobj 4 0 obj << /Type /Page ... Additional entries describing the attributes of this page ... >> endobj 10 0 obj << /Type /Page ... Additional entries describing the attributes of this page ... >> endobj 24 0 obj << /Type /Page ... Additional entries describing the attributes of this page ... >> endobj
/Type은 /Pages에 의해 설정되어야 한다.
/Parent는 루트 노드에서 제외하고 설정되어야 한다.
/Kids 배열은 하위 페이지를 지정하기 위해 설정되어야 한다.
/Count는 리프 노드(페이지 오브젝트)의 수를 지정하도록 설계되어야 한다.
Page Object
3 0 obj << /Type /Page /Parent 2 0 R /MediaBox [0 0 600 400] /Resources << >> >> endobj
/Type은 /Page에 의해 설정되어야 한다.
/Parent는 부모 오브젝트에 의해 설정되어야 한다.
/MediaBox는 미디어 내용을 저장하는 사각형이다.
/Resources에는 페이지가 요구하는 모든 자원(e.g. 폰트)이 포함된다.
■ pdf 파일 포맷 형태
○ header, body, xref, trailer로 구성
○ trailer가 없는 경우도 있음
편의상 header-trailer-xref-body순으로 설명
■ header
○ pdf 버전 표시
■ trailer
○ /Root : 문서의 시작 오브젝트 위치
○ startxref : 참조테이블 위치
<<
/Root 1 0 R : 문서는 1번 오브젝트에서 시작
/Size 10
>>
startref
1000 : 참조테이블 위치는 offset 1000
%EOF■ cross-reference table(xref)
○ 참조테이블로 각각의 오브젝트들의 offset을 기록
xref
0 10
0000000000 65535 f : 0번 오브젝트 없음
0000000010 00000 n : 1번 오브젝트는 Offset 10에 있음
0000000020 00000 n : 2번 오브젝트는 Offset 20에 있음
0000000030 00000 n : 3번 오브젝트는 Offset 30에 있음■ body
○ page, image, font, forms 등이 object로 되어있으며 트리구조를 이룸
○ 각각의 오브젝트는 << >>로 구분
1 0 obj : 오브젝트 1번
<<
/Type /Catalog /PageLayout /SinglePage : catalog 형태, single 페이지
/Pages 2 0 R : 내용은 오브젝트 2번 참조
/OpenAction 4 0 R : 실행시 오브젝트 4번 실행
>>
endobj : 오브젝트 끝2 0 obj
<<
/Length 0
/Filter /FlateDecode : 압축
>>
stream …….. endstream : 압축된 내용
endobjReferences