or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli.mdcore-processing.mddata-structures.mdexceptions.mdheic.mdindex.mdlogging.mdutilities.md

data-structures.mddocs/

0

# Data Structures

1

2

Classes and objects for representing EXIF metadata, including individual tags, file headers, and specialized data types. These structures provide access to raw tag values, metadata, and processing capabilities.

3

4

## Capabilities

5

6

### IfdTag Class

7

8

Represents an individual EXIF tag with its value and associated metadata.

9

10

```python { .api }

11

class IfdTag:

12

"""

13

Represents a single EXIF tag with value and metadata.

14

15

This class encapsulates all information about an EXIF tag including

16

its printable representation, raw values, type information, and

17

file location details.

18

"""

19

20

def __init__(self, printable, tag, field_type, values, field_offset, field_length):

21

"""

22

Initialize an IfdTag instance.

23

24

Parameters:

25

- printable: str, human-readable representation of tag value

26

- tag: int, tag ID number (hex identifier)

27

- field_type: int, field type as index into FIELD_TYPES

28

- values: str or list, raw tag values (string or array of data items)

29

- field_offset: int, offset of field start in bytes from IFD beginning

30

- field_length: int, length of data field in bytes

31

"""

32

33

printable: str

34

"""Human-readable version of the tag value."""

35

36

tag: int

37

"""Tag ID number (hexadecimal identifier)."""

38

39

field_type: int

40

"""Field type as index into FIELD_TYPES tuple."""

41

42

values: Union[str, List[Any]]

43

"""Raw tag values - either string or array of data items."""

44

45

field_offset: int

46

"""Offset of field start in bytes from beginning of IFD."""

47

48

field_length: int

49

"""Length of data field in bytes."""

50

51

def __str__(self) -> str:

52

"""Return printable representation of tag value."""

53

54

def __repr__(self) -> str:

55

"""Return detailed string representation for debugging."""

56

```

57

58

### ExifHeader Class

59

60

Handles EXIF header parsing and processing for extracting metadata from image files.

61

62

```python { .api }

63

class ExifHeader:

64

"""

65

Handle EXIF header parsing and tag extraction.

66

67

This class manages the low-level details of reading EXIF data from

68

image files, parsing IFD structures, and extracting individual tags.

69

"""

70

71

def __init__(self, file_handle, endian, offset, fake_exif, strict, debug=False, detailed=True, truncate_tags=True):

72

"""

73

Initialize ExifHeader for processing.

74

75

Parameters:

76

- file_handle: file object, open binary file handle

77

- endian: str, byte order ('I' for Intel/little-endian, 'M' for Motorola/big-endian)

78

- offset: int, offset to start of EXIF data in file

79

- fake_exif: int, flag indicating synthetic EXIF header

80

- strict: bool, strict processing mode

81

- debug: bool, enable debug output

82

- detailed: bool, process MakerNotes and thumbnails

83

- truncate_tags: bool, truncate long tag values

84

"""

85

86

tags: Dict[str, IfdTag]

87

"""Dictionary of extracted EXIF tags."""

88

89

def s2n(self, offset, length, signed=False) -> int:

90

"""

91

Convert slice to integer based on endian and sign flags.

92

93

Parameters:

94

- offset: int, offset relative to EXIF data start

95

- length: int, number of bytes to read (1, 2, 4, or 8)

96

- signed: bool, whether to interpret as signed integer

97

98

Returns:

99

int: Converted integer value

100

"""

101

102

def n2s(self, offset, length) -> str:

103

"""

104

Convert integer offset to string representation.

105

106

Parameters:

107

- offset: int, integer value to convert

108

- length: int, number of bytes for output

109

110

Returns:

111

str: String representation

112

"""

113

114

def list_ifd(self) -> List[int]:

115

"""

116

Return list of IFD (Image File Directory) offsets in header.

117

118

Returns:

119

List[int]: List of IFD offset positions

120

"""

121

122

def dump_ifd(self, ifd, ifd_name, tag_dict=None, relative=0, stop_tag='UNDEF'):

123

"""

124

Process and extract entries from an IFD.

125

126

Parameters:

127

- ifd: int, IFD offset position

128

- ifd_name: str, name for this IFD (e.g., 'Image', 'EXIF', 'GPS')

129

- tag_dict: dict, tag definitions dictionary (defaults to EXIF_TAGS)

130

- relative: int, relative addressing flag for MakerNotes

131

- stop_tag: str, tag name to stop processing at

132

"""

133

134

def extract_tiff_thumbnail(self, thumb_ifd):

135

"""

136

Extract uncompressed TIFF thumbnail from thumbnail IFD.

137

138

Parameters:

139

- thumb_ifd: int, thumbnail IFD offset

140

"""

141

142

def extract_jpeg_thumbnail(self):

143

"""

144

Extract JPEG thumbnail data from EXIF.

145

146

Stores thumbnail data in tags['JPEGThumbnail'] if found.

147

"""

148

149

def decode_maker_note(self):

150

"""

151

Decode camera-specific MakerNote formats.

152

153

Supports MakerNotes from Canon, Nikon, Olympus, Fujifilm,

154

Casio, and Apple cameras with format-specific parsing.

155

"""

156

157

def parse_xmp(self, xmp_string):

158

"""

159

Parse Adobe XMP (Extensible Metadata Platform) data.

160

161

Parameters:

162

- xmp_string: bytes, XMP XML data

163

"""

164

```

