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

utilities.mddocs/

0

# Utilities

1

2

Helper functions for processing extracted EXIF metadata, including GPS coordinate conversion, string handling, and format compatibility utilities. These functions provide essential data transformation and extraction capabilities.

3

4

## Capabilities

5

6

### GPS Coordinate Extraction

7

8

Extract GPS coordinates from EXIF tags and convert to decimal degrees.

9

10

```python { .api }

11

def get_gps_coords(tags):

12

"""

13

Extract GPS coordinates from EXIF tags.

14

15

Converts GPS latitude and longitude from EXIF format (degrees, minutes, seconds)

16

to decimal degrees with proper hemisphere handling.

17

18

Parameters:

19

- tags: dict, dictionary of EXIF tags from process_file()

20

21

Returns:

22

tuple or None: Tuple of (latitude, longitude) as float values in decimal degrees,

23

or None if GPS tags are not present or incomplete

24

25

Notes:

26

- Requires GPS GPSLatitude, GPS GPSLatitudeRef, GPS GPSLongitude, GPS GPSLongitudeRef tags

27

- North/East coordinates are positive, South/West are negative

28

- Returns None if any required GPS tags are missing

29

"""

30

```

31

32

### String Conversion Utilities

33

34

Functions for converting EXIF data sequences to readable strings.

35

36

```python { .api }

37

def make_string(seq):

38

"""

39

Convert sequence to printable string without throwing exceptions.

40

41

Filters out non-printing characters and handles type conversion safely.

42

43

Parameters:

44

- seq: sequence, iterable of character codes or bytes

45

46

Returns:

47

str: Printable string representation, or string representation of

48

original sequence if no printable characters found

49

"""

50

51

def make_string_uc(seq):

52

"""

53

Convert user comment field to string with encoding handling.

54

55

Handles the special encoding format used in EXIF UserComment fields where

56

the first 8 bytes specify the character encoding (ASCII, JIS, Unicode).

57

58

Parameters:

59

- seq: sequence or str, user comment data with encoding prefix

60

61

Returns:

62

str: Decoded string content (skips first 8 encoding bytes if sequence)

63

"""

64

```

65

66

### Python Compatibility Utilities

67

68

Cross-version compatibility functions for Python 2/3 support.

69

70

```python { .api }

71

def ord_(dta):

72

"""

73

Python 2/3 compatible ord() function.

74

75

Handles the difference in string/byte handling between Python versions.

76

77

Parameters:

78

- dta: str or int, character data

79

80

Returns:

81

int: ASCII/Unicode code point value

82

"""

83

```

84

85

## Usage Examples

86

87

### Extracting GPS Coordinates

88

89

```python

90

import exifread

91

from exifread.utils import get_gps_coords

92

93

# Open image and extract tags

94

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

95

tags = exifread.process_file(f)

96

97

# Extract GPS coordinates

98

coords = get_gps_coords(tags)

99

100

if coords:

101

latitude, longitude = coords

102

print(f"Location: {latitude:.6f}, {longitude:.6f}")

103

104

# Determine hemispheres

105

lat_hemisphere = "N" if latitude >= 0 else "S"

106

lon_hemisphere = "E" if longitude >= 0 else "W"

107

108

print(f"Latitude: {abs(latitude):.6f}° {lat_hemisphere}")

109

print(f"Longitude: {abs(longitude):.6f}° {lon_hemisphere}")

110

else:

111

print("No GPS coordinates found in image")

112

```

113

114

### Working with GPS Tags Manually

115

116

```python

117

import exifread

118

119

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

120

tags = exifread.process_file(f)

121

122

# Check individual GPS tags

123

gps_tags = ['GPS GPSLatitude', 'GPS GPSLatitudeRef', 'GPS GPSLongitude', 'GPS GPSLongitudeRef']

124

125

print("GPS Tags:")

126

for tag_name in gps_tags:

127

if tag_name in tags:

128

tag_value = tags[tag_name]

129

print(f" {tag_name}: {tag_value.printable}")

130

if hasattr(tag_value, 'values'):

131

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

132

133

# Additional GPS information

134

gps_info_tags = ['GPS GPSAltitude', 'GPS GPSTimeStamp', 'GPS GPSDateStamp', 'GPS GPSMapDatum']

135

for tag_name in gps_info_tags:

136

if tag_name in tags:

137

print(f" {tag_name}: {tags[tag_name].printable}")

138

```

