Skip to content

Commit e128099

Browse files
committed
Merge branch 'dev'
2 parents 2c16b92 + 4b04e61 commit e128099

16 files changed

+1213
-262
lines changed

.pylintrc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
[TYPECHECK]
22
generated-members=cv2.*
3+
[FORMAT]
4+
max-line-length=100

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ dependencies = [
4545
"ninepatch>=0.2.0",
4646
"pi_heif>=0.8.0",
4747
"python-vlc",
48-
"opencv-python"
48+
"rubicon-objc; sys_platform == 'darwin'"
4949
]
5050

5151
[project.urls]

src/picframe/controller.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,17 +85,17 @@ def next(self):
8585
self.__viewer.stop_video()
8686
else:
8787
self.__next_tm = 0
88+
self.__force_navigate = True
8889
self.__viewer.reset_name_tm()
89-
self.__force_navigate = True
90-
90+
9191
def back(self):
9292
if self.__viewer.is_video_playing():
9393
self.__viewer.stop_video()
9494
else:
9595
self.__next_tm = 0
96+
self.__force_navigate = True
9697
self.__model.set_next_file_to_previous_file()
9798
self.__viewer.reset_name_tm()
98-
self.__force_navigate = True
9999

100100
def delete(self):
101101
if self.__viewer.is_video_playing():

src/picframe/get_image_meta.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@ def __init__(self, filename):
1717
self.__logger = logging.getLogger("get_image_meta.GetImageMeta")
1818
self.__tags = {}
1919
self.__filename = filename # in case no exif data in which case needed for size
20+
self.__image_width: int = 0
21+
self.__image_height: int = 0
2022
image = self.get_image_object(filename)
2123
if image:
24+
self.__image_width, self.__image_height = image.size
2225
exif = image.getexif()
2326
self.__do_image_tags(exif)
2427
self.__do_exif_tags(exif)
@@ -31,6 +34,11 @@ def __init__(self, filename):
3134
except Exception as e:
3235
xmp = {}
3336
self.__logger.warning("PILL getxmp() failed: %s -> %s", filename, e)
37+
38+
@property
39+
def size(self) -> tuple[int, int]:
40+
"""Returns the (width, height) tuple of the image."""
41+
return (self.__image_width, self.__image_height)
3442

