PNG (Portable Network Graphics) file: Go parsing library

NOTICE: Many of the documentation comments (or docstrings) in this file were copied from or derived from the Portable Network Graphics (PNG) Specification (Third Edition). Copyright © 1996-2025 World Wide Web Consortium. https://www.w3.org/copyright/software-license-2023/

The full text of the license for the original W3C PNG specification is provided below:

Software and Document license - 2023 version

This work is being provided by the copyright holders under the following license.

License

By obtaining and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions.

Permission to copy, modify, and distribute this work, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the work or portions thereof, including modifications:

  • The full text of this NOTICE in a location viewable to users of the redistributed or derivative work.
  • Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none exist, the W3C software and document short notice should be included.
  • Notice of any changes or modifications, through a copyright statement on the new code or document such as "This software or document includes material copied from or derived from [title and URI of the W3C document]. Copyright © [$year-of-document] World Wide Web Consortium. https://www.w3.org/copyright/software-license-2023/"

Disclaimers

THIS WORK IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENT WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.

COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENT.

The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the work without specific, written prior permission. Title to copyright in this work will at all times remain with copyright holders.


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.

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"
	"unicode/utf8"
	"golang.org/x/text/encoding/charmap"
)


/**
 * NOTICE: Many of the documentation comments (or docstrings) in this file were
 * copied from or derived from the [Portable Network Graphics (PNG) Specification
 * (Third Edition)](https://www.w3.org/TR/2025/REC-png-3-20250624/).
 * Copyright © 1996-2025 [World Wide Web Consortium](https://www.w3.org/).
 * <https://www.w3.org/copyright/software-license-2023/>
 * 
 * The full text of the license for the original W3C PNG specification is
 * provided below:
 * 
 * > ## Software and Document license - 2023 version
 * >
 * > This work is being provided by the copyright holders under the following
 * > license.
 * >
 * > ### License
 * >
 * > By obtaining and/or copying this work, you (the licensee) agree that you
 * > have read, understood, and will comply with the following terms and
 * > conditions.
 * >
 * > Permission to copy, modify, and distribute this work, with or without
 * > modification, for any purpose and without fee or royalty is hereby granted,
 * > provided that you include the following on ALL copies of the work or
 * > portions thereof, including modifications:
 * >
 * > * The full text of this NOTICE in a location viewable to users of the
 * >   redistributed or derivative work.
 * > * Any pre-existing intellectual property disclaimers, notices, or terms and
 * >   conditions. If none exist, the [W3C software and document short
 * >   notice](https://www.w3.org/Consortium/Legal/2023/copyright-software-short-notice.html)
 * >   should be included.
 * > * Notice of any changes or modifications, through a copyright statement on
 * >   the new code or document such as "This software or document includes
 * >   material copied from or derived from [title and URI of the W3C document].
 * >   Copyright © [$year-of-document] [World Wide Web
 * >   Consortium](https://www.w3.org/).
 * >   <https://www.w3.org/copyright/software-license-2023/>"
 * >
 * > ### Disclaimers
 * >
 * > THIS WORK IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS
 * > OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES
 * > OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF
 * > THE SOFTWARE OR DOCUMENT WILL NOT INFRINGE ANY THIRD PARTY PATENTS,
 * > COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
 * >
 * > COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR
 * > CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENT.
 * >
 * > The name and trademarks of copyright holders may NOT be used in advertising
 * > or publicity pertaining to the work without specific, written prior
 * > permission. Title to copyright in this work will at all times remain with
 * > copyright holders.
 * 
 * ---
 * 
 * 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_FilterMethod int
const (
	Png_FilterMethod__Base Png_FilterMethod = 0
)
var values_Png_FilterMethod = map[Png_FilterMethod]struct{}{0: {}}
func (v Png_FilterMethod) isDefined() bool {
	_, ok := values_Png_FilterMethod[v]
	return ok
}

type Png_InterlaceMethod int
const (
	Png_InterlaceMethod__None Png_InterlaceMethod = 0
	Png_InterlaceMethod__Adam7 Png_InterlaceMethod = 1
)
var values_Png_InterlaceMethod = map[Png_InterlaceMethod]struct{}{0: {}, 1: {}}
func (v Png_InterlaceMethod) isDefined() bool {
	_, ok := values_Png_InterlaceMethod[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 uint32
	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.ReadU4be()
	if err != nil {
		return err
	}
	this.IhdrCrc = uint32(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 := _it.Type()
		if err != nil {
			return err
		}
		tmp8, err := this._io.EOF()
		if err != nil {
			return err
		}
		if  ((tmp7 == "IEND") || (tmp8))  {
			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

	tmp9, err := this._io.ReadBytesFull()
	if err != nil {
		return err
	}
	tmp9 = tmp9
	this._raw_PreviewData = tmp9
	tmp10, err := kaitai.ProcessZlib(this._raw_PreviewData)
	if err != nil {
		return err
	}
	this.PreviewData = tmp10
	return err
}

/**
 * @see <a href="https://www.w3.org/TR/png/#acTL-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

	tmp11, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.NumFrames = uint32(tmp11)
	tmp12, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.NumPlays = uint32(tmp12)
	return err
}

/**
 * Number of frames, must be equal to the number of `fcTL` chunks (i.e.
 * `frame_control_chunk` objects)
 */

/**
 * 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

	tmp13, err := this._io.ReadBytesTerm(0, false, true, true)
	if err != nil {
		return err
	}
	this.FileName = string(tmp13)
	{
		_it := this.FileName
		if !( ((utf8.RuneCountInString(_it) != 0) && (_it[0:1] != ".")) ) {
			return kaitai.NewValidationExprError(this.FileName, this._io, "/types/atch_chunk/seq/0")
		}
	}
	tmp14, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Compression = Png_AtchChunk_CompressionAttachMethods(tmp14)
	if !this.Compression.isDefined() {
		return kaitai.NewValidationNotInEnumError(this.Compression, this._io, "/types/atch_chunk/seq/1")
	}
	if (this.Compression == Png_AtchChunk_CompressionAttachMethods__None) {
		tmp15, err := this._io.ReadBytesFull()
		if err != nil {
			return err
		}
		tmp15 = tmp15
		this.DataPlain = tmp15
	}
	if (this.Compression == Png_AtchChunk_CompressionAttachMethods__Zlib) {
		tmp16, err := this._io.ReadBytesFull()
		if err != nil {
			return err
		}
		tmp16 = tmp16
		this._raw_DataZlib = tmp16
		tmp17, err := kaitai.ProcessZlib(this._raw_DataZlib)
		if err != nil {
			return err
		}
		this.DataZlib = tmp17
	}
	return err
}
func (this *Png_AtchChunk) Data() (v []byte, err error) {
	if (this._f_data) {
		return this.data, nil
	}
	this._f_data = true
	var tmp18 []byte;
	if (this.Compression == Png_AtchChunk_CompressionAttachMethods__None) {
		tmp18 = this.DataPlain
	} else {
		tmp18 = this.DataZlib
	}
	this.data = []byte(tmp18)
	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:
		tmp19 := NewPng_BkgdGreyscale()
		err = tmp19.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Bkgd = tmp19
	case Png_ColorType__GreyscaleAlpha:
		tmp20 := NewPng_BkgdGreyscale()
		err = tmp20.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Bkgd = tmp20
	case Png_ColorType__Indexed:
		tmp21 := NewPng_BkgdIndexed()
		err = tmp21.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Bkgd = tmp21
	case Png_ColorType__Truecolor:
		tmp22 := NewPng_BkgdTruecolor()
		err = tmp22.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Bkgd = tmp22
	case Png_ColorType__TruecolorAlpha:
		tmp23 := NewPng_BkgdTruecolor()
		err = tmp23.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Bkgd = tmp23
	}
	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

	tmp24, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.Value = uint16(tmp24)
	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

	tmp25, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.PaletteIndex = tmp25
	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

	tmp26, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.Red = uint16(tmp26)
	tmp27, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.Green = uint16(tmp27)
	tmp28, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.Blue = uint16(tmp28)
	return err
}
type Png_ChrmChromaticity 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_ChrmChromaticity() *Png_ChrmChromaticity {
	return &Png_ChrmChromaticity{
	}
}

func (this Png_ChrmChromaticity) IO_() *kaitai.Stream {
	return this._io
}

func (this *Png_ChrmChromaticity) Read(io *kaitai.Stream, parent *Png_ChrmChunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp29, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.XInt = uint32(tmp29)
	tmp30, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.YInt = uint32(tmp30)
	return err
}
func (this *Png_ChrmChromaticity) 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_ChrmChromaticity) 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
}

/**
 * @see <a href="https://www.w3.org/TR/png/#11cHRM">Source</a>
 */
