PNG (Portable Network Graphics) file: Go parsing library

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.

Go source code to parse PNG (Portable Network Graphics) file

png.go

// 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"
	"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_PhysUnit int
const (
	Png_PhysUnit__Unknown Png_PhysUnit = 0
	Png_PhysUnit__Meter Png_PhysUnit = 1
)

type Png_BlendOpValues int
const (
	Png_BlendOpValues__Source Png_BlendOpValues = 0
	Png_BlendOpValues__Over Png_BlendOpValues = 1
)

type Png_CompressionMethods int
const (
	Png_CompressionMethods__Zlib Png_CompressionMethods = 0
)

type Png_DisposeOpValues int
const (
	Png_DisposeOpValues__None Png_DisposeOpValues = 0
	Png_DisposeOpValues__Background Png_DisposeOpValues = 1
	Png_DisposeOpValues__Previous Png_DisposeOpValues = 2
)

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
)
type Png struct {
	Magic []byte
	IhdrLen uint32
	IhdrType []byte
	Ihdr *Png_IhdrChunk
	IhdrCrc []byte
	Chunks []*Png_Chunk
	_io *kaitai.Stream
	_root *Png
	_parent interface{}
}
func NewPng() *Png {
	return &Png{
	}
}

func (this *Png) Read(io *kaitai.Stream, parent interface{}, 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
}
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) Read(io *kaitai.Stream, parent *Png_PlteChunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp8, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.R = tmp8
	tmp9, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.G = tmp9
	tmp10, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.B = tmp10
	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) Read(io *kaitai.Stream, parent *Png, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp11, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.Len = uint32(tmp11)
	tmp12, err := this._io.ReadBytes(int(4))
	if err != nil {
		return err
	}
	tmp12 = tmp12
	this.Type = string(tmp12)
	switch (this.Type) {
	case "iTXt":
		tmp13, err := this._io.ReadBytes(int(this.Len))
		if err != nil {
			return err
		}
		tmp13 = tmp13
		this._raw_Body = tmp13
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp14 := NewPng_InternationalTextChunk()
		err = tmp14.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp14
	case "gAMA":
		tmp15, err := this._io.ReadBytes(int(this.Len))
		if err != nil {
			return err
		}
		tmp15 = tmp15
		this._raw_Body = tmp15
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp16 := NewPng_GamaChunk()
		err = tmp16.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp16
	case "tIME":
		tmp17, err := this._io.ReadBytes(int(this.Len))
		if err != nil {
			return err
		}
		tmp17 = tmp17
		this._raw_Body = tmp17
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp18 := NewPng_TimeChunk()
		err = tmp18.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp18
	case "PLTE":
		tmp19, err := this._io.ReadBytes(int(this.Len))
		if err != nil {
			return err
		}
		tmp19 = tmp19
		this._raw_Body = tmp19
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp20 := NewPng_PlteChunk()
		err = tmp20.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp20
	case "bKGD":
		tmp21, err := this._io.ReadBytes(int(this.Len))
		if err != nil {
			return err
		}
		tmp21 = tmp21
		this._raw_Body = tmp21
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp22 := NewPng_BkgdChunk()
		err = tmp22.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp22
	case "pHYs":
		tmp23, err := this._io.ReadBytes(int(this.Len))
		if err != nil {
			return err
		}
		tmp23 = tmp23
		this._raw_Body = tmp23
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp24 := NewPng_PhysChunk()
		err = tmp24.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp24
	case "fdAT":
		tmp25, err := this._io.ReadBytes(int(this.Len))
		if err != nil {
			return err
		}
		tmp25 = tmp25
		this._raw_Body = tmp25
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp26 := NewPng_FrameDataChunk()
		err = tmp26.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp26
	case "tEXt":
		tmp27, err := this._io.ReadBytes(int(this.Len))
		if err != nil {
			return err
		}
		tmp27 = tmp27
		this._raw_Body = tmp27
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp28 := NewPng_TextChunk()
		err = tmp28.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp28
	case "cHRM":
		tmp29, err := this._io.ReadBytes(int(this.Len))
		if err != nil {
			return err
		}
		tmp29 = tmp29
		this._raw_Body = tmp29
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp30 := NewPng_ChrmChunk()
		err = tmp30.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp30
	case "acTL":
		tmp31, err := this._io.ReadBytes(int(this.Len))
		if err != nil {
			return err
		}
		tmp31 = tmp31
		this._raw_Body = tmp31
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp32 := NewPng_AnimationControlChunk()
		err = tmp32.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp32
	case "sRGB":
		tmp33, err := this._io.ReadBytes(int(this.Len))
		if err != nil {
			return err
		}
		tmp33 = tmp33
		this._raw_Body = tmp33
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp34 := NewPng_SrgbChunk()
		err = tmp34.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp34
	case "zTXt":
		tmp35, err := this._io.ReadBytes(int(this.Len))
		if err != nil {
			return err
		}
		tmp35 = tmp35
		this._raw_Body = tmp35
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp36 := NewPng_CompressedTextChunk()
		err = tmp36.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp36
	case "fcTL":
		tmp37, err := this._io.ReadBytes(int(this.Len))
		if err != nil {
			return err
		}
		tmp37 = tmp37
		this._raw_Body = tmp37
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp38 := NewPng_FrameControlChunk()
		err = tmp38.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp38
	default:
		tmp39, err := this._io.ReadBytes(int(this.Len))
		if err != nil {
			return err
		}
		tmp39 = tmp39
		this._raw_Body = tmp39
	}
	tmp40, err := this._io.ReadBytes(int(4))
	if err != nil {
		return err
	}
	tmp40 = tmp40
	this.Crc = tmp40
	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) Read(io *kaitai.Stream, parent *Png_BkgdChunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp41, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.PaletteIndex = tmp41
	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) Read(io *kaitai.Stream, parent *Png_ChrmChunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp42, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.XInt = uint32(tmp42)
	tmp43, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.YInt = uint32(tmp43)
	return err
}
func (this *Png_Point) X() (v float64, err error) {
	if (this._f_x) {
		return this.x, nil
	}
	this.x = float64((this.XInt / 100000.0))
	this._f_x = true
	return this.x, nil
}
func (this *Png_Point) Y() (v float64, err error) {
	if (this._f_y) {
		return this.y, nil
	}
	this.y = float64((this.YInt / 100000.0))
	this._f_y = true
	return this.y, nil
}

