python-pillow / Pillow

Python Imaging Library (Fork)
https://python-pillow.org
Other
12.32k stars 2.23k forks source link

exif_transpose does not work if gps data is missing #8548

Closed IngeborgGjerde closed 1 week ago

IngeborgGjerde commented 1 week ago

What did you do?

I was attempting to rotate a picture taken on mobile phone to its upright position.

from PIL import Image
from PIL.ImageOps import exif_transpose
im = Image.open("image.jpg")
width, height = im.size
im = exif_transpose(im)

The image can be downloaded here: https://github.com/user-attachments/assets/b357f0b5-35b3-4b0d-94b1-7f60e3edd075 Running identify -verbose on the image shows that it contains orientation data

Orientation: RightTop

but that it does not contain valid GPS data:

    exif:GPSLatitude: 0/0, 0/0, 0/0
    exif:GPSLatitudeRef: 
    exif:GPSLongitude: 0/0, 0/0, 0/0
    exif:GPSLongitudeRef: 

What did you expect to happen?

I expected the image to be rotated :)

What actually happened?

exif_transpose crashes with

Traceback (most recent call last):
  File "/the_code/test_exif_transpose.py", line 7, in <module>
    im = exif_transpose(im)
         ^^^^^^^^^^^^^^^^^^
  File "the_code/.venv/lib/python3.12/site-packages/PIL/ImageOps.py", line 711, in exif_transpose
    exif_image.info["exif"] = exif.tobytes()
                              ^^^^^^^^^^^^^^
  File "the_code/.venv/lib/python3.12/site-packages/PIL/Image.py", line 4044, in tobytes
    return b"Exif\x00\x00" + head + ifd.tobytes(offset)
                                    ^^^^^^^^^^^^^^^^^^^
  File "the_code/.venv/lib/python3.12/site-packages/PIL/TiffImagePlugin.py", line 963, in tobytes
    data = ifd.tobytes(offset)
           ^^^^^^^^^^^^^^^^^^^
  File "/the_code/.venv/lib/python3.12/site-packages/PIL/TiffImagePlugin.py", line 968, in tobytes
    data = self._write_dispatch[typ](self, *values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/the_code/.venv/lib/python3.12/site-packages/PIL/TiffImagePlugin.py", line 827, in write_rational
    return b"".join(
           ^^^^^^^^^
  File "the_code/.venv/lib/python3.12/site-packages/PIL/TiffImagePlugin.py", line 828, in <genexpr>
    self._pack("2L", *_limit_rational(frac, 2**32 - 1)) for frac in values
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "the_code/.venv/lib/python3.12/site-packages/PIL/TiffImagePlugin.py", line 297, in _limit_rational
    inv = abs(float(val)) > 1
              ^^^^^^^^^^
  File "/usr/lib/python3.12/numbers.py", line 316, in __float__
    return int(self.numerator) / int(self.denominator)
           ~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~
ZeroDivisionError: division by zero

The error is caused by attempting to serialize the gps data.

What are your OS, Python and Pillow versions?

--------------------------------------------------------------------
Pillow 11.0.0
Python 3.12.5 (main, Aug 17 2024, 16:46:05) [GCC 11.4.0]
--------------------------------------------------------------------
Python executable is /home/ingeborg/Code/field-manager-data-api/.venv/bin/python3
Environment Python files loaded from /home/ingeborg/Code/field-manager-data-api/.venv
System Python files loaded from /usr
--------------------------------------------------------------------
Python Pillow modules loaded from /home/ingeborg/Code/field-manager-data-api/.venv/lib/python3.12/site-packages/PIL
Binary Pillow modules loaded from /home/ingeborg/Code/field-manager-data-api/.venv/lib/python3.12/site-packages/PIL
--------------------------------------------------------------------
--- PIL CORE support ok, compiled for 11.0.0
*** TKINTER support not installed
--- FREETYPE2 support ok, loaded 2.13.2
--- LITTLECMS2 support ok, loaded 2.16
--- WEBP support ok, loaded 1.4.0
--- JPEG support ok, compiled for libjpeg-turbo 3.0.4
--- OPENJPEG (JPEG2000) support ok, loaded 2.5.2
--- ZLIB (PNG/ZIP) support ok, loaded 1.2.11
--- LIBTIFF support ok, loaded 4.6.0
--- RAQM (Bidirectional Text) support ok, loaded 0.10.1, fribidi 1.0.8, harfbuzz 10.0.1
*** LIBIMAGEQUANT (Quantization method) support not installed
--- XCB (X protocol) support ok
--------------------------------------------------------------------

image

radarhere commented 1 week ago

Hi. This is a duplicate of #8471, which has been resolved by #8474.

The next Pillow release is scheduled for January 2.

If you would like to patch your copy of Pillow so that it works in the meantime, you can

from PIL import TiffImagePlugin

# Patch
def _limit_rational(val, max_val):
    inv = abs(val) > 1
    n_d = TiffImagePlugin.IFDRational(1 / val if inv else val).limit_rational(max_val)
    return n_d[::-1] if inv else n_d
TiffImagePlugin._limit_rational = _limit_rational

from PIL import Image
from PIL.ImageOps import exif_transpose
im = Image.open("image.jpg")
width, height = im.size
im = exif_transpose(im)
IngeborgGjerde commented 1 week ago

Hi, many thanks for the quick reply and for providing a workaround!