165

166

### Ratio Class

167

168

Specialized numeric type for representing rational numbers commonly used in EXIF data.

169

170

```python { .api }

171

class Ratio:

172

"""

173

Ratio object for EXIF rational number values.

174

175

Inherits from fractions.Fraction to provide rational number

176

arithmetic with EXIF-specific display formatting.

177

"""

178

179

def __new__(cls, numerator=0, denominator=None):

180

"""

181

Create new Ratio instance.

182

183

Parameters:

184

- numerator: int, numerator value

185

- denominator: int, denominator value (None for whole numbers)

186

187

Returns:

188

Ratio: New ratio instance

189

"""

190

191

@property

192

def num(self) -> int:

193

"""Get numerator value."""

194

195

@property

196

def den(self) -> int:

197

"""Get denominator value."""

198

199

def decimal(self) -> float:

200

"""

201

Convert ratio to decimal floating point.

202

203

Returns:

204

float: Decimal representation of the ratio

205

"""

206

207

def __repr__(self) -> str:

208

"""Return string representation of ratio."""

209

```

210

211

## Usage Examples

212

213

### Working with IfdTag Objects

214

215

```python

216

import exifread

217

218

with open('photo.jpg', 'rb') as f:

219

tags = exifread.process_file(f)

220

221

# Access tag properties

222

if 'EXIF FocalLength' in tags:

223

focal_length_tag = tags['EXIF FocalLength']

224

225

print(f"Printable value: {focal_length_tag.printable}")

226

print(f"Raw values: {focal_length_tag.values}")

227

print(f"Tag ID: 0x{focal_length_tag.tag:04X}")

228

print(f"Field type: {focal_length_tag.field_type}")

229

print(f"File offset: {focal_length_tag.field_offset}")

230

print(f"Data length: {focal_length_tag.field_length}")

231

```

232

233

### Working with Ratio Values

234

235

```python

236

import exifread

237

238

with open('photo.jpg', 'rb') as f:

239

tags = exifread.process_file(f)

240

241

# Many EXIF values are ratios (fractions)

242

if 'EXIF ExposureTime' in tags:

243

exposure_tag = tags['EXIF ExposureTime']

244

245

# Access as Ratio object

246

if hasattr(exposure_tag.values[0], 'decimal'):

247

ratio_value = exposure_tag.values[0]

248

print(f"Exposure time: {ratio_value.num}/{ratio_value.den}")

249

print(f"Decimal seconds: {ratio_value.decimal()}")

250

```

251

252

### Accessing Thumbnail Data

253

254

```python

255

import exifread

256

257

with open('photo.jpg', 'rb') as f:

258

tags = exifread.process_file(f)

259

260

# Check for embedded thumbnails

261

if 'JPEGThumbnail' in tags:

262

thumbnail_data = tags['JPEGThumbnail']

263

print(f"JPEG thumbnail found, size: {len(thumbnail_data)} bytes")

264

265

# Save thumbnail to file

266

with open('thumbnail.jpg', 'wb') as thumb_file:

267

thumb_file.write(thumbnail_data)

268

269

if 'TIFFThumbnail' in tags:

270

tiff_thumbnail = tags['TIFFThumbnail']

271

print(f"TIFF thumbnail found, size: {len(tiff_thumbnail)} bytes")

272

```

273

274

### Iterating Through Tag Categories

275

276

```python

277

import exifread

278

279

with open('photo.jpg', 'rb') as f:

280

tags = exifread.process_file(f)

281

282

# Organize tags by category

283

image_tags = {}

284

exif_tags = {}

285

gps_tags = {}

286

makernote_tags = {}

287

288

for tag_name, tag_value in tags.items():

289

if tag_name.startswith('Image '):

290

image_tags[tag_name] = tag_value

291

elif tag_name.startswith('EXIF '):

292

exif_tags[tag_name] = tag_value

293

elif tag_name.startswith('GPS '):

294

gps_tags[tag_name] = tag_value

295

elif tag_name.startswith('MakerNote '):

296

makernote_tags[tag_name] = tag_value

297

298

print(f"Image tags: {len(image_tags)}")

299

print(f"EXIF tags: {len(exif_tags)}")

300

print(f"GPS tags: {len(gps_tags)}")

301

print(f"MakerNote tags: {len(makernote_tags)}")

302

```