Skip to content

Handle XML whitespace and single quotes in XMP orientation - #10062

Open
GreedyC wants to merge 2 commits into
python-pillow:mainfrom
GreedyC:codex/xmp-orientation-xml-whitespace
Open

GreedyC wants to merge 2 commits into
python-pillow:mainfrom
GreedyC:codex/xmp-orientation-xml-whitespace

Conversation

@GreedyC

@GreedyC GreedyC commented Sep 26, 2026

Copy link
Copy Markdown

Changes proposed in this pull request:

  • Read XMP orientation attributes using either quote style, whitespace around =, and whitespace around the orientation value. Also allow whitespace around element values and before the closing >.
  • Remove the same forms from XMP after exif_transpose(). Reading the metadata without updating the removal patterns would leave stale orientation information that can be loaded again.
  • Add parametrized regression tests for string and byte XMP, copy and in-place transposition, and metadata reload. Include a release note.

For example, this valid XMP currently leaves the image untransposed:

from PIL import Image, ImageOps

im = Image.new("RGB", (2, 1))
im.info["xmp"] = b'''<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:tiff="http://ns.adobe.com/tiff/1.0/">
    <rdf:Description tiff:Orientation = '6'/>
</rdf:RDF>'''
print(ImageOps.exif_transpose(im).size)
# Before: (2, 1)
# After:  (1, 2)

Validation on macOS / Python 3.14 with Pillow built from this checkout:

  • python3 selftest.py: 59 passed.
  • The initial regression matrix failed in 20 cases before the implementation change; the final matrix includes an additional element-tag whitespace case.
  • Final ImageOps test suite: 82 passed.
  • Final full Pillow test suite: 5,145 passed, 400 skipped, 3 xfailed. Skips are for unavailable optional libraries, fixtures, or platform-specific tests; the xfails are existing resampling/drawing cases.
  • Ruff lint and Black checks passed for the modified Python files.
  • Mypy passed for the three modified Python files; Sphinx release-note lint passed.
  • All applicable upstream pre-commit hooks passed for the four changed files, including Ruff, Black, Bandit, and Sphinx Lint.

This PR was prepared with OpenAI Codex assistance. It does not add an XML parser or a new runtime dependency, and EXIF orientation precedence is unchanged.

Copilot AI lite review requested due to automatic review settings September 26, 2026 03:26

Copilot AI 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.

Copilot review overview

🟢 Approval recommended

No unresolved review issues were identified.

Review effort: Lite
Findings: None

What changed in this PR

Updates XMP orientation handling to support quote variations and surrounding whitespace, with regression tests and release documentation.

Changes:

  • Expanded XMP orientation parsing and cleanup.
  • Added parametrized regression tests.
  • Documented the behavior change.
File Description
Tests/​test_imageops.py Adds regression coverage.
src/​PIL/​ImageOps.py Removes expanded orientation metadata forms.
src/​PIL/​Image.py Parses expanded XMP orientation syntax.
docs/​releasenotes/​13.0.0.rst Documents the behavior change.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@radarhere radarhere added the 🤖-assisted AI-assisted label Sep 26, 2026
@radarhere

Copy link
Copy Markdown
Member

Hi. Did you actually find XMP data in a real image that doesn't load correctly with Pillow, or are you simply creating this PR for its theoretical value?

@GreedyC

GreedyC commented Sep 26, 2026

Copy link
Copy Markdown
Author

No, I did not find this in a real-world image. The report is based on synthetic regression cases containing valid XML whitespace and quote variants; I should have made that distinction explicit in the description. The change was developed with OpenAI Codex assistance. If a real-world sample is required for this change, these tests alone do not establish that evidence.

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.

3 participants