현재 번역은 완벽하지 않습니다. 한국어로 문서 번역에 동참해주세요.
작성자
APNG 명세의 작성자는 다음과 같습니다:
- Stuart Parmenter <[email protected]>
- Vladimir Vukicevic <[email protected]>
- Andrew Smith <[email protected]>
개요
APNG는 움직이는 이미지에 대한 지원을 추가한 이식가능한 네트워크 그래픽 (PNG) 포맷의 확장입니다. 이는 전통적으로 GIF 포맷을 사용했던 간단한 움직이는 이미지를 대체하기 위한 것이며 24비트 이미지와 8비트 투명도 지원을 추가하고 있습니다. APNG는 MNG에 대한 보다 간단한 대안으로서 인터넷 상에서 움직이는 이미지의 가장 일반적인 사용에 적합한 명세를 제공하고 있습니다.
APNG는 PNG와 후위 호환이 가능(backwards-compatible)합니다. 즉, 모든 PNG 디코더는 APNG 특정 청크를 무시하고 단일 이미지를 표시할 수 있어야 합니다.
용어
기본 이미지(default image)는 표준 'IDAT' 청크가 기술하는 이미지로서 APNG를 지원하지 않는 디코더가 표시하는 이미지입니다.
캔버스(canvas)는 프레임이 표시되는 출력 장치의 영역입니다. 디코더가 꼭 출력 버퍼의 내용을 이용할 수 있는 것은 아닙니다. PNG 명세에 따르면 선택할 만한 바탕이 없는 경우 'bKGD' 청크가 존재하면 이를 캔버스를 채우는데 사용하게 됩니다.
출력 버퍼(output buffer)는 PNG 'IHDR' 청크의 너비와 높이 매개 변수로 지정된 치수를 가진 픽셀 배열입니다. 개념적으로 각 프레임은 캔버스에서 조합되기 전에 출력 버퍼에서 구성됩니다. 디코더는 출력 버퍼의 내용을 이용할 수 있습니다. 출력 버퍼의 모퉁이는 캔버스의 모퉁이에 대응됩니다.
완전 투명 흑색(Fully transparent black)은 적색, 녹색, 청색, 투명 요소가 모두 0으로 설정된 것을 의미합니다.
청크를 기술할 때, unsigned int
는 0부터 (2^31)-1 범위로 제한된 네트워크 바이트 순서를 따르는 32비트 부호없는 정수입니다. unsigned short
는 0부터 (2^16)-1 범위의 네트워크 바이트 순서를 따르는 16비트 부호없는 정수입니다. byte
는 0부터 (2^8)-1 범위의 8비트 부호없는 정수입니다.
오류 처리
APNG는 전체 이미지를 읽기 전에 점증적인 프레임 표시가 가능하도록 설계되었습니다. 그러므로 애니메이션이 일정 부분 진행될 때까지 오류가 발견되지 않을 수도 있습니다. 오류가 발생하는 경우, 디코더는 그 후의 모든 프레임을 버리고 애니메이션을 멈추고 기본 이미지를 표시하는 것으로 돌아가야 합니다. 디코더가 애니매이션을 시작하기 전에 오류를 발견하면 기본 이미지를 표시해야 합니다. 적합한 경우에는 오류 메시지를 사용자에게 표시할 수도 있습니다.
구조
APNG 스트림은 PNG 명세에 정의된 일반적인 PNG 스트림으로서 애니메이션을 기술하고 부가적인 프레임 자료를 제공하는 세 개의 추가 청크 형식을 포함합니다.
APNG로 인식되려면 'acTL' 청크가 'IDAT' 청크보다 먼저 스트림에 나타나야 합니다. 'acTL' 구조는 아래에서 설명하고 있습니다.
개념적으로 각 재연의 처음에 출력 버퍼는 'IHDR' 청크의 너비와 높이 치수를 따르는 완전 투명 흑색 직사각형으로 완전하게 초기화되어야 합니다.
'IDAT' 이전에 단일 'fcTL' 청크가 있으면 기본 이미지는 애니메이션의 첫 번째 프레임으로 포함됩니다. 그렇지 않으면, 기본 이미지는 애니메이션의 일부가 아닙니다.
그 후 프레임은 순서 번호가 앞에 나오는 것을 제외하면 'IDAT' 청크와 같은 구조를 가진 'fdAT' 청크에 인코드됩니다. 배치와 렌더링에 관한 각 프레임에 대한 정보는 'fcTL' 청크에 저장됩니다. 'fdAT'와 'fcTL' 청크의 전체 레이아웃은 아래에서 설명하고 있습니다.
전체 애니메이션의 경계는 기본 이미지가 애니메이션의 일부인지와 상관없이 PNG 'IHDR' 청크의 너비와 높이 매개 변수에 따라 지정됩니다. 나중 프레임에 추가 공간이 필요하면 기본 이미지에는 완전 투명 흑색 픽셀을 덧대야 합니다.
각 프레임은 각 재연에 대해 동일하므로 애플리케이션이 프레임을 캐시하는 것은 안전합니다.
청크 순서 번호
'fcTL'과 'fdAT' 청크는 4바이트 순서 번호를 가지고 있습니다. 두 청크 형식은 순서를 공유합니다. 이 번호의 목적은 APNG의 순서 오류를 감지(하고 선택에 따라 수정)하는 것입니다. PNG 명세는 부수적인 청크에 순서의 제약을 부여하지 않기 때문입니다.
첫 번째 'fcTL' 청크는 순서 번호 0을 꼭 포함하고 나머지 'fcTL'과 'fdAT' 청크의 순서 번호는 공백이나 중복없이 순서대로 되어야 합니다.
아래 표는 하나 이상의 프레임과 하나 이상의 'fdAT' 청크를 포함한 이미지에 대한 순서 번호 사용을 보여줍니다.
기본 이미지가 첫 번째 프레임인 경우:
순서 번호 | 청크 |
---|---|
(없음) | 'acTL' |
0 | 'fcTL' (첫 번째 프레임) |
(없음) | 'IDAT' (첫 번째 프레임 -- 기본 이미지로 사용) |
1 | 'fcTL' (두 번째 프레임) |
2 | 'fdAT' (두 번째 프레임을 위한 첫 번째 'fDAT') |
3 | 'fdAT' (두 번째 프레임을 위한 두 번째 'fDAT') |
... | ... |
기본 이미지가 애니메이션의 일부분이 아닌 경우:
순서 번호 | 청크 |
---|---|
(없음) | 'acTL' |
(없음) | 'IDAT' (기본 이미지) |
0 | 'fcTL' (첫 번째 프레임) |
1 | 첫 번째 프레임을 위한 첫 번째 'fdAT' |
2 | 첫 번째 프레임을 위한 두 번째 'fDAT' |
... | ... |
디코더는 순서가 잘못된 APNG 청크를 오류로 처리해야 합니다. APNG를 인식하는 PNG 편집기는 순서 번호를 이용하여 올바른 순서로 복구해야 합니다.
'acTL': 애니메이션 제어(Animation Control) 청크
'acTL' 청크는 PNG 명세에 정의된 부수적인 청크입니다. 이는 올바른 PNG 스트림에서 첫 번째 'IDAT' 청크 앞에 나와야 합니다.
'acTL' 청크는 다음과 같은 필드를 포함합니다.
바이트 오프셋 | 필드 이름 | 필드 형식 | 설명 |
---|---|---|---|
0 | num_frames |
unsigned int |
APNG의 프레임 수. |
4 | num_plays |
unsigned int |
APNG 반복 횟수. 0은 무한 반복을 가리킴. |
num_frames
은 애니메이션의 전체 프레임 수를 가리킵니다. 이 값은 'fcTL' 청크의 개수와 같아야 합니다. 0은 올바른 값이 아닙니다. 1은 단일 프레임 APNG에 대해 올바른 값입니다. 이 값이 실제 프레임의 개수와 다른 경우, 이는 오류로 처리해야 합니다.
num_plays
은 애니메이션을 재생하는 횟수를 가리킵니다. 이 값이 0이면 애니메이션을 계속 재생해야 합니다. 0이 아니면 애니메애션은 마지막 재생의 최종 프레임에서 멈춰야 합니다.
'fcTL': 프레임 제어(Frame Control) 청크
'fcTL' 청크는 PNG 명세에 정의된 부수적인 청크입니다. 이는 'IDAT' 청크의 앞에 나오거나 적용되는 프레임의 'fdAT' 청크 앞에 나와야 합니다. 구체적으로 이야기하면,
- 기본 이미지의 경우, 'fcTL' 청크가 있으면 첫 번째 'IDAT' 청크 앞에 나와야 합니다. 'acTL' 청크에 대한 상대적인 위치는 명시하지 않습니다.
- 기본 이미지를 제외한 첫 번째 프레임의 경우 (이는 첫 번째 또는 두 번째 프레임이 됩니다), 'fcTL' 청크는 모든 'IDAT' 청크의 뒤에 그리고 해당 프레임의 'fdAT' 청크 앞에 나와야 합니다.
- 그 후 모든 프레임의 경우, 프레임 N의 'fcTL' 청크는 프레임 N-1의 'fdAT' 청크 뒤에 그리고 프레임 N의 'fdAT' 청크 앞에 나와야 합니다.
- 다른 부수적인 청크는 'fdAT' 청크 사이를 포함하여 APNG 청크 사이에 나올 수 있습니다.
각 프레임에 대하여 정확하게 하나의 'fcTL' 청크가 필요합니다.
바이트 오프셋 | 필드 이름 | 필드 형식 | 설명 |
---|---|---|---|
0 | sequence_number |
unsigned int |
0부터 시작하는 애니메이션 청크의 순서 번호. |
4 | width |
unsigned int |
따르는 프레임의 너비. |
8 | height |
unsigned int |
따르는 프레임의 높이. |
12 | x_offset |
unsigned int |
따르는 프레임을 그릴 X 위치. |
16 | y_offset |
unsigned int |
따르는 프레임을 그릴 Y 위치. |
20 | delay_num |
unsigned short |
프레임 지연 분수 분자. |
22 | delay_den |
unsigned short |
프레임 지연 분수 분모. |
24 | dispose_op |
byte |
현재 프레임을 렌더링한 후 실행할 프레임 영역 처리의 종류. |
25 | blend_op |
byte |
현재 프레임에 대한 프레임 영역 렌더링의 종류. |
프레임은 x_offset
, y_offset
, width
, height
로 정의되는 영역에 그려야 합니다. 오프셋은 0 또는 0보다 크고 치수는 양수이며 영역은 기본 이미지를 벗어나면 안됩니다.
프레임 영역에 대한 제약은 다음과 같습니다.
x_offset
>= 0y_offset
>= 0width
> 0height
> 0x_offset
+width
<= 'IHDR' widthy_offset
+height
<= 'IHDR' height
delay_num
과 delay_den
매개 변수는 함께 현재 프레임을 표시할 시간(초)을 의미하는 분수를 지정합니다. 분모가 0이면 분모를 100인 것으로 간주합니다. (즉, delay_num
은 1/100초 단위로 시간을 지정하게 됩니다). 만약 분자 값이 0이면 뷰어가 적당한 최소값을 지정할 수도 있겠지만 디코더는 다음 프레임을 가능한 빨리 그려야 합니다.
애니메이션을 디코더 구현의 성능과 상관없이 동일한 속도로 실행하려면 프레임 타이밍은 각 프레임의 디코딩과 표시에 필요한 시간과 무관해야 합니다.
dispose_op
는 지연의 마지막에 (다음 프레임을 그리기 전에) 출력 버퍼를 어떻게 바꾸어야 하는지 지정합니다.
\dispose_op
의 올바른 값은 다음과 같습니다.
값 | 상수 | 설명 |
---|---|---|
0 | APNG_DISPOSE_OP_NONE |
다음 프레임을 그리기 전에 현재 프레임을 처리하지 않습니다. 출력 버퍼의 내용은 그대로 남아 있습니다. |
1 | APNG_DISPOSE_OP_BACKGROUND |
다음 프레임을 그리기 전에 프레임의 출력 버퍼 영역을 완전 투명 흑색으로 지웁니다. |
2 | APNG_DISPOSE_OP_PREVIOUS |
다음 프레임을 그리기 전에 프레임의 출력 버퍼 영역을 이전 내용으로 되돌립니다. |
만약 첫 번째 'fcTL' 청크가 dispose_op
값으로 APNG_DISPOSE_OP_PREVIOUS
를 사용하면 이는 APNG_DISPOSE_OP_BACKGROUND
로 처리해야 합니다.
blend_op<code>는 프레임이 현재의 출력 버퍼 내용에 중첩되어야 하는지, 아니면 출력 버퍼의 영역을 완전히 바꿀 것인지 지정합니다.
<code>blend_op의 올바른 값은 다음과 같습니다.
값 | 상수 | 설명 |
---|---|---|
0 | APNG_BLEND_OP_SOURCE |
투명도를 포함한 프레임의 모든 색상 요소가 프레임의 출력 버퍼 영역의 현재 내용을 덮어씁니다. |
1 | APNG_BLEND_OP_OVER |
프레임이 투명도에 따라 Extensions to the PNG Specification, Version 1.2.0의 Alpha Channel Processing 섹션에서 설명한 간단한 OVER 연산을 이용하여 출력 버퍼에 중첩됩니다. 참고로 예제 코드의 두 번째 변종이 적용 가능합니다. |
첫 번째 프레임에 대하여 두 가지 중첩 모드는 각 재생의 시작에 출력 버퍼를 지우기 때문에 기능적으로 동일합니다.
기본 이미지에 대응하는 'fcTL' 청크가 있을 때 이는 다음과 같은 제약이 있습니다.
x_offset
과y_offset
필드는 0이 되어야 합니다.width
와height
필드는 'IHDR' 청크의 해당 필드와 같아야 합니다.
앞서 언급했듯이 출력 버퍼는 각 재생의 시작에 완전 투명 흑색으로 완전히 초기화되어야 합니다. 이는 각 애니메이션 재생이 같도록 하기 위한 것입니다. 디코더는 결과가 같다고 보장되면 명시적인 지우기 단계를 피할 수 있습니다. 예를 들어, 기본 이미지가 애니메이션에 포함되어 있고 blend_op
값으로 APNG_BLEND_OP_SOURCE
를 사용하는 경우에는 전체 출력 버퍼를 덮어쓰게 되므로 지우기가 필요하지 않습니다.
'fdAT': 프레임 데이터(Frame Data) 청크
'fdAT' 청크는 'IDAT' 청크와 같은 목적을 가지고 있습니다. 이는 순서 번호가 앞에 나오는 것을 제외하면 'IDAT' 청크와 같은 구조를 가지고 있습니다.
각 프레임에 대하여 적어도 하나의 'fdAT' 청크가 필요합니다. 그리고 압축된 데이터 스트림은 한 프레임 내의 모든 'fdAT' 청크의 데이터 필드의 내용을 연결한 것입니다. 압축을 해제하면 데이터 스트림은 PNG 이지미의 완전한 픽셀 데이터입니다. 이는 모든 'IDAT' 청크의 압축 해제된 데이터와 마찬가지로 각 주사선의 처음에 필터 바이트를 포함합니다. 이는 기본 이미지와 같은 비트 수, 색상 종류, 압축 방법, 필터 방법, 인터레이스 방법, 팔레트를 사용합니다.
바이트 오프셋 | 필드 이름 | 필드 형식 | 설명 |
---|---|---|---|
0 | sequence_number |
unsigned int |
0부터 시작하는 애니메이션 청크의 순서 번호. |
4 | frame_data |
X bytes |
현재 프레임의 프레임 데이터. |
각 프레임은 'fcTL' 청크에서 오는 너비와 높이를 제외하고 파일의 첫 번째 'IDAT' 이전의 중요한 혹은 부수적인 청크에 지정된 모든 속성을 물려받습니다.
PNG 'pHYs' 청크가 있으면 APNG 이미지와 그 이미지의 x_offset
과 y_offset
값은 주 이미지와 같은 방식으로 비례를 조절해야 합니다. 개념적으로 그러한 비례 조절은 출력 버퍼를 캔버스에 대응하는 동안에 일어납니다.
본 명세서의 수정 사항
From 0.1
- Renamed chunks to 'anIm' and 'frAm' to comply with chunk naming conventions in the PNG spec.
- Added a more detailed explanation of APNG structure in Section 2.
- Added information for png interaction with other chunks in section 3.2.
- Changed 'frAm' chunk offsets and delay into signed integers.
From 0.2
- Changed 'frAm' chunk to 'afRa' to avoid conflict with MNG 'FRAM' chunk.
- Changed format: instead of sequences of IHDR..IDAT..IEND, frames other than frame 0 are stored in 'afRa' chunks.
- Added
start_frame
to 'anIm' to indicate which frame the animation should start on.
- Removed
num_frames
from 'anIm' chunk
From 0.3
- Added 'aCTL', 'fdAT', 'fcTL' chunk descriptions as per the latest png-list discussion
- Added section 4, "Interactions with other PNG chunks"; described global and local palettes and transparency
- Changed 'oFFs' chunk section to refer to more general chunks
- Updated 'aDAT' description to indicate that all frames must either be in a single chunk, or that the first chunk must have empty data.
- Added notice that each frame's region (x,y,width,height) must lie completely within the parent PNG canvas
- Fixed
dispose_op
description (after, not before)
- Changed
dispose_op
torender_op
; added disposal description; addedBLEND
flag
- Changed
delay_time
to a delay numerator and denominator, for specifying delays that don't into integer numbers of milliseconds.
- Added note to clarify that palette animation is not supported.
- Removed
start_frame
from aCTL; require fcTL for frame 0; addedSKIP_FRAME
fCTL flag.
From 0.4
- Reintroduced
num_frames
into aCTL
- Moved
sequence_number
from aDAT into fCTL
- Changed contents of aDAT to fCTL+IDATs+fEND
- Added clarifications on what's allowed and what isn't
- Renamed aCTL to acTL, fCTL to fcTL, aDAT to fdAT and fEND to feND to comply with the PNG spec chunk naming requirements
From 0.5
- Added the IHDR and PLTE CRCs to the acTl chunk
- The acTL fcTL and adAT are now copy safe, renamed them to acTl, fcTl and adAt
From 0.6
- The fdAt chunk is no longer a container for other chunks, but rather a replacement for an IDAT chunk
- Removed the feND chunk
- Added a sequence number field to fdAt
- Reintroduced the
width
andheight
fields in fcTl
From 0.7
- Removed
hidden
flag, instead only the first frame can be hidden and it is signaled with a missing fcTl
- IDAT, fcTl and fdAt are no longer required to have no other chunks in between them
From 0.8
- Removed CRCs for IHDR and PLTE from acTl
- The acTL fcTL and adAT are now not copy safe, renamed them to acTL, fcTL and adAT
From 0.9
- Split
render_op
intodispose_op
andblend_op
From 0.10
- No changes
테스트 인코더와 예제 이미지
https://littlesvr.ca/apng/ 에 있는 APNG 구현 페이지에서 예제 이미지를 구할 수 있습니다.
(오픈 소스) 인코더는 Gecko 엔진의 1.9 알파 4 버전에서부터 구할 수 있습니다.
모질라 인코더를 이용하는 (오픈 소스) 애플리케이션은 다음 페이에서 구할 수 있습니다: https://littlesvr.ca/apng/apngedit.html