type Png_ChrmChunk struct {
	WhitePoint *Png_ChrmChromaticity
	Red *Png_ChrmChromaticity
	Green *Png_ChrmChromaticity
	Blue *Png_ChrmChromaticity
	_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

	tmp31 := NewPng_ChrmChromaticity()
	err = tmp31.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.WhitePoint = tmp31
	tmp32 := NewPng_ChrmChromaticity()
	err = tmp32.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.Red = tmp32
	tmp33 := NewPng_ChrmChromaticity()
	err = tmp33.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.Green = tmp33
	tmp34 := NewPng_ChrmChromaticity()
	err = tmp34.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.Blue = tmp34
	return err
}
type Png_Chunk struct {
	Len uint32
	TypeRaw []byte
	Body interface{}
	Crc uint32
	_io *kaitai.Stream
	_root *Png
	_parent *Png
	_raw_Body []byte
	_f_isAncillary bool
	isAncillary bool
	_f_isPrivate bool
	isPrivate bool
	_f_isSafeToCopy bool
	isSafeToCopy bool
	_f_reservedBit bool
	reservedBit bool
	_f_type bool
	type string
}
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

	tmp35, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.Len = uint32(tmp35)
	tmp36, err := this._io.ReadBytes(int(4))
	if err != nil {
		return err
	}
	tmp36 = tmp36
	this.TypeRaw = tmp36
	{
		_it := this.TypeRaw
		if !( (( (( ((_it[0] >= 65) && (_it[0] <= 90)) ) || ( ((_it[0] >= 97) && (_it[0] <= 122)) )) ) && ( (( ((_it[1] >= 65) && (_it[1] <= 90)) ) || ( ((_it[1] >= 97) && (_it[1] <= 122)) )) ) && ( (( ((_it[2] >= 65) && (_it[2] <= 90)) ) || ( ((_it[2] >= 97) && (_it[2] <= 122)) )) ) && ( (( ((_it[3] >= 65) && (_it[3] <= 90)) ) || ( ((_it[3] >= 97) && (_it[3] <= 122)) )) )) ) {
			return kaitai.NewValidationExprError(this.TypeRaw, this._io, "/types/chunk/seq/1")
		}
	}
	tmp37, err := this.Type()
	if err != nil {
		return err
	}
	switch (tmp37) {
	case "PLTE":
		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_PlteChunk()
		err = tmp39.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp39
	case "acTL":
		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_AnimationControlChunk()
		err = tmp41.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp41
	case "atCh":
		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_AtchChunk()
		err = tmp43.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp43
	case "bKGD":
		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_BkgdChunk()
		err = tmp45.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp45
	case "cHRM":
		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_ChrmChunk()
		err = tmp47.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp47
	case "cICP":
		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_CicpChunk()
		err = tmp49.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp49
	case "cLLI":
		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_ClliChunk()
		err = tmp51.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp51
	case "eXIf":
		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_ExifChunk()
		err = tmp53.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp53
	case "fcTL":
		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_FrameControlChunk()
		err = tmp55.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp55
	case "fdAT":
		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_FrameDataChunk()
		err = tmp57.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp57
	case "gAMA":
		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_GamaChunk()
		err = tmp59.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp59
	case "hIST":
		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_HistChunk()
		err = tmp61.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp61
	case "iCCP":
		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_IccpChunk()
		err = tmp63.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp63
	case "iTXt":
		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_InternationalTextChunk()
		err = tmp65.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp65
	case "mDCV":
		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_MdcvChunk()
		err = tmp67.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp67
	case "mkBS":
		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_AdobeFireworksChunk()
		err = tmp69.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp69
	case "mkTS":
		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_AdobeFireworksChunk()
		err = tmp71.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp71
	case "pHYs":
		tmp72, err := this._io.ReadBytes(int(this.Len))
		if err != nil {
			return err
		}
		tmp72 = tmp72
		this._raw_Body = tmp72
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp73 := NewPng_PhysChunk()
		err = tmp73.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp73
	case "prVW":
		tmp74, err := this._io.ReadBytes(int(this.Len))
		if err != nil {
			return err
		}
		tmp74 = tmp74
		this._raw_Body = tmp74
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp75 := NewPng_AdobeFireworksChunk()
		err = tmp75.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp75
	case "sBIT":
		tmp76, err := this._io.ReadBytes(int(this.Len))
		if err != nil {
			return err
		}
		tmp76 = tmp76
		this._raw_Body = tmp76
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp77 := NewPng_SbitChunk()
		err = tmp77.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp77
	case "sPLT":
		tmp78, err := this._io.ReadBytes(int(this.Len))
		if err != nil {
			return err
		}
		tmp78 = tmp78
		this._raw_Body = tmp78
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp79 := NewPng_SpltChunk()
		err = tmp79.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp79
	case "sRGB":
		tmp80, err := this._io.ReadBytes(int(this.Len))
		if err != nil {
			return err
		}
		tmp80 = tmp80
		this._raw_Body = tmp80
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp81 := NewPng_SrgbChunk()
		err = tmp81.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp81
	case "skMf":
		tmp82, err := this._io.ReadBytes(int(this.Len))
		if err != nil {
			return err
		}
		tmp82 = tmp82
		this._raw_Body = tmp82
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp83 := NewPng_EvernoteSkmfChunk()
		err = tmp83.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp83
	case "skRf":
		tmp84, err := this._io.ReadBytes(int(this.Len))
		if err != nil {
			return err
		}
		tmp84 = tmp84
		this._raw_Body = tmp84
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp85 := NewPng_EvernoteSkrfChunk()
		err = tmp85.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp85
	case "tEXt":
		tmp86, err := this._io.ReadBytes(int(this.Len))
		if err != nil {
			return err
		}
		tmp86 = tmp86
		this._raw_Body = tmp86
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp87 := NewPng_TextChunk()
		err = tmp87.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp87
	case "tIME":
		tmp88, err := this._io.ReadBytes(int(this.Len))
		if err != nil {
			return err
		}
		tmp88 = tmp88
		this._raw_Body = tmp88
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp89 := NewPng_TimeChunk()
		err = tmp89.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp89
	case "tRNS":
		tmp90, err := this._io.ReadBytes(int(this.Len))
		if err != nil {
			return err
		}
		tmp90 = tmp90
		this._raw_Body = tmp90
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp91 := NewPng_TrnsChunk()
		err = tmp91.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp91
	case "zTXt":
		tmp92, err := this._io.ReadBytes(int(this.Len))
		if err != nil {
			return err
		}
		tmp92 = tmp92
		this._raw_Body = tmp92
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp93 := NewPng_CompressedTextChunk()
		err = tmp93.Read(_io__raw_Body, this, this._root)
		if err != nil {
			return err
		}
		this.Body = tmp93
	default:
		tmp94, err := this._io.ReadBytes(int(this.Len))
		if err != nil {
			return err
		}
		tmp94 = tmp94
		this._raw_Body = tmp94
	}
	tmp95, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.Crc = uint32(tmp95)
	return err
}

/**
 * false = critical chunk, true = ancillary chunk
 */
func (this *Png_Chunk) IsAncillary() (v bool, err error) {
	if (this._f_isAncillary) {
		return this.isAncillary, nil
	}
	this._f_isAncillary = true
	this.isAncillary = bool(this.TypeRaw[0] & 32 != 0)
	return this.isAncillary, nil
}

/**
 * false = public chunk (defined by the W3C), true = private chunk (can
 * be defined by anyone)
 */
func (this *Png_Chunk) IsPrivate() (v bool, err error) {
	if (this._f_isPrivate) {
		return this.isPrivate, nil
	}
	this._f_isPrivate = true
	this.isPrivate = bool(this.TypeRaw[1] & 32 != 0)
	return this.isPrivate, nil
}

/**
 * Defines whether the chunk may be copied if the image data (i.e.
 * pixels) is modified. This tells PNG editors how to handle unknown
 * chunks - see section [14.2 Behavior of PNG
 * editors](https://www.w3.org/TR/2025/REC-png-3-20250624/#14Ordering) in
 * the official specification.
 */
func (this *Png_Chunk) IsSafeToCopy() (v bool, err error) {
	if (this._f_isSafeToCopy) {
		return this.isSafeToCopy, nil
	}
	this._f_isSafeToCopy = true
	this.isSafeToCopy = bool(this.TypeRaw[3] & 32 != 0)
	return this.isSafeToCopy, nil
}

/**
 * Should be `false`, i.e. all chunk types should have uppercase third
 * letters (the lowercase third letter is reserved for possible future
 * extensions to the PNG standard)
 */
func (this *Png_Chunk) ReservedBit() (v bool, err error) {
	if (this._f_reservedBit) {
		return this.reservedBit, nil
	}
	this._f_reservedBit = true
	this.reservedBit = bool(this.TypeRaw[2] & 32 != 0)
	return this.reservedBit, nil
}
func (this *Png_Chunk) Type() (v string, err error) {
	if (this._f_type) {
		return this.type, nil
	}
	this._f_type = true
	this.type = string(string(this.TypeRaw))
	return this.type, nil
}

/**
 * Each byte of a chunk type is restricted to the hexadecimal values
 * 0x41..0x5a and 0x61..0x7a, i.e. uppercase and lowercase ASCII letters
 * (`A-Z` and `a-z`).
 * @see <a href="https://www.w3.org/TR/2025/REC-png-3-20250624/#table51">Source</a>
 */

/**
 * @see <a href="https://www.w3.org/TR/png/#cICP-chunk">Source</a>
 * @see <a href="https://w3c.github.io/png/Implementation_Report_3e/#cicp">Source</a>
 */
type Png_CicpChunk struct {
	ColorPrimaries uint8
	TransferFunction uint8
	MatrixCoefficients uint8
	VideoFullRangeFlag uint8
	_io *kaitai.Stream
	_root *Png
	_parent *Png_Chunk
}
func NewPng_CicpChunk() *Png_CicpChunk {
	return &Png_CicpChunk{
	}
}

func (this Png_CicpChunk) IO_() *kaitai.Stream {
	return this._io
}

func (this *Png_CicpChunk) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp96, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.ColorPrimaries = tmp96
	tmp97, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.TransferFunction = tmp97
	tmp98, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.MatrixCoefficients = tmp98
	if !(this.MatrixCoefficients == 0) {
		return kaitai.NewValidationNotEqualError(0, this.MatrixCoefficients, this._io, "/types/cicp_chunk/seq/2")
	}
	tmp99, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.VideoFullRangeFlag = tmp99
	if !( ((this.VideoFullRangeFlag == 0) || (this.VideoFullRangeFlag == 1)) ) {
		return kaitai.NewValidationNotAnyOfError(this.VideoFullRangeFlag, this._io, "/types/cicp_chunk/seq/3")
	}
	return err
}

/**
 * values above 22 are reserved, see
 * <https://github.com/pnggroup/pngcheck/blob/bd33ad6490269df07cac81e5305f4ebf56c2b637/pngcheck.c#L3322-L3325>
 */

/**
 * values above 18 are reserved, see
 * <https://github.com/pnggroup/pngcheck/blob/bd33ad6490269df07cac81e5305f4ebf56c2b637/pngcheck.c#L3326-L3329>
 */

/**
 * From the [official
 * specification](https://www.w3.org/TR/2025/REC-png-3-20250624/#cICP-chunk):
 * 
 * > RGB is currently the only supported color model in PNG, and as such
 * > `Matrix Coefficients` shall be set to `0`.
 */

/**
 * From the [official
 * specification](https://www.w3.org/TR/2025/REC-png-3-20250624/#cICP-chunk):
 * 
 * > If `Video Full Range Flag` value is `1`, then the image is a
 * > full-range image. Typically, images in the RGB color representation
 * > are stored in the full-range signal quantization, therefore the vast
 * > majority of computer graphics and web images, including those used
 * > in traditional PNG workflows, are full-range images.
 * 
 * > If `Video Full Range Flag` value is `0`, then the image is a
 * > narrow-range image.
 */

/**
 * @see <a href="https://www.w3.org/TR/png/#cLLI-chunk">Source</a>
 * @see <a href="https://w3c.github.io/png/Implementation_Report_3e/#light">Source</a>
 */
type Png_ClliChunk struct {
	MaxContentLightLevelInt uint32
	MaxFrameAverageLightLevelInt uint32
	_io *kaitai.Stream
	_root *Png
	_parent *Png_Chunk
	_f_maxContentLightLevel bool
	maxContentLightLevel float64
	_f_maxFrameAverageLightLevel bool
	maxFrameAverageLightLevel float64
}
func NewPng_ClliChunk() *Png_ClliChunk {
	return &Png_ClliChunk{
	}
}

func (this Png_ClliChunk) IO_() *kaitai.Stream {
	return this._io
}

func (this *Png_ClliChunk) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp100, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.MaxContentLightLevelInt = uint32(tmp100)
	tmp101, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.MaxFrameAverageLightLevelInt = uint32(tmp101)
	return err
}

/**
 * Maximum Content Light Level (MaxCLL), in cd/m^2
 */
func (this *Png_ClliChunk) MaxContentLightLevel() (v float64, err error) {
	if (this._f_maxContentLightLevel) {
		return this.maxContentLightLevel, nil
	}
	this._f_maxContentLightLevel = true
	this.maxContentLightLevel = float64(this.MaxContentLightLevelInt * 0.0001)
	return this.maxContentLightLevel, nil
}

/**
 * Maximum Frame Average Light Level (MaxFALL), in cd/m^2
 */
func (this *Png_ClliChunk) MaxFrameAverageLightLevel() (v float64, err error) {
	if (this._f_maxFrameAverageLightLevel) {
		return this.maxFrameAverageLightLevel, nil
	}
	this._f_maxFrameAverageLightLevel = true
	this.maxFrameAverageLightLevel = float64(this.MaxFrameAverageLightLevelInt * 0.0001)
	return this.maxFrameAverageLightLevel, nil
}
type Png_CompressedText struct {
	Value string
	_io *kaitai.Stream
	_root *Png
	_parent *Png_CompressedTextChunk
}
func NewPng_CompressedText() *Png_CompressedText {
	return &Png_CompressedText{
	}
}

func (this Png_CompressedText) IO_() *kaitai.Stream {
	return this._io
}

func (this *Png_CompressedText) Read(io *kaitai.Stream, parent *Png_CompressedTextChunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp102, err := this._io.ReadBytesFull()
	if err != nil {
		return err
	}
	tmp102 = tmp102
	tmp103, err := kaitai.BytesToStr(tmp102, charmap.ISO8859_1.NewDecoder())
	if err != nil {
		return err
	}
	this.Value = tmp103
	return err
}

/**
 * Text string (the "value" of this key-value pair).
 * 
 * Although it is not null-terminated (unlike the keyword), it must not
 * contain a zero byte (U+0000 NULL character). A newline should be
 * represented by a single U+000A LINE FEED (LF) character (aka `\n`).
 * The remaining control characters (U+0001..U+0009, U+000B..0+001F,
 * U+007F..U+009F) are discouraged.
 */

/**
 * Compressed textual data (`zTXt`) chunk effectively allows you to store
 * key-value string pairs in the PNG container, compressing the "value" part
 * (which can be quite lengthy) with zlib compression.
 * 
 * The `zTXt` and `tEXt` chunks are semantically equivalent, but the `zTXt`
 * chunk is recommended for storing large blocks of text.
 * @see <a href="https://www.w3.org/TR/png/#11zTXt">Source</a>
 */
type Png_CompressedTextChunk struct {
	Keyword string
	CompressionMethod Png_CompressionMethods
	Text *Png_CompressedText
	_io *kaitai.Stream
	_root *Png
	_parent *Png_Chunk
	_raw_Text []byte
	_raw__raw_Text []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

	tmp104, err := this._io.ReadBytesTerm(0, false, true, true)
	if err != nil {
		return err
	}
	tmp105, err := kaitai.BytesToStr(tmp104, charmap.ISO8859_1.NewDecoder())
	if err != nil {
		return err
	}
	this.Keyword = tmp105
	tmp106, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.CompressionMethod = Png_CompressionMethods(tmp106)
	if !(this.CompressionMethod == Png_CompressionMethods__Zlib) {
		return kaitai.NewValidationNotEqualError(Png_CompressionMethods__Zlib, this.CompressionMethod, this._io, "/types/compressed_text_chunk/seq/1")
	}
	tmp107, err := this._io.ReadBytesFull()
	if err != nil {
		return err
	}
	tmp107 = tmp107
	this._raw__raw_Text = tmp107
	tmp108, err := kaitai.ProcessZlib(this._raw__raw_Text)
	if err != nil {
		return err
	}
	this._raw_Text = tmp108
	_io__raw_Text := kaitai.NewStream(bytes.NewReader(this._raw_Text))
	tmp109 := NewPng_CompressedText()
	err = tmp109.Read(_io__raw_Text, this, this._root)
	if err != nil {
		return err
	}
	this.Text = tmp109
	return err
}

/**
 * Indicates the type of information represented by the text string.
 * 
 * Keywords must consist exclusively of printable ISO-8859-1 (Latin-1)
 * characters and spaces; that is, only code points 0x20-0x7E and
 * 0xA1-0xFF are allowed. To reduce the chances for human misreading of a
 * keyword, leading spaces, trailing spaces, and consecutive spaces are
 * not permitted.
 * @see <a href="https://www.w3.org/TR/2025/REC-png-3-20250624/#11keywords">Source</a>
 */

/**
 * @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

	tmp110, err := this._io.ReadBytesFull()
	if err != nil {
		return err
	}
	tmp110 = tmp110
	this.Json = string(tmp110)
	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

	tmp111, err := this._io.ReadBytes(int(16))
	if err != nil {
		return err
	}
	tmp111 = tmp111
	this.Uuid = tmp111
	tmp112, err := this._io.ReadBytesFull()
	if err != nil {
		return err
	}
	tmp112 = tmp112
	this.OrigImg = tmp112
	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.
 */

/**
 * Exchangeable Image File (Exif) Profile (`eXIf`) chunk.
 * 
 * Only one `eXIf` chunk is allowed in a PNG datastream.
 * 
 * The `eXIf` chunk contains metadata concerning the original image data. If
 * the image has been edited subsequent to creation of the Exif profile, this
 * data might no longer apply to the PNG image data.
 * @see <a href="https://www.w3.org/TR/png/#eXIf">Source</a>
 */
type Png_ExifChunk struct {
	Exif *Exif
	_io *kaitai.Stream
	_root *Png
	_parent *Png_Chunk
}
func NewPng_ExifChunk() *Png_ExifChunk {
	return &Png_ExifChunk{
	}
}

func (this Png_ExifChunk) IO_() *kaitai.Stream {
	return this._io
}