139

140

### String Processing Examples

141

142

```python

143

import exifread

144

from exifread.utils import make_string, make_string_uc

145

146

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

147

tags = exifread.process_file(f)

148

149

# Process user comments with encoding handling

150

if 'EXIF UserComment' in tags:

151

user_comment_tag = tags['EXIF UserComment']

152

153

# The raw values might include encoding bytes

154

if hasattr(user_comment_tag, 'values'):

155

# Use make_string_uc to handle encoding prefix

156

comment = make_string_uc(user_comment_tag.values)

157

print(f"User Comment: {comment}")

158

159

# Process other string fields safely

160

string_tags = ['Image Make', 'Image Model', 'Image Software', 'Image Artist']

161

for tag_name in string_tags:

162

if tag_name in tags:

163

tag_value = tags[tag_name]

164

# Values are already processed as strings, but you could use make_string for raw data

165

print(f"{tag_name}: {tag_value.printable}")

166

```

167

168

### Handling Non-ASCII Content

169

170

```python

171

import exifread

172

from exifread.utils import make_string

173

174

# Example of processing raw byte sequences

175

def process_maker_note_string(raw_bytes):

176

"""Process raw MakerNote string data."""

177

if isinstance(raw_bytes, (list, tuple)):

178

# Convert byte sequence to printable string

179

printable_string = make_string(raw_bytes)

180

return printable_string

181

return str(raw_bytes)

182

183

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

184

tags = exifread.process_file(f)

185

186

# Process MakerNote tags that might contain raw byte data

187

for tag_name, tag_value in tags.items():

188

if tag_name.startswith('MakerNote') and hasattr(tag_value, 'values'):

189

if isinstance(tag_value.values, (list, tuple)) and len(tag_value.values) > 0:

190

processed = process_maker_note_string(tag_value.values)

191

print(f"{tag_name}: {processed}")

192

```

193

194

### Creating GPS URL Links

195

196

```python

197

import exifread

198

from exifread.utils import get_gps_coords

199

200

def create_map_url(latitude, longitude, service='google'):

201

"""Create map service URL from coordinates."""

202

if service == 'google':

203

return f"https://maps.google.com/?q={latitude},{longitude}"

204

elif service == 'osm':

205

return f"https://www.openstreetmap.org/?mlat={latitude}&mlon={longitude}&zoom=15"

206

else:

207

return f"{latitude},{longitude}"

208

209

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

210

tags = exifread.process_file(f)

211

212

coords = get_gps_coords(tags)

213

if coords:

214

latitude, longitude = coords

215

216

# Create map links

217

google_url = create_map_url(latitude, longitude, 'google')

218

osm_url = create_map_url(latitude, longitude, 'osm')

219

220

print(f"Google Maps: {google_url}")

221

print(f"OpenStreetMap: {osm_url}")

222

```

223

224

### Validating GPS Data

225

226

```python

227

import exifread

228

from exifread.utils import get_gps_coords

229

230

def validate_coordinates(latitude, longitude):

231

"""Validate GPS coordinates are within valid ranges."""

232

if not (-90 <= latitude <= 90):

233

return False, f"Invalid latitude: {latitude} (must be -90 to 90)"

234

if not (-180 <= longitude <= 180):

235

return False, f"Invalid longitude: {longitude} (must be -180 to 180)"

236

return True, "Valid coordinates"

237

238

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

239

tags = exifread.process_file(f)

240

241

coords = get_gps_coords(tags)

242

if coords:

243

latitude, longitude = coords

244

is_valid, message = validate_coordinates(latitude, longitude)

245

246

if is_valid:

247

print(f"Valid GPS coordinates: {latitude:.6f}, {longitude:.6f}")

248

else:

249

print(f"GPS validation error: {message}")

250

else:

251

print("No GPS coordinates found")

252

```