-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils.py
More file actions
106 lines (84 loc) · 3.15 KB
/
Copy pathutils.py
File metadata and controls
106 lines (84 loc) · 3.15 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
"""
utils.py
--------
Helper Functions for Image Metadata Analyzer Pro.
Contains small, reusable utilities:
- File size formatting
- GPS DMS -> Decimal Degree conversion
- File hashing (MD5 / SHA-256) for integrity checks
- Safe string cleaning for display
- Timestamp formatting
"""
import os
import hashlib
from datetime import datetime
def format_file_size(size_bytes: int) -> str:
"""Convert a raw byte count into a human readable string (e.g. 2.35 MB)."""
if size_bytes is None:
return "N/A"
if size_bytes == 0:
return "0 B"
units = ["B", "KB", "MB", "GB", "TB"]
index = 0
size = float(size_bytes)
while size >= 1024 and index < len(units) - 1:
size /= 1024
index += 1
return f"{size:.2f} {units[index]}"
def get_file_basic_info(filepath: str) -> dict:
"""Return basic filesystem info about the image file."""
if not os.path.exists(filepath):
return {}
stat = os.stat(filepath)
return {
"File Name": os.path.basename(filepath),
"File Path": os.path.abspath(filepath),
"File Size": format_file_size(stat.st_size),
"Created": datetime.fromtimestamp(stat.st_ctime).strftime("%Y-%m-%d %H:%M:%S"),
"Modified": datetime.fromtimestamp(stat.st_mtime).strftime("%Y-%m-%d %H:%M:%S"),
}
def dms_to_decimal(dms, ref) -> float:
"""
Convert GPS coordinates from (Degrees, Minutes, Seconds) format,
as stored in EXIF tags, into decimal degrees.
dms -> tuple/list of 3 numbers or exifread Ratio objects: (deg, min, sec)
ref -> 'N', 'S', 'E', or 'W'
"""
try:
degrees = float(dms[0])
minutes = float(dms[1])
seconds = float(dms[2])
except (TypeError, IndexError, ValueError):
return None
decimal = degrees + (minutes / 60.0) + (seconds / 3600.0)
if ref in ("S", "W"):
decimal = -decimal
return round(decimal, 6)
def calculate_file_hash(filepath: str, algo: str = "sha256") -> str:
"""Calculate a cryptographic hash of the file for integrity verification."""
hash_func = hashlib.sha256() if algo == "sha256" else hashlib.md5()
try:
with open(filepath, "rb") as f:
for chunk in iter(lambda: f.read(8192), b""):
hash_func.update(chunk)
return hash_func.hexdigest()
except OSError:
return "N/A"
def clean_value(value) -> str:
"""Convert any EXIF value into a clean, printable string."""
try:
text = str(value).strip()
# Remove null bytes / control characters that sometimes appear in EXIF
text = "".join(ch for ch in text if ch.isprintable())
return text if text else "N/A"
except Exception:
return "N/A"
def is_supported_image(filepath: str) -> bool:
"""Check whether a file has a supported image extension."""
supported = (".jpg", ".jpeg", ".png", ".tiff", ".tif", ".bmp", ".heic", ".webp")
return filepath.lower().endswith(supported)
def build_google_maps_link(lat: float, lon: float) -> str:
"""Build a Google Maps URL from decimal latitude/longitude."""
if lat is None or lon is None:
return "N/A"
return f"https://www.google.com/maps?q={lat},{lon}"