Skip to content

Commit

Permalink
Merge pull request #6747 from ashafaei/webp-params
Browse files Browse the repository at this point in the history
Added WebP encoding with exact config
  • Loading branch information
mergify[bot] committed Nov 21, 2022
2 parents df8e872 + 8f73a89 commit 4f68047
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 1 deletion.
29 changes: 29 additions & 0 deletions Tests/test_file_webp_alpha.py
Expand Up @@ -97,6 +97,35 @@ def test_write_rgba(tmp_path):
assert_image_similar(image, pil_image, 1.0)


def test_keep_rgb_values_when_transparent(tmp_path):
"""
Saving transparent pixels should retain their original RGB values
when using the "exact" parameter.
"""

image = hopper("RGB")

# create a copy of the image
# with the left half transparent
half_transparent_image = image.copy()
new_alpha = Image.new("L", (128, 128), 255)
new_alpha.paste(0, (0, 0, 64, 128))
half_transparent_image.putalpha(new_alpha)

# save with transparent area preserved
temp_file = str(tmp_path / "temp.webp")
half_transparent_image.save(temp_file, exact=True, lossless=True)

with Image.open(temp_file) as reloaded:
assert reloaded.mode == "RGBA"
assert reloaded.format == "WEBP"

# even though it is lossless, if we don't use exact=True
# in libwebp >= 0.5, the transparent area will be filled with black
# (or something more conducive to compression)
assert_image_equal(reloaded.convert("RGB"), image)


def test_write_unsupported_mode_PA(tmp_path):
"""
Saving a palette-based file with transparency to WebP format
Expand Down
5 changes: 5 additions & 0 deletions docs/handbook/image-file-formats.rst
Expand Up @@ -1124,6 +1124,11 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options:
**method**
Quality/speed trade-off (0=fast, 6=slower-better). Defaults to 4.

**exact**
If true, preserve the transparent RGB values. Otherwise, discard
invisible RGB values for better compression. Defaults to false.
Requires libwebp 0.5.0 or later.

**icc_profile**
The ICC Profile to include in the saved file. Only supported if
the system WebP library was built with webpmux support.
Expand Down
8 changes: 8 additions & 0 deletions docs/releasenotes/9.4.0.rst
Expand Up @@ -37,6 +37,14 @@ support a ``start`` argument. This tuple of horizontal and vertical offset
will be used internally by :py:meth:`.ImageDraw.text` to more accurately place
text at the ``xy`` coordinates.

Added the ``exact`` encoding option for WebP
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The ``exact`` encoding option for WebP is now supported. The WebP encoder
removes the hidden RGB values for better compression by default in libwebp 0.5
or later. By setting this option to ``True``, the encoder will keep the hidden
RGB values.

Security
========

Expand Down
2 changes: 2 additions & 0 deletions src/PIL/WebPImagePlugin.py
Expand Up @@ -318,6 +318,7 @@ def _save(im, fp, filename):
exif = exif[6:]
xmp = im.encoderinfo.get("xmp", "")
method = im.encoderinfo.get("method", 4)
exact = 1 if im.encoderinfo.get("exact") else 0

if im.mode not in _VALID_WEBP_LEGACY_MODES:
alpha = (
Expand All @@ -336,6 +337,7 @@ def _save(im, fp, filename):
im.mode,
icc_profile,
method,
exact,
exif,
xmp,
)
Expand Down
8 changes: 7 additions & 1 deletion src/_webp.c
Expand Up @@ -576,6 +576,7 @@ WebPEncode_wrapper(PyObject *self, PyObject *args) {
int lossless;
float quality_factor;
int method;
int exact;
uint8_t *rgb;
uint8_t *icc_bytes;
uint8_t *exif_bytes;
Expand All @@ -597,7 +598,7 @@ WebPEncode_wrapper(PyObject *self, PyObject *args) {

if (!PyArg_ParseTuple(
args,
"y#iiifss#is#s#",
"y#iiifss#iis#s#",
(char **)&rgb,
&size,
&width,
Expand All @@ -608,6 +609,7 @@ WebPEncode_wrapper(PyObject *self, PyObject *args) {
&icc_bytes,
&icc_size,
&method,
&exact,
&exif_bytes,
&exif_size,
&xmp_bytes,
Expand All @@ -633,6 +635,10 @@ WebPEncode_wrapper(PyObject *self, PyObject *args) {
config.lossless = lossless;
config.quality = quality_factor;
config.method = method;
#if WEBP_ENCODER_ABI_VERSION >= 0x0209
// the "exact" flag is only available in libwebp 0.5.0 and later
config.exact = exact;
#endif

// Validate the config
if (!WebPValidateConfig(&config)) {
Expand Down

0 comments on commit 4f68047

Please sign in to comment.