From 6e4766155d2678f3152340be9c2025753774a791 Mon Sep 17 00:00:00 2001 From: Jason Douglas Date: Mon, 25 Sep 2017 18:53:31 -0700 Subject: [PATCH 01/19] Add support for writing animated webp files --- PIL/WebPImagePlugin.py | 99 ++++++++++- _webp.c | 247 ++++++++++++++++++++++++++- docs/handbook/image-file-formats.rst | 56 +++++- 3 files changed, 393 insertions(+), 9 deletions(-) diff --git a/PIL/WebPImagePlugin.py b/PIL/WebPImagePlugin.py index b93e0d3e7..4057448e0 100644 --- a/PIL/WebPImagePlugin.py +++ b/PIL/WebPImagePlugin.py @@ -45,10 +45,105 @@ class WebPImageFile(ImageFile.ImageFile): return _getexif(self) +def _save_all(im, fp, filename): + encoderinfo = im.encoderinfo.copy() + append_images = encoderinfo.get("append_images", []) + background = encoderinfo.get("background", (0, 0, 0, 0)) + duration = im.encoderinfo.get("duration", 0) + loop = im.encoderinfo.get("loop", 0) + minimize_size = im.encoderinfo.get("minimize_size", False) + kmin = im.encoderinfo.get("kmin", None) + kmax = im.encoderinfo.get("kmax", None) + allow_mixed = im.encoderinfo.get("allow_mixed", False) + verbose = False + lossless = im.encoderinfo.get("lossless", False) + quality = im.encoderinfo.get("quality", 80) + method = im.encoderinfo.get("method", 0) + icc_profile = im.encoderinfo.get("icc_profile", "") + exif = im.encoderinfo.get("exif", "") + if allow_mixed: + lossless = False + + # Sensible keyframe defaults are from gif2webp.c script + if kmin is None: + kmin = 9 if lossless else 3 + if kmax is None: + kmax = 17 if lossless else 5 + + # Validate background color + if (not isinstance(background, (list, tuple)) or len(background) != 4 or + not all(v >= 0 and v < 256 for v in background)): + raise IOError("Background color is not an RGBA tuple clamped to (0-255): %s" % str(background)) + bg_r, bg_g, bg_b, bg_a = background + background = (bg_a << 24) | (bg_r << 16) | (bg_g << 8) | (bg_b << 0) # Convert to packed uint + + # Setup the WebP animation encoder + enc = _webp.WebPAnimEncoder( + im.size[0], im.size[1], + background, + loop, + minimize_size, + kmin, kmax, + allow_mixed, + verbose + ) + + # Add each frame + frame_idx = 0 + timestamp = 0 + cur_idx = im.tell() + try: + for ims in [im]+append_images: + # Get # of frames in this image + if not hasattr(ims, "n_frames"): + nfr = 1 + else: + nfr = ims.n_frames + + for idx in range(nfr): + ims.seek(idx) + ims.load() + + # Make sure image mode is supported + frame = ims if ims.mode in _VALID_WEBP_MODES else ims.convert("RGBA") + + # Append the frame to the animation encoder + enc.add( + frame.tobytes(), + timestamp, + frame.size[0], frame.size[1], + frame.mode, + lossless, + quality, + method + ) + + # Update timestamp and frame index + timestamp += duration[frame_idx] if isinstance(duration, (list, tuple)) else duration + frame_idx += 1 + + finally: + im.seek(cur_idx) + + # Force encoder to flush frames + enc.add( + None, + timestamp, + 0, 0, "", lossless, quality, 0 + ) + + # Get the final output from the encoder + data = enc.assemble(icc_profile, exif) + if data is None: + raise IOError("cannot write file as WEBP (encoder returned None)") + + fp.write(data) + + def _save(im, fp, filename): image_mode = im.mode if im.mode not in _VALID_WEBP_MODES: - raise IOError("cannot write mode %s as WEBP" % image_mode) + im = im.convert("RGBA") lossless = im.encoderinfo.get("lossless", False) quality = im.encoderinfo.get("quality", 80) @@ -73,6 +168,6 @@ def _save(im, fp, filename): Image.register_open(WebPImageFile.format, WebPImageFile, _accept) Image.register_save(WebPImageFile.format, _save) - +Image.register_save_all(WebPImageFile.format, _save_all) Image.register_extension(WebPImageFile.format, ".webp") Image.register_mime(WebPImageFile.format, "image/webp") diff --git a/_webp.c b/_webp.c index 260f2182b..4df63c883 100644 --- a/_webp.c +++ b/_webp.c @@ -10,6 +10,179 @@ #include #endif +/* -------------------------------------------------------------------- */ +/* WebP Animation Support */ +/* -------------------------------------------------------------------- */ +#ifdef HAVE_WEBPMUX + +typedef struct { + PyObject_HEAD + WebPAnimEncoder* enc; + WebPPicture frame; +} WebPAnimEncoderObject; + +static PyTypeObject WebPAnimEncoder_Type; + +PyObject* _anim_encoder_new(PyObject* self, PyObject* args) +{ + int width, height; + uint32_t bgcolor; + int loop_count; + int minimize_size; + int kmin, kmax; + int allow_mixed; + int verbose; + + if (!PyArg_ParseTuple(args, "iiIiiiiii", + &width, &height, &bgcolor, &loop_count, &minimize_size, + &kmin, &kmax, &allow_mixed, &verbose)) { + return NULL; + } + + // Setup and configure the encoder's options (these are animation-specific) + WebPAnimEncoderOptions enc_options; + if (!WebPAnimEncoderOptionsInit(&enc_options)) { + fprintf(stderr, "Error! Failed to initialize encoder options\n"); + Py_RETURN_NONE; + } + enc_options.anim_params.bgcolor = bgcolor; + enc_options.anim_params.loop_count = loop_count; + enc_options.minimize_size = minimize_size; + enc_options.kmin = kmin; + enc_options.kmax = kmax; + enc_options.allow_mixed = allow_mixed; + enc_options.verbose = verbose; + + // Validate canvas dimensions + if (width <= 0 || height <= 0) { + fprintf(stderr, "Error! Invalid canvas dimensions: width=%d, height=%d\n", width, height); + Py_RETURN_NONE; + } + + // Create a new animation encoder and picture frame + WebPAnimEncoderObject* encp; + encp = PyObject_New(WebPAnimEncoderObject, &WebPAnimEncoder_Type); + if (encp) { + if (WebPPictureInit(&(encp->frame))) { + WebPAnimEncoder* enc = WebPAnimEncoderNew(width, height, &enc_options); + if (enc) { + encp->enc = enc; + return (PyObject*) encp; + } + } + PyObject_Del(encp); + } + fprintf(stderr, "Error! Could not create encoder object.\n"); + Py_RETURN_NONE; +} + +PyObject* _anim_encoder_dealloc(PyObject* self) +{ + WebPAnimEncoderObject* encp = (WebPAnimEncoderObject *)self; + WebPPictureFree(&(encp->frame)); + WebPAnimEncoderDelete(encp->enc); + Py_RETURN_NONE; +} + +PyObject* _anim_encoder_add(PyObject* self, PyObject* args) +{ + uint8_t *rgb; + Py_ssize_t size; + int timestamp; + int width; + int height; + char *mode; + int lossless; + float quality_factor; + int method; + + if (!PyArg_ParseTuple(args, "z#iiisifi", + (char**)&rgb, &size, ×tamp, &width, &height, &mode, + &lossless, &quality_factor, &method)) { + return NULL; + } + + WebPAnimEncoderObject* encp = (WebPAnimEncoderObject *)self; + WebPAnimEncoder* enc = encp->enc; + WebPPicture* frame = &(encp->frame); + + // Check for NULL frame, which sets duration of final frame + if (!rgb) { + WebPAnimEncoderAdd(enc, NULL, timestamp, NULL); + Py_RETURN_NONE; + } + + // Setup config for this frame + WebPConfig config; + if (!WebPConfigInit(&config)) { + fprintf(stderr, "Error! Failed to initialize config!\n"); + Py_RETURN_NONE; + } + config.lossless = lossless; + config.quality = quality_factor; + config.method = method; + + // Validate the config + if (!WebPValidateConfig(&config)) { + fprintf(stderr, "Error! Invalid configuration\n"); + Py_RETURN_NONE; + } + + // Populate the frame with raw bytes passed to us + frame->width = width; + frame->height = height; + frame->use_argb = 1; // Don't convert RGB pixels to YUV + if (strcmp(mode, "RGBA")==0) { + WebPPictureImportRGBA(frame, rgb, 4 * width); + } else if (strcmp(mode, "RGB")==0) { + WebPPictureImportRGB(frame, rgb, 3 * width); + } + + // Add the frame to the encoder + if (!WebPAnimEncoderAdd(enc, frame, timestamp, &config)) { + fprintf(stderr, "Error! Could not add frame: %s\n", WebPAnimEncoderGetError(enc)); + Py_RETURN_NONE; + } + + Py_RETURN_NONE; +} + +PyObject* _anim_encoder_assemble(PyObject* self, PyObject* args) +{ + uint8_t *icc_bytes; + uint8_t *exif_bytes; + Py_ssize_t icc_size; + Py_ssize_t exif_size; + + if (!PyArg_ParseTuple(args, "s#s#", + &icc_bytes, &icc_size, &exif_bytes, &exif_size)) { + return NULL; + } + + // Init the output buffer + WebPData webp_data; + WebPDataInit(&webp_data); + + // Assemble everything into the output buffer + WebPAnimEncoderObject* encp = (WebPAnimEncoderObject *)self; + WebPAnimEncoder* enc = encp->enc; + if (!WebPAnimEncoderAssemble(enc, &webp_data)) { + fprintf(stderr, "%s\n", WebPAnimEncoderGetError(enc)); + Py_RETURN_NONE; + } + + // Convert to Python bytes and return + PyObject *ret = PyBytes_FromStringAndSize((char*)webp_data.bytes, webp_data.size); + WebPDataClear(&webp_data); + return ret; +} + +#endif + +/* -------------------------------------------------------------------- */ +/* WebP Single-Frame Support */ +/* -------------------------------------------------------------------- */ + PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args) { int width; @@ -255,8 +428,63 @@ PyObject* WebPDecoderBuggyAlpha_wrapper(PyObject* self, PyObject* args){ return Py_BuildValue("i", WebPDecoderBuggyAlpha()); } +/* -------------------------------------------------------------------- */ +/* WebPAnimEncoder Type */ +/* -------------------------------------------------------------------- */ +#ifdef HAVE_WEBPMUX + +static struct PyMethodDef _anim_encoder_methods[] = { + {"add", (PyCFunction)_anim_encoder_add, 1}, + {"assemble", (PyCFunction)_anim_encoder_assemble, 1}, + {NULL, NULL} /* sentinel */ +}; + +/* type description */ +static PyTypeObject WebPAnimEncoder_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "WebPAnimEncoder", /*tp_name */ + sizeof(WebPAnimEncoderObject), /*tp_size */ + 0, /*tp_itemsize */ + /* methods */ + (destructor)_anim_encoder_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number */ + 0, /*tp_as_sequence */ + 0, /*tp_as_mapping */ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + _anim_encoder_methods, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ +}; + +#endif + +/* -------------------------------------------------------------------- */ +/* Module Setup */ +/* -------------------------------------------------------------------- */ + static PyMethodDef webpMethods[] = { +#ifdef HAVE_WEBPMUX + {"WebPAnimEncoder", _anim_encoder_new, METH_VARARGS, "WebPAnimEncoder"}, +#endif {"WebPEncode", WebPEncode_wrapper, METH_VARARGS, "WebPEncode"}, {"WebPDecode", WebPDecode_wrapper, METH_VARARGS, "WebPDecode"}, {"WebPDecoderVersion", WebPDecoderVersion_wrapper, METH_VARARGS, "WebPVersion"}, @@ -277,6 +505,17 @@ void addTransparencyFlagToModule(PyObject* m) { PyBool_FromLong(!WebPDecoderBuggyAlpha())); } +static int setup_module(PyObject* m) { + addMuxFlagToModule(m); + addTransparencyFlagToModule(m); + +#ifdef HAVE_WEBPMUX + /* Ready object types */ + if (PyType_Ready(&WebPAnimEncoder_Type) < 0) + return -1; +#endif + return 0; +} #if PY_VERSION_HEX >= 0x03000000 PyMODINIT_FUNC @@ -292,8 +531,9 @@ PyInit__webp(void) { }; m = PyModule_Create(&module_def); - addMuxFlagToModule(m); - addTransparencyFlagToModule(m); + if (setup_module(m) < 0) + return NULL; + return m; } #else @@ -301,7 +541,6 @@ PyMODINIT_FUNC init_webp(void) { PyObject* m = Py_InitModule("_webp", webpMethods); - addMuxFlagToModule(m); - addTransparencyFlagToModule(m); + setup_module(m); } #endif diff --git a/docs/handbook/image-file-formats.rst b/docs/handbook/image-file-formats.rst index 7975c6900..8528b24e1 100644 --- a/docs/handbook/image-file-formats.rst +++ b/docs/handbook/image-file-formats.rst @@ -110,7 +110,7 @@ are available:: **append_images** A list of images to append as additional frames. Each of the images in the list can be single or multiframe images. - This is currently only supported for GIF, PDF and TIFF. + This is currently only supported for GIF, PDF, TIFF, and WebP. **duration** The display duration of each frame of the multiframe gif, in @@ -661,8 +661,13 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options: If present and true, instructs the WEBP writer to use lossless compression. **quality** - Integer, 1-100, Defaults to 80. Sets the quality level for - lossy compression. + Integer, 1-100, Defaults to 80. For lossy, 0 gives the smallest + size and 100 the largest. For lossless, this parameter is the amount + of effort put into the compression: 0 is the fastest, but gives larger + files compared to the slowest, but best, 100. + +**method** + Quality/speed trade-off (0=fast, 6=slower-better). Defaults to 0. **icc_procfile** The ICC Profile to include in the saved file. Only supported if @@ -672,6 +677,51 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options: The exif data to include in the saved file. Only supported if the system webp library was built with webpmux support. +Saving sequences +~~~~~~~~~~~~~~~~~ + +.. note:: + + Support for animated WebP files will only be enabled if the system webp + library was built with webpmux support. You can check webpmux support + at runtime by inspecting the `_webp.HAVE_WEBPMUX` module flag. + +When calling :py:meth:`~PIL.Image.Image.save`, the following options +are available when the save_all argument is present and true. + +**append_images** + A list of images to append as additional frames. Each of the + images in the list can be single or multiframe images. + +**duration** + The display duration of each frame, in milliseconds. Pass a single + integer for a constant duration, or a list or tuple to set the + duration for each frame separately. + +**loop** + Number of times to repeat the animation. Defaults to [0 = infinite]. + +**background** + Background color of the canvas, as an RGBA tuple with values in + the range of (0-255). + +**minimize_size** + If true, minimize the output size (slow). Implicitly disables + key-frame insertion. + +**kmin, kmax** + Minimum and maximum distance between consecutive key frames in + the output. The library may insert some key frames as needed + to satisfy this criteria. Note that these conditions should + hold: kmax > kmin and kmin >= kmax / 2 + 1. Also, if kmax <= 0, + then key-frame insertion is disabled; and if kmax == 1, then all + frames will be key-frames (kmin value does not matter for these + special cases). + +**allow_mixed** + If true, use mixed compression mode; the encoder heuristically + chooses between lossy and lossless for each frame. + XBM ^^^ From 482d8037175839dab571fc097921f15e1a52ad15 Mon Sep 17 00:00:00 2001 From: Jason Douglas Date: Tue, 26 Sep 2017 02:58:54 -0700 Subject: [PATCH 02/19] Add support for reading animated WebP files --- PIL/WebPImagePlugin.py | 133 ++++++++++++++++++-- _webp.c | 273 +++++++++++++++++++++++++++++++++-------- 2 files changed, 344 insertions(+), 62 deletions(-) diff --git a/PIL/WebPImagePlugin.py b/PIL/WebPImagePlugin.py index 4057448e0..97a910930 100644 --- a/PIL/WebPImagePlugin.py +++ b/PIL/WebPImagePlugin.py @@ -28,24 +28,134 @@ class WebPImageFile(ImageFile.ImageFile): format_description = "WebP image" def _open(self): - data, width, height, self.mode, icc_profile, exif = \ - _webp.WebPDecode(self.fp.read()) + if not _webp.HAVE_WEBPMUX: + # Legacy mode + data, width, height, self.mode = _webp.WebPDecode(self.fp.read()) + self.size = width, height + self.fp = BytesIO(data) + self.tile = [("raw", (0, 0) + self.size, 0, self.mode)] + return + # Use the newer AnimDecoder API to parse the (possibly) animated file, + # and access muxed chunks like ICC/EXIF/XMP. + self._decoder = _webp.WebPAnimDecoder(self.fp.read()) + + # Get info from decoder + width, height, loop_count, bgcolor, frame_count, mode = self._decoder.get_info() + self.size = width, height + self.info["loop"] = loop_count + bg_a, bg_r, bg_g, bg_b = \ + (bgcolor >> 24) & 0xFF, \ + (bgcolor >> 16) & 0xFF, \ + (bgcolor >> 8) & 0xFF, \ + bgcolor & 0xFF + self.info["background"] = (bg_r, bg_g, bg_b, bg_a) + self._n_frames = frame_count + self.mode = mode + self.tile = [] + + # Attempt to read ICC / EXIF / XMP chunks from file + icc_profile = self._decoder.get_chunk("ICCP") + exif = self._decoder.get_chunk("EXIF") + xmp = self._decoder.get_chunk("XMP ") if icc_profile: self.info["icc_profile"] = icc_profile if exif: self.info["exif"] = exif + if xmp: + self.info["xmp"] = xmp - self.size = width, height - self.fp = BytesIO(data) - self.tile = [("raw", (0, 0) + self.size, 0, self.mode)] + # Initialize seek state + self._reset(reset=False) + self.seek(0) def _getexif(self): from .JpegImagePlugin import _getexif return _getexif(self) + @property + def n_frames(self): + if not _webp.HAVE_WEBPMUX: + return 1 + return self._n_frames + + @property + def is_animated(self): + if not _webp.HAVE_WEBPMUX: + return False + return self._n_frames > 1 + + def seek(self, frame): + # Perform some simple checks first + if frame >= self._n_frames: + raise EOFError("attempted to seek beyond end of sequence") + if frame < 0: + raise EOFError("negative frame index is not valid") + + # Set logical frame to requested position + self.__logical_frame = frame + + def _reset(self, reset=True): + if reset: + self._decoder.reset() + self.__physical_frame = 0 + self.__loaded = -1 + self.__timestamp = 0 + + def _get_next(self): + # Get next frame + ret = self._decoder.get_next() + self.__physical_frame += 1 + + # Check if an error occurred + if ret is None: + self._reset() # Reset just to be safe + self.seek(0) + raise EOFError("failed to decode next frame in WebP file") + + # Compute duration + data, timestamp = ret + duration = timestamp - self.__timestamp + self.__timestamp = timestamp + timestamp -= duration # libwebp gives frame end, adjust to start of frame + return data, timestamp, duration + + def _seek(self, frame): + if self.__physical_frame == frame: + return # Nothing to do + + if frame < self.__physical_frame: + # Rewind to beginning + self._reset() + + # Advance to the requested frame + while self.__physical_frame < frame: + self._get_next() + + def load(self): + if self.__loaded != self.__logical_frame: + self._seek(self.__logical_frame) + + # We need to load the image data for this frame + data, timestamp, duration = self._get_next() + self.info["timestamp"] = timestamp + self.info["duration"] = duration + self.__loaded = self.__logical_frame + + # Set tile + self.fp = BytesIO(data) + self.tile = [("raw", (0, 0) + self.size, 0, self.mode)] + + return super(WebPImageFile, self).load() + + def tell(self): + return self.__logical_frame def _save_all(im, fp, filename): + if not _webp.HAVE_WEBPMUX: + _save(im, fp, filename) + return + encoderinfo = im.encoderinfo.copy() append_images = encoderinfo.get("append_images", []) background = encoderinfo.get("background", (0, 0, 0, 0)) @@ -105,7 +215,10 @@ def _save_all(im, fp, filename): ims.load() # Make sure image mode is supported - frame = ims if ims.mode in _VALID_WEBP_MODES else ims.convert("RGBA") + frame = ims + if not ims.mode in _VALID_WEBP_MODES: + alpha = 'A' in ims.im.getpalettemode() + frame = image.convert('RGBA' if alpha else 'RGB') # Append the frame to the animation encoder enc.add( @@ -139,11 +252,15 @@ def _save_all(im, fp, filename): fp.write(data) - def _save(im, fp, filename): + if _webp.HAVE_WEBPMUX: + _save_all(im, fp, filename) + return + image_mode = im.mode if im.mode not in _VALID_WEBP_MODES: - im = im.convert("RGBA") + alpha = 'A' in im.im.getpalettemode() + im = im.convert('RGBA' if alpha else 'RGB') lossless = im.encoderinfo.get("lossless", False) quality = im.encoderinfo.get("quality", 80) diff --git a/_webp.c b/_webp.c index 4df63c883..8a54c6935 100644 --- a/_webp.c +++ b/_webp.c @@ -8,13 +8,13 @@ #ifdef HAVE_WEBPMUX #include -#endif +#include /* -------------------------------------------------------------------- */ /* WebP Animation Support */ /* -------------------------------------------------------------------- */ -#ifdef HAVE_WEBPMUX +// Encoder type typedef struct { PyObject_HEAD WebPAnimEncoder* enc; @@ -23,6 +23,17 @@ typedef struct { static PyTypeObject WebPAnimEncoder_Type; +// Decoder type +typedef struct { + PyObject_HEAD + WebPAnimDecoder* dec; + WebPAnimInfo info; + WebPData data; +} WebPAnimDecoderObject; + +static PyTypeObject WebPAnimDecoder_Type; + +// Encoder functions PyObject* _anim_encoder_new(PyObject* self, PyObject* args) { int width, height; @@ -177,10 +188,207 @@ PyObject* _anim_encoder_assemble(PyObject* self, PyObject* args) return ret; } -#endif +// Decoder functions +PyObject* _anim_decoder_new(PyObject* self, PyObject* args) +{ + PyBytesObject *webp_string; + const uint8_t *webp; + Py_ssize_t size; + + if (!PyArg_ParseTuple(args, "S", &webp_string)) { + return NULL; + } + PyBytes_AsStringAndSize((PyObject *) webp_string, (char**)&webp, &size); + WebPData webp_src = {webp, size}; + + // Create the decoder (default mode is RGBA, if no options passed) + WebPAnimDecoderObject* decp; + decp = PyObject_New(WebPAnimDecoderObject, &WebPAnimDecoder_Type); + if (decp) { + if (WebPDataCopy(&webp_src, &(decp->data))) { + WebPAnimDecoder* dec = WebPAnimDecoderNew(&(decp->data), NULL); + if (dec) { + if (WebPAnimDecoderGetInfo(dec, &(decp->info))) { + decp->dec = dec; + return (PyObject*) decp; + } + } + } + PyObject_Del(decp); + } + fprintf(stderr, "Error! Could not create decoder object.\n"); + Py_RETURN_NONE; +} + +PyObject* _anim_decoder_dealloc(PyObject* self) +{ + WebPAnimDecoderObject* decp = (WebPAnimDecoderObject *)self; + WebPDataClear(&(decp->data)); + WebPAnimDecoderDelete(decp->dec); + Py_RETURN_NONE; +} + +PyObject* _anim_decoder_get_info(PyObject* self, PyObject* args) +{ + WebPAnimDecoderObject* decp = (WebPAnimDecoderObject *)self; + WebPAnimInfo* info = &(decp->info); + return Py_BuildValue("IIIIIs", + info->canvas_width, info->canvas_height, + info->loop_count, + info->bgcolor, + info->frame_count, + "RGBA" // WebPAnimDecoder defaults to RGBA if no mode is specified + ); +} + +PyObject* _anim_decoder_get_chunk(PyObject* self, PyObject* args) +{ + char *mode; + PyObject *ret; + WebPChunkIterator iter; + + if (!PyArg_ParseTuple(args, "s", &mode)) { + return NULL; + } + + WebPAnimDecoderObject* decp = (WebPAnimDecoderObject *)self; + const WebPDemuxer* demux = WebPAnimDecoderGetDemuxer(decp->dec); + if (!WebPDemuxGetChunk(demux, mode, 1, &iter)) { + Py_RETURN_NONE; + } + + ret = PyBytes_FromStringAndSize((const char*)iter.chunk.bytes, iter.chunk.size); + WebPDemuxReleaseChunkIterator(&iter); + + return ret; +} + +PyObject* _anim_decoder_get_next(PyObject* self, PyObject* args) +{ + uint8_t* buf; + int timestamp; + PyObject *bytes; + + WebPAnimDecoderObject* decp = (WebPAnimDecoderObject *)self; + if (!WebPAnimDecoderGetNext(decp->dec, &buf, ×tamp)) { + fprintf(stderr, "Error! Failed to read next frame.\n"); + Py_RETURN_NONE; + } + + bytes = PyBytes_FromStringAndSize((char *)buf, + decp->info.canvas_width * 4 * decp->info.canvas_height); + return Py_BuildValue("Si", bytes, timestamp); +} + +PyObject* _anim_decoder_has_more_frames(PyObject* self, PyObject* args) +{ + WebPAnimDecoderObject* decp = (WebPAnimDecoderObject *)self; + return Py_BuildValue("i", WebPAnimDecoderHasMoreFrames(decp->dec)); +} + +PyObject* _anim_decoder_reset(PyObject* self, PyObject* args) +{ + WebPAnimDecoderObject* decp = (WebPAnimDecoderObject *)self; + WebPAnimDecoderReset(decp->dec); + Py_RETURN_NONE; +} /* -------------------------------------------------------------------- */ -/* WebP Single-Frame Support */ +/* Type Definitions */ +/* -------------------------------------------------------------------- */ + +// WebPAnimEncoder methods +static struct PyMethodDef _anim_encoder_methods[] = { + {"add", (PyCFunction)_anim_encoder_add, METH_VARARGS, "add"}, + {"assemble", (PyCFunction)_anim_encoder_assemble, METH_VARARGS, "assemble"}, + {NULL, NULL} /* sentinel */ +}; + +// WebPAnimDecoder type definition +static PyTypeObject WebPAnimEncoder_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "WebPAnimEncoder", /*tp_name */ + sizeof(WebPAnimEncoderObject), /*tp_size */ + 0, /*tp_itemsize */ + /* methods */ + (destructor)_anim_encoder_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number */ + 0, /*tp_as_sequence */ + 0, /*tp_as_mapping */ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + _anim_encoder_methods, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ +}; + +// WebPAnimDecoder methods +static struct PyMethodDef _anim_decoder_methods[] = { + {"get_info", (PyCFunction)_anim_decoder_get_info, METH_VARARGS, "get_info"}, + {"get_chunk", (PyCFunction)_anim_decoder_get_chunk, METH_VARARGS, "get_chunk"}, + {"get_next", (PyCFunction)_anim_decoder_get_next, METH_VARARGS, "get_next"}, + {"has_more_frames", (PyCFunction)_anim_decoder_has_more_frames, METH_VARARGS, "has_more_frames"}, + {"reset", (PyCFunction)_anim_decoder_reset, METH_VARARGS, "reset"}, + {NULL, NULL} /* sentinel */ +}; + +// WebPAnimDecoder type definition +static PyTypeObject WebPAnimDecoder_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "WebPAnimDecoder", /*tp_name */ + sizeof(WebPAnimDecoderObject), /*tp_size */ + 0, /*tp_itemsize */ + /* methods */ + (destructor)_anim_decoder_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number */ + 0, /*tp_as_sequence */ + 0, /*tp_as_mapping */ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + _anim_decoder_methods, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ +}; + +#endif + +#ifdef HAVE_WEBPMUX +/* -------------------------------------------------------------------- */ +/* Legacy WebP Support */ /* -------------------------------------------------------------------- */ PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args) @@ -410,6 +618,8 @@ end: return ret; } +#endif + // Return the decoder's version number, packed in hexadecimal using 8bits for // each of major/minor/revision. E.g: v2.5.7 is 0x020507. PyObject* WebPDecoderVersion_wrapper(PyObject* self, PyObject* args){ @@ -428,54 +638,6 @@ PyObject* WebPDecoderBuggyAlpha_wrapper(PyObject* self, PyObject* args){ return Py_BuildValue("i", WebPDecoderBuggyAlpha()); } -/* -------------------------------------------------------------------- */ -/* WebPAnimEncoder Type */ -/* -------------------------------------------------------------------- */ -#ifdef HAVE_WEBPMUX - -static struct PyMethodDef _anim_encoder_methods[] = { - {"add", (PyCFunction)_anim_encoder_add, 1}, - {"assemble", (PyCFunction)_anim_encoder_assemble, 1}, - {NULL, NULL} /* sentinel */ -}; - -/* type description */ -static PyTypeObject WebPAnimEncoder_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "WebPAnimEncoder", /*tp_name */ - sizeof(WebPAnimEncoderObject), /*tp_size */ - 0, /*tp_itemsize */ - /* methods */ - (destructor)_anim_encoder_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number */ - 0, /*tp_as_sequence */ - 0, /*tp_as_mapping */ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - _anim_encoder_methods, /*tp_methods*/ - 0, /*tp_members*/ - 0, /*tp_getset*/ -}; - -#endif - /* -------------------------------------------------------------------- */ /* Module Setup */ /* -------------------------------------------------------------------- */ @@ -483,10 +645,12 @@ static PyTypeObject WebPAnimEncoder_Type = { static PyMethodDef webpMethods[] = { #ifdef HAVE_WEBPMUX + {"WebPAnimDecoder", _anim_decoder_new, METH_VARARGS, "WebPAnimDecoder"}, {"WebPAnimEncoder", _anim_encoder_new, METH_VARARGS, "WebPAnimEncoder"}, -#endif +#else {"WebPEncode", WebPEncode_wrapper, METH_VARARGS, "WebPEncode"}, {"WebPDecode", WebPDecode_wrapper, METH_VARARGS, "WebPDecode"}, +#endif {"WebPDecoderVersion", WebPDecoderVersion_wrapper, METH_VARARGS, "WebPVersion"}, {"WebPDecoderBuggyAlpha", WebPDecoderBuggyAlpha_wrapper, METH_VARARGS, "WebPDecoderBuggyAlpha"}, {NULL, NULL} @@ -511,7 +675,8 @@ static int setup_module(PyObject* m) { #ifdef HAVE_WEBPMUX /* Ready object types */ - if (PyType_Ready(&WebPAnimEncoder_Type) < 0) + if (PyType_Ready(&WebPAnimDecoder_Type) < 0 || + PyType_Ready(&WebPAnimEncoder_Type) < 0) return -1; #endif return 0; From cd12a48fe041b3aad270eb4914b42636faa72912 Mon Sep 17 00:00:00 2001 From: Jason Douglas Date: Tue, 26 Sep 2017 20:27:40 -0700 Subject: [PATCH 03/19] - Support non-alpha modes with WebPAnimDecoder - Support writing metadata chunks with WebPAnimEncoder - Add XMP metadata support to legacy WebPEncode wrapper - Cleanup unused mux code in legacy WebPDecode wrapper - Fix some bugs present when compiled without WebP Mux support - Fix conversion from L/P/PA modes when saving WebP files - Update existing tests, and add new ones for WebP animation and metadata support --- PIL/WebPImagePlugin.py | 66 ++++++----- Tests/images/anim_frame1.webp | Bin 0 -> 302 bytes Tests/images/anim_frame2.webp | Bin 0 -> 288 bytes Tests/images/iss634.webp | Bin 0 -> 207838 bytes Tests/images/transparent.gif | Bin 0 -> 9678 bytes Tests/test_file_webp.py | 61 +++++++++- Tests/test_file_webp_alpha.py | 31 +++++ Tests/test_file_webp_animated.py | 120 +++++++++++++++++++ Tests/test_file_webp_metadata.py | 20 ++++ _webp.c | 191 ++++++++++++++++++++++--------- 10 files changed, 400 insertions(+), 89 deletions(-) create mode 100644 Tests/images/anim_frame1.webp create mode 100644 Tests/images/anim_frame2.webp create mode 100644 Tests/images/iss634.webp create mode 100644 Tests/images/transparent.gif create mode 100644 Tests/test_file_webp_animated.py diff --git a/PIL/WebPImagePlugin.py b/PIL/WebPImagePlugin.py index 97a910930..886648a7f 100644 --- a/PIL/WebPImagePlugin.py +++ b/PIL/WebPImagePlugin.py @@ -86,6 +86,9 @@ class WebPImageFile(ImageFile.ImageFile): return self._n_frames > 1 def seek(self, frame): + if not _webp.HAVE_WEBPMUX: + return super(WebPImageFile, self).seek(frame) + # Perform some simple checks first if frame >= self._n_frames: raise EOFError("attempted to seek beyond end of sequence") @@ -133,31 +136,41 @@ class WebPImageFile(ImageFile.ImageFile): self._get_next() def load(self): - if self.__loaded != self.__logical_frame: - self._seek(self.__logical_frame) + if _webp.HAVE_WEBPMUX: + if self.__loaded != self.__logical_frame: + self._seek(self.__logical_frame) - # We need to load the image data for this frame - data, timestamp, duration = self._get_next() - self.info["timestamp"] = timestamp - self.info["duration"] = duration - self.__loaded = self.__logical_frame + # We need to load the image data for this frame + data, timestamp, duration = self._get_next() + self.info["timestamp"] = timestamp + self.info["duration"] = duration + self.__loaded = self.__logical_frame - # Set tile - self.fp = BytesIO(data) - self.tile = [("raw", (0, 0) + self.size, 0, self.mode)] + # Set tile + self.fp = BytesIO(data) + self.tile = [("raw", (0, 0) + self.size, 0, self.mode)] return super(WebPImageFile, self).load() def tell(self): + if not _webp.HAVE_WEBPMUX: + return super(WebPImageFile, self).tell() + return self.__logical_frame def _save_all(im, fp, filename): - if not _webp.HAVE_WEBPMUX: + encoderinfo = im.encoderinfo.copy() + append_images = encoderinfo.get("append_images", []) + + # If total frame count is 1, then save using the legacy API, which + # will preserve non-alpha modes + total = 0 + for ims in [im]+append_images: + total += 1 if not hasattr(ims, "n_frames") else ims.n_frames + if total == 1: _save(im, fp, filename) return - encoderinfo = im.encoderinfo.copy() - append_images = encoderinfo.get("append_images", []) background = encoderinfo.get("background", (0, 0, 0, 0)) duration = im.encoderinfo.get("duration", 0) loop = im.encoderinfo.get("loop", 0) @@ -171,6 +184,7 @@ def _save_all(im, fp, filename): method = im.encoderinfo.get("method", 0) icc_profile = im.encoderinfo.get("icc_profile", "") exif = im.encoderinfo.get("exif", "") + xmp = im.encoderinfo.get("xmp", "") if allow_mixed: lossless = False @@ -217,8 +231,8 @@ def _save_all(im, fp, filename): # Make sure image mode is supported frame = ims if not ims.mode in _VALID_WEBP_MODES: - alpha = 'A' in ims.im.getpalettemode() - frame = image.convert('RGBA' if alpha else 'RGB') + alpha = ims.mode == 'P' and 'A' in ims.im.getpalettemode() + frame = ims.convert('RGBA' if alpha else 'RGB') # Append the frame to the animation encoder enc.add( @@ -246,26 +260,22 @@ def _save_all(im, fp, filename): ) # Get the final output from the encoder - data = enc.assemble(icc_profile, exif) + data = enc.assemble(icc_profile, exif, xmp) if data is None: raise IOError("cannot write file as WEBP (encoder returned None)") fp.write(data) def _save(im, fp, filename): - if _webp.HAVE_WEBPMUX: - _save_all(im, fp, filename) - return - - image_mode = im.mode - if im.mode not in _VALID_WEBP_MODES: - alpha = 'A' in im.im.getpalettemode() - im = im.convert('RGBA' if alpha else 'RGB') - lossless = im.encoderinfo.get("lossless", False) quality = im.encoderinfo.get("quality", 80) icc_profile = im.encoderinfo.get("icc_profile", "") exif = im.encoderinfo.get("exif", "") + xmp = im.encoderinfo.get("xmp", "") + + if im.mode not in _VALID_WEBP_MODES: + alpha = im.mode == 'P' and 'A' in im.im.getpalettemode() + im = im.convert('RGBA' if alpha else 'RGB') data = _webp.WebPEncode( im.tobytes(), @@ -275,7 +285,8 @@ def _save(im, fp, filename): float(quality), im.mode, icc_profile, - exif + exif, + xmp ) if data is None: raise IOError("cannot write file as WEBP (encoder returned None)") @@ -285,6 +296,7 @@ def _save(im, fp, filename): Image.register_open(WebPImageFile.format, WebPImageFile, _accept) Image.register_save(WebPImageFile.format, _save) -Image.register_save_all(WebPImageFile.format, _save_all) +if _webp.HAVE_WEBPMUX: + Image.register_save_all(WebPImageFile.format, _save_all) Image.register_extension(WebPImageFile.format, ".webp") Image.register_mime(WebPImageFile.format, "image/webp") diff --git a/Tests/images/anim_frame1.webp b/Tests/images/anim_frame1.webp new file mode 100644 index 0000000000000000000000000000000000000000..74e1592bd94c4a1e3381074db00e2f7d36517b67 GIT binary patch literal 302 zcmV+}0nz?aNk&E{0RRA3MM6+kP&gnO0RRB-2mqY{DpCMa06vjOpGzgAqamerSrD)i z31t9R4p6UoNQnSo1NQWn%ct$>CKlKR$DAzYrA1+9t`O4`q>H&SeSTOt?}OR9ZGWl8 z5F;P}{`vxd07G`(VA=e{e62#vLapH$0woF#6z}WKW1mhZo9xPYk9Rv^@92J?sII!# zF!bFX(yeq()wCZLv}gdUJJ#0)%*$xteLn}gxQ?u8u&`B+_?D?uLQlsrulfD2w74zf zJiqt+!}eAZfma`i&e44k!XH5Jtx16KF>h{S+@_nG;n$c-i^Y%lJO6cqLC!oNk&E(0RRA3MM6+kP&gnA0RRBd2mqY{DpCMa06vjMo=c^pqM@Ud3Ba%t z31t9N1^5c4Y@}Df8QBfXDhT)&3AK{vs324SNJbIy@Fle5MBXmAp`StTQ&}Lf%FbVb zUjP99`d$D5X^1wU{+VZq)`~Lsayn3jKe(xCjr)f8{-5!FJA~++&;4k^?Ty%ia%xZ` zd*l18v8gN+2apGJoh=;I1o2Gc=>B}#-R#C#m0>v mPCTu*lwolmjh4ba8!XRYwt8%XS&p8GsPo0JOCx){00004wTZs~ literal 0 HcmV?d00001 diff --git a/Tests/images/iss634.webp b/Tests/images/iss634.webp new file mode 100644 index 0000000000000000000000000000000000000000..5181da736e2500e9af7081d64b846f95d183bea3 GIT binary patch literal 207838 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%0D0k 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

;Fg&H_Ix_fu60VPrU_9oUBE7IVFo3CqlvtaK) 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±|uH+%;efBhZ?e8!;a`x`h-wf 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

DjXzoO&# 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 C5WC(0 literal 0 HcmV?d00001 diff --git a/Tests/images/transparent.gif b/Tests/images/transparent.gif new file mode 100644 index 0000000000000000000000000000000000000000..911e4ee34d9d2ebd6cb96b723e22e5dffe7610eb GIT binary patch literal 9678 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 EUj;9NdjJ3c literal 0 HcmV?d00001 diff --git a/Tests/test_file_webp.py b/Tests/test_file_webp.py index 6c16882fd..0997011ff 100644 --- a/Tests/test_file_webp.py +++ b/Tests/test_file_webp.py @@ -22,6 +22,10 @@ class TestFileWebp(PillowTestCase): _webp.WebPDecoderBuggyAlpha() def test_read_rgb(self): + """ + Can we read a RGB mode webp file without error. + Does it have the bits we expect? + """ file_path = "Tests/images/hopper.webp" image = Image.open(file_path) @@ -46,9 +50,7 @@ class TestFileWebp(PillowTestCase): temp_file = self.tempfile("temp.webp") hopper("RGB").save(temp_file) - image = Image.open(temp_file) - image.load() self.assertEqual(image.mode, "RGB") self.assertEqual(image.size, (128, 128)) @@ -70,19 +72,66 @@ class TestFileWebp(PillowTestCase): # the image. The old lena images for WebP are showing ~16 on # Ubuntu, the jpegs are showing ~18. target = hopper("RGB") - self.assert_image_similar(image, target, 12) + self.assert_image_similar(image, target, 12.0) + + def test_write_unsupported_mode_L(self): + """ + Saving a black-and-white file to webp format should work, and be + similar to the original file. + """ - def test_write_unsupported_mode(self): temp_file = self.tempfile("temp.webp") + hopper("L").save(temp_file) + image = Image.open(temp_file) - im = hopper("L") - self.assertRaises(IOError, im.save, temp_file) + self.assertEqual(image.mode, "RGB") + self.assertEqual(image.size, (128, 128)) + self.assertEqual(image.format, "WEBP") + + image.load() + image.getdata() + target = hopper("L").convert("RGB") + + self.assert_image_similar(image, target, 10.0) + + def test_write_unsupported_mode_P(self): + """ + Saving a palette-based file to webp format should work, and be + similar to the original file. + """ + + temp_file = self.tempfile("temp.webp") + hopper("P").save(temp_file) + image = Image.open(temp_file) + + self.assertEqual(image.mode, "RGB") + self.assertEqual(image.size, (128, 128)) + self.assertEqual(image.format, "WEBP") + + image.load() + image.getdata() + target = hopper("P").convert("RGB") + + self.assert_image_similar(image, target, 50.0) def test_WebPEncode_with_invalid_args(self): + """ + Calling encoder functions with no arguments should result in an error. + """ + + if _webp.HAVE_WEBPMUX: + self.assertRaises(TypeError, _webp.WebPAnimEncoder) self.assertRaises(TypeError, _webp.WebPEncode) def test_WebPDecode_with_invalid_args(self): + """ + Calling decoder functions with no arguments should result in an error. + """ + + if _webp.HAVE_WEBPMUX: + self.assertRaises(TypeError, _webp.WebPAnimDecoder) self.assertRaises(TypeError, _webp.WebPDecode) + if __name__ == '__main__': unittest.main() diff --git a/Tests/test_file_webp_alpha.py b/Tests/test_file_webp_alpha.py index 70a4d7354..9ac68c6c1 100644 --- a/Tests/test_file_webp_alpha.py +++ b/Tests/test_file_webp_alpha.py @@ -22,6 +22,11 @@ class TestFileWebpAlpha(PillowTestCase): "not testing transparency") def test_read_rgba(self): + """ + Can we read a RGBA mode file without error. + Does it have the bits we expect? + """ + # Generated with `cwebp transparent.png -o transparent.webp` file_path = "Tests/images/transparent.webp" image = Image.open(file_path) @@ -38,6 +43,11 @@ class TestFileWebpAlpha(PillowTestCase): self.assert_image_similar(image, target, 20.0) def test_write_lossless_rgb(self): + """ + Can we write a RGBA mode file with lossless compression without error. + Does it have the bits we expect? + """ + temp_file = self.tempfile("temp.webp") # temp_file = "temp.webp" @@ -90,6 +100,27 @@ class TestFileWebpAlpha(PillowTestCase): else: self.assert_image_similar(image, pil_image, 1.0) + def test_write_unsupported_mode_PA(self): + """ + Saving a palette-based file with transparency to webp format + should work, and be similar to the original file. + """ + + temp_file = self.tempfile("temp.webp") + file_path = "Tests/images/transparent.gif" + Image.open(file_path).save(temp_file) + image = Image.open(temp_file) + + self.assertEqual(image.mode, "RGBA") + self.assertEqual(image.size, (200, 150)) + self.assertEqual(image.format, "WEBP") + + image.load() + image.getdata() + target = Image.open(file_path).convert("RGBA") + + self.assert_image_similar(image, target, 10.0) + if __name__ == '__main__': unittest.main() diff --git a/Tests/test_file_webp_animated.py b/Tests/test_file_webp_animated.py new file mode 100644 index 000000000..1aaceed04 --- /dev/null +++ b/Tests/test_file_webp_animated.py @@ -0,0 +1,120 @@ +from helper import unittest, PillowTestCase, hopper + +from PIL import Image + +try: + from PIL import _webp +except ImportError: + pass + # Skip in setUp() + + +class TestFileWebpAnimation(PillowTestCase): + + def setUp(self): + try: + from PIL import _webp + except ImportError: + self.skipTest('WebP support not installed') + + if not _webp.HAVE_WEBPMUX: + self.skipTest("WebP not compiled with mux support, " + "not testing animation") + + def test_n_frames(self): + """ + Ensure that webp format sets n_frames and is_animated + attributes correctly. + """ + + im = Image.open("Tests/images/hopper.webp") + self.assertEqual(im.n_frames, 1) + self.assertFalse(im.is_animated) + + im = Image.open("Tests/images/iss634.webp") + self.assertEqual(im.n_frames, 42) + self.assertTrue(im.is_animated) + + def test_write_animation(self): + """ + Convert an animated GIF to animated WebP, then compare the + frame count, and first and last frames to ensure they're + visually similar. + """ + + orig = Image.open("Tests/images/iss634.gif") + self.assertGreater(orig.n_frames, 1) + + temp_file = self.tempfile("temp.webp") + orig.save(temp_file, save_all=True) + im = Image.open(temp_file) + self.assertEqual(im.n_frames, orig.n_frames) + + # Compare first and last frames to the original animated GIF + orig.load() + im.load() + self.assert_image_similar(im, orig.convert("RGBA"), 25.0) + orig.seek(orig.n_frames-1) + im.seek(im.n_frames-1) + orig.load() + im.load() + self.assert_image_similar(im, orig.convert("RGBA"), 25.0) + + def test_timestamp_and_duration(self): + """ + Try passing a list of durations, and make sure the encoded + timestamps and durations are correct. + """ + + durations = [0, 10, 20, 30, 40] + temp_file = self.tempfile("temp.webp") + frame1 = Image.open('Tests/images/anim_frame1.webp') + frame2 = Image.open('Tests/images/anim_frame2.webp') + frame1.save(temp_file, save_all=True, + append_images=[frame2, frame1, frame2, frame1], + duration=durations) + + im = Image.open(temp_file) + self.assertEqual(im.n_frames, 5) + self.assertTrue(im.is_animated) + + # Double-check that timestamps and durations match original values specified + ts = 0 + for frame in range(im.n_frames): + im.seek(frame) + im.load() + self.assertEqual(im.info["duration"], durations[frame]) + self.assertEqual(im.info["timestamp"], ts) + ts += durations[frame] + + def test_seeking(self): + """ + Create an animated webp file, and then try seeking through + frames in reverse-order, verifying the timestamps and durations + are correct. + """ + + dur = 33 + temp_file = self.tempfile("temp.webp") + frame1 = Image.open('Tests/images/anim_frame1.webp') + frame2 = Image.open('Tests/images/anim_frame2.webp') + frame1.save(temp_file, save_all=True, + append_images=[frame2, frame1, frame2, frame1], + duration=dur) + + im = Image.open(temp_file) + self.assertEqual(im.n_frames, 5) + self.assertTrue(im.is_animated) + + # Traverse frames in reverse order, double-check timestamps and duration + ts = dur * (im.n_frames-1) + for frame in reversed(range(im.n_frames)): + im.seek(frame) + im.load() + self.assertEqual(im.info["duration"], dur) + self.assertEqual(im.info["timestamp"], ts) + ts -= dur + + +if __name__ == '__main__': + unittest.main() diff --git a/Tests/test_file_webp_metadata.py b/Tests/test_file_webp_metadata.py index 88e2b3b88..0360ec67e 100644 --- a/Tests/test_file_webp_metadata.py +++ b/Tests/test_file_webp_metadata.py @@ -107,6 +107,26 @@ class TestFileWebpMetadata(PillowTestCase): self.assertFalse(webp_image._getexif()) + def test_write_animated_metadata(self): + iccp_data = "" + exif_data = "" + xmp_data = "" + + temp_file = self.tempfile("temp.webp") + frame1 = Image.open('Tests/images/anim_frame1.webp') + frame2 = Image.open('Tests/images/anim_frame2.webp') + frame1.save(temp_file, save_all=True, + append_images=[frame2, frame1, frame2], + icc_profile=iccp_data, exif=exif_data, xmp=xmp_data) + + image = Image.open(temp_file) + self.assertIn('icc_profile', image.info) + self.assertIn('exif', image.info) + self.assertIn('xmp', image.info) + self.assertEqual(iccp_data, image.info.get('icc_profile', None)) + self.assertEqual(exif_data, image.info.get('exif', None)) + self.assertEqual(xmp_data, image.info.get('xmp', None)) + if __name__ == '__main__': unittest.main() diff --git a/_webp.c b/_webp.c index 8a54c6935..a6002e99c 100644 --- a/_webp.c +++ b/_webp.c @@ -10,6 +10,20 @@ #include #include +/* -------------------------------------------------------------------- */ +/* WebP Muxer Error Codes */ +/* -------------------------------------------------------------------- */ + +static const char* const kErrorMessages[-WEBP_MUX_NOT_ENOUGH_DATA + 1] = { + "WEBP_MUX_NOT_FOUND", "WEBP_MUX_INVALID_ARGUMENT", "WEBP_MUX_BAD_DATA", + "WEBP_MUX_MEMORY_ERROR", "WEBP_MUX_NOT_ENOUGH_DATA" + }; + + static const char* ErrorString(WebPMuxError err) { + assert(err <= WEBP_MUX_NOT_FOUND && err >= WEBP_MUX_NOT_ENOUGH_DATA); + return kErrorMessages[-err]; + } + /* -------------------------------------------------------------------- */ /* WebP Animation Support */ /* -------------------------------------------------------------------- */ @@ -29,6 +43,7 @@ typedef struct { WebPAnimDecoder* dec; WebPAnimInfo info; WebPData data; + char *mode; } WebPAnimDecoderObject; static PyTypeObject WebPAnimDecoder_Type; @@ -80,6 +95,7 @@ PyObject* _anim_encoder_new(PyObject* self, PyObject* args) encp->enc = enc; return (PyObject*) encp; } + WebPPictureFree(&(encp->frame)); } PyObject_Del(encp); } @@ -162,11 +178,13 @@ PyObject* _anim_encoder_assemble(PyObject* self, PyObject* args) { uint8_t *icc_bytes; uint8_t *exif_bytes; + uint8_t *xmp_bytes; Py_ssize_t icc_size; - Py_ssize_t exif_size; + Py_ssize_t exif_size; + Py_ssize_t xmp_size; - if (!PyArg_ParseTuple(args, "s#s#", - &icc_bytes, &icc_size, &exif_bytes, &exif_size)) { + if (!PyArg_ParseTuple(args, "s#s#s#", + &icc_bytes, &icc_size, &exif_bytes, &exif_size, &xmp_bytes, &xmp_size)) { return NULL; } @@ -182,9 +200,67 @@ PyObject* _anim_encoder_assemble(PyObject* self, PyObject* args) Py_RETURN_NONE; } - // Convert to Python bytes and return + // Re-mux to add metadata as needed + WebPMux* mux = NULL; + if (icc_size > 0 || exif_size > 0 || xmp_size > 0) { + WebPMuxError err = WEBP_MUX_OK; + int i_icc_size = (int)icc_size; + int i_exif_size = (int)exif_size; + int i_xmp_size = (int)xmp_size; + WebPData icc_profile = { icc_bytes, i_icc_size }; + WebPData exif = { exif_bytes, i_exif_size }; + WebPData xmp = { xmp_bytes, i_xmp_size }; + + mux = WebPMuxCreate(&webp_data, 1); + if (mux == NULL) { + fprintf(stderr, "ERROR: Could not re-mux to add metadata.\n"); + Py_RETURN_NONE; + } + WebPDataClear(&webp_data); + + // Add ICCP chunk + if (i_icc_size > 0) { + err = WebPMuxSetChunk(mux, "ICCP", &icc_profile, 1); + if (err != WEBP_MUX_OK) { + fprintf(stderr, "ERROR (%s): Could not set ICC chunk.\n", ErrorString(err)); + Py_RETURN_NONE; + } + } + + // Add EXIF chunk + if (i_exif_size > 0) { + err = WebPMuxSetChunk(mux, "EXIF", &exif, 1); + if (err != WEBP_MUX_OK) { + fprintf(stderr, "ERROR (%s): Could not set EXIF chunk.\n", ErrorString(err)); + Py_RETURN_NONE; + } + } + + // Add XMP chunk + if (i_xmp_size > 0) { + err = WebPMuxSetChunk(mux, "XMP ", &xmp, 1); + if (err != WEBP_MUX_OK) { + fprintf(stderr, "ERROR (%s): Could not set XMP chunk.\n", ErrorString(err)); + Py_RETURN_NONE; + } + } + + err = WebPMuxAssemble(mux, &webp_data); + if (err != WEBP_MUX_OK) { + fprintf(stderr, "ERROR (%s): Could not assemble when re-muxing to add metadata.\n", ErrorString(err)); + Py_RETURN_NONE; + } + } + + // Convert to Python bytes PyObject *ret = PyBytes_FromStringAndSize((char*)webp_data.bytes, webp_data.size); WebPDataClear(&webp_data); + + // If we had to re-mux, we should free it now that we're done with it + if (mux != NULL) { + WebPMuxDelete(mux); + } + return ret; } @@ -201,10 +277,20 @@ PyObject* _anim_decoder_new(PyObject* self, PyObject* args) PyBytes_AsStringAndSize((PyObject *) webp_string, (char**)&webp, &size); WebPData webp_src = {webp, size}; + // Sniff the mode, since the decoder API doesn't tell us + WebPDecoderConfig config; + char* mode = "RGBA"; + if (WebPGetFeatures(webp, size, &config.input) == VP8_STATUS_OK) { + if (!config.input.has_alpha) { + mode = "RGB"; + } + } + // Create the decoder (default mode is RGBA, if no options passed) WebPAnimDecoderObject* decp; decp = PyObject_New(WebPAnimDecoderObject, &WebPAnimDecoder_Type); if (decp) { + decp->mode = mode; if (WebPDataCopy(&webp_src, &(decp->data))) { WebPAnimDecoder* dec = WebPAnimDecoderNew(&(decp->data), NULL); if (dec) { @@ -237,7 +323,7 @@ PyObject* _anim_decoder_get_info(PyObject* self, PyObject* args) info->loop_count, info->bgcolor, info->frame_count, - "RGBA" // WebPAnimDecoder defaults to RGBA if no mode is specified + decp->mode ); } @@ -275,8 +361,24 @@ PyObject* _anim_decoder_get_next(PyObject* self, PyObject* args) Py_RETURN_NONE; } - bytes = PyBytes_FromStringAndSize((char *)buf, - decp->info.canvas_width * 4 * decp->info.canvas_height); + // HACK: If original mode was RGB, we need to strip alpha before passing back, this + // is needed because internally WebPAnimDecoder doesn't suppor ta non-alpha mode + uint32_t size = decp->info.canvas_width * 4 * decp->info.canvas_height; + if (strcmp(decp->mode, "RGB")==0 && buf != NULL) { + uint32_t pixel_count = size / 4; + uint8_t* src = buf; + uint8_t* dst = buf; + for (uint32_t idx = 0; idx < pixel_count; ++idx) { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst += 3; + src += 4; + } + size = pixel_count * 3; + } + + bytes = PyBytes_FromStringAndSize((char *)buf, size); return Py_BuildValue("Si", bytes, timestamp); } @@ -386,7 +488,6 @@ static PyTypeObject WebPAnimDecoder_Type = { #endif -#ifdef HAVE_WEBPMUX /* -------------------------------------------------------------------- */ /* Legacy WebP Support */ /* -------------------------------------------------------------------- */ @@ -400,16 +501,18 @@ PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args) uint8_t *rgb; uint8_t *icc_bytes; uint8_t *exif_bytes; + uint8_t *xmp_bytes; uint8_t *output; char *mode; Py_ssize_t size; Py_ssize_t icc_size; - Py_ssize_t exif_size; + Py_ssize_t exif_size; + Py_ssize_t xmp_size; size_t ret_size; - if (!PyArg_ParseTuple(args, PY_ARG_BYTES_LENGTH"iiifss#s#", + if (!PyArg_ParseTuple(args, PY_ARG_BYTES_LENGTH"iiifss#s#s#", (char**)&rgb, &size, &width, &height, &lossless, &quality_factor, &mode, - &icc_bytes, &icc_size, &exif_bytes, &exif_size)) { + &icc_bytes, &icc_size, &exif_bytes, &exif_size, &xmp_bytes, &xmp_size)) { return NULL; } if (strcmp(mode, "RGBA")==0){ @@ -454,10 +557,12 @@ PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args) */ int i_icc_size = (int)icc_size; int i_exif_size = (int)exif_size; + int i_xmp_size = (int)xmp_size; WebPData output_data = {0}; WebPData image = { output, ret_size }; WebPData icc_profile = { icc_bytes, i_icc_size }; WebPData exif = { exif_bytes, i_exif_size }; + WebPData xmp = { xmp_bytes, i_xmp_size }; WebPMuxError err; int dbg = 0; @@ -499,6 +604,21 @@ PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args) } } + if (dbg) { + fprintf(stderr, "xmp size %d \n", i_xmp_size); + } + if (i_xmp_size > 0) { + if (dbg){ + fprintf (stderr, "Adding XMP Data\n"); + } + err = WebPMuxSetChunk(mux, "XMP ", &xmp, copy_data); + if (dbg && err == WEBP_MUX_INVALID_ARGUMENT) { + fprintf(stderr, "Invalid XMP Argument\n"); + } else if (dbg && err == WEBP_MUX_MEMORY_ERROR) { + fprintf(stderr, "XMP Memory Error\n"); + } + } + WebPMuxAssemble(mux, &output_data); WebPMuxDelete(mux); free(output); @@ -520,7 +640,7 @@ PyObject* WebPDecode_wrapper(PyObject* self, PyObject* args) PyBytesObject *webp_string; const uint8_t *webp; Py_ssize_t size; - PyObject *ret = Py_None, *bytes = NULL, *pymode = NULL, *icc_profile = NULL, *exif = NULL; + PyObject *ret = Py_None, *bytes = NULL, *pymode = NULL; WebPDecoderConfig config; VP8StatusCode vp8_status_code = VP8_STATUS_OK; char* mode = "RGB"; @@ -544,41 +664,7 @@ PyObject* WebPDecode_wrapper(PyObject* self, PyObject* args) mode = "RGBA"; } -#ifndef HAVE_WEBPMUX vp8_status_code = WebPDecode(webp, size, &config); -#else - { - int copy_data = 0; - WebPData data = { webp, size }; - WebPMuxFrameInfo image; - WebPData icc_profile_data = {0}; - WebPData exif_data = {0}; - - WebPMux* mux = WebPMuxCreate(&data, copy_data); - if (NULL == mux) - goto end; - - if (WEBP_MUX_OK != WebPMuxGetFrame(mux, 1, &image)) - { - WebPMuxDelete(mux); - goto end; - } - - webp = image.bitstream.bytes; - size = image.bitstream.size; - - vp8_status_code = WebPDecode(webp, size, &config); - - if (WEBP_MUX_OK == WebPMuxGetChunk(mux, "ICCP", &icc_profile_data)) - icc_profile = PyBytes_FromStringAndSize((const char*)icc_profile_data.bytes, icc_profile_data.size); - - if (WEBP_MUX_OK == WebPMuxGetChunk(mux, "EXIF", &exif_data)) - exif = PyBytes_FromStringAndSize((const char*)exif_data.bytes, exif_data.size); - - WebPDataClear(&image.bitstream); - WebPMuxDelete(mux); - } -#endif } if (vp8_status_code != VP8_STATUS_OK) @@ -599,18 +685,14 @@ PyObject* WebPDecode_wrapper(PyObject* self, PyObject* args) #else pymode = PyString_FromString(mode); #endif - ret = Py_BuildValue("SiiSSS", bytes, config.output.width, - config.output.height, pymode, - NULL == icc_profile ? Py_None : icc_profile, - NULL == exif ? Py_None : exif); + ret = Py_BuildValue("SiiS", bytes, config.output.width, + config.output.height, pymode); end: WebPFreeDecBuffer(&config.output); Py_XDECREF(bytes); Py_XDECREF(pymode); - Py_XDECREF(icc_profile); - Py_XDECREF(exif); if (Py_None == ret) Py_RETURN_NONE; @@ -618,8 +700,6 @@ end: return ret; } -#endif - // Return the decoder's version number, packed in hexadecimal using 8bits for // each of major/minor/revision. E.g: v2.5.7 is 0x020507. PyObject* WebPDecoderVersion_wrapper(PyObject* self, PyObject* args){ @@ -647,10 +727,9 @@ static PyMethodDef webpMethods[] = #ifdef HAVE_WEBPMUX {"WebPAnimDecoder", _anim_decoder_new, METH_VARARGS, "WebPAnimDecoder"}, {"WebPAnimEncoder", _anim_encoder_new, METH_VARARGS, "WebPAnimEncoder"}, -#else +#endif {"WebPEncode", WebPEncode_wrapper, METH_VARARGS, "WebPEncode"}, {"WebPDecode", WebPDecode_wrapper, METH_VARARGS, "WebPDecode"}, -#endif {"WebPDecoderVersion", WebPDecoderVersion_wrapper, METH_VARARGS, "WebPVersion"}, {"WebPDecoderBuggyAlpha", WebPDecoderBuggyAlpha_wrapper, METH_VARARGS, "WebPDecoderBuggyAlpha"}, {NULL, NULL} From 356da806862796e47491df043f8747d142ece6bd Mon Sep 17 00:00:00 2001 From: Jason Douglas Date: Tue, 26 Sep 2017 20:46:35 -0700 Subject: [PATCH 04/19] Fix metadata test for python3 --- Tests/test_file_webp_metadata.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/test_file_webp_metadata.py b/Tests/test_file_webp_metadata.py index 0360ec67e..f773b802f 100644 --- a/Tests/test_file_webp_metadata.py +++ b/Tests/test_file_webp_metadata.py @@ -108,9 +108,9 @@ class TestFileWebpMetadata(PillowTestCase): self.assertFalse(webp_image._getexif()) def test_write_animated_metadata(self): - iccp_data = "" - exif_data = "" - xmp_data = "" + iccp_data = ''.encode('utf-8') + exif_data = ''.encode('utf-8') + xmp_data = ''.encode('utf-8') temp_file = self.tempfile("temp.webp") frame1 = Image.open('Tests/images/anim_frame1.webp') From b46cf528838b8bd798608a8be7eef463ae82b113 Mon Sep 17 00:00:00 2001 From: Jason Douglas Date: Tue, 26 Sep 2017 21:45:25 -0700 Subject: [PATCH 05/19] Fix 'for' loop initial declaration error --- _webp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/_webp.c b/_webp.c index a6002e99c..fe825587d 100644 --- a/_webp.c +++ b/_webp.c @@ -368,7 +368,8 @@ PyObject* _anim_decoder_get_next(PyObject* self, PyObject* args) uint32_t pixel_count = size / 4; uint8_t* src = buf; uint8_t* dst = buf; - for (uint32_t idx = 0; idx < pixel_count; ++idx) { + uint32_t idx; + for (idx = 0; idx < pixel_count; ++idx) { dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; From e534991409fa4c528a9ef18c2f450fb01f530de5 Mon Sep 17 00:00:00 2001 From: Jason Douglas Date: Wed, 27 Sep 2017 17:10:25 -0700 Subject: [PATCH 06/19] - Styling changes to be C89-conformant - Change WebPAnimEncoder/Decoder to use RGBX mode instead of RGB (since internally it is using RGBA always) --- PIL/WebPImagePlugin.py | 9 ++- Tests/test_file_webp.py | 18 ++--- Tests/test_file_webp_lossless.py | 6 +- _webp.c | 125 ++++++++++++++----------------- 4 files changed, 76 insertions(+), 82 deletions(-) diff --git a/PIL/WebPImagePlugin.py b/PIL/WebPImagePlugin.py index 886648a7f..1472d67f7 100644 --- a/PIL/WebPImagePlugin.py +++ b/PIL/WebPImagePlugin.py @@ -3,6 +3,11 @@ from io import BytesIO _VALID_WEBP_MODES = { + "RGBX": True, + "RGBA": True, + } + +_VALID_WEBP_LEGACY_MODES = { "RGB": True, "RGBA": True, } @@ -232,7 +237,7 @@ def _save_all(im, fp, filename): frame = ims if not ims.mode in _VALID_WEBP_MODES: alpha = ims.mode == 'P' and 'A' in ims.im.getpalettemode() - frame = ims.convert('RGBA' if alpha else 'RGB') + frame = ims.convert('RGBA' if alpha else 'RGBX') # Append the frame to the animation encoder enc.add( @@ -273,7 +278,7 @@ def _save(im, fp, filename): exif = im.encoderinfo.get("exif", "") xmp = im.encoderinfo.get("xmp", "") - if im.mode not in _VALID_WEBP_MODES: + if im.mode not in _VALID_WEBP_LEGACY_MODES: alpha = im.mode == 'P' and 'A' in im.im.getpalettemode() im = im.convert('RGBA' if alpha else 'RGB') diff --git a/Tests/test_file_webp.py b/Tests/test_file_webp.py index 0997011ff..63ef06b9a 100644 --- a/Tests/test_file_webp.py +++ b/Tests/test_file_webp.py @@ -30,7 +30,7 @@ class TestFileWebp(PillowTestCase): file_path = "Tests/images/hopper.webp" image = Image.open(file_path) - self.assertEqual(image.mode, "RGB") + self.assertEqual(image.mode, "RGBX") self.assertEqual(image.size, (128, 128)) self.assertEqual(image.format, "WEBP") image.load() @@ -38,7 +38,7 @@ class TestFileWebp(PillowTestCase): # generated with: # dwebp -ppm ../../Tests/images/hopper.webp -o hopper_webp_bits.ppm - target = Image.open('Tests/images/hopper_webp_bits.ppm') + target = Image.open('Tests/images/hopper_webp_bits.ppm').convert("RGBX") self.assert_image_similar(image, target, 20.0) def test_write_rgb(self): @@ -49,10 +49,10 @@ class TestFileWebp(PillowTestCase): temp_file = self.tempfile("temp.webp") - hopper("RGB").save(temp_file) + hopper("RGBX").save(temp_file) image = Image.open(temp_file) - self.assertEqual(image.mode, "RGB") + self.assertEqual(image.mode, "RGBX") self.assertEqual(image.size, (128, 128)) self.assertEqual(image.format, "WEBP") image.load() @@ -71,7 +71,7 @@ class TestFileWebp(PillowTestCase): # then we're going to accept that it's a reasonable lossy version of # the image. The old lena images for WebP are showing ~16 on # Ubuntu, the jpegs are showing ~18. - target = hopper("RGB") + target = hopper("RGBX") self.assert_image_similar(image, target, 12.0) def test_write_unsupported_mode_L(self): @@ -84,13 +84,13 @@ class TestFileWebp(PillowTestCase): hopper("L").save(temp_file) image = Image.open(temp_file) - self.assertEqual(image.mode, "RGB") + self.assertEqual(image.mode, "RGBX") self.assertEqual(image.size, (128, 128)) self.assertEqual(image.format, "WEBP") image.load() image.getdata() - target = hopper("L").convert("RGB") + target = hopper("L").convert("RGBX") self.assert_image_similar(image, target, 10.0) @@ -104,13 +104,13 @@ class TestFileWebp(PillowTestCase): hopper("P").save(temp_file) image = Image.open(temp_file) - self.assertEqual(image.mode, "RGB") + self.assertEqual(image.mode, "RGBX") self.assertEqual(image.size, (128, 128)) self.assertEqual(image.format, "WEBP") image.load() image.getdata() - target = hopper("P").convert("RGB") + target = hopper("P").convert("RGBX") self.assert_image_similar(image, target, 50.0) diff --git a/Tests/test_file_webp_lossless.py b/Tests/test_file_webp_lossless.py index f653eb8b4..d0a94cb39 100644 --- a/Tests/test_file_webp_lossless.py +++ b/Tests/test_file_webp_lossless.py @@ -23,18 +23,18 @@ class TestFileWebpLossless(PillowTestCase): def test_write_lossless_rgb(self): temp_file = self.tempfile("temp.webp") - hopper("RGB").save(temp_file, lossless=True) + hopper("RGBX").save(temp_file, lossless=True) image = Image.open(temp_file) image.load() - self.assertEqual(image.mode, "RGB") + self.assertEqual(image.mode, "RGBX") self.assertEqual(image.size, (128, 128)) self.assertEqual(image.format, "WEBP") image.load() image.getdata() - self.assert_image_equal(image, hopper("RGB")) + self.assert_image_equal(image, hopper("RGBX")) if __name__ == '__main__': diff --git a/_webp.c b/_webp.c index fe825587d..10b8b3601 100644 --- a/_webp.c +++ b/_webp.c @@ -43,7 +43,7 @@ typedef struct { WebPAnimDecoder* dec; WebPAnimInfo info; WebPData data; - char *mode; + char* mode; } WebPAnimDecoderObject; static PyTypeObject WebPAnimDecoder_Type; @@ -58,6 +58,9 @@ PyObject* _anim_encoder_new(PyObject* self, PyObject* args) int kmin, kmax; int allow_mixed; int verbose; + WebPAnimEncoderOptions enc_options; + WebPAnimEncoderObject* encp = NULL; + WebPAnimEncoder* enc = NULL; if (!PyArg_ParseTuple(args, "iiIiiiiii", &width, &height, &bgcolor, &loop_count, &minimize_size, @@ -66,7 +69,6 @@ PyObject* _anim_encoder_new(PyObject* self, PyObject* args) } // Setup and configure the encoder's options (these are animation-specific) - WebPAnimEncoderOptions enc_options; if (!WebPAnimEncoderOptionsInit(&enc_options)) { fprintf(stderr, "Error! Failed to initialize encoder options\n"); Py_RETURN_NONE; @@ -86,11 +88,10 @@ PyObject* _anim_encoder_new(PyObject* self, PyObject* args) } // Create a new animation encoder and picture frame - WebPAnimEncoderObject* encp; encp = PyObject_New(WebPAnimEncoderObject, &WebPAnimEncoder_Type); if (encp) { if (WebPPictureInit(&(encp->frame))) { - WebPAnimEncoder* enc = WebPAnimEncoderNew(width, height, &enc_options); + enc = WebPAnimEncoderNew(width, height, &enc_options); if (enc) { encp->enc = enc; return (PyObject*) encp; @@ -105,7 +106,7 @@ PyObject* _anim_encoder_new(PyObject* self, PyObject* args) PyObject* _anim_encoder_dealloc(PyObject* self) { - WebPAnimEncoderObject* encp = (WebPAnimEncoderObject *)self; + WebPAnimEncoderObject* encp = (WebPAnimEncoderObject*)self; WebPPictureFree(&(encp->frame)); WebPAnimEncoderDelete(encp->enc); Py_RETURN_NONE; @@ -113,15 +114,18 @@ PyObject* _anim_encoder_dealloc(PyObject* self) PyObject* _anim_encoder_add(PyObject* self, PyObject* args) { - uint8_t *rgb; + uint8_t* rgb; Py_ssize_t size; int timestamp; int width; int height; - char *mode; + char* mode; int lossless; float quality_factor; int method; + WebPAnimEncoderObject* encp = (WebPAnimEncoderObject*)self; + WebPAnimEncoder* enc = encp->enc; + WebPPicture* frame = &(encp->frame); if (!PyArg_ParseTuple(args, "z#iiisifi", (char**)&rgb, &size, ×tamp, &width, &height, &mode, @@ -129,10 +133,6 @@ PyObject* _anim_encoder_add(PyObject* self, PyObject* args) return NULL; } - WebPAnimEncoderObject* encp = (WebPAnimEncoderObject *)self; - WebPAnimEncoder* enc = encp->enc; - WebPPicture* frame = &(encp->frame); - // Check for NULL frame, which sets duration of final frame if (!rgb) { WebPAnimEncoderAdd(enc, NULL, timestamp, NULL); @@ -161,8 +161,8 @@ PyObject* _anim_encoder_add(PyObject* self, PyObject* args) frame->use_argb = 1; // Don't convert RGB pixels to YUV if (strcmp(mode, "RGBA")==0) { WebPPictureImportRGBA(frame, rgb, 4 * width); - } else if (strcmp(mode, "RGB")==0) { - WebPPictureImportRGB(frame, rgb, 3 * width); + } else if (strcmp(mode, "RGBX")==0) { + WebPPictureImportRGBX(frame, rgb, 3 * width); } // Add the frame to the encoder @@ -176,12 +176,16 @@ PyObject* _anim_encoder_add(PyObject* self, PyObject* args) PyObject* _anim_encoder_assemble(PyObject* self, PyObject* args) { - uint8_t *icc_bytes; - uint8_t *exif_bytes; - uint8_t *xmp_bytes; + uint8_t* icc_bytes; + uint8_t* exif_bytes; + uint8_t* xmp_bytes; Py_ssize_t icc_size; Py_ssize_t exif_size; Py_ssize_t xmp_size; + WebPAnimEncoderObject* encp = (WebPAnimEncoderObject*)self; + WebPAnimEncoder* enc = encp->enc; + WebPMux* mux = NULL; + PyObject* ret = NULL; if (!PyArg_ParseTuple(args, "s#s#s#", &icc_bytes, &icc_size, &exif_bytes, &exif_size, &xmp_bytes, &xmp_size)) { @@ -193,15 +197,12 @@ PyObject* _anim_encoder_assemble(PyObject* self, PyObject* args) WebPDataInit(&webp_data); // Assemble everything into the output buffer - WebPAnimEncoderObject* encp = (WebPAnimEncoderObject *)self; - WebPAnimEncoder* enc = encp->enc; if (!WebPAnimEncoderAssemble(enc, &webp_data)) { fprintf(stderr, "%s\n", WebPAnimEncoderGetError(enc)); Py_RETURN_NONE; } // Re-mux to add metadata as needed - WebPMux* mux = NULL; if (icc_size > 0 || exif_size > 0 || xmp_size > 0) { WebPMuxError err = WEBP_MUX_OK; int i_icc_size = (int)icc_size; @@ -253,7 +254,7 @@ PyObject* _anim_encoder_assemble(PyObject* self, PyObject* args) } // Convert to Python bytes - PyObject *ret = PyBytes_FromStringAndSize((char*)webp_data.bytes, webp_data.size); + ret = PyBytes_FromStringAndSize((char*)webp_data.bytes, webp_data.size); WebPDataClear(&webp_data); // If we had to re-mux, we should free it now that we're done with it @@ -270,33 +271,36 @@ PyObject* _anim_decoder_new(PyObject* self, PyObject* args) PyBytesObject *webp_string; const uint8_t *webp; Py_ssize_t size; + WebPData webp_src; + WebPDecoderConfig config; + WebPAnimDecoderObject* decp = NULL; + WebPAnimDecoder* dec = NULL; if (!PyArg_ParseTuple(args, "S", &webp_string)) { return NULL; } PyBytes_AsStringAndSize((PyObject *) webp_string, (char**)&webp, &size); - WebPData webp_src = {webp, size}; + webp_src.bytes = webp; + webp_src.size = size; // Sniff the mode, since the decoder API doesn't tell us - WebPDecoderConfig config; char* mode = "RGBA"; if (WebPGetFeatures(webp, size, &config.input) == VP8_STATUS_OK) { if (!config.input.has_alpha) { - mode = "RGB"; + mode = "RGBX"; } } // Create the decoder (default mode is RGBA, if no options passed) - WebPAnimDecoderObject* decp; decp = PyObject_New(WebPAnimDecoderObject, &WebPAnimDecoder_Type); if (decp) { decp->mode = mode; if (WebPDataCopy(&webp_src, &(decp->data))) { - WebPAnimDecoder* dec = WebPAnimDecoderNew(&(decp->data), NULL); + dec = WebPAnimDecoderNew(&(decp->data), NULL); if (dec) { if (WebPAnimDecoderGetInfo(dec, &(decp->info))) { decp->dec = dec; - return (PyObject*) decp; + return (PyObject*)decp; } } } @@ -318,6 +322,7 @@ PyObject* _anim_decoder_get_info(PyObject* self, PyObject* args) { WebPAnimDecoderObject* decp = (WebPAnimDecoderObject *)self; WebPAnimInfo* info = &(decp->info); + return Py_BuildValue("IIIIIs", info->canvas_width, info->canvas_height, info->loop_count, @@ -329,16 +334,17 @@ PyObject* _anim_decoder_get_info(PyObject* self, PyObject* args) PyObject* _anim_decoder_get_chunk(PyObject* self, PyObject* args) { - char *mode; - PyObject *ret; + char* mode; + WebPAnimDecoderObject* decp = (WebPAnimDecoderObject *)self; + const WebPDemuxer* demux; WebPChunkIterator iter; + PyObject *ret; if (!PyArg_ParseTuple(args, "s", &mode)) { return NULL; } - WebPAnimDecoderObject* decp = (WebPAnimDecoderObject *)self; - const WebPDemuxer* demux = WebPAnimDecoderGetDemuxer(decp->dec); + demux = WebPAnimDecoderGetDemuxer(decp->dec); if (!WebPDemuxGetChunk(demux, mode, 1, &iter)) { Py_RETURN_NONE; } @@ -353,39 +359,22 @@ PyObject* _anim_decoder_get_next(PyObject* self, PyObject* args) { uint8_t* buf; int timestamp; - PyObject *bytes; + PyObject* bytes; + WebPAnimDecoderObject* decp = (WebPAnimDecoderObject*)self; - WebPAnimDecoderObject* decp = (WebPAnimDecoderObject *)self; if (!WebPAnimDecoderGetNext(decp->dec, &buf, ×tamp)) { fprintf(stderr, "Error! Failed to read next frame.\n"); Py_RETURN_NONE; } - // HACK: If original mode was RGB, we need to strip alpha before passing back, this - // is needed because internally WebPAnimDecoder doesn't suppor ta non-alpha mode - uint32_t size = decp->info.canvas_width * 4 * decp->info.canvas_height; - if (strcmp(decp->mode, "RGB")==0 && buf != NULL) { - uint32_t pixel_count = size / 4; - uint8_t* src = buf; - uint8_t* dst = buf; - uint32_t idx; - for (idx = 0; idx < pixel_count; ++idx) { - dst[0] = src[0]; - dst[1] = src[1]; - dst[2] = src[2]; - dst += 3; - src += 4; - } - size = pixel_count * 3; - } - - bytes = PyBytes_FromStringAndSize((char *)buf, size); + bytes = PyBytes_FromStringAndSize((char *)buf, + decp->info.canvas_width * 4 * decp->info.canvas_height); return Py_BuildValue("Si", bytes, timestamp); } PyObject* _anim_decoder_has_more_frames(PyObject* self, PyObject* args) { - WebPAnimDecoderObject* decp = (WebPAnimDecoderObject *)self; + WebPAnimDecoderObject* decp = (WebPAnimDecoderObject*)self; return Py_BuildValue("i", WebPAnimDecoderHasMoreFrames(decp->dec)); } @@ -499,12 +488,12 @@ PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args) int height; int lossless; float quality_factor; - uint8_t *rgb; - uint8_t *icc_bytes; - uint8_t *exif_bytes; - uint8_t *xmp_bytes; - uint8_t *output; - char *mode; + uint8_t* rgb; + uint8_t* icc_bytes; + uint8_t* exif_bytes; + uint8_t* xmp_bytes; + uint8_t* output; + char* mode; Py_ssize_t size; Py_ssize_t icc_size; Py_ssize_t exif_size; @@ -522,11 +511,11 @@ PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args) } #if WEBP_ENCODER_ABI_VERSION >= 0x0100 if (lossless) { - ret_size = WebPEncodeLosslessRGBA(rgb, width, height, 4* width, &output); + ret_size = WebPEncodeLosslessRGBA(rgb, width, height, 4 * width, &output); } else #endif { - ret_size = WebPEncodeRGBA(rgb, width, height, 4* width, quality_factor, &output); + ret_size = WebPEncodeRGBA(rgb, width, height, 4 * width, quality_factor, &output); } } else if (strcmp(mode, "RGB")==0){ if (size < width * height * 3){ @@ -534,11 +523,11 @@ PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args) } #if WEBP_ENCODER_ABI_VERSION >= 0x0100 if (lossless) { - ret_size = WebPEncodeLosslessRGB(rgb, width, height, 3* width, &output); + ret_size = WebPEncodeLosslessRGB(rgb, width, height, 3 * width, &output); } else #endif { - ret_size = WebPEncodeRGB(rgb, width, height, 3* width, quality_factor, &output); + ret_size = WebPEncodeRGB(rgb, width, height, 3 * width, quality_factor, &output); } } else { Py_RETURN_NONE; @@ -551,7 +540,7 @@ PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args) return ret; } #else - { + { /* I want to truncate the *_size items that get passed into webp data. Pypy2.1.0 had some issues where the Py_ssize_t items had data in the upper byte. (Not sure why, it shouldn't have been there) @@ -638,8 +627,8 @@ PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args) PyObject* WebPDecode_wrapper(PyObject* self, PyObject* args) { - PyBytesObject *webp_string; - const uint8_t *webp; + PyBytesObject* webp_string; + const uint8_t* webp; Py_ssize_t size; PyObject *ret = Py_None, *bytes = NULL, *pymode = NULL; WebPDecoderConfig config; @@ -654,7 +643,7 @@ PyObject* WebPDecode_wrapper(PyObject* self, PyObject* args) Py_RETURN_NONE; } - PyBytes_AsStringAndSize((PyObject *) webp_string, (char**)&webp, &size); + PyBytes_AsStringAndSize((PyObject*) webp_string, (char**)&webp, &size); vp8_status_code = WebPGetFeatures(webp, size, &config.input); if (vp8_status_code == VP8_STATUS_OK) { @@ -672,12 +661,12 @@ PyObject* WebPDecode_wrapper(PyObject* self, PyObject* args) goto end; if (config.output.colorspace < MODE_YUV) { - bytes = PyBytes_FromStringAndSize((char *)config.output.u.RGBA.rgba, + bytes = PyBytes_FromStringAndSize((char*)config.output.u.RGBA.rgba, config.output.u.RGBA.size); } else { // Skipping YUV for now. Need Test Images. // UNDONE -- unclear if we'll ever get here if we set mode_rgb* - bytes = PyBytes_FromStringAndSize((char *)config.output.u.YUVA.y, + bytes = PyBytes_FromStringAndSize((char*)config.output.u.YUVA.y, config.output.u.YUVA.y_size); } From c18d26b04b74e052ef6774c972da25d752818780 Mon Sep 17 00:00:00 2001 From: Jason Douglas Date: Wed, 27 Sep 2017 19:04:24 -0700 Subject: [PATCH 07/19] - Conditonally compile animation support, only if the mux.h and demux.h headers meet the ABI version requirements - Add WEBPMUX support back to WebPDecode_wrapper (to support older versions of libwebp that have mux support, but not animation) - Add HAVE_WEBPANIM flag, and use it appropriately - Update documentation / tests --- PIL/WebPImagePlugin.py | 14 +++--- PIL/features.py | 5 +- Tests/test_features.py | 5 ++ Tests/test_file_webp_animated.py | 4 +- Tests/test_file_webp_metadata.py | 14 ++++-- _webp.c | 71 +++++++++++++++++++++++++--- docs/handbook/image-file-formats.rst | 4 +- selftest.py | 3 +- 8 files changed, 96 insertions(+), 24 deletions(-) diff --git a/PIL/WebPImagePlugin.py b/PIL/WebPImagePlugin.py index 1472d67f7..9b15bf14f 100644 --- a/PIL/WebPImagePlugin.py +++ b/PIL/WebPImagePlugin.py @@ -33,7 +33,7 @@ class WebPImageFile(ImageFile.ImageFile): format_description = "WebP image" def _open(self): - if not _webp.HAVE_WEBPMUX: + if not _webp.HAVE_WEBPANIM: # Legacy mode data, width, height, self.mode = _webp.WebPDecode(self.fp.read()) self.size = width, height @@ -80,18 +80,18 @@ class WebPImageFile(ImageFile.ImageFile): @property def n_frames(self): - if not _webp.HAVE_WEBPMUX: + if not _webp.HAVE_WEBPANIM: return 1 return self._n_frames @property def is_animated(self): - if not _webp.HAVE_WEBPMUX: + if not _webp.HAVE_WEBPANIM: return False return self._n_frames > 1 def seek(self, frame): - if not _webp.HAVE_WEBPMUX: + if not _webp.HAVE_WEBPANIM: return super(WebPImageFile, self).seek(frame) # Perform some simple checks first @@ -141,7 +141,7 @@ class WebPImageFile(ImageFile.ImageFile): self._get_next() def load(self): - if _webp.HAVE_WEBPMUX: + if _webp.HAVE_WEBPANIM: if self.__loaded != self.__logical_frame: self._seek(self.__logical_frame) @@ -158,7 +158,7 @@ class WebPImageFile(ImageFile.ImageFile): return super(WebPImageFile, self).load() def tell(self): - if not _webp.HAVE_WEBPMUX: + if not _webp.HAVE_WEBPANIM: return super(WebPImageFile, self).tell() return self.__logical_frame @@ -301,7 +301,7 @@ def _save(im, fp, filename): Image.register_open(WebPImageFile.format, WebPImageFile, _accept) Image.register_save(WebPImageFile.format, _save) -if _webp.HAVE_WEBPMUX: +if _webp.HAVE_WEBPANIM: Image.register_save_all(WebPImageFile.format, _save_all) Image.register_extension(WebPImageFile.format, ".webp") Image.register_mime(WebPImageFile.format, "image/webp") diff --git a/PIL/features.py b/PIL/features.py index 60f4c10ca..9cbd523c9 100644 --- a/PIL/features.py +++ b/PIL/features.py @@ -43,6 +43,7 @@ def get_supported_codecs(): return [f for f in codecs if check_codec(f)] features = { + "webp_anim": ("PIL._webp", 'HAVE_WEBPANIM'), "webp_mux": ("PIL._webp", 'HAVE_WEBPMUX'), "transp_webp": ("PIL._webp", "HAVE_TRANSPARENCY"), "raqm": ("PIL._imagingft", "HAVE_RAQM") @@ -53,7 +54,7 @@ def check_feature(feature): raise ValueError("Unknown feature %s" % feature) module, flag = features[feature] - + try: imported_module = __import__(module, fromlist=['PIL']) return getattr(imported_module, flag) @@ -75,4 +76,4 @@ def get_supported(): ret.extend(get_supported_features()) ret.extend(get_supported_codecs()) return ret - + diff --git a/Tests/test_features.py b/Tests/test_features.py index cdabcad5e..54d668d2f 100644 --- a/Tests/test_features.py +++ b/Tests/test_features.py @@ -35,6 +35,11 @@ class TestFeatures(PillowTestCase): self.assertEqual(features.check('webp_mux'), _webp.HAVE_WEBPMUX) + @unittest.skipUnless(HAVE_WEBP, True) + def check_webp_anim(self): + self.assertEqual(features.check('webp_anim'), + _webp.HAVE_WEBPANIM) + def test_check_modules(self): for feature in features.modules: self.assertIn(features.check_module(feature), [True, False]) diff --git a/Tests/test_file_webp_animated.py b/Tests/test_file_webp_animated.py index 1aaceed04..16c6de129 100644 --- a/Tests/test_file_webp_animated.py +++ b/Tests/test_file_webp_animated.py @@ -17,8 +17,8 @@ class TestFileWebpAnimation(PillowTestCase): except ImportError: self.skipTest('WebP support not installed') - if not _webp.HAVE_WEBPMUX: - self.skipTest("WebP not compiled with mux support, " + if not _webp.HAVE_WEBPANIM: + self.skipTest("WebP library does not contain animation support, " "not testing animation") def test_n_frames(self): diff --git a/Tests/test_file_webp_metadata.py b/Tests/test_file_webp_metadata.py index f773b802f..cb45f45fa 100644 --- a/Tests/test_file_webp_metadata.py +++ b/Tests/test_file_webp_metadata.py @@ -2,17 +2,22 @@ from helper import unittest, PillowTestCase from PIL import Image +try: + from PIL import _webp + HAVE_WEBP = True + HAVE_WEBPMUX = _webp.HAVE_WEBPMUX + HAVE_WEBPANIM = _webp.HAVE_WEBPANIM +except ImportError: + HAVE_WEBP = False class TestFileWebpMetadata(PillowTestCase): def setUp(self): - try: - from PIL import _webp - except ImportError: + if not HAVE_WEBP: self.skipTest('WebP support not installed') return - if not _webp.HAVE_WEBPMUX: + if not HAVE_WEBPMUX: self.skipTest('WebPMux support not installed') def test_read_exif_metadata(self): @@ -107,6 +112,7 @@ class TestFileWebpMetadata(PillowTestCase): self.assertFalse(webp_image._getexif()) + @unittest.skipUnless(HAVE_WEBPANIM, 'WebP animation support not available') def test_write_animated_metadata(self): iccp_data = ''.encode('utf-8') exif_data = ''.encode('utf-8') diff --git a/_webp.c b/_webp.c index 10b8b3601..fe4049835 100644 --- a/_webp.c +++ b/_webp.c @@ -10,6 +10,19 @@ #include #include +/* + * Check the versions from mux.h and demux.h, to ensure the WebPAnimEncoder and + * WebPAnimDecoder API's are present (initial support was added in 0.5.0). The + * very early versions added had some significant differences, so we require + * later versions, before enabling animation support. + */ +#if WEBP_MUX_ABI_VERSION >= 0x0104 && WEBP_DEMUX_ABI_VERSION >= 0x0105 +#define HAVE_WEBPANIM +#endif +#endif + +#ifdef HAVE_WEBPANIM + /* -------------------------------------------------------------------- */ /* WebP Muxer Error Codes */ /* -------------------------------------------------------------------- */ @@ -624,13 +637,12 @@ PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args) Py_RETURN_NONE; } - PyObject* WebPDecode_wrapper(PyObject* self, PyObject* args) { PyBytesObject* webp_string; const uint8_t* webp; Py_ssize_t size; - PyObject *ret = Py_None, *bytes = NULL, *pymode = NULL; + PyObject *ret = Py_None, *bytes = NULL, *pymode = NULL, *icc_profile = NULL, *exif = NULL; WebPDecoderConfig config; VP8StatusCode vp8_status_code = VP8_STATUS_OK; char* mode = "RGB"; @@ -654,7 +666,41 @@ PyObject* WebPDecode_wrapper(PyObject* self, PyObject* args) mode = "RGBA"; } +#ifndef HAVE_WEBPMUX vp8_status_code = WebPDecode(webp, size, &config); +#else + { + int copy_data = 0; + WebPData data = { webp, size }; + WebPMuxFrameInfo image; + WebPData icc_profile_data = {0}; + WebPData exif_data = {0}; + + WebPMux* mux = WebPMuxCreate(&data, copy_data); + if (NULL == mux) + goto end; + + if (WEBP_MUX_OK != WebPMuxGetFrame(mux, 1, &image)) + { + WebPMuxDelete(mux); + goto end; + } + + webp = image.bitstream.bytes; + size = image.bitstream.size; + + vp8_status_code = WebPDecode(webp, size, &config); + + if (WEBP_MUX_OK == WebPMuxGetChunk(mux, "ICCP", &icc_profile_data)) + icc_profile = PyBytes_FromStringAndSize((const char*)icc_profile_data.bytes, icc_profile_data.size); + + if (WEBP_MUX_OK == WebPMuxGetChunk(mux, "EXIF", &exif_data)) + exif = PyBytes_FromStringAndSize((const char*)exif_data.bytes, exif_data.size); + + WebPDataClear(&image.bitstream); + WebPMuxDelete(mux); + } +#endif } if (vp8_status_code != VP8_STATUS_OK) @@ -675,14 +721,18 @@ PyObject* WebPDecode_wrapper(PyObject* self, PyObject* args) #else pymode = PyString_FromString(mode); #endif - ret = Py_BuildValue("SiiS", bytes, config.output.width, - config.output.height, pymode); + ret = Py_BuildValue("SiiSSS", bytes, config.output.width, + config.output.height, pymode, + NULL == icc_profile ? Py_None : icc_profile, + NULL == exif ? Py_None : exif); end: WebPFreeDecBuffer(&config.output); Py_XDECREF(bytes); Py_XDECREF(pymode); + Py_XDECREF(icc_profile); + Py_XDECREF(exif); if (Py_None == ret) Py_RETURN_NONE; @@ -714,7 +764,7 @@ PyObject* WebPDecoderBuggyAlpha_wrapper(PyObject* self, PyObject* args){ static PyMethodDef webpMethods[] = { -#ifdef HAVE_WEBPMUX +#ifdef HAVE_WEBPANIM {"WebPAnimDecoder", _anim_decoder_new, METH_VARARGS, "WebPAnimDecoder"}, {"WebPAnimEncoder", _anim_encoder_new, METH_VARARGS, "WebPAnimEncoder"}, #endif @@ -733,6 +783,14 @@ void addMuxFlagToModule(PyObject* m) { #endif } +void addAnimFlagToModule(PyObject* m) { +#ifdef HAVE_WEBPANIM + PyModule_AddObject(m, "HAVE_WEBPANIM", Py_True); +#else + PyModule_AddObject(m, "HAVE_WEBPANIM", Py_False); +#endif +} + void addTransparencyFlagToModule(PyObject* m) { PyModule_AddObject(m, "HAVE_TRANSPARENCY", PyBool_FromLong(!WebPDecoderBuggyAlpha())); @@ -740,9 +798,10 @@ void addTransparencyFlagToModule(PyObject* m) { static int setup_module(PyObject* m) { addMuxFlagToModule(m); + addAnimFlagToModule(m); addTransparencyFlagToModule(m); -#ifdef HAVE_WEBPMUX +#ifdef HAVE_WEBPANIM /* Ready object types */ if (PyType_Ready(&WebPAnimDecoder_Type) < 0 || PyType_Ready(&WebPAnimEncoder_Type) < 0) diff --git a/docs/handbook/image-file-formats.rst b/docs/handbook/image-file-formats.rst index 8528b24e1..d0b9453db 100644 --- a/docs/handbook/image-file-formats.rst +++ b/docs/handbook/image-file-formats.rst @@ -683,8 +683,8 @@ Saving sequences .. note:: Support for animated WebP files will only be enabled if the system webp - library was built with webpmux support. You can check webpmux support - at runtime by inspecting the `_webp.HAVE_WEBPMUX` module flag. + library is v0.5.0 or later. You can check webp animation support at + runtime by inspecting the `_webp.HAVE_WEBPANIM` module flag. When calling :py:meth:`~PIL.Image.Image.save`, the following options are available when the save_all argument is present and true. diff --git a/selftest.py b/selftest.py index 108e57fd2..324d23b45 100755 --- a/selftest.py +++ b/selftest.py @@ -178,8 +178,9 @@ if __name__ == "__main__": ("freetype2", "FREETYPE2"), ("littlecms2", "LITTLECMS2"), ("webp", "WEBP"), - ("transp_webp", "Transparent WEBP"), + ("transp_webp", "WEBP Transparency"), ("webp_mux", "WEBPMUX"), + ("webp_anim", "WEBP Animation"), ("jpg", "JPEG"), ("jpg_2000", "OPENJPEG (JPEG2000)"), ("zlib", "ZLIB (PNG/ZIP)"), From 80b96246c4d0f27221b2cac0b2c0fc8a025de430 Mon Sep 17 00:00:00 2001 From: Jason Douglas Date: Wed, 27 Sep 2017 19:28:43 -0700 Subject: [PATCH 08/19] Fix tests to support different output modes (RGB vs RGBX) --- PIL/WebPImagePlugin.py | 7 ++++++- Tests/test_file_webp.py | 31 ++++++++++++++++--------------- Tests/test_file_webp_animated.py | 10 ++++------ Tests/test_file_webp_lossless.py | 19 ++++++++++--------- Tests/test_file_webp_metadata.py | 6 ++---- 5 files changed, 38 insertions(+), 35 deletions(-) diff --git a/PIL/WebPImagePlugin.py b/PIL/WebPImagePlugin.py index 9b15bf14f..f23c793f8 100644 --- a/PIL/WebPImagePlugin.py +++ b/PIL/WebPImagePlugin.py @@ -35,7 +35,12 @@ class WebPImageFile(ImageFile.ImageFile): def _open(self): if not _webp.HAVE_WEBPANIM: # Legacy mode - data, width, height, self.mode = _webp.WebPDecode(self.fp.read()) + data, width, height, self.mode, icc_profile, exif = \ + _webp.WebPDecode(self.fp.read()) + if icc_profile: + self.info["icc_profile"] = icc_profile + if exif: + self.info["exif"] = exif self.size = width, height self.fp = BytesIO(data) self.tile = [("raw", (0, 0) + self.size, 0, self.mode)] diff --git a/Tests/test_file_webp.py b/Tests/test_file_webp.py index 63ef06b9a..1ae75d573 100644 --- a/Tests/test_file_webp.py +++ b/Tests/test_file_webp.py @@ -4,18 +4,19 @@ from PIL import Image try: from PIL import _webp + HAVE_WEBP = True except ImportError: - # Skip in setUp() - pass - + HAVE_WEBP = False class TestFileWebp(PillowTestCase): def setUp(self): - try: - from PIL import _webp - except ImportError: + if not HAVE_WEBP: self.skipTest('WebP support not installed') + return + + # WebPAnimDecoder only retuns RGBA or RGBX, never RGB + self.rgb_mode = "RGBX" if _webp.HAVE_WEBPANIM else "RGB" def test_version(self): _webp.WebPDecoderVersion() @@ -30,7 +31,7 @@ class TestFileWebp(PillowTestCase): file_path = "Tests/images/hopper.webp" image = Image.open(file_path) - self.assertEqual(image.mode, "RGBX") + self.assertEqual(image.mode, self.rgb_mode) self.assertEqual(image.size, (128, 128)) self.assertEqual(image.format, "WEBP") image.load() @@ -38,7 +39,7 @@ class TestFileWebp(PillowTestCase): # generated with: # dwebp -ppm ../../Tests/images/hopper.webp -o hopper_webp_bits.ppm - target = Image.open('Tests/images/hopper_webp_bits.ppm').convert("RGBX") + target = Image.open('Tests/images/hopper_webp_bits.ppm').convert(self.rgb_mode) self.assert_image_similar(image, target, 20.0) def test_write_rgb(self): @@ -49,10 +50,10 @@ class TestFileWebp(PillowTestCase): temp_file = self.tempfile("temp.webp") - hopper("RGBX").save(temp_file) + hopper(self.rgb_mode).save(temp_file) image = Image.open(temp_file) - self.assertEqual(image.mode, "RGBX") + self.assertEqual(image.mode, self.rgb_mode) self.assertEqual(image.size, (128, 128)) self.assertEqual(image.format, "WEBP") image.load() @@ -71,7 +72,7 @@ class TestFileWebp(PillowTestCase): # then we're going to accept that it's a reasonable lossy version of # the image. The old lena images for WebP are showing ~16 on # Ubuntu, the jpegs are showing ~18. - target = hopper("RGBX") + target = hopper(self.rgb_mode) self.assert_image_similar(image, target, 12.0) def test_write_unsupported_mode_L(self): @@ -84,13 +85,13 @@ class TestFileWebp(PillowTestCase): hopper("L").save(temp_file) image = Image.open(temp_file) - self.assertEqual(image.mode, "RGBX") + self.assertEqual(image.mode, self.rgb_mode) self.assertEqual(image.size, (128, 128)) self.assertEqual(image.format, "WEBP") image.load() image.getdata() - target = hopper("L").convert("RGBX") + target = hopper("L").convert(self.rgb_mode) self.assert_image_similar(image, target, 10.0) @@ -104,13 +105,13 @@ class TestFileWebp(PillowTestCase): hopper("P").save(temp_file) image = Image.open(temp_file) - self.assertEqual(image.mode, "RGBX") + self.assertEqual(image.mode, self.rgb_mode) self.assertEqual(image.size, (128, 128)) self.assertEqual(image.format, "WEBP") image.load() image.getdata() - target = hopper("P").convert("RGBX") + target = hopper("P").convert(self.rgb_mode) self.assert_image_similar(image, target, 50.0) diff --git a/Tests/test_file_webp_animated.py b/Tests/test_file_webp_animated.py index 16c6de129..02cf5a146 100644 --- a/Tests/test_file_webp_animated.py +++ b/Tests/test_file_webp_animated.py @@ -4,18 +4,16 @@ from PIL import Image try: from PIL import _webp + HAVE_WEBP = True except ImportError: - pass - # Skip in setUp() - + HAVE_WEBP = False class TestFileWebpAnimation(PillowTestCase): def setUp(self): - try: - from PIL import _webp - except ImportError: + if not HAVE_WEBP: self.skipTest('WebP support not installed') + return if not _webp.HAVE_WEBPANIM: self.skipTest("WebP library does not contain animation support, " diff --git a/Tests/test_file_webp_lossless.py b/Tests/test_file_webp_lossless.py index d0a94cb39..dfcbd869a 100644 --- a/Tests/test_file_webp_lossless.py +++ b/Tests/test_file_webp_lossless.py @@ -4,37 +4,38 @@ from PIL import Image try: from PIL import _webp + HAVE_WEBP = True except ImportError: - pass - # Skip in setUp() - + HAVE_WEBP = False class TestFileWebpLossless(PillowTestCase): def setUp(self): - try: - from PIL import _webp - except: + if not HAVE_WEBP: self.skipTest('WebP support not installed') + return if (_webp.WebPDecoderVersion() < 0x0200): self.skipTest('lossless not included') + # WebPAnimDecoder only retuns RGBA or RGBX, never RGB + self.rgb_mode = "RGBX" if _webp.HAVE_WEBPANIM else "RGB" + def test_write_lossless_rgb(self): temp_file = self.tempfile("temp.webp") - hopper("RGBX").save(temp_file, lossless=True) + hopper(self.rgb_mode).save(temp_file, lossless=True) image = Image.open(temp_file) image.load() - self.assertEqual(image.mode, "RGBX") + self.assertEqual(image.mode, self.rgb_mode) self.assertEqual(image.size, (128, 128)) self.assertEqual(image.format, "WEBP") image.load() image.getdata() - self.assert_image_equal(image, hopper("RGBX")) + self.assert_image_equal(image, hopper(self.rgb_mode)) if __name__ == '__main__': diff --git a/Tests/test_file_webp_metadata.py b/Tests/test_file_webp_metadata.py index cb45f45fa..805125357 100644 --- a/Tests/test_file_webp_metadata.py +++ b/Tests/test_file_webp_metadata.py @@ -5,8 +5,6 @@ from PIL import Image try: from PIL import _webp HAVE_WEBP = True - HAVE_WEBPMUX = _webp.HAVE_WEBPMUX - HAVE_WEBPANIM = _webp.HAVE_WEBPANIM except ImportError: HAVE_WEBP = False @@ -17,7 +15,7 @@ class TestFileWebpMetadata(PillowTestCase): self.skipTest('WebP support not installed') return - if not HAVE_WEBPMUX: + if not _webp.HAVE_WEBPMUX: self.skipTest('WebPMux support not installed') def test_read_exif_metadata(self): @@ -112,7 +110,7 @@ class TestFileWebpMetadata(PillowTestCase): self.assertFalse(webp_image._getexif()) - @unittest.skipUnless(HAVE_WEBPANIM, 'WebP animation support not available') + @unittest.skipUnless(_webp.HAVE_WEBPANIM, 'WebP animation support not available') def test_write_animated_metadata(self): iccp_data = ''.encode('utf-8') exif_data = ''.encode('utf-8') From 247c2f59a10fd4ff338fa011eab6a1267bf7bbd9 Mon Sep 17 00:00:00 2001 From: Jason Douglas Date: Wed, 27 Sep 2017 20:12:10 -0700 Subject: [PATCH 09/19] Use PyErr_* functions instead of fprintf for error handling in _webp.c --- _webp.c | 118 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 69 insertions(+), 49 deletions(-) diff --git a/_webp.c b/_webp.c index fe4049835..bea9dccd5 100644 --- a/_webp.c +++ b/_webp.c @@ -24,18 +24,48 @@ #ifdef HAVE_WEBPANIM /* -------------------------------------------------------------------- */ -/* WebP Muxer Error Codes */ +/* WebP Muxer Error Handling */ /* -------------------------------------------------------------------- */ static const char* const kErrorMessages[-WEBP_MUX_NOT_ENOUGH_DATA + 1] = { "WEBP_MUX_NOT_FOUND", "WEBP_MUX_INVALID_ARGUMENT", "WEBP_MUX_BAD_DATA", "WEBP_MUX_MEMORY_ERROR", "WEBP_MUX_NOT_ENOUGH_DATA" - }; +}; - static const char* ErrorString(WebPMuxError err) { +static PyObject* HandleMuxError(WebPMuxError err, char* chunk) { assert(err <= WEBP_MUX_NOT_FOUND && err >= WEBP_MUX_NOT_ENOUGH_DATA); - return kErrorMessages[-err]; - } + + // Check for a memory error first + if (err == WEBP_MUX_MEMORY_ERROR) { + return PyErr_NoMemory(); + } + + // Create the error message + char message[100]; + if (chunk == NULL) { + sprintf(message, "could not assemble chunks: %s", kErrorMessages[-err]); + } else { + sprintf(message, "could not set %.4s chunk: %s", chunk, kErrorMessages[-err]); + } + + // Set the proper error type + switch (err) { + case WEBP_MUX_NOT_FOUND: + case WEBP_MUX_INVALID_ARGUMENT: + PyErr_SetString(PyExc_ValueError, message); + break; + + case WEBP_MUX_BAD_DATA: + case WEBP_MUX_NOT_ENOUGH_DATA: + PyErr_SetString(PyExc_IOError, message); + break; + + default: + PyErr_SetString(PyExc_RuntimeError, message); + break; + } + return NULL; +} /* -------------------------------------------------------------------- */ /* WebP Animation Support */ @@ -83,8 +113,8 @@ PyObject* _anim_encoder_new(PyObject* self, PyObject* args) // Setup and configure the encoder's options (these are animation-specific) if (!WebPAnimEncoderOptionsInit(&enc_options)) { - fprintf(stderr, "Error! Failed to initialize encoder options\n"); - Py_RETURN_NONE; + PyErr_SetString(PyExc_RuntimeError, "failed to initialize encoder options"); + return NULL; } enc_options.anim_params.bgcolor = bgcolor; enc_options.anim_params.loop_count = loop_count; @@ -96,8 +126,8 @@ PyObject* _anim_encoder_new(PyObject* self, PyObject* args) // Validate canvas dimensions if (width <= 0 || height <= 0) { - fprintf(stderr, "Error! Invalid canvas dimensions: width=%d, height=%d\n", width, height); - Py_RETURN_NONE; + PyErr_SetString(PyExc_ValueError, "invalid canvas dimensions"); + return NULL; } // Create a new animation encoder and picture frame @@ -113,8 +143,8 @@ PyObject* _anim_encoder_new(PyObject* self, PyObject* args) } PyObject_Del(encp); } - fprintf(stderr, "Error! Could not create encoder object.\n"); - Py_RETURN_NONE; + PyErr_SetString(PyExc_RuntimeError, "could not create encoder object"); + return NULL; } PyObject* _anim_encoder_dealloc(PyObject* self) @@ -155,8 +185,8 @@ PyObject* _anim_encoder_add(PyObject* self, PyObject* args) // Setup config for this frame WebPConfig config; if (!WebPConfigInit(&config)) { - fprintf(stderr, "Error! Failed to initialize config!\n"); - Py_RETURN_NONE; + PyErr_SetString(PyExc_RuntimeError, "failed to initialize config!"); + return NULL; } config.lossless = lossless; config.quality = quality_factor; @@ -164,8 +194,8 @@ PyObject* _anim_encoder_add(PyObject* self, PyObject* args) // Validate the config if (!WebPValidateConfig(&config)) { - fprintf(stderr, "Error! Invalid configuration\n"); - Py_RETURN_NONE; + PyErr_SetString(PyExc_ValueError, "invalid configuration"); + return NULL; } // Populate the frame with raw bytes passed to us @@ -180,8 +210,8 @@ PyObject* _anim_encoder_add(PyObject* self, PyObject* args) // Add the frame to the encoder if (!WebPAnimEncoderAdd(enc, frame, timestamp, &config)) { - fprintf(stderr, "Error! Could not add frame: %s\n", WebPAnimEncoderGetError(enc)); - Py_RETURN_NONE; + PyErr_SetString(PyExc_RuntimeError, WebPAnimEncoderGetError(enc)); + return NULL; } Py_RETURN_NONE; @@ -211,8 +241,8 @@ PyObject* _anim_encoder_assemble(PyObject* self, PyObject* args) // Assemble everything into the output buffer if (!WebPAnimEncoderAssemble(enc, &webp_data)) { - fprintf(stderr, "%s\n", WebPAnimEncoderGetError(enc)); - Py_RETURN_NONE; + PyErr_SetString(PyExc_RuntimeError, WebPAnimEncoderGetError(enc)); + return NULL; } // Re-mux to add metadata as needed @@ -227,8 +257,8 @@ PyObject* _anim_encoder_assemble(PyObject* self, PyObject* args) mux = WebPMuxCreate(&webp_data, 1); if (mux == NULL) { - fprintf(stderr, "ERROR: Could not re-mux to add metadata.\n"); - Py_RETURN_NONE; + PyErr_SetString(PyExc_RuntimeError, "could not re-mux to add metadata"); + return NULL; } WebPDataClear(&webp_data); @@ -236,8 +266,7 @@ PyObject* _anim_encoder_assemble(PyObject* self, PyObject* args) if (i_icc_size > 0) { err = WebPMuxSetChunk(mux, "ICCP", &icc_profile, 1); if (err != WEBP_MUX_OK) { - fprintf(stderr, "ERROR (%s): Could not set ICC chunk.\n", ErrorString(err)); - Py_RETURN_NONE; + return HandleMuxError(err, "ICCP"); } } @@ -245,8 +274,7 @@ PyObject* _anim_encoder_assemble(PyObject* self, PyObject* args) if (i_exif_size > 0) { err = WebPMuxSetChunk(mux, "EXIF", &exif, 1); if (err != WEBP_MUX_OK) { - fprintf(stderr, "ERROR (%s): Could not set EXIF chunk.\n", ErrorString(err)); - Py_RETURN_NONE; + return HandleMuxError(err, "EXIF"); } } @@ -254,15 +282,13 @@ PyObject* _anim_encoder_assemble(PyObject* self, PyObject* args) if (i_xmp_size > 0) { err = WebPMuxSetChunk(mux, "XMP ", &xmp, 1); if (err != WEBP_MUX_OK) { - fprintf(stderr, "ERROR (%s): Could not set XMP chunk.\n", ErrorString(err)); - Py_RETURN_NONE; + return HandleMuxError(err, "XMP"); } } err = WebPMuxAssemble(mux, &webp_data); if (err != WEBP_MUX_OK) { - fprintf(stderr, "ERROR (%s): Could not assemble when re-muxing to add metadata.\n", ErrorString(err)); - Py_RETURN_NONE; + return HandleMuxError(err, NULL); } } @@ -319,8 +345,8 @@ PyObject* _anim_decoder_new(PyObject* self, PyObject* args) } PyObject_Del(decp); } - fprintf(stderr, "Error! Could not create decoder object.\n"); - Py_RETURN_NONE; + PyErr_SetString(PyExc_RuntimeError, "could not create decoder object"); + return NULL; } PyObject* _anim_decoder_dealloc(PyObject* self) @@ -376,8 +402,8 @@ PyObject* _anim_decoder_get_next(PyObject* self, PyObject* args) WebPAnimDecoderObject* decp = (WebPAnimDecoderObject*)self; if (!WebPAnimDecoderGetNext(decp->dec, &buf, ×tamp)) { - fprintf(stderr, "Error! Failed to read next frame.\n"); - Py_RETURN_NONE; + PyErr_SetString(PyExc_IOError, "failed to read next frame"); + return NULL; } bytes = PyBytes_FromStringAndSize((char *)buf, @@ -582,13 +608,11 @@ PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args) if (i_icc_size > 0) { if (dbg) { - fprintf (stderr, "Adding ICC Profile\n"); + fprintf(stderr, "Adding ICC Profile\n"); } err = WebPMuxSetChunk(mux, "ICCP", &icc_profile, copy_data); - if (dbg && err == WEBP_MUX_INVALID_ARGUMENT) { - fprintf(stderr, "Invalid ICC Argument\n"); - } else if (dbg && err == WEBP_MUX_MEMORY_ERROR) { - fprintf(stderr, "ICC Memory Error\n"); + if (err != WEBP_MUX_OK) { + return HandleMuxError(err, "ICCP"); } } @@ -596,14 +620,12 @@ PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args) fprintf(stderr, "exif size %d \n", i_exif_size); } if (i_exif_size > 0) { - if (dbg){ - fprintf (stderr, "Adding Exif Data\n"); + if (dbg) { + fprintf(stderr, "Adding Exif Data\n"); } err = WebPMuxSetChunk(mux, "EXIF", &exif, copy_data); - if (dbg && err == WEBP_MUX_INVALID_ARGUMENT) { - fprintf(stderr, "Invalid Exif Argument\n"); - } else if (dbg && err == WEBP_MUX_MEMORY_ERROR) { - fprintf(stderr, "Exif Memory Error\n"); + if (err != WEBP_MUX_OK) { + return HandleMuxError(err, "EXIF"); } } @@ -612,13 +634,11 @@ PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args) } if (i_xmp_size > 0) { if (dbg){ - fprintf (stderr, "Adding XMP Data\n"); + fprintf(stderr, "Adding XMP Data\n"); } err = WebPMuxSetChunk(mux, "XMP ", &xmp, copy_data); - if (dbg && err == WEBP_MUX_INVALID_ARGUMENT) { - fprintf(stderr, "Invalid XMP Argument\n"); - } else if (dbg && err == WEBP_MUX_MEMORY_ERROR) { - fprintf(stderr, "XMP Memory Error\n"); + if (err != WEBP_MUX_OK) { + return HandleMuxError(err, "XMP "); } } From 5b2dd29f44edbd77706bc80bc29454a914727589 Mon Sep 17 00:00:00 2001 From: Jason Douglas Date: Wed, 27 Sep 2017 20:21:18 -0700 Subject: [PATCH 10/19] Fix invalid_args test for older versions of libwebp --- Tests/test_file_webp.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/test_file_webp.py b/Tests/test_file_webp.py index 1ae75d573..41e424f6a 100644 --- a/Tests/test_file_webp.py +++ b/Tests/test_file_webp.py @@ -120,7 +120,7 @@ class TestFileWebp(PillowTestCase): Calling encoder functions with no arguments should result in an error. """ - if _webp.HAVE_WEBPMUX: + if _webp.HAVE_WEBPANIM: self.assertRaises(TypeError, _webp.WebPAnimEncoder) self.assertRaises(TypeError, _webp.WebPEncode) @@ -129,7 +129,7 @@ class TestFileWebp(PillowTestCase): Calling decoder functions with no arguments should result in an error. """ - if _webp.HAVE_WEBPMUX: + if _webp.HAVE_WEBPANIM: self.assertRaises(TypeError, _webp.WebPAnimDecoder) self.assertRaises(TypeError, _webp.WebPDecode) From b3e90a37e9efb9e9cb9c9b6db0749953d1375851 Mon Sep 17 00:00:00 2001 From: Jason Douglas Date: Wed, 27 Sep 2017 21:20:03 -0700 Subject: [PATCH 11/19] Fix implicit function declaration warning --- _webp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_webp.c b/_webp.c index bea9dccd5..cd283266c 100644 --- a/_webp.c +++ b/_webp.c @@ -32,7 +32,7 @@ static const char* const kErrorMessages[-WEBP_MUX_NOT_ENOUGH_DATA + 1] = { "WEBP_MUX_MEMORY_ERROR", "WEBP_MUX_NOT_ENOUGH_DATA" }; -static PyObject* HandleMuxError(WebPMuxError err, char* chunk) { +PyObject* HandleMuxError(WebPMuxError err, char* chunk) { assert(err <= WEBP_MUX_NOT_FOUND && err >= WEBP_MUX_NOT_ENOUGH_DATA); // Check for a memory error first From 405d1a64d87bbe4f22b800f8bf0850db7160ecc4 Mon Sep 17 00:00:00 2001 From: Jason Douglas Date: Wed, 27 Sep 2017 21:22:05 -0700 Subject: [PATCH 12/19] - Fix incorrect pixel width in WebP RGBX import call - Add a test to cover RGBX import --- Tests/test_file_webp_animated.py | 29 ++++++++++++++++++++++++++++- _webp.c | 2 +- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Tests/test_file_webp_animated.py b/Tests/test_file_webp_animated.py index 02cf5a146..7e9f3e4fe 100644 --- a/Tests/test_file_webp_animated.py +++ b/Tests/test_file_webp_animated.py @@ -33,7 +33,7 @@ class TestFileWebpAnimation(PillowTestCase): self.assertEqual(im.n_frames, 42) self.assertTrue(im.is_animated) - def test_write_animation(self): + def test_write_animation_L(self): """ Convert an animated GIF to animated WebP, then compare the frame count, and first and last frames to ensure they're @@ -58,6 +58,33 @@ class TestFileWebpAnimation(PillowTestCase): im.load() self.assert_image_similar(im, orig.convert("RGBA"), 25.0) + def test_write_animation_RGB(self): + """ + Write an animated WebP from RGB frames, and ensure the frames + are visually similar to the originals. + """ + + temp_file = self.tempfile("temp.webp") + temp_file2 = self.tempfile("temp.png") + frame1 = Image.open('Tests/images/anim_frame1.webp') + frame2 = Image.open('Tests/images/anim_frame2.webp') + frame1.save(temp_file, save_all=True, append_images=[frame2], lossless=True) + + im = Image.open(temp_file) + self.assertEqual(im.n_frames, 2) + print("Test File: " + temp_file) + + # Compare first frame to original + im.load() + im.save(temp_file2) + print("Frame 1: " + temp_file2) + self.assert_image_equal(im, frame1.convert("RGBA")) + + # Compare second frame to original + im.seek(1) + im.load() + self.assert_image_equal(im, frame2.convert("RGBA")) + def test_timestamp_and_duration(self): """ Try passing a list of durations, and make sure the encoded diff --git a/_webp.c b/_webp.c index cd283266c..4f43d6879 100644 --- a/_webp.c +++ b/_webp.c @@ -205,7 +205,7 @@ PyObject* _anim_encoder_add(PyObject* self, PyObject* args) if (strcmp(mode, "RGBA")==0) { WebPPictureImportRGBA(frame, rgb, 4 * width); } else if (strcmp(mode, "RGBX")==0) { - WebPPictureImportRGBX(frame, rgb, 3 * width); + WebPPictureImportRGBX(frame, rgb, 4 * width); } // Add the frame to the encoder From acc43342911f74db9a6bc40f6b65b11eaaa0146f Mon Sep 17 00:00:00 2001 From: Jason Douglas Date: Wed, 27 Sep 2017 22:13:13 -0700 Subject: [PATCH 13/19] - Fix _webp reference when _webp is not available - HandleMuxError function needs to be tied to WEBP_HAVEMUX, not WEBP_HAVEANIM --- Tests/test_file_webp_metadata.py | 4 +++- _webp.c | 9 +++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Tests/test_file_webp_metadata.py b/Tests/test_file_webp_metadata.py index 805125357..6cb61fdd4 100644 --- a/Tests/test_file_webp_metadata.py +++ b/Tests/test_file_webp_metadata.py @@ -5,8 +5,10 @@ from PIL import Image try: from PIL import _webp HAVE_WEBP = True + HAVE_WEBPANIM = True except ImportError: HAVE_WEBP = False + HAVE_WEBPANIM = False class TestFileWebpMetadata(PillowTestCase): @@ -110,7 +112,7 @@ class TestFileWebpMetadata(PillowTestCase): self.assertFalse(webp_image._getexif()) - @unittest.skipUnless(_webp.HAVE_WEBPANIM, 'WebP animation support not available') + @unittest.skipUnless(HAVE_WEBPANIM, 'WebP animation support not available') def test_write_animated_metadata(self): iccp_data = ''.encode('utf-8') exif_data = ''.encode('utf-8') diff --git a/_webp.c b/_webp.c index 4f43d6879..dcb2e29b5 100644 --- a/_webp.c +++ b/_webp.c @@ -19,14 +19,15 @@ #if WEBP_MUX_ABI_VERSION >= 0x0104 && WEBP_DEMUX_ABI_VERSION >= 0x0105 #define HAVE_WEBPANIM #endif -#endif -#ifdef HAVE_WEBPANIM +#endif /* -------------------------------------------------------------------- */ /* WebP Muxer Error Handling */ /* -------------------------------------------------------------------- */ +#ifdef HAVE_WEBPMUX + static const char* const kErrorMessages[-WEBP_MUX_NOT_ENOUGH_DATA + 1] = { "WEBP_MUX_NOT_FOUND", "WEBP_MUX_INVALID_ARGUMENT", "WEBP_MUX_BAD_DATA", "WEBP_MUX_MEMORY_ERROR", "WEBP_MUX_NOT_ENOUGH_DATA" @@ -67,10 +68,14 @@ PyObject* HandleMuxError(WebPMuxError err, char* chunk) { return NULL; } +#endif + /* -------------------------------------------------------------------- */ /* WebP Animation Support */ /* -------------------------------------------------------------------- */ +#ifdef HAVE_WEBPANIM + // Encoder type typedef struct { PyObject_HEAD From c5e6211936f5fda076b27c9b973050c1fef4c80d Mon Sep 17 00:00:00 2001 From: Jason Douglas Date: Wed, 27 Sep 2017 23:10:44 -0700 Subject: [PATCH 14/19] Don't use unittest skip decorator, doesn't seem to work --- Tests/test_file_webp_metadata.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/test_file_webp_metadata.py b/Tests/test_file_webp_metadata.py index 6cb61fdd4..b69de76be 100644 --- a/Tests/test_file_webp_metadata.py +++ b/Tests/test_file_webp_metadata.py @@ -5,10 +5,8 @@ from PIL import Image try: from PIL import _webp HAVE_WEBP = True - HAVE_WEBPANIM = True except ImportError: HAVE_WEBP = False - HAVE_WEBPANIM = False class TestFileWebpMetadata(PillowTestCase): @@ -112,8 +110,10 @@ class TestFileWebpMetadata(PillowTestCase): self.assertFalse(webp_image._getexif()) - @unittest.skipUnless(HAVE_WEBPANIM, 'WebP animation support not available') def test_write_animated_metadata(self): + if not _webp.HAVE_WEBPANIM: + self.skipTest('WebP animation support not available') + iccp_data = ''.encode('utf-8') exif_data = ''.encode('utf-8') xmp_data = ''.encode('utf-8') From e32fb4f7779c80e1f332cc339de669e686dd76be Mon Sep 17 00:00:00 2001 From: Jason Douglas Date: Fri, 29 Sep 2017 13:21:26 -0700 Subject: [PATCH 15/19] Move variable declaration to top of block --- _webp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_webp.c b/_webp.c index dcb2e29b5..08fa39dc7 100644 --- a/_webp.c +++ b/_webp.c @@ -34,6 +34,7 @@ static const char* const kErrorMessages[-WEBP_MUX_NOT_ENOUGH_DATA + 1] = { }; PyObject* HandleMuxError(WebPMuxError err, char* chunk) { + char message[100]; assert(err <= WEBP_MUX_NOT_FOUND && err >= WEBP_MUX_NOT_ENOUGH_DATA); // Check for a memory error first @@ -42,7 +43,6 @@ PyObject* HandleMuxError(WebPMuxError err, char* chunk) { } // Create the error message - char message[100]; if (chunk == NULL) { sprintf(message, "could not assemble chunks: %s", kErrorMessages[-err]); } else { From c9258d6cdb2e1d2c59381009c2612cbc08059fad Mon Sep 17 00:00:00 2001 From: Jason Douglas Date: Fri, 29 Sep 2017 13:59:05 -0700 Subject: [PATCH 16/19] Move some more declarations to top of block --- _webp.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/_webp.c b/_webp.c index 08fa39dc7..5e5eedaad 100644 --- a/_webp.c +++ b/_webp.c @@ -35,6 +35,7 @@ static const char* const kErrorMessages[-WEBP_MUX_NOT_ENOUGH_DATA + 1] = { PyObject* HandleMuxError(WebPMuxError err, char* chunk) { char message[100]; + int message_len; assert(err <= WEBP_MUX_NOT_FOUND && err >= WEBP_MUX_NOT_ENOUGH_DATA); // Check for a memory error first @@ -44,9 +45,13 @@ PyObject* HandleMuxError(WebPMuxError err, char* chunk) { // Create the error message if (chunk == NULL) { - sprintf(message, "could not assemble chunks: %s", kErrorMessages[-err]); + message_len = sprintf_s(message, 100, "could not assemble chunks: %s", kErrorMessages[-err]); } else { - sprintf(message, "could not set %.4s chunk: %s", chunk, kErrorMessages[-err]); + message_len = sprintf_s(message, 100, "could not set %.4s chunk: %s", chunk, kErrorMessages[-err]); + } + if (message_len < 0) { + PyErr_SetString(PyExc_RuntimeError, "failed to construct error message"); + return NULL; } // Set the proper error type @@ -171,6 +176,7 @@ PyObject* _anim_encoder_add(PyObject* self, PyObject* args) int lossless; float quality_factor; int method; + WebPConfig config; WebPAnimEncoderObject* encp = (WebPAnimEncoderObject*)self; WebPAnimEncoder* enc = encp->enc; WebPPicture* frame = &(encp->frame); @@ -188,7 +194,6 @@ PyObject* _anim_encoder_add(PyObject* self, PyObject* args) } // Setup config for this frame - WebPConfig config; if (!WebPConfigInit(&config)) { PyErr_SetString(PyExc_RuntimeError, "failed to initialize config!"); return NULL; @@ -230,6 +235,7 @@ PyObject* _anim_encoder_assemble(PyObject* self, PyObject* args) Py_ssize_t icc_size; Py_ssize_t exif_size; Py_ssize_t xmp_size; + WebPData webp_data; WebPAnimEncoderObject* encp = (WebPAnimEncoderObject*)self; WebPAnimEncoder* enc = encp->enc; WebPMux* mux = NULL; @@ -241,7 +247,6 @@ PyObject* _anim_encoder_assemble(PyObject* self, PyObject* args) } // Init the output buffer - WebPData webp_data; WebPDataInit(&webp_data); // Assemble everything into the output buffer @@ -316,6 +321,7 @@ PyObject* _anim_decoder_new(PyObject* self, PyObject* args) const uint8_t *webp; Py_ssize_t size; WebPData webp_src; + char* mode; WebPDecoderConfig config; WebPAnimDecoderObject* decp = NULL; WebPAnimDecoder* dec = NULL; @@ -323,12 +329,12 @@ PyObject* _anim_decoder_new(PyObject* self, PyObject* args) if (!PyArg_ParseTuple(args, "S", &webp_string)) { return NULL; } - PyBytes_AsStringAndSize((PyObject *) webp_string, (char**)&webp, &size); + PyBytes_AsStringAndSize((PyObject *)webp_string, (char**)&webp, &size); webp_src.bytes = webp; webp_src.size = size; // Sniff the mode, since the decoder API doesn't tell us - char* mode = "RGBA"; + mode = "RGBA"; if (WebPGetFeatures(webp, size, &config.input) == VP8_STATUS_OK) { if (!config.input.has_alpha) { mode = "RGBX"; From e75c38676017f8b686baaf3f261c31ce5f268a95 Mon Sep 17 00:00:00 2001 From: hugovk Date: Sat, 30 Sep 2017 19:25:06 +0300 Subject: [PATCH 17/19] Avoid 'Symbol not found: _sprintf_s' on 'from PIL import _webp' --- _webp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_webp.c b/_webp.c index 5e5eedaad..8d9804117 100644 --- a/_webp.c +++ b/_webp.c @@ -45,9 +45,9 @@ PyObject* HandleMuxError(WebPMuxError err, char* chunk) { // Create the error message if (chunk == NULL) { - message_len = sprintf_s(message, 100, "could not assemble chunks: %s", kErrorMessages[-err]); + message_len = sprintf(message, "could not assemble chunks: %s", kErrorMessages[-err]); } else { - message_len = sprintf_s(message, 100, "could not set %.4s chunk: %s", chunk, kErrorMessages[-err]); + message_len = sprintf(message, "could not set %.4s chunk: %s", chunk, kErrorMessages[-err]); } if (message_len < 0) { PyErr_SetString(PyExc_RuntimeError, "failed to construct error message"); From 28bec69e98e5140e1ee38e26325ad3aef7858c06 Mon Sep 17 00:00:00 2001 From: Jason Douglas Date: Sun, 1 Oct 2017 15:23:18 -0700 Subject: [PATCH 18/19] - flake8 formatting fixes - webp => WebP doc and comment changes --- PIL/WebPImagePlugin.py | 44 +++++++++++++++------------- Tests/test_file_webp.py | 10 ++++--- Tests/test_file_webp_alpha.py | 8 ++--- Tests/test_file_webp_animated.py | 16 +++++----- Tests/test_file_webp_lossless.py | 1 + Tests/test_file_webp_metadata.py | 1 + _webp.c | 4 +-- docs/handbook/image-file-formats.rst | 12 ++++---- 8 files changed, 52 insertions(+), 44 deletions(-) diff --git a/PIL/WebPImagePlugin.py b/PIL/WebPImagePlugin.py index f23c793f8..36579dddd 100644 --- a/PIL/WebPImagePlugin.py +++ b/PIL/WebPImagePlugin.py @@ -44,6 +44,7 @@ class WebPImageFile(ImageFile.ImageFile): self.size = width, height self.fp = BytesIO(data) self.tile = [("raw", (0, 0) + self.size, 0, self.mode)] + self._n_frames = 1 return # Use the newer AnimDecoder API to parse the (possibly) animated file, @@ -51,7 +52,8 @@ class WebPImageFile(ImageFile.ImageFile): self._decoder = _webp.WebPAnimDecoder(self.fp.read()) # Get info from decoder - width, height, loop_count, bgcolor, frame_count, mode = self._decoder.get_info() + width, height, loop_count, bgcolor, frame_count, mode = \ + self._decoder.get_info() self.size = width, height self.info["loop"] = loop_count bg_a, bg_r, bg_g, bg_b = \ @@ -85,14 +87,10 @@ class WebPImageFile(ImageFile.ImageFile): @property def n_frames(self): - if not _webp.HAVE_WEBPANIM: - return 1 return self._n_frames @property def is_animated(self): - if not _webp.HAVE_WEBPANIM: - return False return self._n_frames > 1 def seek(self, frame): @@ -122,7 +120,7 @@ class WebPImageFile(ImageFile.ImageFile): # Check if an error occurred if ret is None: - self._reset() # Reset just to be safe + self._reset() # Reset just to be safe self.seek(0) raise EOFError("failed to decode next frame in WebP file") @@ -130,20 +128,18 @@ class WebPImageFile(ImageFile.ImageFile): data, timestamp = ret duration = timestamp - self.__timestamp self.__timestamp = timestamp - timestamp -= duration # libwebp gives frame end, adjust to start of frame + + # libwebp gives frame end, adjust to start of frame + timestamp -= duration return data, timestamp, duration def _seek(self, frame): if self.__physical_frame == frame: - return # Nothing to do - + return # Nothing to do if frame < self.__physical_frame: - # Rewind to beginning - self._reset() - - # Advance to the requested frame + self._reset() # Rewind to beginning while self.__physical_frame < frame: - self._get_next() + self._get_next() # Advance to the requested frame def load(self): if _webp.HAVE_WEBPANIM: @@ -168,6 +164,7 @@ class WebPImageFile(ImageFile.ImageFile): return self.__logical_frame + def _save_all(im, fp, filename): encoderinfo = im.encoderinfo.copy() append_images = encoderinfo.get("append_images", []) @@ -207,9 +204,12 @@ def _save_all(im, fp, filename): # Validate background color if (not isinstance(background, (list, tuple)) or len(background) != 4 or not all(v >= 0 and v < 256 for v in background)): - raise IOError("Background color is not an RGBA tuple clamped to (0-255): %s" % str(background)) + raise IOError("Background color is not an RGBA tuple clamped " + "to (0-255): %s" % str(background)) + + # Convert to packed uint bg_r, bg_g, bg_b, bg_a = background - background = (bg_a << 24) | (bg_r << 16) | (bg_g << 8) | (bg_b << 0) # Convert to packed uint + background = (bg_a << 24) | (bg_r << 16) | (bg_g << 8) | (bg_b << 0) # Setup the WebP animation encoder enc = _webp.WebPAnimEncoder( @@ -240,7 +240,7 @@ def _save_all(im, fp, filename): # Make sure image mode is supported frame = ims - if not ims.mode in _VALID_WEBP_MODES: + if ims.mode not in _VALID_WEBP_MODES: alpha = ims.mode == 'P' and 'A' in ims.im.getpalettemode() frame = ims.convert('RGBA' if alpha else 'RGBX') @@ -256,7 +256,10 @@ def _save_all(im, fp, filename): ) # Update timestamp and frame index - timestamp += duration[frame_idx] if isinstance(duration, (list, tuple)) else duration + if isinstance(duration, (list, tuple)): + timestamp += duration[frame_idx] + else: + timestamp += duration frame_idx += 1 finally: @@ -272,10 +275,11 @@ def _save_all(im, fp, filename): # Get the final output from the encoder data = enc.assemble(icc_profile, exif, xmp) if data is None: - raise IOError("cannot write file as WEBP (encoder returned None)") + raise IOError("cannot write file as WebP (encoder returned None)") fp.write(data) + def _save(im, fp, filename): lossless = im.encoderinfo.get("lossless", False) quality = im.encoderinfo.get("quality", 80) @@ -299,7 +303,7 @@ def _save(im, fp, filename): xmp ) if data is None: - raise IOError("cannot write file as WEBP (encoder returned None)") + raise IOError("cannot write file as WebP (encoder returned None)") fp.write(data) diff --git a/Tests/test_file_webp.py b/Tests/test_file_webp.py index 41e424f6a..46be3ad08 100644 --- a/Tests/test_file_webp.py +++ b/Tests/test_file_webp.py @@ -8,6 +8,7 @@ try: except ImportError: HAVE_WEBP = False + class TestFileWebp(PillowTestCase): def setUp(self): @@ -24,7 +25,7 @@ class TestFileWebp(PillowTestCase): def test_read_rgb(self): """ - Can we read a RGB mode webp file without error. + Can we read a RGB mode WebP file without error? Does it have the bits we expect? """ @@ -39,7 +40,8 @@ class TestFileWebp(PillowTestCase): # generated with: # dwebp -ppm ../../Tests/images/hopper.webp -o hopper_webp_bits.ppm - target = Image.open('Tests/images/hopper_webp_bits.ppm').convert(self.rgb_mode) + target = Image.open('Tests/images/hopper_webp_bits.ppm') + target = target.convert(self.rgb_mode) self.assert_image_similar(image, target, 20.0) def test_write_rgb(self): @@ -77,7 +79,7 @@ class TestFileWebp(PillowTestCase): def test_write_unsupported_mode_L(self): """ - Saving a black-and-white file to webp format should work, and be + Saving a black-and-white file to WebP format should work, and be similar to the original file. """ @@ -97,7 +99,7 @@ class TestFileWebp(PillowTestCase): def test_write_unsupported_mode_P(self): """ - Saving a palette-based file to webp format should work, and be + Saving a palette-based file to WebP format should work, and be similar to the original file. """ diff --git a/Tests/test_file_webp_alpha.py b/Tests/test_file_webp_alpha.py index 9ac68c6c1..ef9d74f3a 100644 --- a/Tests/test_file_webp_alpha.py +++ b/Tests/test_file_webp_alpha.py @@ -23,7 +23,7 @@ class TestFileWebpAlpha(PillowTestCase): def test_read_rgba(self): """ - Can we read a RGBA mode file without error. + Can we read an RGBA mode file without error? Does it have the bits we expect? """ @@ -44,8 +44,8 @@ class TestFileWebpAlpha(PillowTestCase): def test_write_lossless_rgb(self): """ - Can we write a RGBA mode file with lossless compression without error. - Does it have the bits we expect? + Can we write an RGBA mode file with lossless compression without + error? Does it have the bits we expect? """ temp_file = self.tempfile("temp.webp") @@ -102,7 +102,7 @@ class TestFileWebpAlpha(PillowTestCase): def test_write_unsupported_mode_PA(self): """ - Saving a palette-based file with transparency to webp format + Saving a palette-based file with transparency to WebP format should work, and be similar to the original file. """ diff --git a/Tests/test_file_webp_animated.py b/Tests/test_file_webp_animated.py index 7e9f3e4fe..ba5d4b3af 100644 --- a/Tests/test_file_webp_animated.py +++ b/Tests/test_file_webp_animated.py @@ -1,4 +1,4 @@ -from helper import unittest, PillowTestCase, hopper +from helper import unittest, PillowTestCase from PIL import Image @@ -8,6 +8,7 @@ try: except ImportError: HAVE_WEBP = False + class TestFileWebpAnimation(PillowTestCase): def setUp(self): @@ -21,7 +22,7 @@ class TestFileWebpAnimation(PillowTestCase): def test_n_frames(self): """ - Ensure that webp format sets n_frames and is_animated + Ensure that WebP format sets n_frames and is_animated attributes correctly. """ @@ -68,16 +69,15 @@ class TestFileWebpAnimation(PillowTestCase): temp_file2 = self.tempfile("temp.png") frame1 = Image.open('Tests/images/anim_frame1.webp') frame2 = Image.open('Tests/images/anim_frame2.webp') - frame1.save(temp_file, save_all=True, append_images=[frame2], lossless=True) + frame1.save(temp_file, + save_all=True, append_images=[frame2], lossless=True) im = Image.open(temp_file) self.assertEqual(im.n_frames, 2) - print("Test File: " + temp_file) # Compare first frame to original im.load() im.save(temp_file2) - print("Frame 1: " + temp_file2) self.assert_image_equal(im, frame1.convert("RGBA")) # Compare second frame to original @@ -103,7 +103,7 @@ class TestFileWebpAnimation(PillowTestCase): self.assertEqual(im.n_frames, 5) self.assertTrue(im.is_animated) - # Double-check that timestamps and durations match original values specified + # Check that timestamps and durations match original values specified ts = 0 for frame in range(im.n_frames): im.seek(frame) @@ -114,7 +114,7 @@ class TestFileWebpAnimation(PillowTestCase): def test_seeking(self): """ - Create an animated webp file, and then try seeking through + Create an animated WebP file, and then try seeking through frames in reverse-order, verifying the timestamps and durations are correct. """ @@ -131,7 +131,7 @@ class TestFileWebpAnimation(PillowTestCase): self.assertEqual(im.n_frames, 5) self.assertTrue(im.is_animated) - # Traverse frames in reverse order, double-check timestamps and duration + # Traverse frames in reverse, checking timestamps and durations ts = dur * (im.n_frames-1) for frame in reversed(range(im.n_frames)): im.seek(frame) diff --git a/Tests/test_file_webp_lossless.py b/Tests/test_file_webp_lossless.py index dfcbd869a..ee3336848 100644 --- a/Tests/test_file_webp_lossless.py +++ b/Tests/test_file_webp_lossless.py @@ -8,6 +8,7 @@ try: except ImportError: HAVE_WEBP = False + class TestFileWebpLossless(PillowTestCase): def setUp(self): diff --git a/Tests/test_file_webp_metadata.py b/Tests/test_file_webp_metadata.py index b69de76be..c04443f46 100644 --- a/Tests/test_file_webp_metadata.py +++ b/Tests/test_file_webp_metadata.py @@ -8,6 +8,7 @@ try: except ImportError: HAVE_WEBP = False + class TestFileWebpMetadata(PillowTestCase): def setUp(self): diff --git a/_webp.c b/_webp.c index 5e5eedaad..4e3ff75ca 100644 --- a/_webp.c +++ b/_webp.c @@ -12,7 +12,7 @@ /* * Check the versions from mux.h and demux.h, to ensure the WebPAnimEncoder and - * WebPAnimDecoder API's are present (initial support was added in 0.5.0). The + * WebPAnimDecoder APIs are present (initial support was added in 0.5.0). The * very early versions added had some significant differences, so we require * later versions, before enabling animation support. */ @@ -591,7 +591,7 @@ PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args) } #else { - /* I want to truncate the *_size items that get passed into webp + /* I want to truncate the *_size items that get passed into WebP data. Pypy2.1.0 had some issues where the Py_ssize_t items had data in the upper byte. (Not sure why, it shouldn't have been there) */ diff --git a/docs/handbook/image-file-formats.rst b/docs/handbook/image-file-formats.rst index d0b9453db..130d15908 100644 --- a/docs/handbook/image-file-formats.rst +++ b/docs/handbook/image-file-formats.rst @@ -658,7 +658,7 @@ format are currently undocumented. The :py:meth:`~PIL.Image.Image.save` method supports the following options: **lossless** - If present and true, instructs the WEBP writer to use lossless compression. + If present and true, instructs the WebP writer to use lossless compression. **quality** Integer, 1-100, Defaults to 80. For lossy, 0 gives the smallest @@ -671,23 +671,23 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options: **icc_procfile** The ICC Profile to include in the saved file. Only supported if - the system webp library was built with webpmux support. + the system WebP library was built with webpmux support. **exif** The exif data to include in the saved file. Only supported if - the system webp library was built with webpmux support. + the system WebP library was built with webpmux support. Saving sequences ~~~~~~~~~~~~~~~~~ .. note:: - Support for animated WebP files will only be enabled if the system webp + Support for animated WebP files will only be enabled if the system WebP library is v0.5.0 or later. You can check webp animation support at - runtime by inspecting the `_webp.HAVE_WEBPANIM` module flag. + runtime by calling `features.check("webp_anim")`. When calling :py:meth:`~PIL.Image.Image.save`, the following options -are available when the save_all argument is present and true. +are available when the `save_all` argument is present and true. **append_images** A list of images to append as additional frames. Each of the From cf31e707355528b53fbf0ed39a5d0c4cf8f1796c Mon Sep 17 00:00:00 2001 From: Jason Douglas Date: Tue, 3 Oct 2017 08:05:20 -0700 Subject: [PATCH 19/19] Fixing a typo in comments --- Tests/test_file_webp.py | 2 +- Tests/test_file_webp_lossless.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/test_file_webp.py b/Tests/test_file_webp.py index 46be3ad08..06e274d0a 100644 --- a/Tests/test_file_webp.py +++ b/Tests/test_file_webp.py @@ -16,7 +16,7 @@ class TestFileWebp(PillowTestCase): self.skipTest('WebP support not installed') return - # WebPAnimDecoder only retuns RGBA or RGBX, never RGB + # WebPAnimDecoder only returns RGBA or RGBX, never RGB self.rgb_mode = "RGBX" if _webp.HAVE_WEBPANIM else "RGB" def test_version(self): diff --git a/Tests/test_file_webp_lossless.py b/Tests/test_file_webp_lossless.py index ee3336848..10354c55f 100644 --- a/Tests/test_file_webp_lossless.py +++ b/Tests/test_file_webp_lossless.py @@ -19,7 +19,7 @@ class TestFileWebpLossless(PillowTestCase): if (_webp.WebPDecoderVersion() < 0x0200): self.skipTest('lossless not included') - # WebPAnimDecoder only retuns RGBA or RGBX, never RGB + # WebPAnimDecoder only returns RGBA or RGBX, never RGB self.rgb_mode = "RGBX" if _webp.HAVE_WEBPANIM else "RGB" def test_write_lossless_rgb(self):