func (this *Png_ExifChunk) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp113 := NewExif()
	err = tmp113.Read(this._io, nil, nil)
	if err != nil {
		return err
	}
	this.Exif = tmp113
	return err
}

/**
 * @see <a href="https://www.w3.org/TR/png/#fcTL-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

	tmp114, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.SequenceNumber = uint32(tmp114)
	tmp115, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.Width = uint32(tmp115)
	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")
	}
	tmp116, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.Height = uint32(tmp116)
	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")
	}
	tmp117, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.XOffset = uint32(tmp117)
	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")
	}
	tmp118, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.YOffset = uint32(tmp118)
	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")
	}
	tmp119, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.DelayNum = uint16(tmp119)
	tmp120, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.DelayDen = uint16(tmp120)
	tmp121, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.DisposeOp = Png_DisposeOpValues(tmp121)
	if !this.DisposeOp.isDefined() {
		return kaitai.NewValidationNotInEnumError(this.DisposeOp, this._io, "/types/frame_control_chunk/seq/7")
	}
	tmp122, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.BlendOp = Png_BlendOpValues(tmp122)
	if !this.BlendOp.isDefined() {
		return kaitai.NewValidationNotInEnumError(this.BlendOp, this._io, "/types/frame_control_chunk/seq/8")
	}
	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 tmp123 float64;
	if (this.DelayDen == 0) {
		tmp123 = 100.0
	} else {
		tmp123 = this.DelayDen
	}
	this.delay = float64(this.DelayNum / tmp123)
	return this.delay, nil
}

/**
 * Sequence number of the animation chunk, starting from 0.
 * 
 * The `fcTL` and `fdAT` chunks have a 4-byte sequence number. Both chunk
 * types share the sequence. The purpose of this number is to detect (and
 * optionally correct) sequence errors in an Animated PNG, since the PNG
 * specification does not impose ordering restrictions on ancillary
 * chunks (which means that a PNG editor is technically allowed to
 * reorder them arbitrarily, see [14.2 Behavior of PNG
 * editors](https://www.w3.org/TR/png/#14Ordering) in the spec).
 * 
 * The first `fcTL` chunk must contain sequence number 0, and the
 * sequence numbers in the remaining `fcTL` and `fdAT` chunks must be in
 * ascending order, with no gaps or duplicates.
 */

/**
 * 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://www.w3.org/TR/png/#fdAT-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

	tmp124, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.SequenceNumber = uint32(tmp124)
	tmp125, err := this._io.ReadBytesFull()
	if err != nil {
		return err
	}
	tmp125 = tmp125
	this.FrameData = tmp125
	return err
}

/**
 * Sequence number of the animation chunk, starting from 0.
 * 
 * The `fcTL` and `fdAT` chunks have a 4-byte sequence number. Both chunk
 * types share the sequence. The purpose of this number is to detect (and
 * optionally correct) sequence errors in an Animated PNG, since the PNG
 * specification does not impose ordering restrictions on ancillary
 * chunks (which means that a PNG editor is technically allowed to
 * reorder them arbitrarily, see [14.2 Behavior of PNG
 * editors](https://www.w3.org/TR/png/#14Ordering) in the spec).
 * 
 * The first `fcTL` chunk must contain sequence number 0, and the
 * sequence numbers in the remaining `fcTL` and `fdAT` chunks must be in
 * ascending order, with no gaps or duplicates.
 */

/**
 * Frame data for the frame. At least one `fdAT` chunk is required for
 * each frame, except for the first frame, if that frame is represented
 * by an `IDAT` chunk. The compressed datastream for each frame 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_gamma bool
	gamma float64
	_f_invGamma bool
	invGamma 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

	tmp126, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.GammaInt = uint32(tmp126)
	{
		_it := this.GammaInt
		if !(_it != 0) {
			return kaitai.NewValidationExprError(this.GammaInt, this._io, "/types/gama_chunk/seq/0")
		}
	}
	return err
}

/**
 * Image gamma, typically 0.45455 = 1/2.2
 */
func (this *Png_GamaChunk) Gamma() (v float64, err error) {
	if (this._f_gamma) {
		return this.gamma, nil
	}
	this._f_gamma = true
	this.gamma = float64(this.GammaInt / 100000.0)
	return this.gamma, nil
}

/**
 * Inverse of the image gamma (1 / gamma), typically 2.2 (not considering
 * rounding)
 */
func (this *Png_GamaChunk) InvGamma() (v float64, err error) {
	if (this._f_invGamma) {
		return this.invGamma, nil
	}
	this._f_invGamma = true
	this.invGamma = float64(100000.0 / this.GammaInt)
	return this.invGamma, nil
}

/**
 * Image gamma multiplied by 100000 (a gamma value of 1/2.2 is stored as
 * 45455)
 */

/**
 * Image histogram (`hIST`) chunk gives the approximate usage frequency of
 * each color in the palette. A histogram chunk can appear only when a `PLTE`
 * chunk appears.
 * @see <a href="https://www.w3.org/TR/png/#11hIST">Source</a>
 */
type Png_HistChunk struct {
	UsageFreqs []uint16
	_io *kaitai.Stream
	_root *Png
	_parent *Png_Chunk
}
func NewPng_HistChunk() *Png_HistChunk {
	return &Png_HistChunk{
	}
}

func (this Png_HistChunk) IO_() *kaitai.Stream {
	return this._io
}

func (this *Png_HistChunk) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	for i := 0;; i++ {
		tmp127, err := this._io.EOF()
		if err != nil {
			return err
		}
		if tmp127 {
			break
		}
		tmp128, err := this._io.ReadU2be()
		if err != nil {
			return err
		}
		this.UsageFreqs = append(this.UsageFreqs, tmp128)
	}
	return err
}

/**
 * Usage frequencies of each color in the palette.
 * 
 * There must be exactly one entry for each entry in the `PLTE` chunk. Each
 * entry is proportional to the fraction of pixels in the image that have
 * that palette index; the exact scale factor is chosen by the encoder.
 * 
 * Histogram entries are approximate, with the exception that a zero
 * entry specifies that the corresponding palette entry is not used at
 * all in the image. A histogram entry must be nonzero if there are any
 * pixels of that color.
 */

/**
 * Embedded ICC profile (`iCCP`) chunk.
 * 
 * If the `iCCP` chunk is present, the image samples conform to the color
 * space represented by the embedded ICC profile as defined by the
 * International Color Consortium.
 * 
 * This chunk is ignored unless it is the [highest-precedence color
 * chunk](https://www.w3.org/TR/png/#color-chunk-precendence) understood by
 * the decoder. Unless a `cICP` chunk exists, a PNG datastream should contain
 * at most one embedded profile, whether specified explicitly with an `iCCP`
 * or implicitly with an `sRGB` chunk.
 * 
 * It is recommended that the `sRGB` and `iCCP` chunks do not appear
 * simultaneously in a PNG datastream.
 * @see <a href="https://www.w3.org/TR/png/#11iCCP">Source</a>
 */
type Png_IccpChunk struct {
	ProfileName string
	CompressionMethod Png_CompressionMethods
	Profile *Icc4
	_io *kaitai.Stream
	_root *Png
	_parent *Png_Chunk
	_raw_Profile []byte
	_raw__raw_Profile []byte
}
func NewPng_IccpChunk() *Png_IccpChunk {
	return &Png_IccpChunk{
	}
}

func (this Png_IccpChunk) IO_() *kaitai.Stream {
	return this._io
}

func (this *Png_IccpChunk) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp129, err := this._io.ReadBytesTerm(0, false, true, true)
	if err != nil {
		return err
	}
	tmp130, err := kaitai.BytesToStr(tmp129, charmap.ISO8859_1.NewDecoder())
	if err != nil {
		return err
	}
	this.ProfileName = tmp130
	tmp131, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.CompressionMethod = Png_CompressionMethods(tmp131)
	if !(this.CompressionMethod == Png_CompressionMethods__Zlib) {
		return kaitai.NewValidationNotEqualError(Png_CompressionMethods__Zlib, this.CompressionMethod, this._io, "/types/iccp_chunk/seq/1")
	}
	tmp132, err := this._io.ReadBytesFull()
	if err != nil {
		return err
	}
	tmp132 = tmp132
	this._raw__raw_Profile = tmp132
	tmp133, err := kaitai.ProcessZlib(this._raw__raw_Profile)
	if err != nil {
		return err
	}
	this._raw_Profile = tmp133
	_io__raw_Profile := kaitai.NewStream(bytes.NewReader(this._raw_Profile))
	tmp134 := NewIcc4()
	err = tmp134.Read(_io__raw_Profile, nil, nil)
	if err != nil {
		return err
	}
	this.Profile = tmp134
	return err
}

/**
 * Any convenient name for referring to the profile. It is
 * case-sensitive.
 * 
 * Profile names must contain only printable ISO-8859-1 (Latin-1)
 * characters and spaces; that is, only code points 0x20-0x7E and
 * 0xA1-0xFF are allowed. Leading, trailing, and consecutive spaces are
 * not permitted.
 */

