Skip to content

Instantly share code, notes, and snippets.

@alastairmccormack
Last active June 2, 2025 13:38
Show Gist options
  • Save alastairmccormack/fc8888adb40d80824fb80d3c1523425a to your computer and use it in GitHub Desktop.
Save alastairmccormack/fc8888adb40d80824fb80d3c1523425a to your computer and use it in GitHub Desktop.
meta:
id: tiff
seq:
- id: bom
size: 2 # first two bytes determines endianness
- id: body
type: tiff_body
types:
tiff_body:
meta:
endian:
switch-on: _root.bom
cases:
'[0x49, 0x49]': le
'[0x4d, 0x4d]': be
enums:
tiff_tag:
254: new_subfile_type
255: subfile_type
256: image_width
257: image_length
258: bits_per_sample
259: compression
262: photometric_interpretation
263: threshholding
264: cell_width
265: cell_length
266: fill_order
270: image_description
271: make
272: model
273: strip_offsets
274: orientation
277: samples_per_pixel
278: rows_per_strip
279: strip_byte_counts
282: x_resolution
283: y_resolution
284: planar_configuration
296: resolution_unit
305: software
306: date_time
315: artist
320: color_map
321: halftone_hints
322: tile_width
323: tile_length
324: tile_offsets
325: tile_byte_counts
332: ink_set
333: ink_names
330: sub_ifds
338: extra_samples
# EXIF
33432: copyright
33434: exposure_time
33437: f_number
34850: exposure_program
36864: exif_version
36867: date_time_original
37383: metering_mode
37384: light_source
37385: flash
40962: pixel_x_dimension
40963: pixel_y_dimension
# GeoTIFF
33550: model_pixel_scale
33922: model_tiepoint
34264: model_transformation
34735: geo_key_directory
34736: geo_double_params
34737: geo_ascii_params
# XMP, etc.
34665: exif_ifd_pointer
34853: gps_info_ifd_pointer
40960: flashpix_version
700: xmp
# DNG
50706: dng_version
50707: dng_backward_version
50708: unique_camera_model
50709: localized_camera_model
50710: cfa_plane_color
50711: cfa_layout
50712: linearization_table
50713: black_level_repeat_dim
50714: black_level
50715: black_level_delta_h
50716: black_level_delta_v
50717: white_level
50718: default_scale
50719: default_crop_origin
50720: default_crop_size
50721: color_matrix1
50722: color_matrix2
50723: camera_calibration1
50724: camera_calibration2
50725: reduction_matrix1
50726: reduction_matrix2
50727: analog_balance
50728: as_shot_neutral
50729: as_shot_white_xy
50730: baseline_exposure
50731: baseline_noise
50732: baseline_sharpness
50733: bayer_green_split
50734: linear_response_limit
50735: camera_serial_number
50736: lens_info
50737: chroma_blur_radius
50738: anti_alias_strength
50739: shadow_scale
50740: dng_private_data
50741: maker_note_safety
50778: calibration_illuminant1
50779: calibration_illuminant2
50780: best_quality_scale
50781: raw_data_unique_id
50827: original_raw_file_name
50828: original_raw_file_data
50829: active_area
50830: masked_areas
50831: as_shot_icc_profile
50832: as_shot_pre_profile_matrix
50833: current_icc_profile
50834: current_pre_profile_matrix
50879: colorimetric_reference
50931: camera_calibration_signature
50932: profile_calibration_signature
50933: extra_camera_profiles
50934: as_shot_profile_name
50935: noise_reduction_applied
50936: profile_name
50937: profile_hue_sat_map_dims
50938: profile_hue_sat_map_data1
50939: profile_hue_sat_map_data2
50940: profile_tone_curve
50941: profile_embed_policy
50942: profile_copyright
50964: forward_matrix1
50965: forward_matrix2
50966: preview_application_name
50967: preview_application_version
50968: preview_settings_name
50969: preview_settings_digest
50970: preview_color_space
50971: preview_date_time
50972: raw_image_digest
50973: original_raw_file_digest
50974: sub_tile_block_size
50975: row_interleave_factor
50981: profile_look_table_dims
50982: profile_look_table_data
51125: default_user_crop
51178: depth_near
51179: depth_far
51180: depth_units
52535: illuminant_data3
52536: mask_sub_area
52537: profile_hue_sat_map_data3
52543: rgb_tables
52544: profile_gain_table_map2
52547: column_interleave_factor
51041: noise_profile
51125: default_user_crop
51110: default_black_render
52525: profile_gain_table_map
types:
ifd_entry:
enums:
ftype:
1: byte
2: ascii
3: short
4: long
5: rational
6: signed_byte
7: undefined
8: signed_short
9: signed_long
10: signed_rational
11: float
12: double
types:
byte:
instances:
value:
io: '_parent.direct_value ? _parent.raw_value._io : _root._io '
pos: '_parent.direct_value ? 0 : _parent.offset '
type: u1
repeat: expr
repeat-expr: _parent.count
ascii:
instances:
value:
io: '_parent.direct_value ? _parent.raw_value._io : _root._io '
pos: '_parent.direct_value ? 0 : _parent.offset '
type: str
encoding: UTF-8
size: _parent.count
terminator: 0
consume: false
short:
instances:
value:
io: '_parent.direct_value ? _parent.raw_value._io : _root._io '
pos: '_parent.direct_value ? 0 : _parent.offset '
type:
switch-on: _parent.field_type
cases:
'ftype::short': u2
'ftype::signed_short': s2
repeat: expr
repeat-expr: _parent.count
long:
instances:
value:
io: '_parent.direct_value ? _parent.raw_value._io : _root._io '
pos: '_parent.direct_value ? 0 : _parent.offset '
type:
switch-on: _parent.field_type
cases:
'ftype::long': u4
'ftype::signed_long': s4
repeat: expr
repeat-expr: _parent.count
float:
instances:
value:
io: '_parent.direct_value ? _parent.raw_value._io : _root._io '
pos: '_parent.direct_value ? 0 : _parent.offset '
type: f4
repeat: expr
repeat-expr: _parent.count
double:
instances:
value:
io: '_parent.direct_value ? _parent.raw_value._io : _root._io '
pos: '_parent.direct_value ? 0 : _parent.offset '
type: f8
repeat: expr
repeat-expr: _parent.count
undefined:
instances:
value:
io: '_parent.direct_value ? _parent.raw_value._io : _root._io '
pos: '_parent.direct_value ? 0 : _parent.offset '
size: 1
repeat: expr
repeat-expr: _parent.count
rational:
types:
rational_pair:
seq:
- id: numerator
type:
switch-on: _parent._parent.field_type
cases:
'ftype::rational': u8
'ftype::signed_rational': s8
- id: denominator
type:
switch-on: _parent._parent.field_type
cases:
'ftype::rational': u8
'ftype::signed_rational': s8
instances:
value:
io: '_parent.direct_value ? _parent.raw_value._io : _root._io '
pos: '_parent.direct_value ? 0 : _parent.offset '
type: rational_pair
repeat: expr
repeat-expr: _parent.count
data_exif:
instances:
offset:
io: _parent.raw_value._io
pos: 0
type: u4
exif:
io: _root._io
pos: offset
type: ifd
sub_ifds:
instances:
offset:
io: _parent.raw_value._io
pos: 0
type: u4
sub_ifds:
io: _root._io
pos: offset
type: ifd
raw_value:
seq:
- id: value
size: 4
instances:
direct_value:
value: |
(field_type == ftype::byte and count <= 4) or
(field_type == ftype::signed_byte and count <= 4) or
(field_type == ftype::ascii and count <= 4) or
(field_type == ftype::short and count <= 2) or
(field_type == ftype::signed_short and count <= 2) or
(field_type == ftype::long and count == 1) or
(field_type == ftype::signed_long and count == 1) or
(field_type == ftype::undefined and count <= 4)
seq:
- id: tag
type: u2
enum: tiff_tag
- id: field_type
type: u2
enum: ftype
- id: count
type: u4
- id: raw_value
size: 4
type: raw_value
if: direct_value == true
- id: offset
type: u4
if: direct_value == false
- id: data
type:
switch-on: field_type
cases:
'ftype::byte': byte
'ftype::ascii': ascii
'ftype::short': short
'ftype::signed_short': short
'ftype::long': long
'ftype::signed_long': long
'ftype::rational': rational
'ftype::signed_rational': rational
'ftype::undefined': undefined
'ftype::double': double
'ftype::float': float
- id: parsed_data
type:
switch-on: tag
cases:
'tiff_tag::exif_ifd_pointer': data_exif
'tiff_tag::sub_ifds': sub_ifds
ifd_wrapper:
params:
- id: i
type: u4
instances:
ifd:
io: _root._io
type: ifd
# On the first iteration use ifd_offset,
# then use next_ifd_offset from the previous run
pos: 'i == 0 ? _parent.ifd_offset : _parent.ifds[i - 1].ifd.next_ifd_offset'
ifd:
seq:
- id: num_entries
type: u2
- id: entries
type: ifd_entry
repeat: expr
repeat-expr: num_entries
- id: next_ifd_offset
type: u4
seq:
- id: version
type: u2
- id: ifd_offset
type: u4
- id: ifds
type: ifd_wrapper(_index)
repeat: until
# next_ifd_offset will be 0 when no more ifds are available
repeat-until: _.ifd.next_ifd_offset == 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment