diff --git a/Images/lena.webp b/Images/lena.webp new file mode 100644 index 000000000..210e1ab0b Binary files /dev/null and b/Images/lena.webp differ diff --git a/PIL/WebPImagePlugin.py b/PIL/WebPImagePlugin.py new file mode 100644 index 000000000..387c6434f --- /dev/null +++ b/PIL/WebPImagePlugin.py @@ -0,0 +1,33 @@ +import Image +import ImageFile +import StringIO +import _webp + +def _accept(prefix): + return prefix[:4] == "RIFF" and prefix[8:16] == "WEBPVP8 " + +class WebPImageFile(ImageFile.ImageFile): + + format = "WEBP" + format_description = "WebP image" + + def _open(self): + self.mode = "RGB" + data, width, height = _webp.WebPDecodeRGB(self.fp.read()) + self.size = width, height + self.fp = StringIO.StringIO(data) + self.tile = [("raw", (0, 0) + self.size, 0, 'RGB')] + +def _save(im, fp, filename): + if im.mode != "RGB": + raise IOError("cannot write mode %s as WEBP" % im.mode) + quality = im.encoderinfo.get("quality", 80) + + data = _webp.WebPEncodeRGB(im.tostring(), im.size[0], im.size[1], im.size[0] * 3, float(quality)) + fp.write(data) + +Image.register_open("WEBP", WebPImageFile, _accept) +Image.register_save("WEBP", _save) + +Image.register_extension("WEBP", ".webp") +Image.register_mime("WEBP", "image/webp") diff --git a/_webp.c b/_webp.c new file mode 100644 index 000000000..f361d35ae --- /dev/null +++ b/_webp.c @@ -0,0 +1,72 @@ +#include +#include +#include + +PyObject* WebPEncodeRGB_wrapper(PyObject* self, PyObject* args) +{ + PyStringObject *rgb_string; + int width; + int height; + int stride; + float quality_factor; + + if (!PyArg_ParseTuple(args, "Siiif", &rgb_string, &width, &height, &stride, &quality_factor)) { + Py_INCREF(Py_None); + return Py_None; + } + + uint8_t *rgb; + Py_ssize_t size; + PyString_AsStringAndSize((struct PyObject *) rgb_string, &rgb, &size); + + if (stride * height > size) { + Py_INCREF(Py_None); + return Py_None; + } + + uint8_t *output; + size_t ret_size = WebPEncodeRGB(rgb, width, height, stride, quality_factor, &output); + if (ret_size > 0) { + PyObject *ret = PyString_FromStringAndSize(output, ret_size); + free(output); + return ret; + } + Py_INCREF(Py_None); + return Py_None; + +} + +PyObject* WebPDecodeRGB_wrapper(PyObject* self, PyObject* args) +{ + PyStringObject *webp_string; + float quality_factor; + + if (!PyArg_ParseTuple(args, "S", &webp_string)) { + Py_INCREF(Py_None); + return Py_None; + } + uint8_t *webp; + Py_ssize_t size; + PyString_AsStringAndSize((struct PyObject *) webp_string, &webp, &size); + + int width; + int height; + uint8_t *output = WebPDecodeRGB(webp, size, &width, &height); + + PyObject *ret = PyString_FromStringAndSize(output, width * height * 3); + free(output); + return Py_BuildValue("Sii", ret, width, height); +} + +static PyMethodDef webpMethods[] = +{ + {"WebPEncodeRGB", WebPEncodeRGB_wrapper, METH_VARARGS, "WebPEncodeRGB"}, + {"WebPDecodeRGB", WebPDecodeRGB_wrapper, METH_VARARGS, "WebPEncodeRGB"}, + {NULL, NULL} +}; + +void init_webp() +{ + PyObject* m; + m = Py_InitModule("_webp", webpMethods); +} diff --git a/setup.py b/setup.py index cd3e3380f..e28fdb4f8 100644 --- a/setup.py +++ b/setup.py @@ -211,7 +211,7 @@ class pil_build_ext(build_ext): # look for available libraries class feature: - zlib = jpeg = tiff = freetype = tcl = tk = lcms = None + zlib = jpeg = tiff = freetype = tcl = tk = lcms = webp = None feature = feature() if _find_include_file(self, "zlib.h"): @@ -267,6 +267,10 @@ class pil_build_ext(build_ext): elif _find_library_file(self, "tk" + TCL_VERSION): feature.tk = "tk" + TCL_VERSION + if _find_include_file(self, "webp/encode.h") and _find_include_file(self, "webp/decode.h"): + if _find_library_file(self, "webp"): + feature.webp = "webp" + # # core library @@ -314,6 +318,11 @@ class pil_build_ext(build_ext): exts.append(Extension( "_imagingcms", ["_imagingcms.c"], libraries=["lcms"] + extra)) + if os.path.isfile("_webp.c") and feature.webp: + exts.append(Extension( + "_webp", ["_webp.c"], libraries=["webp"])) + + if sys.platform == "darwin": # locate Tcl/Tk frameworks frameworks = [] @@ -376,6 +385,7 @@ class pil_build_ext(build_ext): # (feature.tiff, "experimental TIFF G3/G4 read"), (feature.freetype, "FREETYPE2"), (feature.lcms, "LITTLECMS"), + (feature.webp, "WEBP"), ] all = 1