Repository navigation
Fix MPO index placement after Adobe JPEG headers - #10328
Muguett-DBY wants to merge 8 commits into
Conversation
Can you link to the part of the libjpeg-turbo source code where it determines which header to use? |
|
Yes — the default selection is in libjpeg-turbo's On Pillow's side, While checking this I found an omission in my patch: Pillow also enables JFIF when both rounded DPI values are positive, so CMYK and |
|
I think you'll agree that the conditions to determine the position are getting a little complicated. How about just searching through the output instead? I've pushed a commit. See what you think. |
|
Thanks, the search is much simpler. I found one compatibility issue with reading the output, though: callers can pass a write-only binary file to from PIL import Image
first = Image.new("RGB", (16, 8))
second = Image.new("RGB", (24, 16))
with open("out.mpo", "wb") as f:
first.save(f, "MPO", save_all=True, append_images=[second])With the new writer this raises |
|
I pushed ab7ad7e to capture the 20-byte search window as the first JPEG is written. That keeps the marker search and lets write-only files work. I added three cases that fail on the previous head and pass with the change. One trade-off: the first frame now uses the Python file-object encoding path instead of the direct file-descriptor path. I checked 288 mode/EXIF/DPI/stream combinations and 60 multi-frame/metadata cases with the exact writer and the existing Pillow 13.0 codec; the full branch CI is running. |
Saving a CMYK MPO, or an RGB MPO with
keep_rgb=True, can place the MP Index at the wrong offset. Pillow then reopens it as a single JPEG instead of exposing the other frames.The writer now locates the MP Index marker in the encoded JPEG rather than calculating its position from marker lengths. It captures the 20-byte search window as the first frame is written, so the output does not need to be readable. The change adds CMYK and write-only-file regression tests and a release note. Related: #10326.
The capture forwards encoded data through Python's file-object path instead of the direct file-descriptor path for the first frame. In a small Windows disk check using the existing Pillow 13.0 codec, a 3000×2000 two-frame save took a median of 73.5 ms before and 73.3 ms after (six paired samples); this is only an indicative local measurement.
Validation:
UnsupportedOperation: readon7fc5ff8and pass on7b456b0. With the exact changed writer and Pillow 13.0's existing codec and reader, 288 mode, EXIF, DPI and stream combinations passed independent JPEG-marker, index and pixel checks; another 60 multi-frame/metadata cases passed.Investigation, implementation and checks assisted by Codex.