유용한 정보

PDF에 대하여

CyberI 2015. 11. 30. 09:07

최근 PDF문서를 생성하는 모듈을 개발하고 유지보수하는 작업이 업무의 큰 부분을 차지하게 되면서, PDF문서와 씨름하는 시간과 빈도가 많아졌다. 현재 webPonent Grid 제품도 기본 기능으로 PDF출력을 제공하고 있는데, 정작 PDF 문서 포맷이 어떤 역사를 가지고 있는지는 모르는게 많았다. 이에 따라 PDF의 배경에 대해 알아보게 되었고 그 내용을 이번 포스팅에서 공유해 보도록 하겠다.




PDF의 시작, The Camelot Project

PDF 문서포맷은 1991년 Adobe의 공동설립자인 John Warnock의 'The Camelot Project'로부터 시작되었다. 'The Camelot Project'에 대해 설명한 문서에서는 프로젝트의 목적을 당시 기업들이 직면한 서로 다른 시스템과 어플리케이션간의 커뮤니케이션에 대한 관심을 해결하기 위함이라고 설명하고 있다.(This project’s goal is to solve a fundamental problem that confronts today’s companies. The problem is concerned with our ability to communicate visual material between different computer applications and systems.)

당시 Adobe사는 Page Description Language인 PostScript를 통해 이 문제를 해결하려는 노력을 했다. 그 결과로 인쇄물과 화면상에서 범용적으로 문서를 표현하는 것에는 어느정도 성공을 거두었으나, (당시의 하드웨어 성능 상) 강력한 성능의 컴퓨터 혹은 프린터가 필요하다는 단점이 있었다. Camelot Project는 이러한 단점을 보완하고 PC에서도 호환이 되고 CGA, EGA, VGA 등의 고해상도의 이미지등을 지원하는 포맷을 만드는데 목표가 있었다. 즉, PDF는 그 당시에 존재하지 않았던 전자문서에 대한 범용적인 공유방법에 대한 해결방안을 제시하는 프로젝트로 시작되었다.

그렇게 시작된 프로젝트는 1992년 가을까지 개발되고, 1993년 Adobe사가 PDF 1.0과 Acrobat 1.0을 발표하면서 세상에 등장했다. 하지만 당시 Adobe Acrobat를 무료로 배포하지 않았고, PDF 초기버전은 당시 환경 상 너무 큰 파일 사이즈와 외부로 Hyperlink가 지원되지 않는 등 기능면에서 조금 부족함이 있었다. 또한 당시에는 Envoy, Common Ground Digital Paper, Farallon Replica등 유사한 파일 포맷에 대한 경쟁이 있었다. 이러한 이유로 발표 직후부터 폭발적으로 수용되지는 않았다. 하지만, 이후 Adobe사가 Acrobat Reader를 무료로 배포하기 시작하고 PDF포맷을 적극적으로 지원하기 시작하면서 PDF는 온라인상 인쇄용 문서의 실질적 산업표준(De facto standard)가 되었다.


PDF/X, PDF/E, PDF/A

PDF가 널리 보급되면서 ISO(International Organization for Standardization)이 PDF의 용도에 따라 정의하였다. 그것이 PDF/X, PDF/E, PDF/A이다. 간단하게 설명하면 PDF/X는 그래픽 콘텐트 교환에 적용되며, PDF/E 표준은 엔지니어링 문서의 상호 교환에 적용된다. 또한 PDF/A는 전자문서의 장기보관에 적용하기 위하여 PDF 1.4스펙을 기반으로 제정되었다.

PDF/A는 PDF 1.4 스펙을 기반으로 파일 첨부나 멀티미디어 파일 임베딩 등 장기보존 문서에 필요없는 기능들을 제거해서 제정한 표준이기 때문에 사실상 PDF 1.4의 subset으로 볼 수 있다. 다음은 PDF 1.4스펙과 비교하여 PDF/A에서 사용하지 않기로 권장하는 대표적인 항목들이다.

  • 암호화(encryption)
  • LZW 압축
  • 파일 첨부
  • 외부 리소스에 대한 참조
  • 투명 설정
  • 멀티미디어
  • 자바스크립트
즉 문서를 오래보관했을 때 시간이 지나면 변경되거나 소멸될 여지가 있는것들이다. 반대로 필수로 들어가야 할 항목들도 있다.
  • Font embedding
  • Device-independent color
  • XMP 메타데이터
등이 대표적인 항목들이다.

PDF의 국제 표준문서 지정

