GIF (Graphics Interchange Format) is an image file format, developed in 1987. It became popular in 1990s as one of the main image formats used in World Wide Web.
GIF format allows encoding of palette-based images up to 256 colors (each of the colors can be chosen from a 24-bit RGB colorspace). Image data stream uses LZW (Lempel-Ziv-Welch) lossless compression.
Over the years, several version of the format were published and several extensions to it were made, namely, a popular Netscape extension that allows to store several images in one file, switching between them, which produces crude form of animation.
Structurally, format consists of several mandatory headers and then a stream of blocks follows. Blocks can carry additional metainformation or image data.
This page hosts a formal specification of GIF (Graphics Interchange Format) image file using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.
// Code generated by kaitai-struct-compiler from a .ksy source file. DO NOT EDIT.
import (
"github.com/kaitai-io/kaitai_struct_go_runtime/kaitai"
"bytes"
)
/**
* GIF (Graphics Interchange Format) is an image file format, developed
* in 1987. It became popular in 1990s as one of the main image formats
* used in World Wide Web.
*
* GIF format allows encoding of palette-based images up to 256 colors
* (each of the colors can be chosen from a 24-bit RGB
* colorspace). Image data stream uses LZW (Lempel-Ziv-Welch) lossless
* compression.
*
* Over the years, several version of the format were published and
* several extensions to it were made, namely, a popular Netscape
* extension that allows to store several images in one file, switching
* between them, which produces crude form of animation.
*
* Structurally, format consists of several mandatory headers and then
* a stream of blocks follows. Blocks can carry additional
* metainformation or image data.
*/
type Gif_BlockType int
const (
Gif_BlockType__Extension Gif_BlockType = 33
Gif_BlockType__LocalImageDescriptor Gif_BlockType = 44
Gif_BlockType__EndOfFile Gif_BlockType = 59
)
var values_Gif_BlockType = map[Gif_BlockType]struct{}{33: {}, 44: {}, 59: {}}
func (v Gif_BlockType) isDefined() bool {
_, ok := values_Gif_BlockType[v]
return ok
}
type Gif_ExtensionLabel int
const (
Gif_ExtensionLabel__GraphicControl Gif_ExtensionLabel = 249
Gif_ExtensionLabel__Comment Gif_ExtensionLabel = 254
Gif_ExtensionLabel__Application Gif_ExtensionLabel = 255
)
var values_Gif_ExtensionLabel = map[Gif_ExtensionLabel]struct{}{249: {}, 254: {}, 255: {}}
func (v Gif_ExtensionLabel) isDefined() bool {
_, ok := values_Gif_ExtensionLabel[v]
return ok
}
type Gif struct {
Hdr *Gif_Header
LogicalScreenDescriptor *Gif_LogicalScreenDescriptorStruct
GlobalColorTable *Gif_ColorTable
Blocks []*Gif_Block
_io *kaitai.Stream
_root *Gif
_parent kaitai.Struct
_raw_GlobalColorTable []byte
}
func NewGif() *Gif {
return &Gif{
}
}
func (this Gif) IO_() *kaitai.Stream {
return this._io
}
func (this *Gif) Read(io *kaitai.Stream, parent kaitai.Struct, root *Gif) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp1 := NewGif_Header()
err = tmp1.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Hdr = tmp1
tmp2 := NewGif_LogicalScreenDescriptorStruct()
err = tmp2.Read(this._io, this, this._root)
if err != nil {
return err
}
this.LogicalScreenDescriptor = tmp2
tmp3, err := this.LogicalScreenDescriptor.HasColorTable()
if err != nil {
return err
}
if (tmp3) {
tmp4, err := this.LogicalScreenDescriptor.ColorTableSize()
if err != nil {
return err
}
tmp5, err := this._io.ReadBytes(int(tmp4 * 3))
if err != nil {
return err
}
tmp5 = tmp5
this._raw_GlobalColorTable = tmp5
_io__raw_GlobalColorTable := kaitai.NewStream(bytes.NewReader(this._raw_GlobalColorTable))
tmp6 := NewGif_ColorTable()
err = tmp6.Read(_io__raw_GlobalColorTable, this, this._root)
if err != nil {
return err
}
this.GlobalColorTable = tmp6
}
for i := 1;; i++ {
tmp7 := NewGif_Block()
err = tmp7.Read(this._io, this, this._root)
if err != nil {
return err
}
_it := tmp7
this.Blocks = append(this.Blocks, _it)
tmp8, err := this._io.EOF()
if err != nil {
return err
}
if ((tmp8) || (_it.BlockType == Gif_BlockType__EndOfFile)) {
break
}
}
return err
}
/**
* @see <a href="https://www.w3.org/Graphics/GIF/spec-gif89a.txt">- section 18</a>
*/
type Gif_ApplicationId struct {
LenBytes uint8
ApplicationIdentifier string
ApplicationAuthCode []byte
_io *kaitai.Stream
_root *Gif
_parent *Gif_ExtApplication
}
func NewGif_ApplicationId() *Gif_ApplicationId {
return &Gif_ApplicationId{
}
}
func (this Gif_ApplicationId) IO_() *kaitai.Stream {
return this._io
}
func (this *Gif_ApplicationId) Read(io *kaitai.Stream, parent *Gif_ExtApplication, root *Gif) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp9, err := this._io.ReadU1()
if err != nil {
return err
}
this.LenBytes = tmp9
if !(this.LenBytes == 11) {
return kaitai.NewValidationNotEqualError(11, this.LenBytes, this._io, "/types/application_id/seq/0")
}
tmp10, err := this._io.ReadBytes(int(8))
if err != nil {
return err
}
tmp10 = tmp10
this.ApplicationIdentifier = string(tmp10)
tmp11, err := this._io.ReadBytes(int(3))
if err != nil {
return err
}
tmp11 = tmp11
this.ApplicationAuthCode = tmp11
return err
}
type Gif_Block struct {
BlockType Gif_BlockType
Body kaitai.Struct
_io *kaitai.Stream
_root *Gif
_parent *Gif
}
func NewGif_Block() *Gif_Block {
return &Gif_Block{
}
}
func (this Gif_Block) IO_() *kaitai.Stream {
return this._io
}
func (this *Gif_Block) Read(io *kaitai.Stream, parent *Gif, root *Gif) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp12, err := this._io.ReadU1()
if err != nil {
return err
}
this.BlockType = Gif_BlockType(tmp12)
switch (this.BlockType) {
case Gif_BlockType__Extension:
tmp13 := NewGif_Extension()
err = tmp13.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Body = tmp13
case Gif_BlockType__LocalImageDescriptor:
tmp14 := NewGif_LocalImageDescriptor()
err = tmp14.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Body = tmp14
}
return err
}
/**
* @see <a href="https://www.w3.org/Graphics/GIF/spec-gif89a.txt">- section 19</a>
*/
type Gif_ColorTable struct {
Entries []*Gif_ColorTableEntry
_io *kaitai.Stream
_root *Gif
_parent kaitai.Struct
}
func NewGif_ColorTable() *Gif_ColorTable {
return &Gif_ColorTable{
}
}
func (this Gif_ColorTable) IO_() *kaitai.Stream {
return this._io
}
func (this *Gif_ColorTable) Read(io *kaitai.Stream, parent kaitai.Struct, root *Gif) (err error) {
this._io = io
this._parent = parent
this._root = root
for i := 0;; i++ {
tmp15, err := this._io.EOF()
if err != nil {
return err
}
if tmp15 {
break
}
tmp16 := NewGif_ColorTableEntry()
err = tmp16.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Entries = append(this.Entries, tmp16)
}
return err
}
type Gif_ColorTableEntry struct {
Red uint8
Green uint8
Blue uint8
_io *kaitai.Stream
_root *Gif
_parent *Gif_ColorTable
}
func NewGif_ColorTableEntry() *Gif_ColorTableEntry {
return &Gif_ColorTableEntry{
}
}
func (this Gif_ColorTableEntry) IO_() *kaitai.Stream {
return this._io
}
func (this *Gif_ColorTableEntry) Read(io *kaitai.Stream, parent *Gif_ColorTable, root *Gif) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp17, err := this._io.ReadU1()
if err != nil {
return err
}
this.Red = tmp17
tmp18, err := this._io.ReadU1()
if err != nil {
return err
}
this.Green = tmp18
tmp19, err := this._io.ReadU1()
if err != nil {
return err
}
this.Blue = tmp19
return err
}
type Gif_ExtApplication struct {
ApplicationId *Gif_ApplicationId
Subblocks []*Gif_Subblock
_io *kaitai.Stream
_root *Gif
_parent *Gif_Extension
}
func NewGif_ExtApplication() *Gif_ExtApplication {
return &Gif_ExtApplication{
}
}
func (this Gif_ExtApplication) IO_() *kaitai.Stream {
return this._io
}
func (this *Gif_ExtApplication) Read(io *kaitai.Stream, parent *Gif_Extension, root *Gif) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp20 := NewGif_ApplicationId()
err = tmp20.Read(this._io, this, this._root)
if err != nil {
return err
}
this.ApplicationId = tmp20
for i := 1;; i++ {
tmp21 := NewGif_Subblock()
err = tmp21.Read(this._io, this, this._root)
if err != nil {
return err
}
_it := tmp21
this.Subblocks = append(this.Subblocks, _it)
if _it.LenBytes == 0 {
break
}
}
return err
}
/**
* @see <a href="https://www.w3.org/Graphics/GIF/spec-gif89a.txt">- section 23</a>
*/
type Gif_ExtGraphicControl struct {
BlockSize []byte
Flags uint8
DelayTime uint16
TransparentIdx uint8
Terminator []byte
_io *kaitai.Stream
_root *Gif
_parent *Gif_Extension
_f_transparentColorFlag bool
transparentColorFlag bool
_f_userInputFlag bool
userInputFlag bool
}
func NewGif_ExtGraphicControl() *Gif_ExtGraphicControl {
return &Gif_ExtGraphicControl{
}
}
func (this Gif_ExtGraphicControl) IO_() *kaitai.Stream {
return this._io
}
func (this *Gif_ExtGraphicControl) Read(io *kaitai.Stream, parent *Gif_Extension, root *Gif) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp22, err := this._io.ReadBytes(int(1))
if err != nil {
return err
}
tmp22 = tmp22
this.BlockSize = tmp22
if !(bytes.Equal(this.BlockSize, []uint8{4})) {
return kaitai.NewValidationNotEqualError([]uint8{4}, this.BlockSize, this._io, "/types/ext_graphic_control/seq/0")
}
tmp23, err := this._io.ReadU1()
if err != nil {
return err
}
this.Flags = tmp23
tmp24, err := this._io.ReadU2le()
if err != nil {
return err
}
this.DelayTime = uint16(tmp24)
tmp25, err := this._io.ReadU1()
if err != nil {
return err
}
this.TransparentIdx = tmp25
tmp26, err := this._io.ReadBytes(int(1))
if err != nil {
return err
}
tmp26 = tmp26
this.Terminator = tmp26
if !(bytes.Equal(this.Terminator, []uint8{0})) {
return kaitai.NewValidationNotEqualError([]uint8{0}, this.Terminator, this._io, "/types/ext_graphic_control/seq/4")
}
return err
}
func (this *Gif_ExtGraphicControl) TransparentColorFlag() (v bool, err error) {
if (this._f_transparentColorFlag) {
return this.transparentColorFlag, nil
}
this._f_transparentColorFlag = true
this.transparentColorFlag = bool(this.Flags & 1 != 0)
return this.transparentColorFlag, nil
}
func (this *Gif_ExtGraphicControl) UserInputFlag() (v bool, err error) {
if (this._f_userInputFlag) {
return this.userInputFlag, nil
}
this._f_userInputFlag = true
this.userInputFlag = bool(this.Flags & 2 != 0)
return this.userInputFlag, nil
}
type Gif_Extension struct {
Label Gif_ExtensionLabel
Body kaitai.Struct
_io *kaitai.Stream
_root *Gif
_parent *Gif_Block
}
func NewGif_Extension() *Gif_Extension {
return &Gif_Extension{
}
}
func (this Gif_Extension) IO_() *kaitai.Stream {
return this._io
}
func (this *Gif_Extension) Read(io *kaitai.Stream, parent *Gif_Block, root *Gif) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp27, err := this._io.ReadU1()
if err != nil {
return err
}
this.Label = Gif_ExtensionLabel(tmp27)
switch (this.Label) {
case Gif_ExtensionLabel__Application:
tmp28 := NewGif_ExtApplication()
err = tmp28.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Body = tmp28
case Gif_ExtensionLabel__Comment:
tmp29 := NewGif_Subblocks()
err = tmp29.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Body = tmp29
case Gif_ExtensionLabel__GraphicControl:
tmp30 := NewGif_ExtGraphicControl()
err = tmp30.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Body = tmp30
default:
tmp31 := NewGif_Subblocks()
err = tmp31.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Body = tmp31
}
return err
}
/**
* @see <a href="https://www.w3.org/Graphics/GIF/spec-gif89a.txt">- section 17</a>
*/
type Gif_Header struct {
Magic []byte
Version string
_io *kaitai.Stream
_root *Gif
_parent *Gif
}
func NewGif_Header() *Gif_Header {
return &Gif_Header{
}
}
func (this Gif_Header) IO_() *kaitai.Stream {
return this._io
}
func (this *Gif_Header) Read(io *kaitai.Stream, parent *Gif, root *Gif) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp32, err := this._io.ReadBytes(int(3))
if err != nil {
return err
}
tmp32 = tmp32
this.Magic = tmp32
if !(bytes.Equal(this.Magic, []uint8{71, 73, 70})) {
return kaitai.NewValidationNotEqualError([]uint8{71, 73, 70}, this.Magic, this._io, "/types/header/seq/0")
}
tmp33, err := this._io.ReadBytes(int(3))
if err != nil {
return err
}
tmp33 = tmp33
this.Version = string(tmp33)
return err
}
/**
* @see <a href="https://www.w3.org/Graphics/GIF/spec-gif89a.txt">- section 22</a>
*/
type Gif_ImageData struct {
LzwMinCodeSize uint8
Subblocks *Gif_Subblocks
_io *kaitai.Stream
_root *Gif
_parent *Gif_LocalImageDescriptor
}
func NewGif_ImageData() *Gif_ImageData {
return &Gif_ImageData{
}
}
func (this Gif_ImageData) IO_() *kaitai.Stream {
return this._io
}
func (this *Gif_ImageData) Read(io *kaitai.Stream, parent *Gif_LocalImageDescriptor, root *Gif) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp34, err := this._io.ReadU1()
if err != nil {
return err
}
this.LzwMinCodeSize = tmp34
tmp35 := NewGif_Subblocks()
err = tmp35.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Subblocks = tmp35
return err
}
type Gif_LocalImageDescriptor struct {
Left uint16
Top uint16
Width uint16
Height uint16
Flags uint8
LocalColorTable *Gif_ColorTable
ImageData *Gif_ImageData
_io *kaitai.Stream
_root *Gif
_parent *Gif_Block
_raw_LocalColorTable []byte
_f_colorTableSize bool
colorTableSize int
_f_hasColorTable bool
hasColorTable bool
_f_hasInterlace bool
hasInterlace bool
_f_hasSortedColorTable bool
hasSortedColorTable bool
}
func NewGif_LocalImageDescriptor() *Gif_LocalImageDescriptor {
return &Gif_LocalImageDescriptor{
}
}
func (this Gif_LocalImageDescriptor) IO_() *kaitai.Stream {
return this._io
}
func (this *Gif_LocalImageDescriptor) Read(io *kaitai.Stream, parent *Gif_Block, root *Gif) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp36, err := this._io.ReadU2le()
if err != nil {
return err
}
this.Left = uint16(tmp36)
tmp37, err := this._io.ReadU2le()
if err != nil {
return err
}
this.Top = uint16(tmp37)
tmp38, err := this._io.ReadU2le()
if err != nil {
return err
}
this.Width = uint16(tmp38)
tmp39, err := this._io.ReadU2le()
if err != nil {
return err
}
this.Height = uint16(tmp39)
tmp40, err := this._io.ReadU1()
if err != nil {
return err
}
this.Flags = tmp40
tmp41, err := this.HasColorTable()
if err != nil {
return err
}
if (tmp41) {
tmp42, err := this.ColorTableSize()
if err != nil {
return err
}
tmp43, err := this._io.ReadBytes(int(tmp42 * 3))
if err != nil {
return err
}
tmp43 = tmp43
this._raw_LocalColorTable = tmp43
_io__raw_LocalColorTable := kaitai.NewStream(bytes.NewReader(this._raw_LocalColorTable))
tmp44 := NewGif_ColorTable()
err = tmp44.Read(_io__raw_LocalColorTable, this, this._root)
if err != nil {
return err
}
this.LocalColorTable = tmp44
}
tmp45 := NewGif_ImageData()
err = tmp45.Read(this._io, this, this._root)
if err != nil {
return err
}
this.ImageData = tmp45
return err
}
func (this *Gif_LocalImageDescriptor) ColorTableSize() (v int, err error) {
if (this._f_colorTableSize) {
return this.colorTableSize, nil
}
this._f_colorTableSize = true
this.colorTableSize = int(2 << (this.Flags & 7))
return this.colorTableSize, nil
}
func (this *Gif_LocalImageDescriptor) HasColorTable() (v bool, err error) {
if (this._f_hasColorTable) {
return this.hasColorTable, nil
}
this._f_hasColorTable = true
this.hasColorTable = bool(this.Flags & 128 != 0)
return this.hasColorTable, nil
}
func (this *Gif_LocalImageDescriptor) HasInterlace() (v bool, err error) {
if (this._f_hasInterlace) {
return this.hasInterlace, nil
}
this._f_hasInterlace = true
this.hasInterlace = bool(this.Flags & 64 != 0)
return this.hasInterlace, nil
}
func (this *Gif_LocalImageDescriptor) HasSortedColorTable() (v bool, err error) {
if (this._f_hasSortedColorTable) {
return this.hasSortedColorTable, nil
}
this._f_hasSortedColorTable = true
this.hasSortedColorTable = bool(this.Flags & 32 != 0)
return this.hasSortedColorTable, nil
}
/**
* @see <a href="https://www.w3.org/Graphics/GIF/spec-gif89a.txt">- section 18</a>
*/
type Gif_LogicalScreenDescriptorStruct struct {
ScreenWidth uint16
ScreenHeight uint16
Flags uint8
BgColorIndex uint8
PixelAspectRatio uint8
_io *kaitai.Stream
_root *Gif
_parent *Gif
_f_colorTableSize bool
colorTableSize int
_f_hasColorTable bool
hasColorTable bool
}
func NewGif_LogicalScreenDescriptorStruct() *Gif_LogicalScreenDescriptorStruct {
return &Gif_LogicalScreenDescriptorStruct{
}
}
func (this Gif_LogicalScreenDescriptorStruct) IO_() *kaitai.Stream {
return this._io
}
func (this *Gif_LogicalScreenDescriptorStruct) Read(io *kaitai.Stream, parent *Gif, root *Gif) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp46, err := this._io.ReadU2le()
if err != nil {
return err
}
this.ScreenWidth = uint16(tmp46)
tmp47, err := this._io.ReadU2le()
if err != nil {
return err
}
this.ScreenHeight = uint16(tmp47)
tmp48, err := this._io.ReadU1()
if err != nil {
return err
}
this.Flags = tmp48
tmp49, err := this._io.ReadU1()
if err != nil {
return err
}
this.BgColorIndex = tmp49
tmp50, err := this._io.ReadU1()
if err != nil {
return err
}
this.PixelAspectRatio = tmp50
return err
}
func (this *Gif_LogicalScreenDescriptorStruct) ColorTableSize() (v int, err error) {
if (this._f_colorTableSize) {
return this.colorTableSize, nil
}
this._f_colorTableSize = true
this.colorTableSize = int(2 << (this.Flags & 7))
return this.colorTableSize, nil
}
func (this *Gif_LogicalScreenDescriptorStruct) HasColorTable() (v bool, err error) {
if (this._f_hasColorTable) {
return this.hasColorTable, nil
}
this._f_hasColorTable = true
this.hasColorTable = bool(this.Flags & 128 != 0)
return this.hasColorTable, nil
}
type Gif_Subblock struct {
LenBytes uint8
Bytes []byte
_io *kaitai.Stream
_root *Gif
_parent kaitai.Struct
}
func NewGif_Subblock() *Gif_Subblock {
return &Gif_Subblock{
}
}
func (this Gif_Subblock) IO_() *kaitai.Stream {
return this._io
}
func (this *Gif_Subblock) Read(io *kaitai.Stream, parent kaitai.Struct, root *Gif) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp51, err := this._io.ReadU1()
if err != nil {
return err
}
this.LenBytes = tmp51
tmp52, err := this._io.ReadBytes(int(this.LenBytes))
if err != nil {
return err
}
tmp52 = tmp52
this.Bytes = tmp52
return err
}
type Gif_Subblocks struct {
Entries []*Gif_Subblock
_io *kaitai.Stream
_root *Gif
_parent kaitai.Struct
}
func NewGif_Subblocks() *Gif_Subblocks {
return &Gif_Subblocks{
}
}
func (this Gif_Subblocks) IO_() *kaitai.Stream {
return this._io
}
func (this *Gif_Subblocks) Read(io *kaitai.Stream, parent kaitai.Struct, root *Gif) (err error) {
this._io = io
this._parent = parent
this._root = root
for i := 1;; i++ {
tmp53 := NewGif_Subblock()
err = tmp53.Read(this._io, this, this._root)
if err != nil {
return err
}
_it := tmp53
this.Entries = append(this.Entries, _it)
if _it.LenBytes == 0 {
break
}
}
return err
}