Skip to content

Read JPEG EXIF YResolution for the vertical DPI - #10334

Open
unvisible789 wants to merge 2 commits into
python-pillow:mainfrom
unvisible789:jpeg-exif-ydpi
Open

unvisible789 wants to merge 2 commits into
python-pillow:mainfrom
unvisible789:jpeg-exif-ydpi

Conversation

@unvisible789

@unvisible789 unvisible789 commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #10331.

Changes proposed in this pull request:

  • When a JPEG has no JFIF density and its DPI comes from EXIF, read YResolution (0x011B) for the vertical axis instead of reusing XResolution. If YResolution is absent, the previous behaviour (X for both axes) is kept, as are the fallbacks to (72, 72) for invalid values.
  • Add test_dpi_from_exif_different_axes (the reproduction from the issue: XResolution 300, YResolution 150 -> (300, 150)).

Testing: I couldn't build the C extensions locally (no system image-library headers), so I applied the change to the 13.0.0 tag and ran it with the official 13.0.0 compiled extensions. JpegImagePlugin.py is the same there as in main apart from this change. Tests/test_file_jpeg.py, test_file_tiff.py and test_file_libtiff.py all pass, and the new test fails without the fix ((300.0, 300.0)). ruff and black pass on the changed files.

Disclosure: this change was prepared by an AI assistant on behalf of @unvisible789.

@radarhere radarhere added the 🤖-assisted AI-assisted label Oct 27, 2026

@Muguett-DBY Muguett-DBY left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The separate X/Y values work in my checks, including the cm-to-inch conversion. I noticed one compatibility case worth deciding on: with a valid XResolution of 300 and an invalid YResolution of IFDRational(0, 0), the existing code returns (300, 300), while this change returns (72, 72). The new Y lookup sends both axes through the fallback, so a broken Y tag also discards the usable X value.

Would it make sense to fall back to X for an invalid Y, as for a missing Y? Either way, a test for that case would make the behavior explicit.

I checked the exact base and PR versions of _read_dpi_from_exif using generated JPEGs and the existing Pillow 12.3 codec; I did not run the full branch test suite.

@unvisible789

Copy link
Copy Markdown
Contributor Author

Good catch, thanks. An invalid YResolution now falls back to the X value, the same as a missing one, so your example gives (300, 300) again. I added a test for that case.

This branch has not been deployed

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

Labels

🤖-assisted AI-assisted

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JPEG dpi read from EXIF uses XResolution for both axes

3 participants