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
```