/**
 * Embedded ICC profile.
 * 
 * The color space of the ICC profile must be:
 * 
 * * an RGB color space for color images (color types
 *   `color_type::truecolor` = 2, `color_type::indexed` = 3, and
 *   `color_type::truecolor_alpha` = 6), or
 * * a greyscale color space for greyscale images (color types
 *   `color_type::greyscale` = 0 and `color_type::greyscale_alpha` = 4).
 * 
 * Note that the imported `icc_4.ksy` spec currently in use here supports
 * only the ICC.1 v4 specification (as the name suggests), not ICC.1 v2.
 * This means that PNG files with an embedded v2 profile (for example
 * https://github.com/web-platform-tests/wpt/blob/495d9d7716298588ff49d6e701bf27c5134bde06/css/css-color/support/swap-990000-iCCP.png)
 * will fail to parse.
 * 
 * TODO: extend `icc_4.ksy` to support both v4 and v2 profiles, rename it
 * to `icc.ksy`, and use it here.
 */

/**
 * @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 Png_CompressionMethods
	FilterMethod Png_FilterMethod
	InterlaceMethod Png_InterlaceMethod
	_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

	tmp135, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.Width = uint32(tmp135)
	if !(this.Width >= 1) {
		return kaitai.NewValidationLessThanError(1, this.Width, this._io, "/types/ihdr_chunk/seq/0")
	}
	tmp136, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.Height = uint32(tmp136)
	if !(this.Height >= 1) {
		return kaitai.NewValidationLessThanError(1, this.Height, this._io, "/types/ihdr_chunk/seq/1")
	}
	tmp137, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.BitDepth = tmp137
	if !( ((this.BitDepth == 1) || (this.BitDepth == 2) || (this.BitDepth == 4) || (this.BitDepth == 8) || (this.BitDepth == 16)) ) {
		return kaitai.NewValidationNotAnyOfError(this.BitDepth, this._io, "/types/ihdr_chunk/seq/2")
	}
	tmp138, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.ColorType = Png_ColorType(tmp138)
	if !this.ColorType.isDefined() {
		return kaitai.NewValidationNotInEnumError(this.ColorType, this._io, "/types/ihdr_chunk/seq/3")
	}
	tmp139, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.CompressionMethod = Png_CompressionMethods(tmp139)
	if !this.CompressionMethod.isDefined() {
		return kaitai.NewValidationNotInEnumError(this.CompressionMethod, this._io, "/types/ihdr_chunk/seq/4")
	}
	tmp140, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.FilterMethod = Png_FilterMethod(tmp140)
	if !this.FilterMethod.isDefined() {
		return kaitai.NewValidationNotInEnumError(this.FilterMethod, this._io, "/types/ihdr_chunk/seq/5")
	}
	tmp141, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.InterlaceMethod = Png_InterlaceMethod(tmp141)
	if !this.InterlaceMethod.isDefined() {
		return kaitai.NewValidationNotInEnumError(this.InterlaceMethod, this._io, "/types/ihdr_chunk/seq/6")
	}
	return err
}
type Png_InternationalText struct {
	Value string
	_io *kaitai.Stream
	_root *Png
	_parent *Png_InternationalTextChunk
}
func NewPng_InternationalText() *Png_InternationalText {
	return &Png_InternationalText{
	}
}

func (this Png_InternationalText) IO_() *kaitai.Stream {
	return this._io
}

func (this *Png_InternationalText) Read(io *kaitai.Stream, parent *Png_InternationalTextChunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp142, err := this._io.ReadBytesFull()
	if err != nil {
		return err
	}
	tmp142 = tmp142
	this.Value = string(tmp142)
	return err
}

/**
 * Text string (the "value" of this key-value pair), written in language
 * specified in `_parent.language_tag`.
 * 
 * Although it is not null-terminated (unlike other textual data in the
 * `iTXt` chunk), it must not contain a zero byte
 * (U+0000 NULL character). A newline should be represented by a single
 * U+000A LINE FEED (LF) character (aka `\n`). The remaining control
 * characters (U+0001..U+0009, U+000B..0+001F, U+007F..U+009F) are
 * discouraged.
 */

/**
 * International textual data (`iTXt`) chunk effectively allows you to store
 * key-value string pairs in the PNG container.
 * 
 * The "key" part (`keyword`) is restricted to printable ISO-8859-1 (Latin-1)
 * characters and spaces. The translated keyword and the "value" part
 * (`text`) are stored in UTF-8 and thus can store text in any language -
 * this language can be indicated via the language tag (`language_tag`).
 * @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
	TextPlain *Png_InternationalText
	TextZlib *Png_InternationalText
	_io *kaitai.Stream
	_root *Png
	_parent *Png_Chunk
	_raw_TextPlain []byte
	_raw_TextZlib []byte
	_raw__raw_TextZlib []byte
	_f_text bool
	text string
}
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

	tmp143, err := this._io.ReadBytesTerm(0, false, true, true)
	if err != nil {
		return err
	}
	tmp144, err := kaitai.BytesToStr(tmp143, charmap.ISO8859_1.NewDecoder())
	if err != nil {
		return err
	}
	this.Keyword = tmp144
	tmp145, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.CompressionFlag = tmp145
	if !( ((this.CompressionFlag == 0) || (this.CompressionFlag == 1)) ) {
		return kaitai.NewValidationNotAnyOfError(this.CompressionFlag, this._io, "/types/international_text_chunk/seq/1")
	}
	tmp146, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.CompressionMethod = Png_CompressionMethods(tmp146)
	var tmp147 Png_CompressionMethods;
	if (this.CompressionFlag == 1) {
		tmp147 = Png_CompressionMethods__Zlib
	} else {
		tmp147 = this.CompressionMethod
	}
	var tmp148 Png_CompressionMethods;
	if (this.CompressionFlag == 1) {
		tmp148 = Png_CompressionMethods__Zlib
	} else {
		tmp148 = this.CompressionMethod
	}
	if !(this.CompressionMethod == tmp147) {
		return kaitai.NewValidationNotEqualError(tmp148, this.CompressionMethod, this._io, "/types/international_text_chunk/seq/2")
	}
	tmp149, err := this._io.ReadBytesTerm(0, false, true, true)
	if err != nil {
		return err
	}
	this.LanguageTag = string(tmp149)
	tmp150, err := this._io.ReadBytesTerm(0, false, true, true)
	if err != nil {
		return err
	}
	this.TranslatedKeyword = string(tmp150)
	if (this.CompressionFlag == 0) {
		tmp151, err := this._io.ReadBytesFull()
		if err != nil {
			return err
		}
		tmp151 = tmp151
		this._raw_TextPlain = tmp151
		_io__raw_TextPlain := kaitai.NewStream(bytes.NewReader(this._raw_TextPlain))
		tmp152 := NewPng_InternationalText()
		err = tmp152.Read(_io__raw_TextPlain, this, this._root)
		if err != nil {
			return err
		}
		this.TextPlain = tmp152
	}
	if (this.CompressionFlag == 1) {
		tmp153, err := this._io.ReadBytesFull()
		if err != nil {
			return err
		}
		tmp153 = tmp153
		this._raw__raw_TextZlib = tmp153
		tmp154, err := kaitai.ProcessZlib(this._raw__raw_TextZlib)
		if err != nil {
			return err
		}
		this._raw_TextZlib = tmp154
		_io__raw_TextZlib := kaitai.NewStream(bytes.NewReader(this._raw_TextZlib))
		tmp155 := NewPng_InternationalText()
		err = tmp155.Read(_io__raw_TextZlib, this, this._root)
		if err != nil {
			return err
		}
		this.TextZlib = tmp155
	}
	return err
}

/**
 * Text string (the "value" of this key-value pair), written in language
 * specified in `language_tag`.
 * 
 * Although it is not null-terminated (unlike other textual data in the
 * `iTXt` chunk), it must not contain a zero byte
 * (U+0000 NULL character). A newline should be represented by a single
 * U+000A LINE FEED (LF) character (aka `\n`). The remaining control
 * characters (U+0001..U+0009, U+000B..0+001F, U+007F..U+009F) are
 * discouraged.
 */
func (this *Png_InternationalTextChunk) Text() (v string, err error) {
	if (this._f_text) {
		return this.text, nil
	}
	this._f_text = true
	var tmp156 *Png_InternationalText;
	if (this.CompressionFlag == 0) {
		tmp156 = this.TextPlain
	} else {
		tmp156 = this.TextZlib
	}
	this.text = string(tmp156.Value)
	return this.text, nil
}

/**
 * Indicates the type of information represented by the text string.
 * 
 * Keywords must consist exclusively of printable ISO-8859-1 (Latin-1)
 * characters and spaces; that is, only code points 0x20-0x7E and
 * 0xA1-0xFF are allowed. To reduce the chances for human misreading of a
 * keyword, leading spaces, trailing spaces, and consecutive spaces are
 * not permitted.
 * @see <a href="https://www.w3.org/TR/2025/REC-png-3-20250624/#11keywords">Source</a>
 */

/**
 * 0 = text is uncompressed, 1 = text is compressed with a
 * method specified in `compression_method`.
 */