이후 2008년 7월, ISO에서는 PDF 1.7버전을 국제표준으로 지정했다(ISO 32000-1). 이 국제표준지정으로 인해 PDF파일 포맷은 더이상 Adobe의 소유가 아니고 ISO로 관리권을 넘기게 되어 이후 업데이트 및 개발버전들은 모두 ISO에서 관리하게 되었다.


PDF의 장점

이제는 완전히 보편화되어 있는 PDF문서의 대표적인 장점들은 다음과 같다.

  • 다양한 플랫폼, 디바이스, OS에서 동일한 문서 형식으로 보여짐
  • 전자 문서 교환을 위한 ISO표준 준서(De jure)
  • 전자 서명
  • 암호화
  • 폰트, 오디오, 이미지 등을 하나의 파일로 embedding가능 (외부 리소스 불필요)

이러한 장점들 때문에 20년동안 계속 발전해 오면서 국제 표준 문서포맷으로 자리 잡을 수 있었을 것이다.


PDF File Structure

현재에는 거의 모든 문서 툴들이 PDF를 지원하고 있다고 해도 과언이 아니다. 또한, Java, Python, Javascript와 같은 프로그래밍 언어를 통해서도 PDF문서를 생성할 수 있는 수많은 라이브러리들이 존재한다. 이러한 툴들은 모두 자신의 문서 포맷을 PDF만의 고유한 File Structure로 변환하여 생성할 것이다. PDF File Structure에 대해 자세히 알아보고 싶지만 내용이 너무 방대하기도 하고 이해하기도 오래걸리기 때문에 핵심적인 내용만 간략히 알아보고자 한다.
먼저, 기본적인 PDF 파일 구조를 도식화 하면 아래의 4개의 요소들로 이루어져 있다.

한 부분씩 나누어 설명해 보도록 하겠다.

  • Header
PDF file의 가장 첫번째 라인이다(PDF 파일은 그 구조상 line단위로 구분한다.). 이 부분에서는 PDF문서 버전에 대한 명세가 기록된다. 예를들어 PDF 1.7버전일 경우 header에는 '%PDF-1.7'이 기록될 것이다.

  • Body
Body 섹션은 실제 PDF문서를 표현하는 object(Ex: fonts, pages, sampled images, etc..)들이 순차적으로 표현된다. 1.5버전이후부터는 stream형태의 오브젝트도 포함이 가능해졌다. PDF에서 지원하는 기본적인 object 타입은 다음 8가지가 있다.
    1. Boolean values
    2. Integer and real numbers
    3. Strings
    4. Names
    5. Arrays
    6. Dictionaries
    7. Streams
    8. Null
Name object는 중복된 값을 가지지 않는 고유한 값을 가진 object이고, Dictionary object는 간단하게 설명해서 key, value 쌍으로 구성된 연계 테이블이다. Dictionary object의 key값은 반드시 name object이어야 한다.

body 섹션 안의 object들은 계층을 이루고 있다. 이 계층의 최상위 root는 catalog dictionary이다. 다음은 object 구조를 나타내는 도식이다.



  • Cross-reference table
PDF문서를 사용하다보면 문서의 항목을 클릭하면 바로 그 항목의 위치로 이동할 수 있다. Cross-reference table 섹션에는 바로 그러한 direct access에 관한 mapping table이 저장된다.
테이블은 하나이상의 cross-reference sections을 가지고 있는데, 기본적으로는 전체 테이블이 하나의 section만을 포함하고 있다가 file이 업데이트 될 때에 section이 추가된다. 각각의 cross-reference section은 'xref'라는 한 줄로 시작된다.
하나의 cross-reference section 에는 또 한개이상의 cross-reference subsection이 포함된다. cross-reference subsection는 다음과 같은 형태로 표현된다.

0 3
0000000003 65535 f
0000000018 00000 n
0000000084 00000 n

첫 번째 라인은 cross-reference subsection이 가지는 객체의 순서를 표현한다. 첫번째 숫자는 cross-reference subsection의 첫번째 항목에 부여된 숫자이고, 공백으로 구분된 후 두번째 숫자에서 한 subsection에 몇 개의 항목이 포함되어 있는지의 갯수를 나타낸다. 즉, 예시에 나타난 subsection은 0부터 시작해서 2까지 3개의 subsection 항목들이 포함되어 있다.
두번째 라인부터는 각각 행마다 subsection 항목들을 표현한다. 각각의 라인은 end-of-line marker와 공백을 포함하여 정확히 20 byte로 구성되어 있다. 항목들이 나타나는 형태를 문자로 표현하면

nnnnnnnnnn ggggg n eol
nnnnnnnnnn ggggg f eol

