Skip to content

Saving a TIFF with EXIF sub-IFDs: compressed save raises "Error setting from dictionary", uncompressed save drops a GPS IFD #10460

Open

Description

@jayhemnani9910

What did you do?

Saved a TIFF with the EXIF from a camera-style JPEG (it has an Exif sub-IFD), using compression:

from PIL import Image, ExifTags

exif = Image.Exif()
exif[ExifTags.Base.Make] = "Canon"
exif.get_ifd(ExifTags.IFD.Exif)[ExifTags.Base.ISOSpeedRatings] = 400
Image.new("RGB", (8, 8)).save("photo.jpg", exif=exif)

with Image.open("photo.jpg") as im:
    im.save("photo.tif", compression="tiff_lzw", exif=im.getexif())

And saved an Image.Exif with a GPS IFD created through get_ifd() as an uncompressed TIFF:

exif = Image.Exif()
exif[ExifTags.Base.Make] = "Canon"
exif.get_ifd(ExifTags.IFD.GPSInfo)[ExifTags.GPS.GPSLatitudeRef] = "N"
for fmt in ("JPEG", "TIFF"):
    Image.new("RGB", (8, 8)).save("out." + fmt.lower(), fmt, exif=exif)
    with Image.open("out." + fmt.lower()) as im:
        print(fmt, im.getexif().get_ifd(ExifTags.IFD.GPSInfo))

What did you expect to happen?

The compressed TIFF saves, and its Exif IFD reads back as {34855: 400}, as it does without compression.

The GPS IFD reads back as {1: 'N'} from the TIFF, as it does from JPEG, PNG and WebP.

What actually happened?

The compressed save fails:

_TIFFVSetField: photo.tif: Bad LONG8 or IFD8 value 18446744073709551615 for "EXIFIFDOffset" tag 34665 in ClassicTIFF. Tag won't be written to file.
RuntimeError: Error setting from dictionary

The same happens with tiff_deflate, tiff_adobe_deflate and jpeg compression. 11.0.0 saved the file (without the Exif IFD), so this started in 11.1.0.

The uncompressed TIFF prints TIFF {} while JPEG prints JPEG {1: 'N'}.

For the libtiff path, _save puts the sub-IFD into ifd as a dict (ifd[key] = info.get_ifd(key)), then gives every tag in TAGS_V2_GROUPS the type LONG8, so encode.c calls PyLong_AsLongLong() on the dict and TIFFSetField fails. That type was added in #8529.

For the second case, _save only loops over the Exif keys, and a sub-IFD created with get_ifd() lives in _ifds until a pointer tag is set. Exif.tobytes() handles this since #8635, but the TIFF writer does not.

What are your OS, Python and Pillow versions?

  • OS: Linux
  • Python: 3.14
  • Pillow: 13.0.0, also main (b2c077b)

Activity

  1. radarhere commented on Nov 8, 2026

    @radarhere
    Member

    I've created #10461 for the second case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions