Spaces:
Sleeping
Sleeping
rmm
commited on
Commit
·
0cc6a8a
1
Parent(s):
cf8541f
fix: timezone from file metadata, or from locale if absent
Browse files- src/input/input_handling.py +24 -5
- src/input/input_validator.py +22 -0
src/input/input_handling.py
CHANGED
|
@@ -11,7 +11,7 @@ import cv2
|
|
| 11 |
import numpy as np
|
| 12 |
|
| 13 |
from input.input_observation import InputObservation
|
| 14 |
-
from input.input_validator import get_image_datetime, is_valid_email, is_valid_number, get_image_latlon
|
| 15 |
|
| 16 |
m_logger = logging.getLogger(__name__)
|
| 17 |
m_logger.setLevel(logging.INFO)
|
|
@@ -186,6 +186,7 @@ def metadata_inputs_one_file(file:UploadedFile, image_hash:str, dbg_ix:int=0) ->
|
|
| 186 |
author_email = st.session_state["input_author_email"]
|
| 187 |
filename = file.name
|
| 188 |
image_datetime_raw = get_image_datetime(file)
|
|
|
|
| 189 |
latitude0, longitude0 = get_image_latlon(file)
|
| 190 |
msg = f"[D] {filename}: lat, lon from image metadata: {latitude0}, {longitude0}"
|
| 191 |
m_logger.debug(msg)
|
|
@@ -226,11 +227,29 @@ def metadata_inputs_one_file(file:UploadedFile, image_hash:str, dbg_ix:int=0) ->
|
|
| 226 |
# 5. Date/time
|
| 227 |
## first from image metadata
|
| 228 |
if image_datetime_raw is not None:
|
| 229 |
-
|
| 230 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 231 |
else:
|
| 232 |
-
|
| 233 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 234 |
|
| 235 |
## either way, give user the option to enter manually (or correct, e.g. if camera has no rtc clock)
|
| 236 |
date = viewcontainer.date_input("Date for "+filename, value=date_value, key=f"input_date_{image_hash}")
|
|
|
|
| 11 |
import numpy as np
|
| 12 |
|
| 13 |
from input.input_observation import InputObservation
|
| 14 |
+
from input.input_validator import get_image_datetime, is_valid_email, is_valid_number, get_image_latlon, get_image_timezone
|
| 15 |
|
| 16 |
m_logger = logging.getLogger(__name__)
|
| 17 |
m_logger.setLevel(logging.INFO)
|
|
|
|
| 186 |
author_email = st.session_state["input_author_email"]
|
| 187 |
filename = file.name
|
| 188 |
image_datetime_raw = get_image_datetime(file)
|
| 189 |
+
image_timezone_raw = get_image_timezone(file)
|
| 190 |
latitude0, longitude0 = get_image_latlon(file)
|
| 191 |
msg = f"[D] {filename}: lat, lon from image metadata: {latitude0}, {longitude0}"
|
| 192 |
m_logger.debug(msg)
|
|
|
|
| 227 |
# 5. Date/time
|
| 228 |
## first from image metadata
|
| 229 |
if image_datetime_raw is not None:
|
| 230 |
+
# if we have a timezone let's use it (but only if we also have datetime)
|
| 231 |
+
time_fmt = '%Y:%m:%d %H:%M:%S'
|
| 232 |
+
if image_timezone_raw is not None:
|
| 233 |
+
image_datetime_raw += f" {image_timezone_raw}"
|
| 234 |
+
time_fmt += ' %z'
|
| 235 |
+
#
|
| 236 |
+
dt = datetime.datetime.strptime(image_datetime_raw, time_fmt)
|
| 237 |
+
date_value = dt.date()
|
| 238 |
+
time_value = dt.time()
|
| 239 |
+
tz_value = dt.tzinfo # could be None...
|
| 240 |
+
|
| 241 |
+
#time_value = datetime.datetime.strptime(image_datetime_raw, '%Y:%m:%d %H:%M:%S').time()
|
| 242 |
+
#date_value = datetime.datetime.strptime(image_datetime_raw, '%Y:%m:%d %H:%M:%S').date()
|
| 243 |
else:
|
| 244 |
+
# get current time, with user timezone (or is it server timezone?! TODO: test with different zones)
|
| 245 |
+
dt = datetime.datetime.now().astimezone().replace(microsecond=0)
|
| 246 |
+
time_value = dt.time()
|
| 247 |
+
date_value = dt.date()
|
| 248 |
+
tz_value = dt.tzinfo
|
| 249 |
+
|
| 250 |
+
#time_value = datetime.datetime.now().time() # Default to current time
|
| 251 |
+
#date_value = datetime.datetime.now().date()
|
| 252 |
+
|
| 253 |
|
| 254 |
## either way, give user the option to enter manually (or correct, e.g. if camera has no rtc clock)
|
| 255 |
date = viewcontainer.date_input("Date for "+filename, value=date_value, key=f"input_date_{image_hash}")
|
src/input/input_validator.py
CHANGED
|
@@ -84,6 +84,28 @@ def get_image_datetime(image_file:UploadedFile) -> Union[str, None]:
|
|
| 84 |
# TODO: add to logger
|
| 85 |
return None
|
| 86 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
|
| 88 |
def decimal_coords(coords:tuple, ref:str) -> Fraction:
|
| 89 |
"""
|
|
|
|
| 84 |
# TODO: add to logger
|
| 85 |
return None
|
| 86 |
|
| 87 |
+
# function to extract the timezone from image metadata
|
| 88 |
+
def get_image_timezone(image_file:UploadedFile) -> Union[str, None]:
|
| 89 |
+
"""
|
| 90 |
+
Extracts the timezone from the EXIF metadata of an uploaded image file.
|
| 91 |
+
|
| 92 |
+
Args:
|
| 93 |
+
image_file (UploadedFile): The uploaded image file from which to extract the timezone.
|
| 94 |
+
|
| 95 |
+
Returns:
|
| 96 |
+
str: The timezone as a string if available, otherwise None.
|
| 97 |
+
|
| 98 |
+
Raises:
|
| 99 |
+
Warning: If the timezone could not be extracted from the image metadata.
|
| 100 |
+
"""
|
| 101 |
+
try:
|
| 102 |
+
image = Image.open(image_file)
|
| 103 |
+
exif_data = image._getexif()
|
| 104 |
+
if exif_data is not None:
|
| 105 |
+
if ExifTags.Base.OffsetTimeOriginal in exif_data:
|
| 106 |
+
return exif_data.get(ExifTags.Base.OffsetTimeOriginal)
|
| 107 |
+
except Exception as e: # FIXME: what types of exception?
|
| 108 |
+
st.warning(f"Could not extract timezone from image metadata. (file: {image_file.name})")
|
| 109 |
|
| 110 |
def decimal_coords(coords:tuple, ref:str) -> Fraction:
|
| 111 |
"""
|