/**
 * Human language used in the `translated_keyword` and `text` fields.
 * 
 * From the [official
 * specification](https://www.w3.org/TR/2025/REC-png-3-20250624/#11iTXt):
 * 
 * > The language tag is a well-formed language tag defined by [RFC 5646:
 * > BCP 47: Tags for Identifying
 * > Languages](https://www.rfc-editor.org/info/rfc5646/). Unlike the
 * > keyword, the language tag is case-insensitive. Subtags must appear
 * > in the [IANA language subtag
 * > registry](https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry).
 * > If the language tag is empty, the language is unspecified. Examples
 * > of language tags include: `en`, `en-GB`, `es-419`, `zh-Hans`,
 * > `zh-Hans-CN`, `tlh-Cyrl-AQ`, `ar-AE-u-nu-latn`, and `x-private`.
 */

/**
 * The keyword (`keyword`) translated into the language specified in
 * `language_tag`.
 * 
 * It must not contain a zero byte (U+0000 NULL character). Line breaks
 * should not appear. The remaining control characters (U+0001..U+0009,
 * U+000B..0+001F, U+007F..U+009F) are discouraged.
 */
type Png_MdcvChromaticity struct {
	XInt uint16
	YInt uint16
	_io *kaitai.Stream
	_root *Png
	_parent *Png_MdcvChunk
	_f_x bool
	x float64
	_f_y bool
	y float64
}
func NewPng_MdcvChromaticity() *Png_MdcvChromaticity {
	return &Png_MdcvChromaticity{
	}
}

func (this Png_MdcvChromaticity) IO_() *kaitai.Stream {
	return this._io
}

func (this *Png_MdcvChromaticity) Read(io *kaitai.Stream, parent *Png_MdcvChunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp157, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.XInt = uint16(tmp157)
	tmp158, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.YInt = uint16(tmp158)
	return err
}
func (this *Png_MdcvChromaticity) X() (v float64, err error) {
	if (this._f_x) {
		return this.x, nil
	}
	this._f_x = true
	this.x = float64(this.XInt * 0.00002)
	return this.x, nil
}
func (this *Png_MdcvChromaticity) Y() (v float64, err error) {
	if (this._f_y) {
		return this.y, nil
	}
	this._f_y = true
	this.y = float64(this.YInt * 0.00002)
	return this.y, nil
}

/**
 * @see <a href="https://www.w3.org/TR/png/#mDCV-chunk">Source</a>
 * @see <a href="https://w3c.github.io/png/Implementation_Report_3e/#mastering">Source</a>
 */
type Png_MdcvChunk struct {
	Red *Png_MdcvChromaticity
	Green *Png_MdcvChromaticity
	Blue *Png_MdcvChromaticity
	WhitePoint *Png_MdcvChromaticity
	MaxLuminanceInt uint32
	MinLuminanceInt uint32
	_io *kaitai.Stream
	_root *Png
	_parent *Png_Chunk
	_f_maxLuminance bool
	maxLuminance float64
	_f_minLuminance bool
	minLuminance float64
}
func NewPng_MdcvChunk() *Png_MdcvChunk {
	return &Png_MdcvChunk{
	}
}

func (this Png_MdcvChunk) IO_() *kaitai.Stream {
	return this._io
}

func (this *Png_MdcvChunk) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp159 := NewPng_MdcvChromaticity()
	err = tmp159.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.Red = tmp159
	tmp160 := NewPng_MdcvChromaticity()
	err = tmp160.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.Green = tmp160
	tmp161 := NewPng_MdcvChromaticity()
	err = tmp161.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.Blue = tmp161
	tmp162 := NewPng_MdcvChromaticity()
	err = tmp162.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.WhitePoint = tmp162
	tmp163, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.MaxLuminanceInt = uint32(tmp163)
	tmp164, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.MinLuminanceInt = uint32(tmp164)
	return err
}

/**
 * Maximum luminance in cd/m^2
 */
func (this *Png_MdcvChunk) MaxLuminance() (v float64, err error) {
	if (this._f_maxLuminance) {
		return this.maxLuminance, nil
	}
	this._f_maxLuminance = true
	this.maxLuminance = float64(this.MaxLuminanceInt * 0.0001)
	return this.maxLuminance, nil
}

/**
 * Minimum luminance in cd/m^2
 */
func (this *Png_MdcvChunk) MinLuminance() (v float64, err error) {
	if (this._f_minLuminance) {
		return this.minLuminance, nil
	}
	this._f_minLuminance = true
	this.minLuminance = float64(this.MinLuminanceInt * 0.0001)
	return this.minLuminance, nil
}

/**
 * Physical pixel dimensions (`pHYs`) chunk specifies the intended physical
 * size of the pixels (in meters) or pixel aspect ratio for display of the
 * image.
 * @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
	_f_dotsPerInchX bool
	dotsPerInchX float64
	_f_dotsPerInchY bool
	dotsPerInchY float64
}
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

	tmp165, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.PixelsPerUnitX = uint32(tmp165)
	tmp166, err := this._io.ReadU4be()
	if err != nil {
		return err
	}
	this.PixelsPerUnitY = uint32(tmp166)
	tmp167, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Unit = Png_PhysUnit(tmp167)
	if !this.Unit.isDefined() {
		return kaitai.NewValidationNotInEnumError(this.Unit, this._io, "/types/phys_chunk/seq/2")
	}
	return err
}

/**
 * Horizontal resolution (DPI)
 */
func (this *Png_PhysChunk) DotsPerInchX() (v float64, err error) {
	if (this._f_dotsPerInchX) {
		return this.dotsPerInchX, nil
	}
	this._f_dotsPerInchX = true
	if (this.Unit == Png_PhysUnit__Meter) {
		this.dotsPerInchX = float64(this.PixelsPerUnitX * 0.0254)
	}
	return this.dotsPerInchX, nil
}

/**
 * Vertical resolution (DPI)
 */
func (this *Png_PhysChunk) DotsPerInchY() (v float64, err error) {
	if (this._f_dotsPerInchY) {
		return this.dotsPerInchY, nil
	}
	this._f_dotsPerInchY = true
	if (this.Unit == Png_PhysUnit__Meter) {
		this.dotsPerInchY = float64(this.PixelsPerUnitY * 0.0254)
	}
	return this.dotsPerInchY, nil
}

/**
 * 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++ {
		tmp168, err := this._io.EOF()
		if err != nil {
			return err
		}
		if tmp168 {
			break
		}
		tmp169 := NewPng_Rgb()
		err = tmp169.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Entries = append(this.Entries, tmp169)
	}
	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) 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

	tmp170, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.R = tmp170
	tmp171, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.G = tmp171
	tmp172, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.B = tmp172
	return err
}

/**
 * Significant bits (`sBIT`) chunk stores the original number of significant
 * bits of the sample values (which can be less than or equal to the sample
 * depth). This allows PNG decoders to recover the original data losslessly
 * even if the data had a sample depth not directly supported by PNG.
 * @see <a href="https://www.w3.org/TR/png/#11sBIT">Source</a>
 */
type Png_SbitChunk struct {
	SignificantBits kaitai.Struct
	_io *kaitai.Stream
	_root *Png
	_parent *Png_Chunk
	_f_sampleDepth bool
	sampleDepth uint8
}
func NewPng_SbitChunk() *Png_SbitChunk {
	return &Png_SbitChunk{
	}
}

func (this Png_SbitChunk) IO_() *kaitai.Stream {
	return this._io
}

func (this *Png_SbitChunk) 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:
		tmp173 := NewPng_SbitGreyscale(false)
		err = tmp173.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.SignificantBits = tmp173
	case Png_ColorType__GreyscaleAlpha:
		tmp174 := NewPng_SbitGreyscale(true)
		err = tmp174.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.SignificantBits = tmp174
	case Png_ColorType__Indexed:
		tmp175 := NewPng_SbitTruecolor(false)
		err = tmp175.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.SignificantBits = tmp175
	case Png_ColorType__Truecolor:
		tmp176 := NewPng_SbitTruecolor(false)
		err = tmp176.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.SignificantBits = tmp176
	case Png_ColorType__TruecolorAlpha:
		tmp177 := NewPng_SbitTruecolor(true)
		err = tmp177.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.SignificantBits = tmp177
	}
	return err
}
func (this *Png_SbitChunk) SampleDepth() (v uint8, err error) {
	if (this._f_sampleDepth) {
		return this.sampleDepth, nil
	}
	this._f_sampleDepth = true
	var tmp178 int8;
	if (this._root.Ihdr.ColorType == Png_ColorType__Indexed) {
		tmp178 = 8
	} else {
		tmp178 = this._root.Ihdr.BitDepth
	}
	this.sampleDepth = uint8(tmp178)
	return this.sampleDepth, nil
}
type Png_SbitGreyscale struct {
	Grey uint8
	Alpha uint8
	HasAlpha bool
	_io *kaitai.Stream
	_root *Png
	_parent *Png_SbitChunk
}
func NewPng_SbitGreyscale(hasAlpha bool) *Png_SbitGreyscale {
	return &Png_SbitGreyscale{
		HasAlpha: hasAlpha,
	}
}

func (this Png_SbitGreyscale) IO_() *kaitai.Stream {
	return this._io
}

