From a49ea5d32660c36cbcdad1b46baa430c0b85b8b6 Mon Sep 17 00:00:00 2001 From: Liu Qishuai Date: Tue, 12 Mar 2013 22:30:59 +0800 Subject: [PATCH] add support for webp --- Images/lena.webp | Bin 0 -> 3866 bytes PIL/WebPImagePlugin.py | 33 +++++++++++++++++++ _webp.c | 72 +++++++++++++++++++++++++++++++++++++++++ setup.py | 12 ++++++- 4 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 Images/lena.webp create mode 100644 PIL/WebPImagePlugin.py create mode 100644 _webp.c diff --git a/Images/lena.webp b/Images/lena.webp new file mode 100644 index 0000000000000000000000000000000000000000..210e1ab0b1cf660d905fc215ab711a641334d8e8 GIT binary patch literal 3866 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 literal 0 HcmV?d00001 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 d05bada12..ea3cbb966 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