Skip to content

ROB: Detect LZW/ASCII85 image format via Pillow and correct image comments - #3902

Open
BiswasNehaa wants to merge 1 commit into
py-pdf:mainfrom
BiswasNehaa:fix-3869-image-xobject-comments
Open

BiswasNehaa wants to merge 1 commit into
py-pdf:mainfrom
BiswasNehaa:fix-3869-image-xobject-comments

Conversation

@BiswasNehaa

@BiswasNehaa BiswasNehaa commented Jun 26, 2026 •

Copy link
Copy Markdown

Closes #3869

This addresses the three points of the issue.

CMYK palette workaround (comment only)

The question was whether Pillow can process CMYK palettes by now, so that the workaround can go. It can partly, but not reliably:

  • Since Pillow 10.1.0 (Added CMYK to RGB unpacker python-pillow/Pillow#7310), putpalette(..., rawmode="CMYK") converts the palette to RGB. The result differs from the manual conversion by at most 1 per channel (Pillow rounds, the workaround truncates).
  • Starting with Pillow 12.2.0, the palette stays CMYK and convert("RGB") no longer converts it, so the colors are wrong (tests/test_filters.py::test_index_lookup fails with similarity 0.49 when the workaround is removed).

So the workaround is still needed and stays. The comment now explains this and lists the versions checked (10.4.0, 11.0.0 - 11.3.0, 12.0.0 - 12.3.0), as suggested in the issue. The unrelated Pillow>=8.0.0 requirement is unchanged.

ICC comment

Checked the behaviour instead of just rewording it: in the /ICCBased branch, mode and data are not changed after img has been created, so the reload (Image.frombytes(mode, size, data)) produces an identical image. The old comment (loads "with a different color space") was therefore inaccurate. I corrected the comment and kept the TODO about actually applying the ICC profile. The behaviour is unchanged; the redundant reload could be removed in a follow-up if wanted.

LZW / ASCII85 image format

The format is now taken from img.format as detected by Pillow, instead of assuming TIFF for LZW and PNG for ASCII85. The filter-based guess is only kept for data without a TIFF/PNG container, which is interpreted as raw samples (unchanged behaviour). The raw-sample fallback keeps using _expand_low_bit_samples; an earlier revision of this PR had accidentally dropped that call, which is why the fallback lines were reported as uncovered.

Behaviour change: a PNG container with the LZW filter is now reported as .png (previously .tiff), and a TIFF container with the ASCII85 filter as .tiff (previously .png).

Tests

  • test_xobj_to_image__lzw_ascii85_image_format covers raw data and real PNG/TIFF containers for both filters, including the fallback branch. The two mislabelled cases fail on current main.
  • test_handle_flate__indexed_cmyk_palette checks the exact converted palette, so it fails on any Pillow version where the palette would not be converted.
  • The image and filter test suites pass locally with both Pillow 10.4.0 and 12.3.0, and the changed lines are covered.

@BiswasNehaa BiswasNehaa changed the title Clarify stale comments in image XObject handling (#3869) ROB: Clarify CMYK comment and detect image format from Pillow instead of guessing Jun 26, 2026
@codecov

codecov Bot commented Jun 26, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.65%. Comparing base (140204c) to head (1f791d9).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #3902   +/-   ##
=======================================
  Coverage   98.65%   98.65%           
=======================================
  Files          59       59           
  Lines       11964    11972    +8     
  Branches     2271     2272    +1     
=======================================
+ Hits        11803    11811    +8     
  Misses         84       84           
  Partials       77       77           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@BiswasNehaa
BiswasNehaa force-pushed the fix-3869-image-xobject-comments branch from 6f2f50c to 81c4851 Compare June 26, 2026 06:47
Comment thread pypdf/generic/_image_xobject.py Resolved
Comment thread pypdf/generic/_image_xobject.py Resolved
Comment thread pypdf/generic/_image_xobject.py Resolved
Comment thread pypdf/generic/_image_xobject.py Resolved
@BiswasNehaa
BiswasNehaa force-pushed the fix-3869-image-xobject-comments branch from 6bd2c99 to ae1cbb9 Compare October 15, 2026 17:55
@BiswasNehaa BiswasNehaa changed the title ROB: Clarify CMYK comment and detect image format from Pillow instead of guessing DEP: Require Pillow>=10.1.0 and clean up image extraction workarounds Oct 15, 2026
@BiswasNehaa
BiswasNehaa force-pushed the fix-3869-image-xobject-comments branch from ae1cbb9 to 8f4171b Compare October 15, 2026 19:34
@BiswasNehaa BiswasNehaa changed the title DEP: Require Pillow>=10.1.0 and clean up image extraction workarounds ROB: Detect LZW/ASCII85 image format via Pillow and correct image comments Oct 15, 2026
Comment thread pypdf/generic/_image_xobject.py Resolved
Comment thread pypdf/generic/_image_xobject.py Resolved
@BiswasNehaa
BiswasNehaa force-pushed the fix-3869-image-xobject-comments branch from d9739de to 1f791d9 Compare November 1, 2026 17:33
@BiswasNehaa

Copy link
Copy Markdown
Author

Thanks for the review, and sorry for the delay. Both comments are addressed:

  • Dropped the NOTE: prefix from the CMYK palette comment.
  • Removed the checked Pillow versions from the code comment. For the record, I verified the behaviour with Pillow 10.4.0, 11.0.0 - 11.3.0 and 12.0.0 - 12.3.0: putpalette(..., rawmode="CMYK") converts the palette to RGB up to 12.1.x, while from 12.2.0 on the palette stays CMYK and convert("RGB") no longer converts it. That is why the manual conversion stays, and test_handle_flate__indexed_cmyk_palette covers it independent of the installed version.

I also rebased onto the current main (one conflict in tests/test_images.py, where both sides appended new tests; I kept both) and squashed everything into a single commit. That replaced the "Merge branch 'main'" commit on the branch, which only synced with main.

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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Check some code in _image_xobject.py and update comments

2 participants