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.
// Code generated by kaitai-struct-compiler from a .ksy source file. DO NOT EDIT.
import (
"github.com/kaitai-io/kaitai_struct_go_runtime/kaitai"
"bytes"
"unicode/utf8"
"golang.org/x/text/encoding/charmap"
)
/**
* Test files for APNG can be found at the following locations:
*
* * <https://philip.html5.org/tests/apng/tests.html>
* * <http://littlesvr.ca/apng/>
*/
type Png_BlendOpValues int
const (
Png_BlendOpValues__Source Png_BlendOpValues = 0
Png_BlendOpValues__Over Png_BlendOpValues = 1
)
var values_Png_BlendOpValues = map[Png_BlendOpValues]struct{}{0: {}, 1: {}}
func (v Png_BlendOpValues) isDefined() bool {
_, ok := values_Png_BlendOpValues[v]
return ok
}
type Png_ColorType int
const (
Png_ColorType__Greyscale Png_ColorType = 0
Png_ColorType__Truecolor Png_ColorType = 2
Png_ColorType__Indexed Png_ColorType = 3
Png_ColorType__GreyscaleAlpha Png_ColorType = 4
Png_ColorType__TruecolorAlpha Png_ColorType = 6
)
var values_Png_ColorType = map[Png_ColorType]struct{}{0: {}, 2: {}, 3: {}, 4: {}, 6: {}}
func (v Png_ColorType) isDefined() bool {
_, ok := values_Png_ColorType[v]
return ok
}
type Png_CompressionMethods int
const (
Png_CompressionMethods__Zlib Png_CompressionMethods = 0
)
var values_Png_CompressionMethods = map[Png_CompressionMethods]struct{}{0: {}}
func (v Png_CompressionMethods) isDefined() bool {
_, ok := values_Png_CompressionMethods[v]
return ok
}
type Png_DisposeOpValues int
const (
Png_DisposeOpValues__None Png_DisposeOpValues = 0
Png_DisposeOpValues__Background Png_DisposeOpValues = 1
Png_DisposeOpValues__Previous Png_DisposeOpValues = 2
)
var values_Png_DisposeOpValues = map[Png_DisposeOpValues]struct{}{0: {}, 1: {}, 2: {}}
func (v Png_DisposeOpValues) isDefined() bool {
_, ok := values_Png_DisposeOpValues[v]
return ok
}
type Png_PhysUnit int
const (
Png_PhysUnit__Unknown Png_PhysUnit = 0
Png_PhysUnit__Meter Png_PhysUnit = 1
)
var values_Png_PhysUnit = map[Png_PhysUnit]struct{}{0: {}, 1: {}}
func (v Png_PhysUnit) isDefined() bool {
_, ok := values_Png_PhysUnit[v]
return ok
}
type Png struct {
Magic []byte
IhdrLen uint32
IhdrType []byte
Ihdr *Png_IhdrChunk
IhdrCrc []byte
Chunks []*Png_Chunk
_io *kaitai.Stream
_root *Png
_parent kaitai.Struct
}
func NewPng() *Png {
return &Png{
}
}
func (this Png) IO_() *kaitai.Stream {
return this._io
}
func (this *Png) Read(io *kaitai.Stream, parent kaitai.Struct, root *Png) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp1, err := this._io.ReadBytes(int(8))
if err != nil {
return err
}
tmp1 = tmp1
this.Magic = tmp1
if !(bytes.Equal(this.Magic, []uint8{137, 80, 78, 71, 13, 10, 26, 10})) {
return kaitai.NewValidationNotEqualError([]uint8{137, 80, 78, 71, 13, 10, 26, 10}, this.Magic, this._io, "/seq/0")
}
tmp2, err := this._io.ReadU4be()
if err != nil {
return err
}
this.IhdrLen = uint32(tmp2)
if !(this.IhdrLen == 13) {
return kaitai.NewValidationNotEqualError(13, this.IhdrLen, this._io, "/seq/1")
}
tmp3, err := this._io.ReadBytes(int(4))
if err != nil {
return err
}
tmp3 = tmp3
this.IhdrType = tmp3
if !(bytes.Equal(this.IhdrType, []uint8{73, 72, 68, 82})) {
return kaitai.NewValidationNotEqualError([]uint8{73, 72, 68, 82}, this.IhdrType, this._io, "/seq/2")
}
tmp4 := NewPng_IhdrChunk()
err = tmp4.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Ihdr = tmp4
tmp5, err := this._io.ReadBytes(int(4))
if err != nil {
return err
}
tmp5 = tmp5
this.IhdrCrc = tmp5
for i := 1;; i++ {
tmp6 := NewPng_Chunk()
err = tmp6.Read(this._io, this, this._root)
if err != nil {
return err
}
_it := tmp6
this.Chunks = append(this.Chunks, _it)
tmp7, err := this._io.EOF()
if err != nil {
return err
}
if ((_it.Type == "IEND") || (tmp7)) {
break
}
}
return err
}
/**
* @see <a href="https://stackoverflow.com/questions/4242402/the-fireworks-png-format-any-insight-any-libs/51683285#51683285">Source</a>
*/
type Png_AdobeFireworksChunk struct {
PreviewData []byte
_io *kaitai.Stream
_root *Png
_parent *Png_Chunk
_raw_PreviewData []byte
}
func NewPng_AdobeFireworksChunk() *Png_AdobeFireworksChunk {
return &Png_AdobeFireworksChunk{
}
}
func (this Png_AdobeFireworksChunk) IO_() *kaitai.Stream {
return this._io
}
func (this *Png_AdobeFireworksChunk) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp8, err := this._io.ReadBytesFull()
if err != nil {
return err
}
tmp8 = tmp8
this._raw_PreviewData = tmp8
tmp9, err := kaitai.ProcessZlib(this._raw_PreviewData)
if err != nil {
return err
}
this.PreviewData = tmp9
return err
}
/**
* @see <a href="https://wiki.mozilla.org/APNG_Specification#.60acTL.60:_The_Animation_Control_Chunk">Source</a>
*/
type Png_AnimationControlChunk struct {
NumFrames uint32
NumPlays uint32
_io *kaitai.Stream
_root *Png
_parent *Png_Chunk
}
func NewPng_AnimationControlChunk() *Png_AnimationControlChunk {
return &Png_AnimationControlChunk{
}
}
func (this Png_AnimationControlChunk) IO_() *kaitai.Stream {
return this._io
}
func (this *Png_AnimationControlChunk) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp10, err := this._io.ReadU4be()
if err != nil {
return err
}
this.NumFrames = uint32(tmp10)
tmp11, err := this._io.ReadU4be()
if err != nil {
return err
}
this.NumPlays = uint32(tmp11)
return err
}
/**
* Number of frames, must be equal to the number of `frame_control_chunk`s
*/
/**
* Number of times to loop, 0 indicates infinite looping.
*/
/**
* @see <a href="https://github.com/skeeto/scratch/tree/58470254f4a95cdf7a53888e405c851c21eb2cae/pngattach">Source</a>
* @see <a href="https://nullprogram.com/blog/2021/12/31/">A new protocol and tool for PNG file attachments</a>
*/
type Png_AtchChunk_CompressionAttachMethods int
const (
Png_AtchChunk_CompressionAttachMethods__None Png_AtchChunk_CompressionAttachMethods = 0
Png_AtchChunk_CompressionAttachMethods__Zlib Png_AtchChunk_CompressionAttachMethods = 1
)
var values_Png_AtchChunk_CompressionAttachMethods = map[Png_AtchChunk_CompressionAttachMethods]struct{}{0: {}, 1: {}}
func (v Png_AtchChunk_CompressionAttachMethods) isDefined() bool {
_, ok := values_Png_AtchChunk_CompressionAttachMethods[v]
return ok
}
type Png_AtchChunk struct {
FileName string
Compression Png_AtchChunk_CompressionAttachMethods
DataPlain []byte
DataZlib []byte
_io *kaitai.Stream
_root *Png
_parent *Png_Chunk
_raw_DataZlib []byte
_f_data bool
data []byte
}
func NewPng_AtchChunk() *Png_AtchChunk {
return &Png_AtchChunk{
}
}
func (this Png_AtchChunk) IO_() *kaitai.Stream {
return this._io
}
func (this *Png_AtchChunk) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp12, err := this._io.ReadBytesTerm(0, false, true, true)
if err != nil {
return err
}
this.FileName = string(tmp12)
{
_it := this.FileName
if !( ((utf8.RuneCountInString(_it) != 0) && (_it[0:1] != ".")) ) {
return kaitai.NewValidationExprError(this.FileName, this._io, "/types/atch_chunk/seq/0")
}
}
tmp13, err := this._io.ReadU1()
if err != nil {
return err
}
this.Compression = Png_AtchChunk_CompressionAttachMethods(tmp13)
if !( ((this.Compression == Png_AtchChunk_CompressionAttachMethods__None) || (this.Compression == Png_AtchChunk_CompressionAttachMethods__Zlib)) ) {
return kaitai.NewValidationNotAnyOfError(this.Compression, this._io, "/types/atch_chunk/seq/1")
}
if (this.Compression == Png_AtchChunk_CompressionAttachMethods__None) {
tmp14, err := this._io.ReadBytesFull()
if err != nil {
return err
}
tmp14 = tmp14
this.DataPlain = tmp14
}
if (this.Compression == Png_AtchChunk_CompressionAttachMethods__Zlib) {
tmp15, err := this._io.ReadBytesFull()
if err != nil {
return err
}
tmp15 = tmp15
this._raw_DataZlib = tmp15
tmp16, err := kaitai.ProcessZlib(this._raw_DataZlib)
if err != nil {
return err
}
this.DataZlib = tmp16
}
return err
}
func (this *Png_AtchChunk) Data() (v []byte, err error) {
if (this._f_data) {
return this.data, nil
}
this._f_data = true
var tmp17 []byte;
if (this.Compression == Png_AtchChunk_CompressionAttachMethods__None) {
tmp17 = this.DataPlain
} else {
tmp17 = this.DataZlib
}
this.data = []byte(tmp17)
return this.data, nil
}
/**
* 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 <a href="https://www.w3.org/TR/png/#11bKGD">Source</a>
*/
type Png_BkgdChunk struct {
Bkgd kaitai.Struct
_io *kaitai.Stream
_root *Png
_parent *Png_Chunk
}
func NewPng_BkgdChunk() *Png_BkgdChunk {
return &Png_BkgdChunk{
}
}
func (this Png_BkgdChunk) IO_() *kaitai.Stream {
return this._io
}
func (this *Png_BkgdChunk) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
this._io = io
this._parent = parent
this._root = root
switch (this._root.Ihdr.ColorType) {
case Png_ColorType__Greyscale:
tmp18 := NewPng_BkgdGreyscale()
err = tmp18.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Bkgd = tmp18
case Png_ColorType__GreyscaleAlpha:
tmp19 := NewPng_BkgdGreyscale()
err = tmp19.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Bkgd = tmp19
case Png_ColorType__Indexed:
tmp20 := NewPng_BkgdIndexed()
err = tmp20.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Bkgd = tmp20
case Png_ColorType__Truecolor:
tmp21 := NewPng_BkgdTruecolor()
err = tmp21.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Bkgd = tmp21
case Png_ColorType__TruecolorAlpha:
tmp22 := NewPng_BkgdTruecolor()
err = tmp22.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Bkgd = tmp22
}
return err
}
/**
* Background chunk for greyscale images.
*/
type Png_BkgdGreyscale struct {
Value uint16
_io *kaitai.Stream
_root *Png
_parent *Png_BkgdChunk
}
func NewPng_BkgdGreyscale() *Png_BkgdGreyscale {
return &Png_BkgdGreyscale{
}
}
func (this Png_BkgdGreyscale) IO_() *kaitai.Stream {
return this._io
}
func (this *Png_BkgdGreyscale) Read(io *kaitai.Stream, parent *Png_BkgdChunk, root *Png) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp23, err := this._io.ReadU2be()
if err != nil {
return err
}
this.Value = uint16(tmp23)
return err
}
/**
* Background chunk for images with indexed palette.
*/
type Png_BkgdIndexed struct {
PaletteIndex uint8
_io *kaitai.Stream
_root *Png
_parent *Png_BkgdChunk
}
func NewPng_BkgdIndexed() *Png_BkgdIndexed {
return &Png_BkgdIndexed{
}
}
func (this Png_BkgdIndexed) IO_() *kaitai.Stream {
return this._io
}
func (this *Png_BkgdIndexed) Read(io *kaitai.Stream, parent *Png_BkgdChunk, root *Png) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp24, err := this._io.ReadU1()
if err != nil {
return err
}
this.PaletteIndex = tmp24
return err
}
/**
* Background chunk for truecolor images.
*/
type Png_BkgdTruecolor struct {
Red uint16
Green uint16
Blue uint16
_io *kaitai.Stream
_root *Png
_parent *Png_BkgdChunk
}
func NewPng_BkgdTruecolor() *Png_BkgdTruecolor {
return &Png_BkgdTruecolor{
}
}
func (this Png_BkgdTruecolor) IO_() *kaitai.Stream {
return this._io
}
func (this *Png_BkgdTruecolor) Read(io *kaitai.Stream, parent *Png_BkgdChunk, root *Png) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp25, err := this._io.ReadU2be()
if err != nil {
return err
}
this.Red = uint16(tmp25)
tmp26, err := this._io.ReadU2be()
if err != nil {
return err
}
this.Green = uint16(tmp26)
tmp27, err := this._io.ReadU2be()
if err != nil {
return err
}
this.Blue = uint16(tmp27)
return err
}
/**
* @see <a href="https://www.w3.org/TR/png/#11cHRM">Source</a>
*/
type Png_ChrmChunk struct {
WhitePoint *Png_Point
Red *Png_Point
Green *Png_Point
Blue *Png_Point
_io *kaitai.Stream
_root *Png
_parent *Png_Chunk
}
func NewPng_ChrmChunk() *Png_ChrmChunk {
return &Png_ChrmChunk{
}
}
func (this Png_ChrmChunk) IO_() *kaitai.Stream {
return this._io
}
func (this *Png_ChrmChunk) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp28 := NewPng_Point()
err = tmp28.Read(this._io, this, this._root)
if err != nil {
return err
}
this.WhitePoint = tmp28
tmp29 := NewPng_Point()
err = tmp29.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Red = tmp29
tmp30 := NewPng_Point()
err = tmp30.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Green = tmp30
tmp31 := NewPng_Point()
err = tmp31.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Blue = tmp31
return err
}
type Png_Chunk struct {
Len uint32
Type string
Body interface{}
Crc []byte
_io *kaitai.Stream
_root *Png
_parent *Png
_raw_Body []byte
}
func NewPng_Chunk() *Png_Chunk {
return &Png_Chunk{
}
}
func (this Png_Chunk) IO_() *kaitai.Stream {
return this._io
}
func (this *Png_Chunk) Read(io *kaitai.Stream, parent *Png, root *Png) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp32, err := this._io.ReadU4be()
if err != nil {
return err
}
this.Len = uint32(tmp32)
tmp33, err := this._io.ReadBytes(int(4))
if err != nil {
return err
}
tmp33 = tmp33
this.Type = string(tmp33)
{
_it := this.Type
if !(this.Type != "\000\000\000\000") {
return kaitai.NewValidationExprError(this.Type, this._io, "/types/chunk/seq/1")
}
}
switch (this.Type) {
case "PLTE":
tmp34, err := this._io.ReadBytes(int(this.Len))
if err != nil {
return err
}
tmp34 = tmp34
this._raw_Body = tmp34
_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
tmp35 := NewPng_PlteChunk()
err = tmp35.Read(_io__raw_Body, this, this._root)
if err != nil {
return err
}
this.Body = tmp35
case "acTL":
tmp36, err := this._io.ReadBytes(int(this.Len))
if err != nil {
return err
}
tmp36 = tmp36
this._raw_Body = tmp36
_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
tmp37 := NewPng_AnimationControlChunk()
err = tmp37.Read(_io__raw_Body, this, this._root)
if err != nil {
return err
}
this.Body = tmp37
case "atCh":
tmp38, err := this._io.ReadBytes(int(this.Len))
if err != nil {
return err
}
tmp38 = tmp38
this._raw_Body = tmp38
_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
tmp39 := NewPng_AtchChunk()
err = tmp39.Read(_io__raw_Body, this, this._root)
if err != nil {
return err
}
this.Body = tmp39
case "bKGD":
tmp40, err := this._io.ReadBytes(int(this.Len))
if err != nil {
return err
}
tmp40 = tmp40
this._raw_Body = tmp40
_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
tmp41 := NewPng_BkgdChunk()
err = tmp41.Read(_io__raw_Body, this, this._root)
if err != nil {
return err
}
this.Body = tmp41
case "cHRM":
tmp42, err := this._io.ReadBytes(int(this.Len))
if err != nil {
return err
}
tmp42 = tmp42
this._raw_Body = tmp42
_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
tmp43 := NewPng_ChrmChunk()
err = tmp43.Read(_io__raw_Body, this, this._root)
if err != nil {
return err
}
this.Body = tmp43
case "fcTL":
tmp44, err := this._io.ReadBytes(int(this.Len))
if err != nil {
return err
}
tmp44 = tmp44
this._raw_Body = tmp44
_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
tmp45 := NewPng_FrameControlChunk()
err = tmp45.Read(_io__raw_Body, this, this._root)
if err != nil {
return err
}
this.Body = tmp45
case "fdAT":
tmp46, err := this._io.ReadBytes(int(this.Len))
if err != nil {
return err
}
tmp46 = tmp46
this._raw_Body = tmp46
_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
tmp47 := NewPng_FrameDataChunk()
err = tmp47.Read(_io__raw_Body, this, this._root)
if err != nil {
return err
}
this.Body = tmp47
case "gAMA":
tmp48, err := this._io.ReadBytes(int(this.Len))
if err != nil {
return err
}
tmp48 = tmp48
this._raw_Body = tmp48
_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
tmp49 := NewPng_GamaChunk()
err = tmp49.Read(_io__raw_Body, this, this._root)
if err != nil {
return err
}
this.Body = tmp49
case "iTXt":
tmp50, err := this._io.ReadBytes(int(this.Len))
if err != nil {
return err
}
tmp50 = tmp50
this._raw_Body = tmp50
_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
tmp51 := NewPng_InternationalTextChunk()
err = tmp51.Read(_io__raw_Body, this, this._root)
if err != nil {
return err
}
this.Body = tmp51
case "mkBS":
tmp52, err := this._io.ReadBytes(int(this.Len))
if err != nil {
return err
}
tmp52 = tmp52
this._raw_Body = tmp52
_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
tmp53 := NewPng_AdobeFireworksChunk()
err = tmp53.Read(_io__raw_Body, this, this._root)
if err != nil {
return err
}
this.Body = tmp53
case "mkTS":
tmp54, err := this._io.ReadBytes(int(this.Len))
if err != nil {
return err
}
tmp54 = tmp54
this._raw_Body = tmp54
_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
tmp55 := NewPng_AdobeFireworksChunk()
err = tmp55.Read(_io__raw_Body, this, this._root)
if err != nil {
return err
}
this.Body = tmp55
case "pHYs":
tmp56, err := this._io.ReadBytes(int(this.Len))
if err != nil {
return err
}
tmp56 = tmp56
this._raw_Body = tmp56
_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
tmp57 := NewPng_PhysChunk()
err = tmp57.Read(_io__raw_Body, this, this._root)
if err != nil {
return err
}
this.Body = tmp57
case "prVW":
tmp58, err := this._io.ReadBytes(int(this.Len))
if err != nil {
return err
}
tmp58 = tmp58
this._raw_Body = tmp58
_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
tmp59 := NewPng_AdobeFireworksChunk()
err = tmp59.Read(_io__raw_Body, this, this._root)
if err != nil {
return err
}
this.Body = tmp59
case "sRGB":
tmp60, err := this._io.ReadBytes(int(this.Len))
if err != nil {
return err
}
tmp60 = tmp60
this._raw_Body = tmp60
_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
tmp61 := NewPng_SrgbChunk()
err = tmp61.Read(_io__raw_Body, this, this._root)
if err != nil {
return err
}
this.Body = tmp61
case "skMf":
tmp62, err := this._io.ReadBytes(int(this.Len))
if err != nil {
return err
}
tmp62 = tmp62
this._raw_Body = tmp62
_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
tmp63 := NewPng_EvernoteSkmfChunk()
err = tmp63.Read(_io__raw_Body, this, this._root)
if err != nil {
return err
}
this.Body = tmp63
case "skRf":
tmp64, err := this._io.ReadBytes(int(this.Len))
if err != nil {
return err
}
tmp64 = tmp64
this._raw_Body = tmp64
_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
tmp65 := NewPng_EvernoteSkrfChunk()
err = tmp65.Read(_io__raw_Body, this, this._root)
if err != nil {
return err
}
this.Body = tmp65
case "tEXt":
tmp66, err := this._io.ReadBytes(int(this.Len))
if err != nil {
return err
}
tmp66 = tmp66
this._raw_Body = tmp66
_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
tmp67 := NewPng_TextChunk()
err = tmp67.Read(_io__raw_Body, this, this._root)
if err != nil {
return err
}
this.Body = tmp67
case "tIME":
tmp68, err := this._io.ReadBytes(int(this.Len))
if err != nil {
return err
}
tmp68 = tmp68
this._raw_Body = tmp68
_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
tmp69 := NewPng_TimeChunk()
err = tmp69.Read(_io__raw_Body, this, this._root)
if err != nil {
return err
}
this.Body = tmp69
case "zTXt":
tmp70, err := this._io.ReadBytes(int(this.Len))
if err != nil {
return err
}
tmp70 = tmp70
this._raw_Body = tmp70
_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
tmp71 := NewPng_CompressedTextChunk()
err = tmp71.Read(_io__raw_Body, this, this._root)
if err != nil {
return err
}
this.Body = tmp71
default:
tmp72, err := this._io.ReadBytes(int(this.Len))
if err != nil {
return err
}
tmp72 = tmp72
this._raw_Body = tmp72
}
tmp73, err := this._io.ReadBytes(int(4))
if err != nil {
return err
}
tmp73 = tmp73
this.Crc = tmp73
return err
}
/**
* 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 <a href="https://www.w3.org/TR/png/#11zTXt">Source</a>
*/
type Png_CompressedTextChunk struct {
Keyword string
CompressionMethod Png_CompressionMethods
TextDatastream []byte
_io *kaitai.Stream
_root *Png
_parent *Png_Chunk
_raw_TextDatastream []byte
}
func NewPng_CompressedTextChunk() *Png_CompressedTextChunk {
return &Png_CompressedTextChunk{
}
}
func (this Png_CompressedTextChunk) IO_() *kaitai.Stream {
return this._io
}
func (this *Png_CompressedTextChunk) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp74, err := this._io.ReadBytesTerm(0, false, true, true)
if err != nil {
return err
}
this.Keyword = string(tmp74)
tmp75, err := this._io.ReadU1()
if err != nil {
return err
}
this.CompressionMethod = Png_CompressionMethods(tmp75)
tmp76, err := this._io.ReadBytesFull()
if err != nil {
return err
}
tmp76 = tmp76
this._raw_TextDatastream = tmp76
tmp77, err := kaitai.ProcessZlib(this._raw_TextDatastream)
if err != nil {
return err
}
this.TextDatastream = tmp77
return err
}
/**
* Indicates purpose of the following text data.
*/
/**
* @see <a href="https://web.archive.org/web/20210302212148/https://discussion.evernote.com/forums/topic/88532-how-to-extract-annotation-information-from-annotated-evernoteskitch-images/#comment-451501">Source</a>
*/
type Png_EvernoteSkmfChunk struct {
Json string
_io *kaitai.Stream
_root *Png
_parent *Png_Chunk
}
func NewPng_EvernoteSkmfChunk() *Png_EvernoteSkmfChunk {
return &Png_EvernoteSkmfChunk{
}
}
func (this Png_EvernoteSkmfChunk) IO_() *kaitai.Stream {
return this._io
}
func (this *Png_EvernoteSkmfChunk) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp78, err := this._io.ReadBytesFull()
if err != nil {
return err
}
tmp78 = tmp78
this.Json = string(tmp78)
return err
}
/**
* 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 <a href="https://web.archive.org/web/20210302212148/https://discussion.evernote.com/forums/topic/88532-how-to-extract-annotation-information-from-annotated-evernoteskitch-images/#comment-451501">Source</a>
*/
type Png_EvernoteSkrfChunk struct {
Uuid []byte
OrigImg []byte
_io *kaitai.Stream
_root *Png
_parent *Png_Chunk
}
func NewPng_EvernoteSkrfChunk() *Png_EvernoteSkrfChunk {
return &Png_EvernoteSkrfChunk{
}
}
func (this Png_EvernoteSkrfChunk) IO_() *kaitai.Stream {
return this._io
}
func (this *Png_EvernoteSkrfChunk) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp79, err := this._io.ReadBytes(int(16))
if err != nil {
return err
}
tmp79 = tmp79
this.Uuid = tmp79
tmp80, err := this._io.ReadBytesFull()
if err != nil {
return err
}
tmp80 = tmp80
this.OrigImg = tmp80
return err
}
/**
* 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 <a href="https://wiki.mozilla.org/APNG_Specification#.60fcTL.60:_The_Frame_Control_Chunk">Source</a>
*/
type Png_FrameControlChunk struct {
SequenceNumber uint32
Width uint32
Height uint32
XOffset uint32
YOffset uint32
DelayNum uint16
DelayDen uint16
DisposeOp Png_DisposeOpValues
BlendOp Png_BlendOpValues
_io *kaitai.Stream
_root *Png
_parent *Png_Chunk
_f_delay bool
delay float64
}
func NewPng_FrameControlChunk() *Png_FrameControlChunk {
return &Png_FrameControlChunk{
}
}
func (this Png_FrameControlChunk) IO_() *kaitai.Stream {
return this._io
}
func (this *Png_FrameControlChunk) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp81, err := this._io.ReadU4be()
if err != nil {
return err
}
this.SequenceNumber = uint32(tmp81)
tmp82, err := this._io.ReadU4be()
if err != nil {
return err
}
this.Width = uint32(tmp82)
if !(this.Width >= 1) {
return kaitai.NewValidationLessThanError(1, this.Width, this._io, "/types/frame_control_chunk/seq/1")
}
if !(this.Width <= this._root.Ihdr.Width) {
return kaitai.NewValidationGreaterThanError(this._root.Ihdr.Width, this.Width, this._io, "/types/frame_control_chunk/seq/1")
}
tmp83, err := this._io.ReadU4be()
if err != nil {
return err
}
this.Height = uint32(tmp83)
if !(this.Height >= 1) {
return kaitai.NewValidationLessThanError(1, this.Height, this._io, "/types/frame_control_chunk/seq/2")
}
if !(this.Height <= this._root.Ihdr.Height) {
return kaitai.NewValidationGreaterThanError(this._root.Ihdr.Height, this.Height, this._io, "/types/frame_control_chunk/seq/2")
}
tmp84, err := this._io.ReadU4be()
if err != nil {
return err
}
this.XOffset = uint32(tmp84)
if !(this.XOffset <= this._root.Ihdr.Width - this.Width) {
return kaitai.NewValidationGreaterThanError(this._root.Ihdr.Width - this.Width, this.XOffset, this._io, "/types/frame_control_chunk/seq/3")
}
tmp85, err := this._io.ReadU4be()
if err != nil {
return err
}
this.YOffset = uint32(tmp85)
if !(this.YOffset <= this._root.Ihdr.Height - this.Height) {
return kaitai.NewValidationGreaterThanError(this._root.Ihdr.Height - this.Height, this.YOffset, this._io, "/types/frame_control_chunk/seq/4")
}
tmp86, err := this._io.ReadU2be()
if err != nil {
return err
}
this.DelayNum = uint16(tmp86)
tmp87, err := this._io.ReadU2be()
if err != nil {
return err
}
this.DelayDen = uint16(tmp87)
tmp88, err := this._io.ReadU1()
if err != nil {
return err
}
this.DisposeOp = Png_DisposeOpValues(tmp88)
tmp89, err := this._io.ReadU1()
if err != nil {
return err
}
this.BlendOp = Png_BlendOpValues(tmp89)
return err
}
/**
* Time to display this frame, in seconds
*/
func (this *Png_FrameControlChunk) Delay() (v float64, err error) {
if (this._f_delay) {
return this.delay, nil
}
this._f_delay = true
var tmp90 float64;
if (this.DelayDen == 0) {
tmp90 = 100.0
} else {
tmp90 = this.DelayDen
}
this.delay = float64(this.DelayNum / tmp90)
return this.delay, nil
}
/**
* 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 <a href="https://wiki.mozilla.org/APNG_Specification#.60fdAT.60:_The_Frame_Data_Chunk">Source</a>
*/
type Png_FrameDataChunk struct {
SequenceNumber uint32
FrameData []byte
_io *kaitai.Stream
_root *Png
_parent *Png_Chunk
}
func NewPng_FrameDataChunk() *Png_FrameDataChunk {
return &Png_FrameDataChunk{
}
}
func (this Png_FrameDataChunk) IO_() *kaitai.Stream {
return this._io
}
func (this *Png_FrameDataChunk) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp91, err := this._io.ReadU4be()
if err != nil {
return err
}
this.SequenceNumber = uint32(tmp91)
tmp92, err := this._io.ReadBytesFull()
if err != nil {
return err
}
tmp92 = tmp92
this.FrameData = tmp92
return err
}
/**
* 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 <a href="https://www.w3.org/TR/png/#11gAMA">Source</a>
*/
type Png_GamaChunk struct {
GammaInt uint32
_io *kaitai.Stream
_root *Png
_parent *Png_Chunk
_f_gammaRatio bool
gammaRatio float64
}
func NewPng_GamaChunk() *Png_GamaChunk {
return &Png_GamaChunk{
}
}
func (this Png_GamaChunk) IO_() *kaitai.Stream {
return this._io
}
func (this *Png_GamaChunk) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp93, err := this._io.ReadU4be()
if err != nil {
return err
}
this.GammaInt = uint32(tmp93)
return err
}
func (this *Png_GamaChunk) GammaRatio() (v float64, err error) {
if (this._f_gammaRatio) {
return this.gammaRatio, nil
}
this._f_gammaRatio = true
this.gammaRatio = float64(100000.0 / this.GammaInt)
return this.gammaRatio, nil
}
/**
* @see <a href="https://www.w3.org/TR/png/#11IHDR">Source</a>
*/
type Png_IhdrChunk struct {
Width uint32
Height uint32
BitDepth uint8
ColorType Png_ColorType
CompressionMethod uint8
FilterMethod uint8
InterlaceMethod uint8
_io *kaitai.Stream
_root *Png
_parent *Png
}
func NewPng_IhdrChunk() *Png_IhdrChunk {
return &Png_IhdrChunk{
}
}
func (this Png_IhdrChunk) IO_() *kaitai.Stream {
return this._io
}
func (this *Png_IhdrChunk) Read(io *kaitai.Stream, parent *Png, root *Png) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp94, err := this._io.ReadU4be()
if err != nil {
return err
}
this.Width = uint32(tmp94)
if !(this.Width >= 1) {
return kaitai.NewValidationLessThanError(1, this.Width, this._io, "/types/ihdr_chunk/seq/0")
}
tmp95, err := this._io.ReadU4be()
if err != nil {
return err
}
this.Height = uint32(tmp95)
if !(this.Height >= 1) {
return kaitai.NewValidationLessThanError(1, this.Height, this._io, "/types/ihdr_chunk/seq/1")
}
tmp96, err := this._io.ReadU1()
if err != nil {
return err
}
this.BitDepth = tmp96
tmp97, err := this._io.ReadU1()
if err != nil {
return err
}
this.ColorType = Png_ColorType(tmp97)
tmp98, err := this._io.ReadU1()
if err != nil {
return err
}
this.CompressionMethod = tmp98
tmp99, err := this._io.ReadU1()
if err != nil {
return err
}
this.FilterMethod = tmp99
tmp100, err := this._io.ReadU1()
if err != nil {
return err
}
this.InterlaceMethod = tmp100
return err
}
/**
* 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 <a href="https://www.w3.org/TR/png/#11iTXt">Source</a>
*/
type Png_InternationalTextChunk struct {
Keyword string
CompressionFlag uint8
CompressionMethod Png_CompressionMethods
LanguageTag string
TranslatedKeyword string
Text string
_io *kaitai.Stream
_root *Png
_parent *Png_Chunk
}
func NewPng_InternationalTextChunk() *Png_InternationalTextChunk {
return &Png_InternationalTextChunk{
}
}
func (this Png_InternationalTextChunk) IO_() *kaitai.Stream {
return this._io
}
func (this *Png_InternationalTextChunk) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp101, err := this._io.ReadBytesTerm(0, false, true, true)
if err != nil {
return err
}
this.Keyword = string(tmp101)
tmp102, err := this._io.ReadU1()
if err != nil {
return err
}
this.CompressionFlag = tmp102
tmp103, err := this._io.ReadU1()
if err != nil {
return err
}
this.CompressionMethod = Png_CompressionMethods(tmp103)
tmp104, err := this._io.ReadBytesTerm(0, false, true, true)
if err != nil {
return err
}
this.LanguageTag = string(tmp104)
tmp105, err := this._io.ReadBytesTerm(0, false, true, true)
if err != nil {
return err
}
this.TranslatedKeyword = string(tmp105)
tmp106, err := this._io.ReadBytesFull()
if err != nil {
return err
}
tmp106 = tmp106
this.Text = string(tmp106)
return err
}
/**
* 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 <a href="https://www.w3.org/TR/png/#11pHYs">Source</a>
*/
type Png_PhysChunk struct {
PixelsPerUnitX uint32
PixelsPerUnitY uint32
Unit Png_PhysUnit
_io *kaitai.Stream
_root *Png
_parent *Png_Chunk
}
func NewPng_PhysChunk() *Png_PhysChunk {
return &Png_PhysChunk{
}
}
func (this Png_PhysChunk) IO_() *kaitai.Stream {
return this._io
}
func (this *Png_PhysChunk) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp107, err := this._io.ReadU4be()
if err != nil {
return err
}
this.PixelsPerUnitX = uint32(tmp107)
tmp108, err := this._io.ReadU4be()
if err != nil {
return err
}
this.PixelsPerUnitY = uint32(tmp108)
tmp109, err := this._io.ReadU1()
if err != nil {
return err
}
this.Unit = Png_PhysUnit(tmp109)
return err
}
/**
* 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 <a href="https://www.w3.org/TR/png/#11PLTE">Source</a>
*/
type Png_PlteChunk struct {
Entries []*Png_Rgb
_io *kaitai.Stream
_root *Png
_parent *Png_Chunk
}
func NewPng_PlteChunk() *Png_PlteChunk {
return &Png_PlteChunk{
}
}
func (this Png_PlteChunk) IO_() *kaitai.Stream {
return this._io
}
func (this *Png_PlteChunk) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
this._io = io
this._parent = parent
this._root = root
for i := 0;; i++ {
tmp110, err := this._io.EOF()
if err != nil {
return err
}
if tmp110 {
break
}
tmp111 := NewPng_Rgb()
err = tmp111.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Entries = append(this.Entries, tmp111)
}
return err
}
type Png_Point struct {
XInt uint32
YInt uint32
_io *kaitai.Stream
_root *Png
_parent *Png_ChrmChunk
_f_x bool
x float64
_f_y bool
y float64
}
func NewPng_Point() *Png_Point {
return &Png_Point{
}
}
func (this Png_Point) IO_() *kaitai.Stream {
return this._io
}
func (this *Png_Point) Read(io *kaitai.Stream, parent *Png_ChrmChunk, root *Png) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp112, err := this._io.ReadU4be()
if err != nil {
return err
}
this.XInt = uint32(tmp112)
tmp113, err := this._io.ReadU4be()
if err != nil {
return err
}
this.YInt = uint32(tmp113)
return err
}
func (this *Png_Point) X() (v float64, err error) {
if (this._f_x) {
return this.x, nil
}
this._f_x = true
this.x = float64(this.XInt / 100000.0)
return this.x, nil
}
func (this *Png_Point) Y() (v float64, err error) {
if (this._f_y) {
return this.y, nil
}
this._f_y = true
this.y = float64(this.YInt / 100000.0)
return this.y, nil
}
type Png_Rgb struct {
R uint8
G uint8
B uint8
_io *kaitai.Stream
_root *Png
_parent *Png_PlteChunk
}
func NewPng_Rgb() *Png_Rgb {
return &Png_Rgb{
}
}
func (this Png_Rgb) IO_() *kaitai.Stream {
return this._io
}
func (this *Png_Rgb) Read(io *kaitai.Stream, parent *Png_PlteChunk, root *Png) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp114, err := this._io.ReadU1()
if err != nil {
return err
}
this.R = tmp114
tmp115, err := this._io.ReadU1()
if err != nil {
return err
}
this.G = tmp115
tmp116, err := this._io.ReadU1()
if err != nil {
return err
}
this.B = tmp116
return err
}
/**
* @see <a href="https://www.w3.org/TR/png/#11sRGB">Source</a>
*/
type Png_SrgbChunk_Intent int
const (
Png_SrgbChunk_Intent__Perceptual Png_SrgbChunk_Intent = 0
Png_SrgbChunk_Intent__RelativeColorimetric Png_SrgbChunk_Intent = 1
Png_SrgbChunk_Intent__Saturation Png_SrgbChunk_Intent = 2
Png_SrgbChunk_Intent__AbsoluteColorimetric Png_SrgbChunk_Intent = 3
)
var values_Png_SrgbChunk_Intent = map[Png_SrgbChunk_Intent]struct{}{0: {}, 1: {}, 2: {}, 3: {}}
func (v Png_SrgbChunk_Intent) isDefined() bool {
_, ok := values_Png_SrgbChunk_Intent[v]
return ok
}
type Png_SrgbChunk struct {
RenderIntent Png_SrgbChunk_Intent
_io *kaitai.Stream
_root *Png
_parent *Png_Chunk
}
func NewPng_SrgbChunk() *Png_SrgbChunk {
return &Png_SrgbChunk{
}
}
func (this Png_SrgbChunk) IO_() *kaitai.Stream {
return this._io
}
func (this *Png_SrgbChunk) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp117, err := this._io.ReadU1()
if err != nil {
return err
}
this.RenderIntent = Png_SrgbChunk_Intent(tmp117)
return err
}
/**
* 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 <a href="https://www.w3.org/TR/png/#11tEXt">Source</a>
*/
type Png_TextChunk struct {
Keyword string
Text string
_io *kaitai.Stream
_root *Png
_parent *Png_Chunk
}
func NewPng_TextChunk() *Png_TextChunk {
return &Png_TextChunk{
}
}
func (this Png_TextChunk) IO_() *kaitai.Stream {
return this._io
}
func (this *Png_TextChunk) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp118, err := this._io.ReadBytesTerm(0, false, true, true)
if err != nil {
return err
}
tmp119, err := kaitai.BytesToStr(tmp118, charmap.ISO8859_1.NewDecoder())
if err != nil {
return err
}
this.Keyword = tmp119
tmp120, err := this._io.ReadBytesFull()
if err != nil {
return err
}
tmp120 = tmp120
tmp121, err := kaitai.BytesToStr(tmp120, charmap.ISO8859_1.NewDecoder())
if err != nil {
return err
}
this.Text = tmp121
return err
}
/**
* 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 <a href="https://www.w3.org/TR/png/#11tIME">Source</a>
*/
type Png_TimeChunk struct {
Year uint16
Month uint8
Day uint8
Hour uint8
Minute uint8
Second uint8
_io *kaitai.Stream
_root *Png
_parent *Png_Chunk
}
func NewPng_TimeChunk() *Png_TimeChunk {
return &Png_TimeChunk{
}
}
func (this Png_TimeChunk) IO_() *kaitai.Stream {
return this._io
}
func (this *Png_TimeChunk) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp122, err := this._io.ReadU2be()
if err != nil {
return err
}
this.Year = uint16(tmp122)
tmp123, err := this._io.ReadU1()
if err != nil {
return err
}
this.Month = tmp123
tmp124, err := this._io.ReadU1()
if err != nil {
return err
}
this.Day = tmp124
tmp125, err := this._io.ReadU1()
if err != nil {
return err
}
this.Hour = tmp125
tmp126, err := this._io.ReadU1()
if err != nil {
return err
}
this.Minute = tmp126
tmp127, err := this._io.ReadU1()
if err != nil {
return err
}
this.Second = tmp127
return err
}