0
# Error Handling
1
2
Exception classes for handling various error conditions during EXIF processing. These exceptions provide specific error types for different failure modes during metadata extraction.
3
4
## Capabilities
5
6
### Core EXIF Exceptions
7
8
Standard exceptions raised during EXIF processing for common error conditions.
9
10
```python { .api }
11
class InvalidExif(Exception):
12
"""
13
Raised when EXIF data is corrupted or invalid.
14
15
This exception indicates that the EXIF data structure does not conform
16
to the EXIF specification, such as:
17
- Corrupted IFD headers
18
- Invalid field types
19
- Malformed tag structures
20
- Inconsistent data lengths
21
22
The exception is raised during process_file() when strict=False mode
23
encounters unrecoverable data corruption.
24
"""
25
26
class ExifNotFound(Exception):
27
"""
28
Raised when no EXIF data is found in the image file.
29
30
This exception indicates that the image file does not contain EXIF
31
metadata or the metadata is not accessible, such as:
32
- Image formats without EXIF support
33
- Files with missing EXIF headers
34
- Corrupted file headers preventing EXIF location
35
- Unsupported EXIF variants
36
37
The exception is raised during format detection when no valid EXIF
38
data can be located in the file.
39
"""
40
```
41
42
### HEIC Format Exceptions
43
44
Specialized exceptions for HEIC/HEIF image format processing.
45
46
```python { .api }
47
class WrongBox(Exception):
48
"""
49
Raised when HEIC box structure is unexpected.
50
51
This exception occurs during HEIC file parsing when the ISO base
52
media file format box structure does not match expectations for
53
standard HEIC files.
54
"""
55
56
class NoParser(Exception):
57
"""
58
Raised when no parser is available for HEIC box type.
59
60
This exception occurs when encountering unsupported or unknown
61
box types in HEIC files that cannot be processed by the current
62
implementation.
63
"""
64
65
class BoxVersion(Exception):
66
"""
67
Raised when HEIC box version is unsupported.
68
69
This exception occurs when the version field in HEIC box headers
70
indicates a format version that is not supported by the parser.
71
"""
72
73
class BadSize(Exception):
74
"""
75
Raised when HEIC box size information is invalid.
76
77
This exception occurs when box size fields contain invalid or
78
inconsistent length information that would cause parsing errors
79
or file corruption.
80
"""
81
```
82
83
## Usage Examples
84
85
### Basic Exception Handling
86
87
```python
88
import exifread
89
90
def safe_extract_exif(filename):
91
"""Safely extract EXIF with proper error handling."""
92
try:
93
with open(filename, 'rb') as f:
94
tags = exifread.process_file(f)
95
return tags
96
except exifread.InvalidExif as e:
97
print(f"Invalid EXIF data in {filename}: {e}")
98
return None
99
except exifread.ExifNotFound as e:
100
print(f"No EXIF data found in {filename}: {e}")
101
return None
102
except IOError as e:
103
print(f"Cannot read file {filename}: {e}")
104
return None
105
106
# Usage
107
tags = safe_extract_exif('photo.jpg')
108
if tags:
109
print(f"Successfully extracted {len(tags)} EXIF tags")
110
else:
111
print("EXIF extraction failed")
112
```
113
114
### Strict Mode Exception Handling
115
116
```python
117
import exifread
118
119
def strict_exif_processing(filename):
120
"""Process EXIF in strict mode with detailed error handling."""
121
try:
122
with open(filename, 'rb') as f:
123
# Strict mode raises exceptions instead of ignoring errors
124
tags = exifread.process_file(f, strict=True)
125
return tags, None
126
except exifread.InvalidExif as e:
127
return None, f"Corrupted EXIF data: {e}"
128
except exifread.ExifNotFound as e:
129
return None, f"No EXIF metadata: {e}"
130
except ValueError as e:
131
# Strict mode may raise ValueError for invalid field types
132
return None, f"Invalid EXIF field: {e}"
133
except Exception as e:
134
return None, f"Unexpected error: {e}"
135
136
# Usage
137
tags, error = strict_exif_processing('photo.jpg')
138
if tags:
139
print("Strict processing successful")
140
else:
141
print(f"Processing failed: {error}")
142
```
143
144
### HEIC Exception Handling
145
146
```python
147
import exifread
148
from exifread.heic import WrongBox, NoParser, BoxVersion, BadSize
149
150
def process_heic_file(filename):
151
"""Process HEIC file with format-specific error handling."""
152
try:
153
with open(filename, 'rb') as f:
154
tags = exifread.process_file(f)
155
return tags, "success"
156
except WrongBox as e:
157
return None, f"HEIC box structure error: {e}"
158
except NoParser as e:
159
return None, f"Unsupported HEIC box type: {e}"
160
except BoxVersion as e:
161
return None, f"Unsupported HEIC version: {e}"
162
except BadSize as e:
163
return None, f"Invalid HEIC box size: {e}"
164
except exifread.ExifNotFound as e:
165
return None, f"No EXIF in HEIC file: {e}"
166
except Exception as e:
167
return None, f"General HEIC processing error: {e}"
168
169
# Usage for HEIC files
170
if filename.lower().endswith('.heic'):
171
tags, status = process_heic_file(filename)
172
if tags:
173
print(f"HEIC processing successful: {len(tags)} tags")
174
else:
175
print(f"HEIC processing failed: {status}")
176
```
177
178
### Batch Processing with Error Reporting
179
180
```python
181
import exifread
182
import os
183
from collections import defaultdict
184
185
def batch_process_with_errors(file_list):
186
"""Process multiple files and categorize errors."""
187
results = {
188
'success': [],
189
'no_exif': [],
190
'invalid_exif': [],
191
'file_errors': [],
192
'other_errors': []
193
}
194
195
error_counts = defaultdict(int)
196
197
for filename in file_list:
198
try:
199
with open(filename, 'rb') as f:
200
tags = exifread.process_file(f, strict=True)
201
results['success'].append((filename, len(tags)))
202
203
except exifread.ExifNotFound:
204
results['no_exif'].append(filename)
205
error_counts['no_exif'] += 1
206
207
except exifread.InvalidExif as e:
208
results['invalid_exif'].append((filename, str(e)))
209
error_counts['invalid_exif'] += 1
210
211
except IOError as e:
212
results['file_errors'].append((filename, str(e)))
213
error_counts['file_errors'] += 1
214
215
except Exception as e:
216
results['other_errors'].append((filename, str(e)))
217
error_counts['other_errors'] += 1
218
219
return results, error_counts
220
221
# Usage example
222
image_files = ['photo1.jpg', 'photo2.tiff', 'corrupted.jpg', 'no_exif.png']
223
results, error_counts = batch_process_with_errors(image_files)
224
225
print(f"Successfully processed: {len(results['success'])} files")
226
print(f"Files without EXIF: {error_counts['no_exif']}")
227
print(f"Files with invalid EXIF: {error_counts['invalid_exif']}")
228
print(f"File access errors: {error_counts['file_errors']}")
229
print(f"Other errors: {error_counts['other_errors']}")
230
```
231
232
### Logging Errors for Debugging
233
234
```python
235
import exifread
236
import logging
237
238
# Configure logging
239
logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s')
240
logger = logging.getLogger(__name__)
241
242
def extract_exif_with_logging(filename):
243
"""Extract EXIF with comprehensive error logging."""
244
logger.info(f"Processing file: {filename}")
245
246
try:
247
with open(filename, 'rb') as f:
248
tags = exifread.process_file(f, debug=True)
249
logger.info(f"Successfully extracted {len(tags)} tags from {filename}")
250
return tags
251
252
except exifread.InvalidExif as e:
253
logger.error(f"Invalid EXIF in {filename}: {e}")
254
# Try non-strict mode as fallback
255
try:
256
with open(filename, 'rb') as f:
257
tags = exifread.process_file(f, strict=False)
258
logger.warning(f"Fallback processing recovered {len(tags)} tags")
259
return tags
260
except Exception as fallback_error:
261
logger.error(f"Fallback also failed: {fallback_error}")
262
return None
263
264
except exifread.ExifNotFound as e:
265
logger.warning(f"No EXIF data in {filename}: {e}")
266
return None
267
268
except Exception as e:
269
logger.error(f"Unexpected error processing {filename}: {e}")
270
return None
271
272
# Usage
273
tags = extract_exif_with_logging('problematic_photo.jpg')
274
```
275
276
### Custom Exception Handling
277
278
```python
279
import exifread
280
281
class ExifProcessingError(Exception):
282
"""Custom exception for EXIF processing workflows."""
283
def __init__(self, filename, original_error, error_type):
284
self.filename = filename
285
self.original_error = original_error
286
self.error_type = error_type
287
super().__init__(f"{error_type} in {filename}: {original_error}")
288
289
def safe_process_with_custom_exceptions(filename):
290
"""Process file with custom exception wrapping."""
291
try:
292
with open(filename, 'rb') as f:
293
return exifread.process_file(f)
294
except exifread.InvalidExif as e:
295
raise ExifProcessingError(filename, e, "INVALID_EXIF")
296
except exifread.ExifNotFound as e:
297
raise ExifProcessingError(filename, e, "NO_EXIF")
298
except IOError as e:
299
raise ExifProcessingError(filename, e, "FILE_ERROR")
300
301
# Usage with custom exception handling
302
try:
303
tags = safe_process_with_custom_exceptions('photo.jpg')
304
print("Processing successful")
305
except ExifProcessingError as e:
306
print(f"Processing failed: {e}")
307
print(f"Error type: {e.error_type}")
308
print(f"Filename: {e.filename}")
309
print(f"Original error: {e.original_error}")
310
```