Skip to content

Commit

Permalink
Merge branch 'main' into infer-target-version
Browse files Browse the repository at this point in the history
  • Loading branch information
radarhere committed Nov 11, 2023
2 parents c3fb0de + aab5a2f commit 4b62012
Show file tree
Hide file tree
Showing 8 changed files with 676 additions and 26 deletions.
6 changes: 6 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ Changelog (Pillow)
10.2.0 (unreleased)
-------------------

- Implement ``streamtype=1`` option for tables-only JPEG encoding #7491
[bgilbert, radarhere]

- If save_all PNG only has one frame, do not create animated image #7522
[radarhere]

- Fixed frombytes() for images with a zero dimension #7493
[radarhere]

Expand Down
38 changes: 21 additions & 17 deletions Tests/test_file_apng.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ def test_apng_save(tmp_path):
im.load()
assert not im.is_animated
assert im.n_frames == 1
assert im.get_format_mimetype() == "image/apng"
assert im.get_format_mimetype() == "image/png"
assert im.info.get("default_image") is None
assert im.getpixel((0, 0)) == (0, 255, 0, 255)
assert im.getpixel((64, 32)) == (0, 255, 0, 255)
Expand Down Expand Up @@ -450,26 +450,29 @@ def test_apng_save_duration_loop(tmp_path):
test_file, save_all=True, append_images=[frame, frame], duration=[500, 100, 150]
)
with Image.open(test_file) as im:
im.load()
assert im.n_frames == 1
assert im.info.get("duration") == 750
assert "duration" not in im.info

# test info duration
frame.info["duration"] = 750
frame.save(test_file, save_all=True)
different_frame = Image.new("RGBA", (128, 64))
frame.save(
test_file,
save_all=True,
append_images=[frame, different_frame],
duration=[500, 100, 150],
)
with Image.open(test_file) as im:
assert im.info.get("duration") == 750

assert im.n_frames == 2
assert im.info["duration"] == 600

def test_apng_save_duplicate_duration(tmp_path):
test_file = str(tmp_path / "temp.png")
frame = Image.new("RGB", (1, 1))
im.seek(1)
assert im.info["duration"] == 150

# Test a single duration is correctly combined across duplicate frames
frame.save(test_file, save_all=True, append_images=[frame, frame], duration=500)
# test info duration
frame.info["duration"] = 300
frame.save(test_file, save_all=True, append_images=[frame, different_frame])
with Image.open(test_file) as im:
assert im.n_frames == 1
assert im.info.get("duration") == 1500
assert im.n_frames == 2
assert im.info["duration"] == 600


def test_apng_save_disposal(tmp_path):
Expand Down Expand Up @@ -674,15 +677,16 @@ def test_seek_after_close():

@pytest.mark.parametrize("mode", ("RGBA", "RGB", "P"))
@pytest.mark.parametrize("default_image", (True, False))
def test_different_modes_in_later_frames(mode, default_image, tmp_path):
@pytest.mark.parametrize("duplicate", (True, False))
def test_different_modes_in_later_frames(mode, default_image, duplicate, tmp_path):
test_file = str(tmp_path / "temp.png")

im = Image.new("L", (1, 1))
im.save(
test_file,
save_all=True,
default_image=default_image,
append_images=[Image.new(mode, (1, 1))],
append_images=[im.convert(mode) if duplicate else Image.new(mode, (1, 1), 1)],
)
with Image.open(test_file) as reloaded:
assert reloaded.mode == mode
22 changes: 22 additions & 0 deletions Tests/test_file_jpeg.py
Original file line number Diff line number Diff line change
Expand Up @@ -961,6 +961,28 @@ def closure(mode, *args):
im.load()
ImageFile.LOAD_TRUNCATED_IMAGES = False

def test_separate_tables(self):
im = hopper()
data = [] # [interchange, tables-only, image-only]
for streamtype in range(3):
out = BytesIO()
im.save(out, format="JPEG", streamtype=streamtype)
data.append(out.getvalue())

# SOI, EOI
for marker in b"\xff\xd8", b"\xff\xd9":
assert marker in data[1] and marker in data[2]
# DHT, DQT
for marker in b"\xff\xc4", b"\xff\xdb":
assert marker in data[1] and marker not in data[2]
# SOF0, SOS, APP0 (JFIF header)
for marker in b"\xff\xc0", b"\xff\xda", b"\xff\xe0":
assert marker not in data[1] and marker in data[2]

with Image.open(BytesIO(data[0])) as interchange_im:
with Image.open(BytesIO(data[1] + data[2])) as combined_im:
assert_image_equal(interchange_im, combined_im)

def test_repr_jpeg(self):
im = hopper()

Expand Down
9 changes: 7 additions & 2 deletions src/PIL/PngImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -1156,6 +1156,9 @@ def _write_multiple_frames(im, fp, chunk, rawmode, default_image, append_images)
encoderinfo["duration"] = duration
im_frames.append({"im": im_frame, "bbox": bbox, "encoderinfo": encoderinfo})

if len(im_frames) == 1 and not default_image:
return im_frames[0]["im"]

# animation control
chunk(
fp,
Expand Down Expand Up @@ -1391,8 +1394,10 @@ def _save(im, fp, filename, chunk=putchunk, save_all=False):
chunk(fp, b"eXIf", exif)

if save_all:
_write_multiple_frames(im, fp, chunk, rawmode, default_image, append_images)
else:
im = _write_multiple_frames(
im, fp, chunk, rawmode, default_image, append_images
)
if im:
ImageFile._save(im, _idat(fp, chunk), [("zip", (0, 0) + im.size, 0, rawmode)])

if info:
Expand Down
7 changes: 4 additions & 3 deletions src/libImaging/JpegEncode.c
Original file line number Diff line number Diff line change
Expand Up @@ -218,9 +218,9 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) {
}
switch (context->streamtype) {
case 1:
/* tables only -- not yet implemented */
state->errcode = IMAGING_CODEC_CONFIG;
return -1;
/* tables only */
jpeg_write_tables(&context->cinfo);
goto cleanup;
case 2:
/* image only */
jpeg_suppress_tables(&context->cinfo, TRUE);
Expand Down Expand Up @@ -316,6 +316,7 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes) {
}
jpeg_finish_compress(&context->cinfo);

cleanup:
/* Clean up */
if (context->comment) {
free(context->comment);
Expand Down
2 changes: 1 addition & 1 deletion wheels/config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ HARFBUZZ_VERSION=8.2.1
LIBPNG_VERSION=1.6.40
JPEGTURBO_VERSION=3.0.1
OPENJPEG_VERSION=2.5.0
XZ_VERSION=5.4.4
XZ_VERSION=5.4.5
TIFF_VERSION=4.6.0
LCMS2_VERSION=2.15
if [[ -n "$IS_MACOS" ]]; then
Expand Down
Loading

0 comments on commit 4b62012

Please sign in to comment.