-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathImageMetadataExtractor.py
More file actions
148 lines (122 loc) · 5.27 KB
/
ImageMetadataExtractor.py
File metadata and controls
148 lines (122 loc) · 5.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
"""
File: ImageMetadataExtractor.py
Authors:
- Amey Thakur (https://github.com/Amey-Thakur)
- Mega Satish (https://github.com/msatmod)
Repository: https://github.com/Amey-Thakur/PYTHON-SHORTS
Release Date: January 9, 2022
License: MIT License
Description:
This module implements an Image Metadata Extraction service using the
Pillow (PIL) library. It focuses on the forensic analysis of EXIF data,
retrieving technical parameters such as GPS coordinates, camera
settings, and creation timestamps.
Complexity Analysis:
- Time Complexity: O(1) for header parsing, O(T) where T is number of tags.
- Space Complexity: O(M) where M is the size of the metadata dictionary.
Logic:
1. Header Parsing: Identify the image format (JPEG, PNG, etc.) via magic bytes.
2. EXIF Decoding: Traverse the Exchangeable Image File Format (EXIF)
directory structures (IFDs).
3. Tag Mapping: Convert numerical EXIF tags into human-readable labels
(e.g., 0x0110 -> Model).
4. Data Normalization: Formatting raw binary or rational values into
standard units (Degrees, Seconds, etc.).
"""
import os
from PIL import Image
from PIL.ExifTags import TAGS, GPSTAGS
from typing import Dict, Any, Optional
class ImageMetadataService:
"""
A service class for extraction and forensic cataloging of image metadata.
"""
def __init__(self, image_path: str):
self.image_path = image_path
if not os.path.exists(image_path):
raise FileNotFoundError(f"Image file not found: {image_path}")
def get_basic_info(self) -> Dict[str, Any]:
"""
Retrieves fundamental image attributes.
"""
with Image.open(self.image_path) as img:
return {
"format": img.format,
"mode": img.mode,
"size": img.size,
"width": img.width,
"height": img.height
}
def get_exif_data(self) -> Dict[str, Any]:
"""
Extracts and decodes EXIF tags including GPS data.
"""
exif_data = {}
try:
with Image.open(self.image_path) as img:
info = img._getexif()
if not info:
return {"status": "No EXIF data found"}
for tag, value in info.items():
tag_name = TAGS.get(tag, tag)
# Handle GPS specifically
if tag_name == "GPSInfo":
gps_decoded = {}
for t in value:
sub_tag_name = GPSTAGS.get(t, t)
gps_decoded[sub_tag_name] = value[t]
exif_data["GPS"] = gps_decoded
else:
exif_data[tag_name] = value
except Exception as e:
return {"error": str(e)}
return exif_data
def main():
"""
Demonstrates the Forensic Image Metadata Extraction service.
"""
print("--- Optical Forensics & EXIF Metadata Extraction ---")
print(f"Service: ImageMetadataExtractor.py | Authors: Amey Thakur & Mega Satish\n")
# Locate the localized forensic evidence stream
script_dir = os.path.dirname(os.path.abspath(__file__))
sample_dir = os.path.join(script_dir, "sample_images")
if not os.path.exists(sample_dir):
print(f"[!] Error: Localized forensic directory not found: {sample_dir}")
return
evidence_files = ["Mega.png", "Mega_Chair.png", "Filly.jpg"]
target_found = False
for filename in evidence_files:
img_path = os.path.join(sample_dir, filename)
if os.path.exists(img_path):
target_found = True
print(f"[+] Analyzing Forensic Stream: {filename}")
try:
service = ImageMetadataService(img_path)
print(" [1] Abstract Level: Base Image Attributes")
basic = service.get_basic_info()
for k, v in basic.items():
print(f" {k.capitalize()}: {v}")
print("\n [2] Structural Level: EXIF Tag Cataloging")
exif = service.get_exif_data()
if "status" in exif:
print(f" Status: {exif['status']}")
elif "error" in exif:
print(f" Error: {exif['error']}")
else:
count = 0
for k, v in exif.items():
if count < 3: # Keep logs concise for demo
print(f" Tag {k}: {v}")
count += 1
print("-" * 50)
except Exception as e:
print(f" Error during forensic extraction of {os.path.basename(img_path)}: {e}")
if not target_found:
print("[!] Warning: Forensic portrait collection not found at specified paths.")
print(" Ensure D:\\GitHub\\PYTHON-CRASH-COURSE\\Mega\\ contents are accessible.")
print("\nForensic Notice:")
print(" Scholarly Logic: Processing involves decoding APP1 segments in JPEG")
print(" and resolving Tier-1 and Tier-2 EXIF tags for cryptographic consistency.")
print("\n--- Extraction Complete ---")
if __name__ == "__main__":
main()