Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow saving of zero quality JPEG images #4440

Merged
merged 2 commits into from Feb 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions Tests/test_file_jpeg.py
Expand Up @@ -299,6 +299,10 @@ def test_quality(self):
assert_image(im1, im2.mode, im2.size)
self.assertGreaterEqual(im1.bytes, im2.bytes)

im3 = self.roundtrip(hopper(), quality=0)
assert_image(im1, im3.mode, im3.size)
self.assertGreater(im2.bytes, im3.bytes)

def test_smooth(self):
im1 = self.roundtrip(hopper())
im2 = self.roundtrip(hopper(), smooth=100)
Expand Down
2 changes: 1 addition & 1 deletion docs/handbook/image-file-formats.rst
Expand Up @@ -302,7 +302,7 @@ The :py:meth:`~PIL.Image.Image.open` method may set the following
The :py:meth:`~PIL.Image.Image.save` method supports the following options:

**quality**
The image quality, on a scale from 1 (worst) to 95 (best). The default is
The image quality, on a scale from 0 (worst) to 95 (best). The default is
75. Values above 95 should be avoided; 100 disables portions of the JPEG
compression algorithm, and results in large files with hardly any gain in
image quality.
Expand Down
16 changes: 16 additions & 0 deletions docs/releasenotes/7.1.0.rst
@@ -0,0 +1,16 @@
7.0.0
-----

Allow saving of zero quality JPEG images
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

If no quality was specified when saving a JPEG, Pillow internally used a value
of zero to indicate that the default quality should be used. However, this
removed the ability to actually save a JPEG with zero quality. This has now
been resolved.

.. code-block:: python

from PIL import Image
im = Image.open("hopper.jpg")
im.save("out.jpg", quality=0)
10 changes: 5 additions & 5 deletions src/PIL/JpegImagePlugin.py
Expand Up @@ -616,17 +616,17 @@ def _save(im, fp, filename):

dpi = [round(x) for x in info.get("dpi", (0, 0))]

quality = info.get("quality", 0)
quality = info.get("quality", -1)
subsampling = info.get("subsampling", -1)
qtables = info.get("qtables")

if quality == "keep":
quality = 0
quality = -1
subsampling = "keep"
qtables = "keep"
elif quality in presets:
preset = presets[quality]
quality = 0
quality = -1
subsampling = preset.get("subsampling", -1)
qtables = preset.get("quantization")
elif not isinstance(quality, int):
Expand Down Expand Up @@ -749,8 +749,8 @@ def validate_qtables(qtables):
# CMYK can be bigger
if im.mode == "CMYK":
bufsize = 4 * im.size[0] * im.size[1]
# keep sets quality to 0, but the actual value may be high.
elif quality >= 95 or quality == 0:
# keep sets quality to -1, but the actual value may be high.
elif quality >= 95 or quality == -1:
bufsize = 2 * im.size[0] * im.size[1]
else:
bufsize = im.size[0] * im.size[1]
Expand Down
2 changes: 1 addition & 1 deletion src/libImaging/Jpeg.h
Expand Up @@ -67,7 +67,7 @@ typedef struct {

/* CONFIGURATION */

/* Quality (1-100, 0 means default) */
/* Quality (0-100, -1 means default) */
int quality;

/* Progressive mode */
Expand Down
4 changes: 2 additions & 2 deletions src/libImaging/JpegEncode.c
Expand Up @@ -153,7 +153,7 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
int i;
int quality = 100;
int last_q = 0;
if (context->quality > 0) {
if (context->quality != -1) {
quality = context->quality;
}
for (i = 0; i < context->qtablesLen; i++) {
Expand All @@ -171,7 +171,7 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
for (i = last_q; i < context->cinfo.num_components; i++) {
context->cinfo.comp_info[i].quant_tbl_no = last_q;
}
} else if (context->quality > 0) {
} else if (context->quality != -1) {
jpeg_set_quality(&context->cinfo, context->quality, 1);
}

Expand Down