Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion Tests/test_file_jpeg.py
Original file line number Diff line number Diff line change
Expand Up @@ -993,11 +993,17 @@ def test_getxmp_padded(self) -> None:

def test_save_xmp(self, tmp_path: Path) -> None:
f = str(tmp_path / "temp.jpg")
hopper().save(f, xmp=b"XMP test")
im = hopper()
im.save(f, xmp=b"XMP test")

with Image.open(f) as reloaded:
assert reloaded.info["xmp"] == b"XMP test"

im.save(f, xmp=b"1" * 65504)

with pytest.raises(ValueError):
im.save(f, xmp=b"1" * 65505)

@pytest.mark.timeout(timeout=1)
def test_eof(self) -> None:
# Even though this decoder never says that it is finished
Expand Down
19 changes: 12 additions & 7 deletions src/PIL/JpegImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -746,23 +746,28 @@ def validate_qtables(

extra = info.get("extra", b"")

MAX_BYTES_IN_MARKER = 65533
xmp = info.get("xmp")
if xmp:
size = o16(31 + len(xmp))
overhead_len = 29
Copy link

Choose a reason for hiding this comment

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

Maybe add a comment that this is len('http://ns.adobe.com/xap/1.0/'+ b"\0")? Otherwise a reader not famliar with the matter might come to the conclusion that this is just a(nother) magic number.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok, I've added a comment.

max_data_bytes_in_marker = MAX_BYTES_IN_MARKER - overhead_len
if len(xmp) > max_data_bytes_in_marker:
msg = "XMP data is too long"
raise ValueError(msg)
size = o16(2 + overhead_len + len(xmp))
extra += b"\xFF\xE1" + size + b"http://ns.adobe.com/xap/1.0/\x00" + xmp

MAX_BYTES_IN_MARKER = 65533
icc_profile = info.get("icc_profile")
if icc_profile:
ICC_OVERHEAD_LEN = 14
MAX_DATA_BYTES_IN_MARKER = MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN
overhead_len = 14
max_data_bytes_in_marker = MAX_BYTES_IN_MARKER - overhead_len
markers = []
while icc_profile:
markers.append(icc_profile[:MAX_DATA_BYTES_IN_MARKER])
icc_profile = icc_profile[MAX_DATA_BYTES_IN_MARKER:]
markers.append(icc_profile[:max_data_bytes_in_marker])
icc_profile = icc_profile[max_data_bytes_in_marker:]
i = 1
for marker in markers:
size = o16(2 + ICC_OVERHEAD_LEN + len(marker))
size = o16(2 + overhead_len + len(marker))
extra += (
b"\xFF\xE2"
+ size
Expand Down