/**
 * 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) Read(io *kaitai.Stream, parent *Png_BkgdChunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp44, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.Value = uint16(tmp44)
	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) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp45 := NewPng_Point()
	err = tmp45.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.WhitePoint = tmp45
	tmp46 := NewPng_Point()
	err = tmp46.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.Red = tmp46
	tmp47 := NewPng_Point()
	err = tmp47.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.Green = tmp47
	tmp48 := NewPng_Point()
	err = tmp48.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.Blue = tmp48
	return err
}

/**
 * @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) Read(io *kaitai.Stream, parent *Png, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp49, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.Width = uint32(tmp49)
	tmp50, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.Height = uint32(tmp50)
	tmp51, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.BitDepth = tmp51
	tmp52, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.ColorType = Png_ColorType(tmp52)
	tmp53, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.CompressionMethod = tmp53
	tmp54, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.FilterMethod = tmp54
	tmp55, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.InterlaceMethod = tmp55
	return err
}

/**
 * @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) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	for i := 1;; i++ {
		tmp56, err := this._io.EOF()
		if err != nil {
			return err
		}
		if tmp56 {
			break
		}
		tmp57 := NewPng_Rgb()
		err = tmp57.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Entries = append(this.Entries, tmp57)
	}
	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
)
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) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp58, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.RenderIntent = Png_SrgbChunk_Intent(tmp58)
	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) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp59, err := this._io.ReadBytesTerm(0, false, true, true)
	if err != nil {
		return err
	}
	this.Keyword = string(tmp59)
	tmp60, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.CompressionMethod = Png_CompressionMethods(tmp60)
	tmp61, err := this._io.ReadBytesFull()
	if err != nil {
		return err
	}
	tmp61 = tmp61
	this._raw_TextDatastream = tmp61
	tmp62, err := kaitai.ProcessZlib(this._raw_TextDatastream)
	if err != nil {
		return err
	}
	this.TextDatastream = tmp62
	return err
}

/**
 * Indicates purpose of the following text data.
 */

/**
 * @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) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp63, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.SequenceNumber = uint32(tmp63)
	tmp64, err := this._io.ReadBytesFull()
	if err != nil {
		return err
	}
	tmp64 = tmp64
	this.FrameData = tmp64
	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.
 */

