Test files for APNG can be found at the following locations:
This page hosts a formal specification of PNG (Portable Network Graphics) file using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.
-- This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
--
-- This file is compatible with Lua 5.3
local class = require("class")
require("kaitaistruct")
local enum = require("enum")
local str_decode = require("string_decode")
local utils = require("utils")
local stringstream = require("string_stream")
--
-- Test files for APNG can be found at the following locations:
--
-- * <https://philip.html5.org/tests/apng/tests.html>
-- * <http://littlesvr.ca/apng/>
Png = class.class(KaitaiStruct)
Png.BlendOpValues = enum.Enum {
source = 0,
over = 1,
}
Png.ColorType = enum.Enum {
greyscale = 0,
truecolor = 2,
indexed = 3,
greyscale_alpha = 4,
truecolor_alpha = 6,
}
Png.CompressionMethods = enum.Enum {
zlib = 0,
}
Png.DisposeOpValues = enum.Enum {
none = 0,
background = 1,
previous = 2,
}
Png.PhysUnit = enum.Enum {
unknown = 0,
meter = 1,
}
function Png:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root or self
self:_read()
end
function Png:_read()
self.magic = self._io:read_bytes(8)
if not(self.magic == "\137\080\078\071\013\010\026\010") then
error("not equal, expected " .. "\137\080\078\071\013\010\026\010" .. ", but got " .. self.magic)
end
self.ihdr_len = self._io:read_u4be()
if not(self.ihdr_len == 13) then
error("not equal, expected " .. 13 .. ", but got " .. self.ihdr_len)
end
self.ihdr_type = self._io:read_bytes(4)
if not(self.ihdr_type == "\073\072\068\082") then
error("not equal, expected " .. "\073\072\068\082" .. ", but got " .. self.ihdr_type)
end
self.ihdr = Png.IhdrChunk(self._io, self, self._root)
self.ihdr_crc = self._io:read_bytes(4)
self.chunks = {}
local i = 0
while true do
local _ = Png.Chunk(self._io, self, self._root)
self.chunks[i + 1] = _
if ((_.type == "IEND") or (self._io:is_eof())) then
break
end
i = i + 1
end
end
--
-- See also: Source (https://stackoverflow.com/questions/4242402/the-fireworks-png-format-any-insight-any-libs/51683285#51683285)
Png.AdobeFireworksChunk = class.class(KaitaiStruct)
function Png.AdobeFireworksChunk:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root
self:_read()
end
function Png.AdobeFireworksChunk:_read()
self._raw_preview_data = self._io:read_bytes_full()
self.preview_data = KaitaiStream.process_zlib(self._raw_preview_data)
end
--
-- See also: Source (https://wiki.mozilla.org/APNG_Specification#.60acTL.60:_The_Animation_Control_Chunk)
Png.AnimationControlChunk = class.class(KaitaiStruct)
function Png.AnimationControlChunk:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root
self:_read()
end
function Png.AnimationControlChunk:_read()
self.num_frames = self._io:read_u4be()
self.num_plays = self._io:read_u4be()
end
--
-- Number of frames, must be equal to the number of `frame_control_chunk`s.
--
-- Number of times to loop, 0 indicates infinite looping.
--
-- See also: Source (https://github.com/skeeto/scratch/tree/58470254f4a95cdf7a53888e405c851c21eb2cae/pngattach)
-- See also: A new protocol and tool for PNG file attachments (https://nullprogram.com/blog/2021/12/31/)
Png.AtchChunk = class.class(KaitaiStruct)
Png.AtchChunk.CompressionAttachMethods = enum.Enum {
none = 0,
zlib = 1,
}
function Png.AtchChunk:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root
self:_read()
end
function Png.AtchChunk:_read()
self.file_name = str_decode.decode(self._io:read_bytes_term(0, false, true, true), "UTF-8")
local _ = self.file_name
if not( ((string.len(_) ~= 0) and (string.sub(_, 0 + 1, 1) ~= ".")) ) then
error("ValidationExprError")
end
self.compression = Png.AtchChunk.CompressionAttachMethods(self._io:read_u1())
if not( ((self.compression == Png.AtchChunk.CompressionAttachMethods.none) or (self.compression == Png.AtchChunk.CompressionAttachMethods.zlib)) ) then
error("ValidationNotAnyOfError")
end
if self.compression == Png.AtchChunk.CompressionAttachMethods.none then
self.data_plain = self._io:read_bytes_full()
end
if self.compression == Png.AtchChunk.CompressionAttachMethods.zlib then
self._raw_data_zlib = self._io:read_bytes_full()
self.data_zlib = KaitaiStream.process_zlib(self._raw_data_zlib)
end
end
Png.AtchChunk.property.data = {}
function Png.AtchChunk.property.data:get()
if self._m_data ~= nil then
return self._m_data
end
self._m_data = utils.box_unwrap((self.compression == Png.AtchChunk.CompressionAttachMethods.none) and utils.box_wrap(self.data_plain) or (self.data_zlib))
return self._m_data
end
--
-- From the [official
-- specification](https://github.com/skeeto/scratch/tree/58470254f4a95cdf7a53888e405c851c21eb2cae/pngattach#atch-chunk-specification):
--
-- > The name can be any length that fits in the chunk, and should be
-- > encoded with UTF-8. It's up to each implementation to determine how
-- > to appropriately interpret the bytestring for the local system.
--
-- > The name must be at least one byte long, not counting the null
-- > terminator. It cannot begin with a period (`0x2e`), nor contain
-- > control bytes (anything less than `0x20`), nor slash (`0x2f`), nor
-- > backslash (`0x5c`), i.e. no directory hierarchies.
--
-- As of Kaitai Struct 0.11, we cannot easily check whether a string
-- contains certain characters, so we only enforce that the file name is
-- not empty and that it doesn't start with a period.
--
-- Background chunk stores default background color to display this
-- image against. Contents depend on `color_type` of the image.
-- See also: Source (https://www.w3.org/TR/png/#11bKGD)
Png.BkgdChunk = class.class(KaitaiStruct)
function Png.BkgdChunk:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root
self:_read()
end
function Png.BkgdChunk:_read()
local _on = self._root.ihdr.color_type
if _on == Png.ColorType.greyscale then
self.bkgd = Png.BkgdGreyscale(self._io, self, self._root)
elseif _on == Png.ColorType.greyscale_alpha then
self.bkgd = Png.BkgdGreyscale(self._io, self, self._root)
elseif _on == Png.ColorType.indexed then
self.bkgd = Png.BkgdIndexed(self._io, self, self._root)
elseif _on == Png.ColorType.truecolor then
self.bkgd = Png.BkgdTruecolor(self._io, self, self._root)
elseif _on == Png.ColorType.truecolor_alpha then
self.bkgd = Png.BkgdTruecolor(self._io, self, self._root)
end
end
--
-- Background chunk for greyscale images.
Png.BkgdGreyscale = class.class(KaitaiStruct)
function Png.BkgdGreyscale:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root
self:_read()
end
function Png.BkgdGreyscale:_read()
self.value = self._io:read_u2be()
end
--
-- Background chunk for images with indexed palette.
Png.BkgdIndexed = class.class(KaitaiStruct)
function Png.BkgdIndexed:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root
self:_read()
end
function Png.BkgdIndexed:_read()
self.palette_index = self._io:read_u1()
end
--
-- Background chunk for truecolor images.
Png.BkgdTruecolor = class.class(KaitaiStruct)
function Png.BkgdTruecolor:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root
self:_read()
end
function Png.BkgdTruecolor:_read()
self.red = self._io:read_u2be()
self.green = self._io:read_u2be()
self.blue = self._io:read_u2be()
end
--
-- See also: Source (https://www.w3.org/TR/png/#11cHRM)
Png.ChrmChunk = class.class(KaitaiStruct)
function Png.ChrmChunk:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root
self:_read()
end
function Png.ChrmChunk:_read()
self.white_point = Png.Point(self._io, self, self._root)
self.red = Png.Point(self._io, self, self._root)
self.green = Png.Point(self._io, self, self._root)
self.blue = Png.Point(self._io, self, self._root)
end
Png.Chunk = class.class(KaitaiStruct)
function Png.Chunk:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root
self:_read()
end
function Png.Chunk:_read()
self.len = self._io:read_u4be()
self.type = str_decode.decode(self._io:read_bytes(4), "UTF-8")
local _ = self.type
if not(self.type ~= "\000\000\000\000") then
error("ValidationExprError")
end
local _on = self.type
if _on == "PLTE" then
self._raw_body = self._io:read_bytes(self.len)
local _io = KaitaiStream(stringstream(self._raw_body))
self.body = Png.PlteChunk(_io, self, self._root)
elseif _on == "acTL" then
self._raw_body = self._io:read_bytes(self.len)
local _io = KaitaiStream(stringstream(self._raw_body))
self.body = Png.AnimationControlChunk(_io, self, self._root)
elseif _on == "atCh" then
self._raw_body = self._io:read_bytes(self.len)
local _io = KaitaiStream(stringstream(self._raw_body))
self.body = Png.AtchChunk(_io, self, self._root)
elseif _on == "bKGD" then
self._raw_body = self._io:read_bytes(self.len)
local _io = KaitaiStream(stringstream(self._raw_body))
self.body = Png.BkgdChunk(_io, self, self._root)
elseif _on == "cHRM" then
self._raw_body = self._io:read_bytes(self.len)
local _io = KaitaiStream(stringstream(self._raw_body))
self.body = Png.ChrmChunk(_io, self, self._root)
elseif _on == "fcTL" then
self._raw_body = self._io:read_bytes(self.len)
local _io = KaitaiStream(stringstream(self._raw_body))
self.body = Png.FrameControlChunk(_io, self, self._root)
elseif _on == "fdAT" then
self._raw_body = self._io:read_bytes(self.len)
local _io = KaitaiStream(stringstream(self._raw_body))
self.body = Png.FrameDataChunk(_io, self, self._root)
elseif _on == "gAMA" then
self._raw_body = self._io:read_bytes(self.len)
local _io = KaitaiStream(stringstream(self._raw_body))
self.body = Png.GamaChunk(_io, self, self._root)
elseif _on == "iTXt" then
self._raw_body = self._io:read_bytes(self.len)
local _io = KaitaiStream(stringstream(self._raw_body))
self.body = Png.InternationalTextChunk(_io, self, self._root)
elseif _on == "mkBS" then
self._raw_body = self._io:read_bytes(self.len)
local _io = KaitaiStream(stringstream(self._raw_body))
self.body = Png.AdobeFireworksChunk(_io, self, self._root)
elseif _on == "mkTS" then
self._raw_body = self._io:read_bytes(self.len)
local _io = KaitaiStream(stringstream(self._raw_body))
self.body = Png.AdobeFireworksChunk(_io, self, self._root)
elseif _on == "pHYs" then
self._raw_body = self._io:read_bytes(self.len)
local _io = KaitaiStream(stringstream(self._raw_body))
self.body = Png.PhysChunk(_io, self, self._root)
elseif _on == "prVW" then
self._raw_body = self._io:read_bytes(self.len)
local _io = KaitaiStream(stringstream(self._raw_body))
self.body = Png.AdobeFireworksChunk(_io, self, self._root)
elseif _on == "sRGB" then
self._raw_body = self._io:read_bytes(self.len)
local _io = KaitaiStream(stringstream(self._raw_body))
self.body = Png.SrgbChunk(_io, self, self._root)
elseif _on == "skMf" then
self._raw_body = self._io:read_bytes(self.len)
local _io = KaitaiStream(stringstream(self._raw_body))
self.body = Png.EvernoteSkmfChunk(_io, self, self._root)
elseif _on == "skRf" then
self._raw_body = self._io:read_bytes(self.len)
local _io = KaitaiStream(stringstream(self._raw_body))
self.body = Png.EvernoteSkrfChunk(_io, self, self._root)
elseif _on == "tEXt" then
self._raw_body = self._io:read_bytes(self.len)
local _io = KaitaiStream(stringstream(self._raw_body))
self.body = Png.TextChunk(_io, self, self._root)
elseif _on == "tIME" then
self._raw_body = self._io:read_bytes(self.len)
local _io = KaitaiStream(stringstream(self._raw_body))
self.body = Png.TimeChunk(_io, self, self._root)
elseif _on == "zTXt" then
self._raw_body = self._io:read_bytes(self.len)
local _io = KaitaiStream(stringstream(self._raw_body))
self.body = Png.CompressedTextChunk(_io, self, self._root)
else
self.body = self._io:read_bytes(self.len)
end
self.crc = self._io:read_bytes(4)
end
--
-- Compressed text chunk effectively allows to store key-value
-- string pairs in PNG container, compressing "value" part (which
-- can be quite lengthy) with zlib compression.
-- See also: Source (https://www.w3.org/TR/png/#11zTXt)
Png.CompressedTextChunk = class.class(KaitaiStruct)
function Png.CompressedTextChunk:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root
self:_read()
end
function Png.CompressedTextChunk:_read()
self.keyword = str_decode.decode(self._io:read_bytes_term(0, false, true, true), "UTF-8")
self.compression_method = Png.CompressionMethods(self._io:read_u1())
self._raw_text_datastream = self._io:read_bytes_full()
self.text_datastream = KaitaiStream.process_zlib(self._raw_text_datastream)
end
--
-- Indicates purpose of the following text data.
--
-- See also: Source (https://web.archive.org/web/20210302212148/https://discussion.evernote.com/forums/topic/88532-how-to-extract-annotation-information-from-annotated-evernoteskitch-images/#comment-451501)
Png.EvernoteSkmfChunk = class.class(KaitaiStruct)
function Png.EvernoteSkmfChunk:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root
self:_read()
end
function Png.EvernoteSkmfChunk:_read()
self.json = str_decode.decode(self._io:read_bytes_full(), "UTF-8")
end
--
-- JSON document with information about editable annotations (text,
-- lines, paths, etc.) in Evernote/Skitch.
--
-- It refers to the original image stored in the `skRf` chunk (which
-- usually follows immediately after `skMf`) via the
-- `.children[0].children[0].uri` JSON property. This has the format
-- `"skitch+uuid:///$UUID"`, where `$UUID` is a random UUIDv4 value that
-- matches the `uuid` field in `evernote_skrf_chunk` (i.e. in the first
-- 16 bytes of the `skRf` chunk).
--
-- See also: Source (https://web.archive.org/web/20210302212148/https://discussion.evernote.com/forums/topic/88532-how-to-extract-annotation-information-from-annotated-evernoteskitch-images/#comment-451501)
Png.EvernoteSkrfChunk = class.class(KaitaiStruct)
function Png.EvernoteSkrfChunk:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root
self:_read()
end
function Png.EvernoteSkrfChunk:_read()
self.uuid = self._io:read_bytes(16)
self.orig_img = self._io:read_bytes_full()
end
--
-- Random UUIDv4 value used to identify the image. It is referenced by
-- the `skMf` chunk - see the documentation for the `json` field in
-- `evernote_skmf_chunk`.
--
-- The original source image without annotations. It's usually a PNG
-- image as well, but it can also be a JPEG or possibly other formats.
--
-- See also: Source (https://wiki.mozilla.org/APNG_Specification#.60fcTL.60:_The_Frame_Control_Chunk)
Png.FrameControlChunk = class.class(KaitaiStruct)
function Png.FrameControlChunk:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root
self:_read()
end
function Png.FrameControlChunk:_read()
self.sequence_number = self._io:read_u4be()
self.width = self._io:read_u4be()
if not(self.width >= 1) then
error("ValidationLessThanError")
end
if not(self.width <= self._root.ihdr.width) then
error("ValidationGreaterThanError")
end
self.height = self._io:read_u4be()
if not(self.height >= 1) then
error("ValidationLessThanError")
end
if not(self.height <= self._root.ihdr.height) then
error("ValidationGreaterThanError")
end
self.x_offset = self._io:read_u4be()
if not(self.x_offset <= self._root.ihdr.width - self.width) then
error("ValidationGreaterThanError")
end
self.y_offset = self._io:read_u4be()
if not(self.y_offset <= self._root.ihdr.height - self.height) then
error("ValidationGreaterThanError")
end
self.delay_num = self._io:read_u2be()
self.delay_den = self._io:read_u2be()
self.dispose_op = Png.DisposeOpValues(self._io:read_u1())
self.blend_op = Png.BlendOpValues(self._io:read_u1())
end
--
-- Time to display this frame, in seconds.
Png.FrameControlChunk.property.delay = {}
function Png.FrameControlChunk.property.delay:get()
if self._m_delay ~= nil then
return self._m_delay
end
self._m_delay = self.delay_num / utils.box_unwrap((self.delay_den == 0) and utils.box_wrap(100.0) or (self.delay_den))
return self._m_delay
end
--
-- Sequence number of the animation chunk.
--
-- Width of the following frame.
--
-- Height of the following frame.
--
-- X position at which to render the following frame.
--
-- Y position at which to render the following frame.
--
-- Frame delay fraction numerator.
--
-- Frame delay fraction denominator.
--
-- Type of frame area disposal to be done after rendering this frame.
--
-- Type of frame area rendering for this frame.
--
-- See also: Source (https://wiki.mozilla.org/APNG_Specification#.60fdAT.60:_The_Frame_Data_Chunk)
Png.FrameDataChunk = class.class(KaitaiStruct)
function Png.FrameDataChunk:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root
self:_read()
end
function Png.FrameDataChunk:_read()
self.sequence_number = self._io:read_u4be()
self.frame_data = self._io:read_bytes_full()
end
--
-- Sequence number of the animation chunk. The fcTL and fdAT chunks
-- have a 4 byte sequence number. Both chunk types share the sequence.
-- The first fcTL chunk must contain sequence number 0, and the sequence
-- numbers in the remaining fcTL and fdAT chunks must be in order, with
-- no gaps or duplicates.
--
-- Frame data for the frame. At least one fdAT chunk is required for
-- each frame. The compressed datastream is the concatenation of the
-- contents of the data fields of all the fdAT chunks within a frame.
--
-- See also: Source (https://www.w3.org/TR/png/#11gAMA)
Png.GamaChunk = class.class(KaitaiStruct)
function Png.GamaChunk:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root
self:_read()
end
function Png.GamaChunk:_read()
self.gamma_int = self._io:read_u4be()
end
Png.GamaChunk.property.gamma_ratio = {}
function Png.GamaChunk.property.gamma_ratio:get()
if self._m_gamma_ratio ~= nil then
return self._m_gamma_ratio
end
self._m_gamma_ratio = 100000.0 / self.gamma_int
return self._m_gamma_ratio
end
--
-- See also: Source (https://www.w3.org/TR/png/#11IHDR)
Png.IhdrChunk = class.class(KaitaiStruct)
function Png.IhdrChunk:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root
self:_read()
end
function Png.IhdrChunk:_read()
self.width = self._io:read_u4be()
if not(self.width >= 1) then
error("ValidationLessThanError")
end
self.height = self._io:read_u4be()
if not(self.height >= 1) then
error("ValidationLessThanError")
end
self.bit_depth = self._io:read_u1()
self.color_type = Png.ColorType(self._io:read_u1())
self.compression_method = self._io:read_u1()
self.filter_method = self._io:read_u1()
self.interlace_method = self._io:read_u1()
end
--
-- International text chunk effectively allows to store key-value string pairs in
-- PNG container. Both "key" (keyword) and "value" (text) parts are
-- given in pre-defined subset of iso8859-1 without control
-- characters.
-- See also: Source (https://www.w3.org/TR/png/#11iTXt)
Png.InternationalTextChunk = class.class(KaitaiStruct)
function Png.InternationalTextChunk:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root
self:_read()
end
function Png.InternationalTextChunk:_read()
self.keyword = str_decode.decode(self._io:read_bytes_term(0, false, true, true), "UTF-8")
self.compression_flag = self._io:read_u1()
self.compression_method = Png.CompressionMethods(self._io:read_u1())
self.language_tag = str_decode.decode(self._io:read_bytes_term(0, false, true, true), "ASCII")
self.translated_keyword = str_decode.decode(self._io:read_bytes_term(0, false, true, true), "UTF-8")
self.text = str_decode.decode(self._io:read_bytes_full(), "UTF-8")
end
--
-- Indicates purpose of the following text data.
--
-- 0 = text is uncompressed, 1 = text is compressed with a
-- method specified in `compression_method`.
--
-- Human language used in `translated_keyword` and `text`
-- attributes - should be a language code conforming to ISO
-- 646.IRV:1991.
--
-- Keyword translated into language specified in
-- `language_tag`. Line breaks are not allowed.
--
-- Text contents ("value" of this key-value pair), written in
-- language specified in `language_tag`. Line breaks are
-- allowed.
--
-- "Physical size" chunk stores data that allows to translate
-- logical pixels into physical units (meters, etc) and vice-versa.
-- See also: Source (https://www.w3.org/TR/png/#11pHYs)
Png.PhysChunk = class.class(KaitaiStruct)
function Png.PhysChunk:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root
self:_read()
end
function Png.PhysChunk:_read()
self.pixels_per_unit_x = self._io:read_u4be()
self.pixels_per_unit_y = self._io:read_u4be()
self.unit = Png.PhysUnit(self._io:read_u1())
end
--
-- Number of pixels per physical unit (typically, 1 meter) by X
-- axis.
--
-- Number of pixels per physical unit (typically, 1 meter) by Y
-- axis.
--
-- See also: Source (https://www.w3.org/TR/png/#11PLTE)
Png.PlteChunk = class.class(KaitaiStruct)
function Png.PlteChunk:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root
self:_read()
end
function Png.PlteChunk:_read()
self.entries = {}
local i = 0
while not self._io:is_eof() do
self.entries[i + 1] = Png.Rgb(self._io, self, self._root)
i = i + 1
end
end
Png.Point = class.class(KaitaiStruct)
function Png.Point:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root
self:_read()
end
function Png.Point:_read()
self.x_int = self._io:read_u4be()
self.y_int = self._io:read_u4be()
end
Png.Point.property.x = {}
function Png.Point.property.x:get()
if self._m_x ~= nil then
return self._m_x
end
self._m_x = self.x_int / 100000.0
return self._m_x
end
Png.Point.property.y = {}
function Png.Point.property.y:get()
if self._m_y ~= nil then
return self._m_y
end
self._m_y = self.y_int / 100000.0
return self._m_y
end
Png.Rgb = class.class(KaitaiStruct)
function Png.Rgb:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root
self:_read()
end
function Png.Rgb:_read()
self.r = self._io:read_u1()
self.g = self._io:read_u1()
self.b = self._io:read_u1()
end
--
-- See also: Source (https://www.w3.org/TR/png/#11sRGB)
Png.SrgbChunk = class.class(KaitaiStruct)
Png.SrgbChunk.Intent = enum.Enum {
perceptual = 0,
relative_colorimetric = 1,
saturation = 2,
absolute_colorimetric = 3,
}
function Png.SrgbChunk:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root
self:_read()
end
function Png.SrgbChunk:_read()
self.render_intent = Png.SrgbChunk.Intent(self._io:read_u1())
end
--
-- Text chunk effectively allows to store key-value string pairs in
-- PNG container. Both "key" (keyword) and "value" (text) parts are
-- given in pre-defined subset of iso8859-1 without control
-- characters.
-- See also: Source (https://www.w3.org/TR/png/#11tEXt)
Png.TextChunk = class.class(KaitaiStruct)
function Png.TextChunk:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root
self:_read()
end
function Png.TextChunk:_read()
self.keyword = str_decode.decode(self._io:read_bytes_term(0, false, true, true), "ISO-8859-1")
self.text = str_decode.decode(self._io:read_bytes_full(), "ISO-8859-1")
end
--
-- Indicates purpose of the following text data.
--
-- Time chunk stores time stamp of last modification of this image,
-- up to 1 second precision in UTC timezone.
-- See also: Source (https://www.w3.org/TR/png/#11tIME)
Png.TimeChunk = class.class(KaitaiStruct)
function Png.TimeChunk:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root
self:_read()
end
function Png.TimeChunk:_read()
self.year = self._io:read_u2be()
self.month = self._io:read_u1()
self.day = self._io:read_u1()
self.hour = self._io:read_u1()
self.minute = self._io:read_u1()
self.second = self._io:read_u1()
end