Fanbase

tiff/tiff-edge

version 1.0

TIFF with tiles, two pages, 1/4/8 bit samples, FillOrder 2 and rare field types

Format
Tagged Image File Format (tiff)
Authors
The Fandango Fuzzer Team
License
Apache-2.0
Fandango
>=1.3
Extensions
tif, tiff
Media type
image/tiff
Specification
https://download.osgeo.org/libtiff/doc/TIFF6.pdf
Its files should decode
always
In the registry
specs/tiff/tiff-edge/tiff-edge.fan

Use it

fanbase install tiff-edge
fandango fuzz -F tiff-edge -n 10

How it does

accepts 100%, covers 9.4%, 56/s. 1000 inputs, seed 1.

ParserAcceptsVersion
ffmpeg100%ffmpeg version 7.1.5-0+deb13u1
imagemagick100%Version: ImageMagick 7.1.1-43 Q16 x86_64 22550
libtiff-cov100%libtiff 4.7.2
pillow100%12.3.0
tiffinfo100%

The spec says its files decode always: as expected.

libtiff-cov

lines reached
9.4% of 14513
real files reach
18.2%
only the generated files
95 lines
only the real files
1367 lines
9.3% after 1 inputs, 9.4% after 1000real files: 18.2%

Cite it

@software{fanbase_tiff_tiff_edge_1_0,
  author  = {{The Fandango Fuzzer Team}},
  title   = {Tagged Image File Format (tiff/tiff-edge), a Fandango input specification},
  version = {1.0},
  url     = {https://github.com/fandango-fuzzer/fanbase},
  note    = {Fanbase registry, specs/tiff/tiff-edge/tiff-edge.fan, sha256 17186f8dcb1e},
}

Source

Source (257 lines)
# TIFF 6.0 with the less common parts: both byte orders, strips and tiles, a
# two page file, 1, 4 and 8 bit samples, FillOrder 2, and the DOUBLE and
# SRATIONAL types for SMin/SMaxSampleValue. Seven flavours, each with its own
# symbols; offsets and byte counts are tied to the real lengths with where
# clauses.

<start> ::= <rg_le> | <gs_le> | <pl_le> | <bl_le> | <be_le> | <tl_le> | <mp_le>


# Flavour 1: RGB, little-endian, strip storage, 8x8, RATIONAL resolution
<rg_le> ::= <rg_header> <rg_ifd> <rg_data>

<rg_header> ::= b'II' b'\x2a\x00' b'\x08\x00\x00\x00'

<rg_ifd> ::= b'\x0d\x00' \
    b'\xfe\x00\x04\x00\x01\x00\x00\x00\x00\x00\x00\x00' \
    b'\x00\x01\x03\x00\x01\x00\x00\x00\x08\x00\x00\x00' \
    b'\x01\x01\x03\x00\x01\x00\x00\x00\x08\x00\x00\x00' \
    b'\x02\x01\x03\x00\x03\x00\x00\x00' <rg_off_bits> \
    b'\x03\x01\x03\x00\x01\x00\x00\x00\x01\x00\x00\x00' \
    b'\x06\x01\x03\x00\x01\x00\x00\x00\x02\x00\x00\x00' \
    b'\x11\x01\x04\x00\x01\x00\x00\x00' <rg_off_strip> \
    b'\x15\x01\x03\x00\x01\x00\x00\x00\x03\x00\x00\x00' \
    b'\x16\x01\x03\x00\x01\x00\x00\x00\x08\x00\x00\x00' \
    b'\x17\x01\x04\x00\x01\x00\x00\x00\xc0\x00\x00\x00' \
    b'\x1a\x01\x05\x00\x01\x00\x00\x00' <rg_off_xres> \
    b'\x1b\x01\x05\x00\x01\x00\x00\x00' <rg_off_yres> \
    b'\x28\x01\x03\x00\x01\x00\x00\x00\x02\x00\x00\x00' \
    b'\x00\x00\x00\x00'

<rg_off_bits> ::= <byte>{4}
<rg_off_strip> ::= <byte>{4}
<rg_off_xres> ::= <byte>{4}
<rg_off_yres> ::= <byte>{4}

<rg_data> ::= <rg_bits> <rg_xres> <rg_yres> <rg_strip>
<rg_bits> ::= b'\x08\x00\x08\x00\x08\x00'
<rg_xres> ::= b'\x48\x00\x00\x00\x01\x00\x00\x00'
<rg_yres> ::= b'\x48\x00\x00\x00\x01\x00\x00\x00'
<rg_strip> ::= <byte>{192}


# Flavour 2: Grayscale, little-endian, ASCII + DOUBLE + SRATIONAL field types
<gs_le> ::= <gs_header> <gs_ifd> <gs_data>

<gs_header> ::= b'II' b'\x2a\x00' b'\x08\x00\x00\x00'

<gs_ifd> ::= b'\x11\x00' \
    b'\xfe\x00\x04\x00\x01\x00\x00\x00\x00\x00\x00\x00' \
    b'\x00\x01\x03\x00\x01\x00\x00\x00\x08\x00\x00\x00' \
    b'\x01\x01\x03\x00\x01\x00\x00\x00\x08\x00\x00\x00' \
    b'\x02\x01\x03\x00\x01\x00\x00\x00\x08\x00\x00\x00' \
    b'\x03\x01\x03\x00\x01\x00\x00\x00\x01\x00\x00\x00' \
    b'\x06\x01\x03\x00\x01\x00\x00\x00\x01\x00\x00\x00' \
    b'\x0e\x01\x02\x00\x22\x00\x00\x00' <gs_off_desc> \
    b'\x11\x01\x04\x00\x01\x00\x00\x00' <gs_off_strip> \
    b'\x15\x01\x03\x00\x01\x00\x00\x00\x01\x00\x00\x00' \
    b'\x16\x01\x03\x00\x01\x00\x00\x00\x08\x00\x00\x00' \
    b'\x17\x01\x04\x00\x01\x00\x00\x00\x40\x00\x00\x00' \
    b'\x1a\x01\x05\x00\x01\x00\x00\x00' <gs_off_xres> \
    b'\x1b\x01\x05\x00\x01\x00\x00\x00' <gs_off_yres> \
    b'\x31\x01\x02\x00\x0d\x00\x00\x00' <gs_off_sw> \
    b'\x32\x01\x02\x00\x14\x00\x00\x00' <gs_off_dt> \
    b'\x54\x01\x0c\x00\x01\x00\x00\x00' <gs_off_smin> \
    b'\x55\x01\x0a\x00\x01\x00\x00\x00' <gs_off_smax> \
    b'\x00\x00\x00\x00'

<gs_off_desc> ::= <byte>{4}
<gs_off_strip> ::= <byte>{4}
<gs_off_xres> ::= <byte>{4}
<gs_off_yres> ::= <byte>{4}
<gs_off_sw> ::= <byte>{4}
<gs_off_dt> ::= <byte>{4}
<gs_off_smin> ::= <byte>{4}
<gs_off_smax> ::= <byte>{4}

<gs_data> ::= <gs_desc> <gs_sw> <gs_dt> <gs_xres> <gs_yres> <gs_smin> <gs_smax> <gs_strip>
<gs_desc> ::= b'Fandango grayscale extreme sample\x00'
<gs_sw> ::= b'fan-tiff 1.0\x00'
<gs_dt> ::= b'2026:08:05 12:00:00\x00'
<gs_xres> ::= b'\x48\x00\x00\x00\x01\x00\x00\x00'
<gs_yres> ::= b'\x48\x00\x00\x00\x01\x00\x00\x00'
<gs_smin> ::= b'\x00\x00\x00\x00\x00\x00\x00\x00'
<gs_smax> ::= b'\xff\x00\x00\x00\x01\x00\x00\x00'
<gs_strip> ::= <byte>{64}


# Flavour 3: Palette-color, little-endian, 4-bit, ColorMap in data region
<pl_le> ::= <pl_header> <pl_ifd> <pl_data>

<pl_header> ::= b'II' b'\x2a\x00' b'\x08\x00\x00\x00'

<pl_ifd> ::= b'\x0b\x00' \
    b'\xfe\x00\x04\x00\x01\x00\x00\x00\x00\x00\x00\x00' \
    b'\x00\x01\x03\x00\x01\x00\x00\x00\x08\x00\x00\x00' \
    b'\x01\x01\x03\x00\x01\x00\x00\x00\x08\x00\x00\x00' \
    b'\x02\x01\x03\x00\x01\x00\x00\x00\x04\x00\x00\x00' \
    b'\x03\x01\x03\x00\x01\x00\x00\x00\x01\x00\x00\x00' \
    b'\x06\x01\x03\x00\x01\x00\x00\x00\x03\x00\x00\x00' \
    b'\x11\x01\x04\x00\x01\x00\x00\x00' <pl_off_strip> \
    b'\x15\x01\x03\x00\x01\x00\x00\x00\x01\x00\x00\x00' \
    b'\x16\x01\x03\x00\x01\x00\x00\x00\x08\x00\x00\x00' \
    b'\x17\x01\x04\x00\x01\x00\x00\x00\x20\x00\x00\x00' \
    b'\x40\x01\x03\x00\x30\x00\x00\x00' <pl_off_cmap> \
    b'\x00\x00\x00\x00'

<pl_off_strip> ::= <byte>{4}
<pl_off_cmap> ::= <byte>{4}

<pl_data> ::= <pl_cmap> <pl_strip>
<pl_cmap> ::= <byte>{96}
<pl_strip> ::= <byte>{32}


# Flavour 4: Bilevel, little-endian, WhiteIsZero, deprecated FillOrder=2
<bl_le> ::= <bl_header> <bl_ifd> <bl_data>

<bl_header> ::= b'II' b'\x2a\x00' b'\x08\x00\x00\x00'

<bl_ifd> ::= b'\x0b\x00' \
    b'\xfe\x00\x04\x00\x01\x00\x00\x00\x00\x00\x00\x00' \
    b'\x00\x01\x03\x00\x01\x00\x00\x00\x08\x00\x00\x00' \
    b'\x01\x01\x03\x00\x01\x00\x00\x00\x08\x00\x00\x00' \
    b'\x02\x01\x03\x00\x01\x00\x00\x00\x01\x00\x00\x00' \
    b'\x03\x01\x03\x00\x01\x00\x00\x00\x01\x00\x00\x00' \
    b'\x06\x01\x03\x00\x01\x00\x00\x00\x00\x00\x00\x00' \
    b'\x0a\x01\x03\x00\x01\x00\x00\x00\x02\x00\x00\x00' \
    b'\x11\x01\x04\x00\x01\x00\x00\x00' <bl_off_strip> \
    b'\x15\x01\x03\x00\x01\x00\x00\x00\x01\x00\x00\x00' \
    b'\x16\x01\x03\x00\x01\x00\x00\x00\x08\x00\x00\x00' \
    b'\x17\x01\x04\x00\x01\x00\x00\x00\x08\x00\x00\x00' \
    b'\x00\x00\x00\x00'

<bl_off_strip> ::= <byte>{4}

<bl_data> ::= <bl_strip>
<bl_strip> ::= <byte>{8}


# Flavour 5: Grayscale, big-endian (MM). SHORT values in high half of field.
<be_le> ::= <be_header> <be_ifd> <be_data>

<be_header> ::= b'MM' b'\x00\x2a' b'\x00\x00\x00\x08'

<be_ifd> ::= b'\x00\x0a' \
    b'\x00\xfe\x00\x04\x00\x00\x00\x01\x00\x00\x00\x00' \
    b'\x01\x00\x00\x03\x00\x00\x00\x01\x00\x08\x00\x00' \
    b'\x01\x01\x00\x03\x00\x00\x00\x01\x00\x08\x00\x00' \
    b'\x01\x02\x00\x03\x00\x00\x00\x01\x00\x08\x00\x00' \
    b'\x01\x03\x00\x03\x00\x00\x00\x01\x00\x01\x00\x00' \
    b'\x01\x06\x00\x03\x00\x00\x00\x01\x00\x01\x00\x00' \
    b'\x01\x11\x00\x04\x00\x00\x00\x01' <be_off_strip> \
    b'\x01\x15\x00\x03\x00\x00\x00\x01\x00\x01\x00\x00' \
    b'\x01\x16\x00\x03\x00\x00\x00\x01\x00\x08\x00\x00' \
    b'\x01\x17\x00\x04\x00\x00\x00\x01\x00\x00\x00\x40' \
    b'\x00\x00\x00\x00'

<be_off_strip> ::= <byte>{4}

<be_data> ::= <be_strip>
<be_strip> ::= <byte>{64}


# Flavour 6: RGB, little-endian, tiled storage (16x16 tile, 16px multiples)
<tl_le> ::= <tl_header> <tl_ifd> <tl_data>

<tl_header> ::= b'II' b'\x2a\x00' b'\x08\x00\x00\x00'

<tl_ifd> ::= b'\x0b\x00' \
    b'\xfe\x00\x04\x00\x01\x00\x00\x00\x00\x00\x00\x00' \
    b'\x00\x01\x03\x00\x01\x00\x00\x00\x10\x00\x00\x00' \
    b'\x01\x01\x03\x00\x01\x00\x00\x00\x10\x00\x00\x00' \
    b'\x02\x01\x03\x00\x03\x00\x00\x00' <tl_off_bits> \
    b'\x03\x01\x03\x00\x01\x00\x00\x00\x01\x00\x00\x00' \
    b'\x06\x01\x03\x00\x01\x00\x00\x00\x02\x00\x00\x00' \
    b'\x15\x01\x03\x00\x01\x00\x00\x00\x03\x00\x00\x00' \
    b'\x42\x01\x03\x00\x01\x00\x00\x00\x10\x00\x00\x00' \
    b'\x43\x01\x03\x00\x01\x00\x00\x00\x10\x00\x00\x00' \
    b'\x44\x01\x04\x00\x01\x00\x00\x00' <tl_off_tile> \
    b'\x45\x01\x04\x00\x01\x00\x00\x00\x00\x03\x00\x00' \
    b'\x00\x00\x00\x00'

<tl_off_bits> ::= <byte>{4}
<tl_off_tile> ::= <byte>{4}

<tl_data> ::= <tl_bits> <tl_tile>
<tl_bits> ::= b'\x08\x00\x08\x00\x08\x00'
<tl_tile> ::= <byte>{768}


# Flavour 7: multi-page, little-endian - two bilevel IFDs chained via next-ptr
<mp_le> ::= <mp_header> <mp_ifd0> <mp_data0> <mp_ifd1> <mp_data1>

<mp_header> ::= b'II' b'\x2a\x00' b'\x08\x00\x00\x00'

<mp_ifd0> ::= b'\x0a\x00' \
    b'\xfe\x00\x04\x00\x01\x00\x00\x00\x02\x00\x00\x00' \
    b'\x00\x01\x03\x00\x01\x00\x00\x00\x08\x00\x00\x00' \
    b'\x01\x01\x03\x00\x01\x00\x00\x00\x08\x00\x00\x00' \
    b'\x02\x01\x03\x00\x01\x00\x00\x00\x01\x00\x00\x00' \
    b'\x03\x01\x03\x00\x01\x00\x00\x00\x01\x00\x00\x00' \
    b'\x06\x01\x03\x00\x01\x00\x00\x00\x00\x00\x00\x00' \
    b'\x11\x01\x04\x00\x01\x00\x00\x00' <mp_off_s0> \
    b'\x15\x01\x03\x00\x01\x00\x00\x00\x01\x00\x00\x00' \
    b'\x16\x01\x03\x00\x01\x00\x00\x00\x08\x00\x00\x00' \
    b'\x17\x01\x04\x00\x01\x00\x00\x00\x08\x00\x00\x00' \
    <mp_next0>

<mp_ifd1> ::= b'\x0a\x00' \
    b'\xfe\x00\x04\x00\x01\x00\x00\x00\x02\x00\x00\x00' \
    b'\x00\x01\x03\x00\x01\x00\x00\x00\x08\x00\x00\x00' \
    b'\x01\x01\x03\x00\x01\x00\x00\x00\x08\x00\x00\x00' \
    b'\x02\x01\x03\x00\x01\x00\x00\x00\x01\x00\x00\x00' \
    b'\x03\x01\x03\x00\x01\x00\x00\x00\x01\x00\x00\x00' \
    b'\x06\x01\x03\x00\x01\x00\x00\x00\x00\x00\x00\x00' \
    b'\x11\x01\x04\x00\x01\x00\x00\x00' <mp_off_s1> \
    b'\x15\x01\x03\x00\x01\x00\x00\x00\x01\x00\x00\x00' \
    b'\x16\x01\x03\x00\x01\x00\x00\x00\x08\x00\x00\x00' \
    b'\x17\x01\x04\x00\x01\x00\x00\x00\x08\x00\x00\x00' \
    b'\x00\x00\x00\x00'

<mp_off_s0> ::= <byte>{4}
<mp_next0> ::= <byte>{4}
<mp_off_s1> ::= <byte>{4}

<mp_data0> ::= <byte>{8}
<mp_data1> ::= <byte>{8}


# Constraints: every offset / next-IFD pointer == actual serialized position
where <rg_off_bits> == (8 + len(bytes(<rg_ifd>))).to_bytes(4, 'little')
where <rg_off_xres> == (8 + len(bytes(<rg_ifd>)) + 6).to_bytes(4, 'little')
where <rg_off_yres> == (8 + len(bytes(<rg_ifd>)) + 14).to_bytes(4, 'little')
where <rg_off_strip> == (8 + len(bytes(<rg_ifd>)) + 22).to_bytes(4, 'little')

where <gs_off_desc> == (8 + len(bytes(<gs_ifd>))).to_bytes(4, 'little')
where <gs_off_sw> == (8 + len(bytes(<gs_ifd>)) + 34).to_bytes(4, 'little')
where <gs_off_dt> == (8 + len(bytes(<gs_ifd>)) + 47).to_bytes(4, 'little')
where <gs_off_xres> == (8 + len(bytes(<gs_ifd>)) + 67).to_bytes(4, 'little')
where <gs_off_yres> == (8 + len(bytes(<gs_ifd>)) + 75).to_bytes(4, 'little')
where <gs_off_smin> == (8 + len(bytes(<gs_ifd>)) + 83).to_bytes(4, 'little')
where <gs_off_smax> == (8 + len(bytes(<gs_ifd>)) + 91).to_bytes(4, 'little')
where <gs_off_strip> == (8 + len(bytes(<gs_ifd>)) + 99).to_bytes(4, 'little')

where <pl_off_cmap> == (8 + len(bytes(<pl_ifd>))).to_bytes(4, 'little')
where <pl_off_strip> == (8 + len(bytes(<pl_ifd>)) + 96).to_bytes(4, 'little')

where <bl_off_strip> == (8 + len(bytes(<bl_ifd>))).to_bytes(4, 'little')

where <be_off_strip> == (8 + len(bytes(<be_ifd>))).to_bytes(4, 'big')

where <tl_off_bits> == (8 + len(bytes(<tl_ifd>))).to_bytes(4, 'little')
where <tl_off_tile> == (8 + len(bytes(<tl_ifd>)) + 6).to_bytes(4, 'little')

where <mp_off_s0> == (8 + len(bytes(<mp_ifd0>))).to_bytes(4, 'little')
where <mp_next0> == (8 + len(bytes(<mp_ifd0>)) + len(bytes(<mp_data0>))).to_bytes(4, 'little')
where <mp_off_s1> == (8 + len(bytes(<mp_ifd0>)) + len(bytes(<mp_data0>)) + len(bytes(<mp_ifd1>))).to_bytes(4, 'little')