/**
 * 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) Read(io *kaitai.Stream, parent *Png_BkgdChunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp65, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.Red = uint16(tmp65)
	tmp66, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.Green = uint16(tmp66)
	tmp67, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.Blue = uint16(tmp67)
	return err
}

/**
 * @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) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp68, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.GammaInt = uint32(tmp68)
	return err
}
func (this *Png_GamaChunk) GammaRatio() (v float64, err error) {
	if (this._f_gammaRatio) {
		return this.gammaRatio, nil
	}
	this.gammaRatio = float64((100000.0 / this.GammaInt))
	this._f_gammaRatio = true
	return this.gammaRatio, nil
}

/**
 * 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 interface{}
	_io *kaitai.Stream
	_root *Png
	_parent *Png_Chunk
}
func NewPng_BkgdChunk() *Png_BkgdChunk {
	return &Png_BkgdChunk{
	}
}

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__Indexed:
		tmp69 := NewPng_BkgdIndexed()
		err = tmp69.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Bkgd = tmp69
	case Png_ColorType__TruecolorAlpha:
		tmp70 := NewPng_BkgdTruecolor()
		err = tmp70.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Bkgd = tmp70
	case Png_ColorType__GreyscaleAlpha:
		tmp71 := NewPng_BkgdGreyscale()
		err = tmp71.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Bkgd = tmp71
	case Png_ColorType__Truecolor:
		tmp72 := NewPng_BkgdTruecolor()
		err = tmp72.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Bkgd = tmp72
	case Png_ColorType__Greyscale:
		tmp73 := NewPng_BkgdGreyscale()
		err = tmp73.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Bkgd = tmp73
	}
	return err
}

/**
 * "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) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp74, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.PixelsPerUnitX = uint32(tmp74)
	tmp75, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.PixelsPerUnitY = uint32(tmp75)
	tmp76, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Unit = Png_PhysUnit(tmp76)
	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://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) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp77, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.SequenceNumber = uint32(tmp77)
	tmp78, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.Width = uint32(tmp78)
	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")
	}
	tmp79, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.Height = uint32(tmp79)
	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")
	}
	tmp80, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.XOffset = uint32(tmp80)
	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")
	}
	tmp81, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.YOffset = uint32(tmp81)
	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")
	}
	tmp82, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.DelayNum = uint16(tmp82)
	tmp83, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.DelayDen = uint16(tmp83)
	tmp84, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.DisposeOp = Png_DisposeOpValues(tmp84)
	tmp85, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.BlendOp = Png_BlendOpValues(tmp85)
	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
	}
	var tmp86 float64;
	if (this.DelayDen == 0) {
		tmp86 = 100.0
	} else {
		tmp86 = this.DelayDen
	}
	this.delay = float64((this.DelayNum / tmp86))
	this._f_delay = true
	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
 */

/**
 * 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) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp87, err := this._io.ReadBytesTerm(0, false, true, true)
	if err != nil {
		return err
	}
	this.Keyword = string(tmp87)
	tmp88, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.CompressionFlag = tmp88
	tmp89, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.CompressionMethod = Png_CompressionMethods(tmp89)
	tmp90, err := this._io.ReadBytesTerm(0, false, true, true)
	if err != nil {
		return err
	}
	this.LanguageTag = string(tmp90)
	tmp91, err := this._io.ReadBytesTerm(0, false, true, true)
	if err != nil {
		return err
	}
	this.TranslatedKeyword = string(tmp91)
	tmp92, err := this._io.ReadBytesFull()
	if err != nil {
		return err
	}
	tmp92 = tmp92
	this.Text = string(tmp92)
	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.
 */

/**
 * 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) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp93, err := this._io.ReadBytesTerm(0, false, true, true)
	if err != nil {
		return err
	}
	tmp94, err := kaitai.BytesToStr(tmp93, charmap.ISO8859_1.NewDecoder())
	if err != nil {
		return err
	}
	this.Keyword = tmp94
	tmp95, err := this._io.ReadBytesFull()
	if err != nil {
		return err
	}
	tmp95 = tmp95
	tmp96, err := kaitai.BytesToStr(tmp95, charmap.ISO8859_1.NewDecoder())
	if err != nil {
		return err
	}
	this.Text = tmp96
	return err
}

/**
 * Indicates purpose of the following text data.
 */

/**
 * @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) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp97, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.NumFrames = uint32(tmp97)
	tmp98, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.NumPlays = uint32(tmp98)
	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.
 */

/**
 * 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) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp99, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.Year = uint16(tmp99)
	tmp100, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Month = tmp100
	tmp101, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Day = tmp101
	tmp102, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Hour = tmp102
	tmp103, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Minute = tmp103
	tmp104, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Second = tmp104
	return err
}