Skip to content

Commit 0cad693

Browse files
committed
FIX: Piexif unsupported filetype
Upon loading metadata information of a image with a type not supported by `piexif` a not caught exception was raised. Thanks @BachoSeven for pointing this out!
1 parent aae1fe2 commit 0cad693

File tree

3 files changed

+61
-39
lines changed

3 files changed

+61
-39
lines changed

docs/changelog.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ Fixed:
5353
* Expanding tilde to home directory when using the ``:write`` command. Thanks
5454
`@jcjgraf`_ for pointing this out!
5555
* Completion for aliases.
56+
* Crash when extracting metadata using piexif from a non JPEG or TIFF image. Thanks `@BachoSeven`_ for pointing this out!
5657

5758

5859
v0.8.0 (2021-01-18)

docs/documentation/exif.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ this is the case:
1414
Advantages of the different exif libraries
1515
------------------------------------------
1616

17-
`Pyexiv2`_ is the more powerful of the two options. One large advantage is that with
18-
pyexiv2 ``:metadata`` formats exif data into human readable format, for example
17+
`Pyexiv2`_ is the more powerful of the two options. One large advantage is that it
18+
supports not only JPEG and TIFF images, but most common file types. In addition,
19+
with pyexiv2 ``:metadata`` formats exif data into human readable format, for example
1920
``FocalLength: 5.0 mm`` where `piexif`_ would only give ``FocalLength: 5.0``. However,
2021
given it is written as python bindings to the c++ api of `exiv2`_, the installation is
2122
more involved compared to the pure python `piexif`_ module.

vimiv/imutils/metadata.py

Lines changed: 57 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -149,52 +149,66 @@ def __init__(self, filename=""):
149149
except FileNotFoundError:
150150
_logger.debug("File %s not found", filename)
151151
self._metadata = None
152+
except piexif.InvalidImageDataError:
153+
log.warning(
154+
"Piexif only supports the file types JPEG and TIFF.<br>\n"
155+
"Please install pyexiv2 for better file type support.<br>\n"
156+
"For more information see<br>\n"
157+
"https://karlch.github.io/vimiv-qt/documentation/exif.html",
158+
once=True,
159+
)
160+
self._metadata = None
152161

153162
def fetch_key(self, base_key: str) -> Tuple[str, str, str]:
154163
key = base_key.rpartition(".")[2]
155164

156-
with contextlib.suppress(piexif.InvalidImageDataError):
157-
for ifd in self._metadata:
158-
if ifd == "thumbnail":
165+
if self._metadata is None:
166+
return {}
167+
168+
for ifd in self._metadata:
169+
if ifd == "thumbnail":
170+
continue
171+
172+
for tag in self._metadata[ifd]:
173+
keyname = piexif.TAGS[ifd][tag]["name"]
174+
keytype = piexif.TAGS[ifd][tag]["type"]
175+
val = self._metadata[ifd][tag]
176+
_logger.debug(
177+
f"name: {keyname}\
178+
type: {keytype}\
179+
value: {val}\
180+
tag: {tag}"
181+
)
182+
if keyname != key:
159183
continue
160-
161-
for tag in self._metadata[ifd]:
162-
keyname = piexif.TAGS[ifd][tag]["name"]
163-
keytype = piexif.TAGS[ifd][tag]["type"]
164-
val = self._metadata[ifd][tag]
165-
_logger.debug(
166-
f"name: {keyname}\
167-
type: {keytype}\
168-
value: {val}\
169-
tag: {tag}"
170-
)
171-
if keyname != key:
172-
continue
173-
if keytype in (
174-
piexif.TYPES.Byte,
175-
piexif.TYPES.Short,
176-
piexif.TYPES.Long,
177-
piexif.TYPES.SByte,
178-
piexif.TYPES.SShort,
179-
piexif.TYPES.SLong,
180-
piexif.TYPES.Float,
181-
piexif.TYPES.DFloat,
182-
): # integer and float
183-
return (keyname, keyname, str(val))
184-
if keytype in (
185-
piexif.TYPES.Ascii,
186-
piexif.TYPES.Undefined,
187-
): # byte encoded
188-
return (keyname, keyname, val.decode())
189-
if keytype in (
190-
piexif.TYPES.Rational,
191-
piexif.TYPES.SRational,
192-
): # (int, int) <=> numerator, denominator
193-
return (keyname, keyname, f"{val[0]}/{val[1]}")
184+
if keytype in (
185+
piexif.TYPES.Byte,
186+
piexif.TYPES.Short,
187+
piexif.TYPES.Long,
188+
piexif.TYPES.SByte,
189+
piexif.TYPES.SShort,
190+
piexif.TYPES.SLong,
191+
piexif.TYPES.Float,
192+
piexif.TYPES.DFloat,
193+
): # integer and float
194+
return (keyname, keyname, str(val))
195+
if keytype in (
196+
piexif.TYPES.Ascii,
197+
piexif.TYPES.Undefined,
198+
): # byte encoded
199+
return (keyname, keyname, val.decode())
200+
if keytype in (
201+
piexif.TYPES.Rational,
202+
piexif.TYPES.SRational,
203+
): # (int, int) <=> numerator, denominator
204+
return (keyname, keyname, f"{val[0]}/{val[1]}")
194205

195206
raise KeyError(f"Key '{base_key}' not found")
196207

197208
def get_keys(self) -> Iterable[str]:
209+
if self._metadata is None:
210+
return iter([])
211+
198212
return (
199213
piexif.TAGS[ifd][tag]["name"]
200214
for ifd in self._metadata
@@ -203,6 +217,9 @@ def get_keys(self) -> Iterable[str]:
203217
)
204218

205219
def copy_metadata(self, dest: str, reset_orientation: bool = True) -> None:
220+
if self._metadata is None:
221+
return
222+
206223
try:
207224
if reset_orientation:
208225
with contextlib.suppress(KeyError):
@@ -218,6 +235,9 @@ def copy_metadata(self, dest: str, reset_orientation: bool = True) -> None:
218235
_logger.debug("No metadata data in '%s'", dest)
219236

220237
def get_date_time(self) -> str:
238+
if self._metadata is None:
239+
return ""
240+
221241
with contextlib.suppress(
222242
piexif.InvalidImageDataError, FileNotFoundError, KeyError
223243
):

0 commit comments

Comments
 (0)