Skip to content

Commit

Permalink
Added height, width to PhotoInfoFromFile
Browse files Browse the repository at this point in the history
  • Loading branch information
RhetTbull committed Apr 28, 2024
1 parent ba768eb commit 3be04f0
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 23 deletions.
6 changes: 3 additions & 3 deletions osxphotos/cli/import_cli.py
Expand Up @@ -58,7 +58,7 @@
from osxphotos.metadata_reader import (
MetaData,
get_sidecar_for_file,
metadata_from_file,
metadata_from_exiftool,
metadata_from_sidecar,
)
from osxphotos.photoinfo import PhotoInfoNone
Expand Down Expand Up @@ -325,7 +325,7 @@ def set_photo_metadata_from_exiftool(
):
"""Set photo's metadata by reading metadata from file with exiftool"""
verbose(f"Setting metadata and location from EXIF for [filename]{filepath.name}[/]")
metadata = metadata_from_file(filepath, exiftool_path)
metadata = metadata_from_exiftool(filepath, exiftool_path)
set_photo_metadata_from_metadata(
photo, filepath, metadata, merge_keywords, True, verbose, dry_run
)
Expand Down Expand Up @@ -654,7 +654,7 @@ def check_templates_and_exit(
else:
echo(f"sidecar file: {sidecar_file}")
if exiftool:
metadata = metadata_from_file(file, exiftool_path)
metadata = metadata_from_exiftool(file, exiftool_path)
echo(f"exiftool title: {metadata.title}")
echo(f"exiftool description: {metadata.description}")
echo(f"exiftool keywords: {metadata.keywords}")
Expand Down
37 changes: 30 additions & 7 deletions osxphotos/metadata_reader.py
Expand Up @@ -6,7 +6,7 @@
import json
import pathlib
import re
from dataclasses import dataclass, field
from dataclasses import dataclass, field, fields
from enum import Enum
from typing import Callable, Optional, Tuple

Expand Down Expand Up @@ -39,18 +39,33 @@ class MetaData:
date: datetime for photo as naive datetime.datetime in local timezone or None if not set
timezone: timezone or None of original date (before conversion to local naive datetime)
tz_offset_sec: int or None if not set, offset from UTC in seconds
height: int or None if not set, height of photo in pixels
width: int or None if not set, width of photo in pixels
"""

title: str
description: str
keywords: list[str]
location: tuple[Optional[float], Optional[float]]
title: str = ""
description: str = ""
keywords: list[str] = field(default_factory=list)
location: tuple[Optional[float], Optional[float]] = (None, None)
favorite: bool = False
rating: int = 0
persons: list[str] = field(default_factory=list)
date: datetime.datetime | None = None
timezone: datetime.tzinfo | None = None
tz_offset_sec: float | None = None
height: int | None = None
width: int | None = None

def __ior__(self, other):
if isinstance(other, MetaData):
for field in fields(self):
other_value = getattr(other, field.name)
self_value = getattr(self, field.name)
if other_value:
setattr(self, field.name, other_value)
else:
raise TypeError("Unsupported operand type")
return self


class SidecarFileType(Enum):
Expand Down Expand Up @@ -188,7 +203,7 @@ def convert_exiftool_longitude(lon_string, lon_ref):
return longitude


def metadata_from_file(
def metadata_from_exiftool(
filepath: str | pathlib.Path, exiftool_path: str | None
) -> MetaData:
"""Get metadata from file with exiftool
Expand All @@ -198,6 +213,9 @@ def metadata_from_file(
description: str, XMP:Description, IPTC:Caption-Abstract, EXIF:ImageDescription, QuickTime:Description
keywords: str, XMP:Subject, XMP:TagsList, IPTC:Keywords (QuickTime:Keywords not supported)
location: Tuple[lat, lon], EXIF:GPSLatitudeRef, EXIF:GPSLongitudeRef, EXIF:GPSLongitude, QuickTime:GPSCoordinates, UserData:GPSCoordinates
rating: int, XMP:Rating
height: int, ImageHeight
width: int, ImageWidth
"""
exiftool = ExifToolCaching(filepath, exiftool_path)
metadata = exiftool.asdict()
Expand Down Expand Up @@ -323,6 +341,9 @@ def metadata_from_metadata_dict(metadata: dict) -> MetaData:

rating = metadata.get("XMP:Rating") or metadata.get("Rating")

height = metadata.get("File:ImageHeight") or metadata.get("ImageHeight")
width = metadata.get("File:ImageWidth") or metadata.get("ImageWidth")

persons = metadata.get("XMP:PersonInImage", []) or metadata.get("PersonInImage", [])
if persons and not isinstance(persons, (tuple, list)):
persons = [persons]
Expand All @@ -349,12 +370,14 @@ def metadata_from_metadata_dict(metadata: dict) -> MetaData:
description=description,
keywords=keywords,
location=location,
rating = rating or 0,
rating=rating or 0,
favorite=False,
persons=persons,
date=date,
timezone=timezone,
tz_offset_sec=tz_offset,
height=height,
width=width,
)


Expand Down
27 changes: 17 additions & 10 deletions osxphotos/photoinfo_file.py
Expand Up @@ -12,7 +12,7 @@
from ._constants import _OSXPHOTOS_NONE_SENTINEL
from .datetime_utils import datetime_naive_to_local
from .exiftool import ExifToolCaching, get_exiftool_path
from .metadata_reader import MetaData, metadata_from_file, metadata_from_sidecar
from .metadata_reader import MetaData, metadata_from_exiftool, metadata_from_sidecar
from .phototemplate import PhotoTemplate, RenderOptions
from .platform import is_macos

Expand Down Expand Up @@ -45,16 +45,13 @@ def __init__(
self._exiftool_path = exiftool or EXIFTOOL_PATH
self._uuid = str(uuid.uuid1()).upper()
self._sidecar = sidecar
if sidecar:
self._metadata = metadata_from_sidecar(pathlib.Path(sidecar), exiftool)
elif self._exiftool_path:
self._metadata = metadata_from_file(
pathlib.Path(filepath), self._exiftool_path
)
else:
self._metadata = MetaData(
title="", description="", keywords=[], location=(None, None)
self._metadata = MetaData()
if self._exiftool_path:
self._metadata |= metadata_from_exiftool(
pathlib.Path(filepath), self._exiftool_path
)
if sidecar:
self._metadata |= metadata_from_sidecar(pathlib.Path(sidecar), exiftool)

@property
def uuid(self):
Expand Down Expand Up @@ -120,6 +117,16 @@ def fingerprint(self) -> str | None:
return fingerprint(self._path)
return None

@property
def height(self) -> int:
"""height of photo in pixels"""
return self._metadata.height

@property
def width(self) -> int:
"""width of photo in pixels"""
return self._metadata.width

@property
def exiftool(self):
"""Returns a ExifToolCaching (read-only instance of ExifTool) object for the photo.
Expand Down
6 changes: 3 additions & 3 deletions tests/test_metadata_reader.py
Expand Up @@ -12,7 +12,7 @@
SidecarFileType,
get_sidecar_filetype,
get_sidecar_for_file,
metadata_from_file,
metadata_from_exiftool,
metadata_from_sidecar,
)

Expand Down Expand Up @@ -64,7 +64,7 @@
@pytest.mark.usefixtures("set_tz_pacific")
def test_metadata_from_file():
"""Test metadata_from_file"""
metadata = metadata_from_file(TEST_IMAGE_1, None)
metadata = metadata_from_exiftool(TEST_IMAGE_1, None)
assert metadata.title == "Waves crashing on rocks"
assert metadata.description == "Used for testing osxphotos"
assert metadata.keywords == ["osxphotos", "Sümmer"]
Expand All @@ -83,7 +83,7 @@ def test_metadata_from_file():
@pytest.mark.skipif(exiftool_path is None, reason="exiftool not installed")
def test_metadata_from_file_person_info():
"""Test metadata_from_file with person info"""
metadata = metadata_from_file(TEST_IMAGE_2, None)
metadata = metadata_from_exiftool(TEST_IMAGE_2, None)
assert sorted(metadata.persons) == ["Katie", "Suzy"]


Expand Down

0 comments on commit 3be04f0

Please sign in to comment.