func (this *Png_SbitGreyscale) Read(io *kaitai.Stream, parent *Png_SbitChunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp179, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Grey = tmp179
	if !(this.Grey >= 1) {
		return kaitai.NewValidationLessThanError(1, this.Grey, this._io, "/types/sbit_greyscale/seq/0")
	}
	tmp180, err := this._parent.SampleDepth()
	if err != nil {
		return err
	}
	tmp181, err := this._parent.SampleDepth()
	if err != nil {
		return err
	}
	if !(this.Grey <= tmp180) {
		return kaitai.NewValidationGreaterThanError(tmp181, this.Grey, this._io, "/types/sbit_greyscale/seq/0")
	}
	if (this.HasAlpha) {
		tmp182, err := this._io.ReadU1()
		if err != nil {
			return err
		}
		this.Alpha = tmp182
		if !(this.Alpha >= 1) {
			return kaitai.NewValidationLessThanError(1, this.Alpha, this._io, "/types/sbit_greyscale/seq/1")
		}
		tmp183, err := this._parent.SampleDepth()
		if err != nil {
			return err
		}
		tmp184, err := this._parent.SampleDepth()
		if err != nil {
			return err
		}
		if !(this.Alpha <= tmp183) {
			return kaitai.NewValidationGreaterThanError(tmp184, this.Alpha, this._io, "/types/sbit_greyscale/seq/1")
		}
	}
	return err
}
type Png_SbitTruecolor struct {
	Red uint8
	Green uint8
	Blue uint8
	Alpha uint8
	HasAlpha bool
	_io *kaitai.Stream
	_root *Png
	_parent *Png_SbitChunk
}
func NewPng_SbitTruecolor(hasAlpha bool) *Png_SbitTruecolor {
	return &Png_SbitTruecolor{
		HasAlpha: hasAlpha,
	}
}

func (this Png_SbitTruecolor) IO_() *kaitai.Stream {
	return this._io
}

func (this *Png_SbitTruecolor) Read(io *kaitai.Stream, parent *Png_SbitChunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp185, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Red = tmp185
	if !(this.Red >= 1) {
		return kaitai.NewValidationLessThanError(1, this.Red, this._io, "/types/sbit_truecolor/seq/0")
	}
	tmp186, err := this._parent.SampleDepth()
	if err != nil {
		return err
	}
	tmp187, err := this._parent.SampleDepth()
	if err != nil {
		return err
	}
	if !(this.Red <= tmp186) {
		return kaitai.NewValidationGreaterThanError(tmp187, this.Red, this._io, "/types/sbit_truecolor/seq/0")
	}
	tmp188, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Green = tmp188
	if !(this.Green >= 1) {
		return kaitai.NewValidationLessThanError(1, this.Green, this._io, "/types/sbit_truecolor/seq/1")
	}
	tmp189, err := this._parent.SampleDepth()
	if err != nil {
		return err
	}
	tmp190, err := this._parent.SampleDepth()
	if err != nil {
		return err
	}
	if !(this.Green <= tmp189) {
		return kaitai.NewValidationGreaterThanError(tmp190, this.Green, this._io, "/types/sbit_truecolor/seq/1")
	}
	tmp191, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Blue = tmp191
	if !(this.Blue >= 1) {
		return kaitai.NewValidationLessThanError(1, this.Blue, this._io, "/types/sbit_truecolor/seq/2")
	}
	tmp192, err := this._parent.SampleDepth()
	if err != nil {
		return err
	}
	tmp193, err := this._parent.SampleDepth()
	if err != nil {
		return err
	}
	if !(this.Blue <= tmp192) {
		return kaitai.NewValidationGreaterThanError(tmp193, this.Blue, this._io, "/types/sbit_truecolor/seq/2")
	}
	if (this.HasAlpha) {
		tmp194, err := this._io.ReadU1()
		if err != nil {
			return err
		}
		this.Alpha = tmp194
		if !(this.Alpha >= 1) {
			return kaitai.NewValidationLessThanError(1, this.Alpha, this._io, "/types/sbit_truecolor/seq/3")
		}
		tmp195, err := this._parent.SampleDepth()
		if err != nil {
			return err
		}
		tmp196, err := this._parent.SampleDepth()
		if err != nil {
			return err
		}
		if !(this.Alpha <= tmp195) {
			return kaitai.NewValidationGreaterThanError(tmp196, this.Alpha, this._io, "/types/sbit_truecolor/seq/3")
		}
	}
	return err
}

/**
 * Suggested palette (`sPLT`) chunk.
 * 
 * Multiple `sPLT` chunks are permitted, but each must have a different
 * palette name.
 * @see <a href="https://www.w3.org/TR/png/#11sPLT">Source</a>
 * @see <a href="https://www.w3.org/TR/png/#12Suggested-palettes">Source</a>
 */
type Png_SpltChunk struct {
	PaletteName string
	SampleDepth uint8
	Entries []*Png_SpltEntry
	_io *kaitai.Stream
	_root *Png
	_parent *Png_Chunk
}
func NewPng_SpltChunk() *Png_SpltChunk {
	return &Png_SpltChunk{
	}
}

func (this Png_SpltChunk) IO_() *kaitai.Stream {
	return this._io
}

func (this *Png_SpltChunk) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp197, err := this._io.ReadBytesTerm(0, false, true, true)
	if err != nil {
		return err
	}
	tmp198, err := kaitai.BytesToStr(tmp197, charmap.ISO8859_1.NewDecoder())
	if err != nil {
		return err
	}
	this.PaletteName = tmp198
	tmp199, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.SampleDepth = tmp199
	if !( ((this.SampleDepth == 8) || (this.SampleDepth == 16)) ) {
		return kaitai.NewValidationNotAnyOfError(this.SampleDepth, this._io, "/types/splt_chunk/seq/1")
	}
	for i := 0;; i++ {
		tmp200, err := this._io.EOF()
		if err != nil {
			return err
		}
		if tmp200 {
			break
		}
		tmp201 := NewPng_SpltEntry()
		err = tmp201.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Entries = append(this.Entries, tmp201)
	}
	return err
}

/**
 * Any convenient name for referring to the palette. It is
 * case-sensitive. The palette name may aid the choice of the appropriate
 * suggested palette when more than one appears in a PNG datastream.
 * 
 * Palette names must contain only printable ISO-8859-1 (Latin-1)
 * characters and spaces; that is, only code points 0x20-0x7E and
 * 0xA1-0xFF are allowed. Leading, trailing, and consecutive spaces are
 * not permitted.
 */

/**
 * There may be any number of entries. Entries must appear "in decreasing
 * order of frequency" (note: strictly speaking, I think the W3C
 * specification actually meant "non-increasing"). There is no
 * requirement that the entries all be used by the image, nor that they
 * all be different.
 * 
 * The color samples are not premultiplied by alpha, nor are they
 * precomposited against any background.
 * 
 * Entries in `sPLT` use the same gamma value and chromaticity values as
 * the PNG image, but may fall outside the range of values used in the
 * color space of the PNG image; for example, in a greyscale PNG image,
 * each `sPLT` entry would typically have equal red, green, and blue
 * values, but this is not required. Similarly, `sPLT` entries can have
 * non-opaque alpha values even when the PNG image does not use
 * transparency.
 */
type Png_SpltEntry struct {
	Red uint16
	Green uint16
	Blue uint16
	Alpha uint16
	Freq uint16
	_io *kaitai.Stream
	_root *Png
	_parent *Png_SpltChunk
}
func NewPng_SpltEntry() *Png_SpltEntry {
	return &Png_SpltEntry{
	}
}

func (this Png_SpltEntry) IO_() *kaitai.Stream {
	return this._io
}

func (this *Png_SpltEntry) Read(io *kaitai.Stream, parent *Png_SpltChunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	switch (this._parent.SampleDepth) {
	case 8:
		tmp202, err := this._io.ReadU1()
		if err != nil {
			return err
		}
		this.Red = uint16(tmp202)
	default:
		tmp203, err := this._io.ReadU2be()
		if err != nil {
			return err
		}
		this.Red = uint16(tmp203)
	}
	switch (this._parent.SampleDepth) {
	case 8:
		tmp204, err := this._io.ReadU1()
		if err != nil {
			return err
		}
		this.Green = uint16(tmp204)
	default:
		tmp205, err := this._io.ReadU2be()
		if err != nil {
			return err
		}
		this.Green = uint16(tmp205)
	}
	switch (this._parent.SampleDepth) {
	case 8:
		tmp206, err := this._io.ReadU1()
		if err != nil {
			return err
		}
		this.Blue = uint16(tmp206)
	default:
		tmp207, err := this._io.ReadU2be()
		if err != nil {
			return err
		}
		this.Blue = uint16(tmp207)
	}
	switch (this._parent.SampleDepth) {
	case 8:
		tmp208, err := this._io.ReadU1()
		if err != nil {
			return err
		}
		this.Alpha = uint16(tmp208)
	default:
		tmp209, err := this._io.ReadU2be()
		if err != nil {
			return err
		}
		this.Alpha = uint16(tmp209)
	}
	tmp210, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.Freq = uint16(tmp210)
	return err
}

/**
 * An alpha value of 0 means fully transparent. An alpha value of 255
 * (when `_parent.sample_depth` is 8) or 65535 (when
 * `_parent.sample_depth` is 16) means fully opaque.
 */