이런 모양이다. 이 때,
nnnnnnnnnn 은 10 바이트로 이루어진 byte offset이다. 필요에 따라 0이 앞자리에서 부터 padding으로 붙는다. 이 숫자는 file의 처음에서부터 그 항목의 object가 시작되는 위치까지의 byte크기를 의미한다.
ggggg 는 5 바이트의 생성번호(generation number)이다. 마찬가지로 필요에 따라 앞에서부터 0이 padding으로 붙을 수 있다. 처음에 이 숫자는 0으로 초기화되었다가 할당된 object가 삭제되면 1씩 증가한다. 그런식으로 65535까지 증가하면 그 cross-reference 항목은 더 이상 재사용되지 않는다.
공백으로 구분된 문자열 중 3번째 항목인 n 혹은 f는 cross-reference 항목의 상태를 나타낸다. n은 현재 항목이 상용되고 있음을 나타내고 f는 현재 항목이 비어있음을 나타낸다. 이 문자열이 f일 때 10 바이트 offset의 의미는 다음 비어있는 object까지의 숫자를 의미한다. 또 비어있는 항목끼리는 각각 다음 비어있는 항목을 가리키고있는 Linked-list를 형성하고 있다.
eol은 end-of-line이다. carriage return이나 line feed둘 중에 하나만 사용되면 앞에 공백이 사용되고, 둘 다 사용될때는 공백이 사용되지 않는다.

이런 방식으로 생성된 cross-reference section의 전체 모양은 다음과 같다
xref
0 3
0000000003 65535 f
0000000018 00000 n
0000000084 00000 n

문서가 업데이트 되어 테이블이 수정되었을 때는 다음과 같을 것이다.
xref
0 1
0000000003 65535 f
3 2
0000000018 00000 n
0000000084 00000 n

  • Trailer

Trailer는 PDF 파일 내에서 cross-reference table과 특정 object들을 빨리 찾을 수 있게 해준다. 이 부분을 찾을 때는 파일의 맨 끝에서부터 읽어한다. 파일의 가장 마지막 라인은 '%%EOF'로 끝나는데 그 두 줄 위에 startxref라는 키워드와 파일의 시작에서부터 마지막 cross-reference section의 xref키워드 까지의 byte수를 나타내는 offset이 존재한다.startxref 키워드 앞에는 trailer dictionary가 존재하는데, trailer 키워드로 시작하고 '<<'로 시작해서 '>>'로 끝나는 구문 안에 key value 형태로 값이 할당되어 있다. trailer dictionary의 주요 항목들은 다음과 같다.

Size : 파일 내 모든 cross-reference table 내의 총 항목(entry) 갯수 (필수)

Prev : 파일의 시작부터 이전 cross-reference section까지의 바이트 offset (파일이 하나이상의 cross-reference section을 가질 때만 표현됨)

Root : 해당 PDF문서의catalog dictionary 이다. (필수)

생성된 후 1번도 업데이트 되지 않은 파일의 trailer는 다음의 형태를 가지게 될 것이다.

trailer

<< /Size 22

    /Root 2 0 R

    /Info 1 0 R

    /ID [<81b14aafa313db63dbd6f981e49f94f4>

    <81b14aafa313db63dbd6f981e49f94f4>

   ]

>>

startxref

18799

%%EOF


PDF 파일이 업데이트 될 경우 전체 내용을 다시 쓰지는 않는다 그 대신 변화된 내용만 파일의 끝에 덧붙여지는 방식을 사용하고 있다. 즉 Body 가 추가됐을 때는 추가된 Body가 파일의 뒤에 붙고, 뒤이어 Cross-reference항목이 추가되고, Trailer까지 추가되는 방식이다. 그 결과를 그림으로 표현하면 다음과 같다.


이 때 cross-reference section은 내용이 바뀌거나 삭제된 object항목이 있을 경우만 추가된다. 추가된 Trailer는 그 이전 trailer의 모든 항목을 가지고 있되, 바로 전 Cross-reference section의 위치를 가지고있는 /Prev 항목이 포함된다. 각각의 trailer는 자신의 end-of-line(%%EOF)로 끝난다.




References

 - https://acrobat.adobe.com/kr/ko/products/about-adobe-pdf.html

 - The Camelot Project(http://blogs.adobe.com/acrobat/files/2013/09/Camelot.pdf)

 - https://ko.wikipedia.org/wiki/PDF#cite_ref-3

 - http://help.adobe.com/ko_KR/acrobat/pro/using/WSd7ad1123a4c5dffe-5183c8012b97790144-8000.html

 - http://pdfmania.blogspot.kr/2007/03/pdfa-part-2-pdf-vs-pdfa.html

 - http://www.test104.com/kr/tech/2511.html

 - http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/pdf_reference_1-7.pdf