3543
def __do_image_tags(self, exif):
3644
tags = {
@@ -219,13 +227,6 @@ def get_exif(self, key):
219227
self.__logger.warning("get_exif failed on %s -> %s", self.__filename, e)
220228
return None
221229

222-
def get_size(self):
223-
try: # corrupt image file might crash app
224-
return GetImageMeta.get_image_object(self.__filename).size
225-
except Exception as e:
226-
self.__logger.warning("get_size failed on %s -> %s", self.__filename, e)
227-
return (0, 0)
228-
229230
@staticmethod
230231
def get_image_object(fname):
231232
try:

src/picframe/html/index.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ <h1>Simple Picture Frame page</h1>
4747
<div id="spans">
4848
</div>
4949
<button id="upload_button" onclick="uploadValues()">UPDATE</button>
50-
<a href="/current_image">See the current image</a> (use browser BACK to return to this page)
50+
<a href="/current_image">See the current image</a>
51+
or <a href="/current_image_original">its unmodified original</a>
52+
(use browser BACK to return to this page)
5153
</body>
5254
</html>

src/picframe/image_cache.py

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
import logging
55
import threading
66
from picframe import get_image_meta
7+
from picframe.video_streamer import VIDEO_EXTENSIONS, get_video_info
78

89

910
class ImageCache:
1011

1112
EXTENSIONS = ['.png', '.jpg', '.jpeg', '.heif', '.heic']
12-
VIDEO_EXTENSIONS = ['.mp4', '.mkv', '.flv', '.mov', '.avi', '.webm', '.hevc']
1313
EXIF_TO_FIELD = {'EXIF FNumber': 'f_number',
1414
'Image Make': 'make',
1515
'Image Model': 'model',
@@ -380,7 +380,7 @@ def __get_modified_files(self, modified_folders):
380380
for dir, _date in modified_folders:
381381
for file in os.listdir(dir):
382382
base, extension = os.path.splitext(file)
383-
if (extension.lower() in (ImageCache.EXTENSIONS + ImageCache.VIDEO_EXTENSIONS)
383+
if (extension.lower() in (ImageCache.EXTENSIONS + VIDEO_EXTENSIONS)
384384
# have to filter out all the Apple junk
385385
and '.AppleDouble' not in dir and not file.startswith('.')):
386386
full_file = os.path.join(dir, file)
@@ -402,7 +402,12 @@ def __insert_file(self, file, file_id=None):
402402
base, extension = os.path.splitext(file_only)
403403

404404
# Get the file's meta info and build the INSERT statement dynamically
405-
meta = self.__get_exif_info(file)
405+
meta = {}
406+
ext = os.path.splitext(file)[1].lower()
407+
if ext in VIDEO_EXTENSIONS: # no exif info available
408+
meta = self.__get_video_info(file)
409+
else:
410+
meta = self.__get_exif_info(file)
406411
meta_insert = self.__get_meta_sql_from_dict(meta)
407412
vals = list(meta.values())
408413
vals.insert(0, file)
@@ -468,17 +473,14 @@ def __purge_missing_files_and_folders(self):
468473
self.__purge_files = False
469474

470475
def __get_exif_info(self, file_path_name):
471-
ext = os.path.splitext(file_path_name)[1].lower()
472-
if ext in ImageCache.VIDEO_EXTENSIONS: # no exif info available
473-
return {'width': 100, 'height': 100} # return early with min info for videos TODO duration available in video_info
474476
exifs = get_image_meta.GetImageMeta(file_path_name)
475477
# Dict to store interesting EXIF data
476478
# Note, the 'key' must match a field in the 'meta' table
477479
e = {}
478480

479481
e['orientation'] = exifs.get_orientation()
480482

481-
width, height = exifs.get_size()
483+
width, height = exifs.size
482484
ext = os.path.splitext(file_path_name)[1].lower()
483485
if ext not in ('.heif', '.heic') and e['orientation'] in (5, 6, 7, 8):
484486
width, height = height, width # swap values
@@ -521,6 +523,59 @@ def __get_exif_info(self, file_path_name):
521523

522524
return e
523525

526+
def __get_video_info(self, file_path_name: str) -> dict:
527+
"""
528+
Extracts metadata information from a video file.
529+
530+
This method retrieves video metadata using the `get_video_info` function and
531+
organizes it into a dictionary. The metadata includes dimensions, orientation,
532+
and other optional EXIF and IPTC data if available.
533+
534+
Args:
535+
file_path_name (str): The full path to the video file.
536+
537+
Returns:
538+
dict: A dictionary containing the meta keys.
539+
Note, the 'key' must match a field in the 'meta' table
540+
"""
541+
meta = get_video_info(file_path_name)
542+
543+
# Dict to store interesting EXIF data
544+
# Note, the 'key' must match a field in the 'meta' table
545+
e: dict = {}
546+
547+
# Orientation is set to 1 by default, as video files rarely have this info.
548+
e['orientation'] = 1
549+
550+
width, height = meta.dimensions
551+
e['width'] = width
552+
e['height'] = height
553+
554+
# Attempt to retrieve additional metadata if available in meta
555+
e['f_number'] = getattr(meta, 'f_number', None)
556+
e['make'] = getattr(meta, 'make', None)
557+
e['model'] = getattr(meta, 'model', None)
558+
e['exposure_time'] = getattr(meta, 'exposure_time', None)
559+
e['iso'] = getattr(meta, 'iso', None)
560+
e['focal_length'] = getattr(meta, 'focal_length', None)
561+
e['rating'] = getattr(meta, 'rating', None)
562+
e['lens'] = getattr(meta, 'lens', None)
563+
e['exif_datetime'] = meta.exif_datetime if not None else os.path.getmtime(file_path_name)
564+
565+
if meta.gps_coords is not None:
566+
lat, lon = meta.gps_coords
567+
else:
568+
lat, lon = None, None
569+
e['latitude'] = round(lat, 4) if lat is not None else lat # TODO sqlite requires (None,) to insert NULL
570+
e['longitude'] = round(lon, 4) if lon is not None else lon
571+
572+
# IPTC
573+
e['tags'] = getattr(meta, 'tags', None)
574+
e['title'] = getattr(meta, 'title', None)
575+
e['caption'] = getattr(meta, 'caption', None)
576+
577+
return e
578+
524579

525580
# If being executed (instead of imported), kick it off...
526581
if __name__ == "__main__":

0 commit comments

Comments
 (0)