/**
 * Each frequency value is proportional to the fraction of the pixels in
 * the image for which that palette entry is the closest match in RGBA
 * space, before the image has been composited against any background.
 * 
 * The exact scale factor is chosen by the PNG encoder; it is recommended
 * that the resulting range of individual values reasonably fills the
 * range 0 to 65535.
 * 
 * Zero is a valid frequency meaning that the color is "least important"
 * or that it is rarely, if ever, used. When all the frequencies are
 * zero, they are meaningless, that is to say, nothing may be inferred
 * about the actual frequencies with which the colors appear in the PNG
 * image.
 */

/**
 * @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

	tmp211, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.RenderIntent = Png_SrgbChunk_Intent(tmp211)
	if !this.RenderIntent.isDefined() {
		return kaitai.NewValidationNotInEnumError(this.RenderIntent, this._io, "/types/srgb_chunk/seq/0")
	}
	return err
}

/**
 * Textual data (`tEXt`) chunk effectively allows you to store key-value
 * string pairs in the PNG container.
 * 
 * Both the "key" (`keyword`) and "value" (`text`) parts are restricted to
 * printable ISO-8859-1 (Latin-1) characters and ASCII spaces, with the
 * exception that `text` can also contain newlines (U+000A LINE FEED (LF)
 * characters) and U+00A0 NON-BREAKING SPACE 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

	tmp212, err := this._io.ReadBytesTerm(0, false, true, true)
	if err != nil {
		return err
	}
	tmp213, err := kaitai.BytesToStr(tmp212, charmap.ISO8859_1.NewDecoder())
	if err != nil {
		return err
	}
	this.Keyword = tmp213
	tmp214, err := this._io.ReadBytesFull()
	if err != nil {
		return err
	}
	tmp214 = tmp214
	tmp215, err := kaitai.BytesToStr(tmp214, charmap.ISO8859_1.NewDecoder())
	if err != nil {
		return err
	}
	this.Text = tmp215
	return err
}

/**
 * Indicates the type of information represented by the text string.
 * 
 * Keywords must consist exclusively of printable ISO-8859-1 (Latin-1)
 * characters and spaces; that is, only code points 0x20-0x7E and
 * 0xA1-0xFF are allowed. To reduce the chances for human misreading of a
 * keyword, leading spaces, trailing spaces, and consecutive spaces are
 * not permitted.
 * @see <a href="https://www.w3.org/TR/2025/REC-png-3-20250624/#11keywords">Source</a>
 */

/**
 * Text string (the "value" of this key-value pair).
 * 
 * Although it is not null-terminated (unlike the keyword), it must not
 * contain a zero byte (U+0000 NULL character). A newline should be
 * represented by a single U+000A LINE FEED (LF) character (aka `\n`).
 * The remaining control characters (U+0001..U+0009, U+000B..0+001F,
 * U+007F..U+009F) are discouraged.
 */

/**
 * 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

	tmp216, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.Year = uint16(tmp216)
	tmp217, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Month = tmp217
	tmp218, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Day = tmp218
	tmp219, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Hour = tmp219
	tmp220, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Minute = tmp220
	tmp221, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Second = tmp221
	return err
}

/**
 * Transparency (`tRNS`) chunk specifies either alpha values that are
 * associated with palette entries (for indexed-color images) or a single
 * transparent color (for greyscale and truecolor images).
 * 
 * A `tRNS` chunk must not appear for color types
 * `color_type::greyscale_alpha` = 4 and `color_type::truecolor_alpha` = 6,
 * since a full alpha channel is already present in those cases.
 * @see <a href="https://www.w3.org/TR/png/#11tRNS">Source</a>
 */
type Png_TrnsChunk struct {
	PaletteAlphas []uint8
	TransparentColor kaitai.Struct
	_io *kaitai.Stream
	_root *Png
	_parent *Png_Chunk
	_f_sampleMask bool
	sampleMask int
}
func NewPng_TrnsChunk() *Png_TrnsChunk {
	return &Png_TrnsChunk{
	}
}

func (this Png_TrnsChunk) IO_() *kaitai.Stream {
	return this._io
}

func (this *Png_TrnsChunk) Read(io *kaitai.Stream, parent *Png_Chunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	if (this._root.Ihdr.ColorType == Png_ColorType__Indexed) {
		for i := 0;; i++ {
			tmp222, err := this._io.EOF()
			if err != nil {
				return err
			}
			if tmp222 {
				break
			}
			tmp223, err := this._io.ReadU1()
			if err != nil {
				return err
			}
			this.PaletteAlphas = append(this.PaletteAlphas, tmp223)
		}
	}
	switch (this._root.Ihdr.ColorType) {
	case Png_ColorType__Greyscale:
		tmp224 := NewPng_TrnsGreyscaleColor()
		err = tmp224.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.TransparentColor = tmp224
	case Png_ColorType__Truecolor:
		tmp225 := NewPng_TrnsTruecolorColor()
		err = tmp225.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.TransparentColor = tmp225
	}
	return err
}
func (this *Png_TrnsChunk) SampleMask() (v int, err error) {
	if (this._f_sampleMask) {
		return this.sampleMask, nil
	}
	this._f_sampleMask = true
	this.sampleMask = int(1 << this._root.Ihdr.BitDepth - 1)
	return this.sampleMask, nil
}

/**
 * Alpha values associated with palette entries in the `PLTE` chunk.
 * 
 * Each entry indicates that pixels of the corresponding palette index
 * shall be treated as having the specified alpha value. Alpha values
 * have the same interpretation as in an 8-bit full alpha channel: 0 is
 * fully transparent, 255 is fully opaque, regardless of image bit depth.
 * 
 * The `tRNS` chunk must not contain more alpha values than there are
 * palette entries, but it may contain fewer values than there are
 * palette entries. In this case, the alpha value for all remaining
 * palette entries is assumed to be 255. If all palette indices are
 * opaque, the `tRNS` chunk may be omitted.
 */

/**
 * Pixels of the specified grey sample value or RGB sample values are
 * treated as transparent (equivalent to alpha value 0); all other pixels
 * are to be treated as fully opaque (alpha value `2^{bitdepth} - 1`).
 * 
 * If the image bit depth is less than 16, the least significant bits of
 * these sample values are used. Encoders should set the other bits to 0,
 * and decoders must mask the other bits to 0 before the value is used.
 * 
 * Note: in this Kaitai Struct implementation, the bitmask used to
 * implement this masking is stored in the value instance `sample_mask`.
 */
type Png_TrnsGreyscaleColor struct {
	GreyRaw uint16
	_io *kaitai.Stream
	_root *Png
	_parent *Png_TrnsChunk
	_f_grey bool
	grey int
}
func NewPng_TrnsGreyscaleColor() *Png_TrnsGreyscaleColor {
	return &Png_TrnsGreyscaleColor{
	}
}

func (this Png_TrnsGreyscaleColor) IO_() *kaitai.Stream {
	return this._io
}

func (this *Png_TrnsGreyscaleColor) Read(io *kaitai.Stream, parent *Png_TrnsChunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp226, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.GreyRaw = uint16(tmp226)
	return err
}
func (this *Png_TrnsGreyscaleColor) Grey() (v int, err error) {
	if (this._f_grey) {
		return this.grey, nil
	}
	this._f_grey = true
	tmp227, err := this._parent.SampleMask()
	if err != nil {
		return 0, err
	}
	this.grey = int(this.GreyRaw & tmp227)
	return this.grey, nil
}
type Png_TrnsTruecolorColor struct {
	RedRaw uint16
	GreenRaw uint16
	BlueRaw uint16
	_io *kaitai.Stream
	_root *Png
	_parent *Png_TrnsChunk
	_f_blue bool
	blue int
	_f_green bool
	green int
	_f_red bool
	red int
}
func NewPng_TrnsTruecolorColor() *Png_TrnsTruecolorColor {
	return &Png_TrnsTruecolorColor{
	}
}

func (this Png_TrnsTruecolorColor) IO_() *kaitai.Stream {
	return this._io
}

func (this *Png_TrnsTruecolorColor) Read(io *kaitai.Stream, parent *Png_TrnsChunk, root *Png) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp228, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.RedRaw = uint16(tmp228)
	tmp229, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.GreenRaw = uint16(tmp229)
	tmp230, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.BlueRaw = uint16(tmp230)
	return err
}
func (this *Png_TrnsTruecolorColor) Blue() (v int, err error) {
	if (this._f_blue) {
		return this.blue, nil
	}
	this._f_blue = true
	tmp231, err := this._parent.SampleMask()
	if err != nil {
		return 0, err
	}
	this.blue = int(this.BlueRaw & tmp231)
	return this.blue, nil
}
func (this *Png_TrnsTruecolorColor) Green() (v int, err error) {
	if (this._f_green) {
		return this.green, nil
	}
	this._f_green = true
	tmp232, err := this._parent.SampleMask()
	if err != nil {
		return 0, err
	}
	this.green = int(this.GreenRaw & tmp232)
	return this.green, nil
}
func (this *Png_TrnsTruecolorColor) Red() (v int, err error) {
	if (this._f_red) {
		return this.red, nil
	}
	this._f_red = true
	tmp233, err := this._parent.SampleMask()
	if err != nil {
		return 0, err
	}
	this.red = int(this.RedRaw & tmp233)
	return this.red, nil
}