Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible to add an IFD to an image's EXIF data? #8229

Closed
tegandbiscuits opened this issue Jul 12, 2024 · 2 comments · Fixed by #8230
Closed

Possible to add an IFD to an image's EXIF data? #8229

tegandbiscuits opened this issue Jul 12, 2024 · 2 comments · Fixed by #8230
Labels

Comments

@tegandbiscuits
Copy link

(apologies if I'm using wrong/weird terminology)

I'm trying to add EXIF tags to an image that doesn't initially have any. Some of the tags I'm trying to set belong to IFD.Exif . When I run img.getexif().get_ifd(IFD.Exif) I get back an empty dict that doesn't persist anything I try to add to it.

However if the image already has data for IFD.Exif (so img.getexif().get_ifd(IFD.Exif) isn't {}) then I'm able to manipulate it as expected.

I'm not super familiar with how EXIF data works at a technical level, but I think I'm missing something that I need to do/set to
the image before I can set the tags I want to set. But I'm not 100% sure if that's the case, and if can I do it with Pillow?

What are your OS, Python and Pillow versions?

  • OS: macOS 14.5
  • Python: 3.12.4
  • Pillow: 10.3.0
--------------------------------------------------------------------
Pillow 10.3.0
Python 3.12.4 (main, Jun 27 2024, 18:40:44) [Clang 15.0.0 (clang-1500.3.9.4)]
--------------------------------------------------------------------
Python executable is /Users/tegan/Library/Caches/pypoetry/virtualenvs/exifmate-Hu18rg69-py3.12/bin/python3
Environment Python files loaded from /Users/tegan/Library/Caches/pypoetry/virtualenvs/exifmate-Hu18rg69-py3.12
System Python files loaded from /Users/tegan/.pyenv/versions/3.12.4
--------------------------------------------------------------------
Python Pillow modules loaded from /Users/tegan/Library/Caches/pypoetry/virtualenvs/exifmate-Hu18rg69-py3.12/lib/python3.12/site-packages/PIL
Binary Pillow modules loaded from /Users/tegan/Library/Caches/pypoetry/virtualenvs/exifmate-Hu18rg69-py3.12/lib/python3.12/site-packages/PIL
--------------------------------------------------------------------
--- PIL CORE support ok, compiled for 10.3.0
*** TKINTER support not installed
--- FREETYPE2 support ok, loaded 2.13.2
--- LITTLECMS2 support ok, loaded 2.16
--- WEBP support ok, loaded 1.3.2
--- WEBP Transparency support ok
--- WEBPMUX support ok
--- WEBP Animation support ok
--- JPEG support ok, compiled for libjpeg-turbo 3.0.2
--- OPENJPEG (JPEG2000) support ok, loaded 2.5.2
--- ZLIB (PNG/ZIP) support ok, loaded 1.3.1
--- LIBTIFF support ok, loaded 4.6.0
*** RAQM (Bidirectional Text) support not installed
*** LIBIMAGEQUANT (Quantization method) support not installed
--- XCB (X protocol) support ok
--------------------------------------------------------------------

Sample Code

from PIL.TiffImagePlugin import IFDRational
from PIL.ExifTags import IFD
from PIL import Image

tag_id = 33434 # exposure time tag
exposure_time = IFDRational(1/500)

# behavior with existing EXIF data
img_one = Image.open("has-exif.jpg")
exif_one = img_one.getexif()
exif_one.get_ifd(IFD.Exif)[tag_id] = exposure_time
assert exif_one.get_ifd(IFD.Exif)[tag_id] == exposure_time

# saving the image with the modified data also works
# img_one.save("has-exif.jpg", exif=exif_one)

# behavior with no existing EXIF data
img_two = Image.open("no-exif.jpg")
exif_two = img_two.getexif() # presumably this is basically the same as `Image.Exif()`
assert exif_two.get_ifd(IFD.Exif) == {}
exif_two.get_ifd(IFD.Exif)[tag_id] = exposure_time

# these assertions pass but I expect them both to fail
assert exif_two.get_ifd(IFD.Exif) == {}
assert exif_two.get_ifd(IFD.Exif).get(tag_id) == None

sample pictures.zip

@radarhere
Copy link
Member

I've created #8230 to change Pillow to behave the way you expect.

In the meantime, you can insert a line like exif_two._ifds.setdefault(IFD.Exif, {}) into your code, such as

exif_two = img_two.getexif() # presumably this is basically the same as `Image.Exif()`
exif_two._ifds.setdefault(IFD.Exif, {})
assert exif_two.get_ifd(IFD.Exif) == {}

@radarhere radarhere added the Exif label Jul 13, 2024
@tegandbiscuits
Copy link
Author

Oh fantastic! Thank you so much for the quick reply!

I'll close the issue now since you've got the PR open and the workaround works.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants