mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-10-31 07:57:27 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			234 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			234 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #define PY_SSIZE_T_CLEAN
 | |
| #include <Python.h>
 | |
| #include "py3.h"
 | |
| #include <webp/encode.h>
 | |
| #include <webp/decode.h>
 | |
| #include <webp/types.h>
 | |
| 
 | |
| #ifdef HAVE_WEBPMUX
 | |
| #include <webp/mux.h>
 | |
| #endif
 | |
| 
 | |
| PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args)
 | |
| {
 | |
|     int width;
 | |
|     int height;
 | |
|     float quality_factor;
 | |
|     uint8_t *rgb;
 | |
|     uint8_t *icc_bytes;
 | |
|     uint8_t *exif_bytes;
 | |
|     uint8_t *output;
 | |
|     char *mode;
 | |
|     Py_ssize_t size;
 | |
|     Py_ssize_t icc_size;
 | |
|     Py_ssize_t exif_size;
 | |
|     size_t ret_size;
 | |
| 
 | |
|     if (!PyArg_ParseTuple(args, "s#iifss#s#",
 | |
|                 (char**)&rgb, &size, &width, &height, &quality_factor, &mode,
 | |
|                 &icc_bytes, &icc_size, &exif_bytes, &exif_size)) {
 | |
|         Py_RETURN_NONE;
 | |
|     }
 | |
| 
 | |
| 	if (strcmp(mode, "RGBA")==0){
 | |
| 		if (size < width * height * 4){
 | |
| 			Py_RETURN_NONE;
 | |
| 		}
 | |
| 		ret_size = WebPEncodeRGBA(rgb, width, height, 4* width, quality_factor, &output);
 | |
| 	} else if (strcmp(mode, "RGB")==0){
 | |
| 		if (size < width * height * 3){
 | |
| 			Py_RETURN_NONE;
 | |
| 		}
 | |
| 		ret_size = WebPEncodeRGB(rgb, width, height, 3* width, quality_factor, &output);
 | |
| 	} else {
 | |
| 		Py_RETURN_NONE;
 | |
| 	}
 | |
| 
 | |
| #ifndef HAVE_WEBPMUX
 | |
|     if (ret_size > 0) {
 | |
|         PyObject *ret = PyBytes_FromStringAndSize((char*)output, ret_size);
 | |
|         free(output);
 | |
|         return ret;
 | |
|     }
 | |
| #else
 | |
|    {
 | |
|     WebPData output_data = {0};
 | |
|     WebPData image = { output, ret_size };
 | |
| 
 | |
|     int copy_data = 0;  // value 1 indicates given data WILL be copied to the mux
 | |
|                         // and value 0 indicates data will NOT be copied.
 | |
| 
 | |
|     WebPMux* mux = WebPMuxNew();
 | |
|     WebPMuxSetImage(mux, &image, copy_data);
 | |
| 
 | |
|     if (icc_size > 0) {
 | |
|         WebPData icc_profile = { icc_bytes, icc_size };
 | |
|         WebPMuxSetChunk(mux, "ICCP", &icc_profile, copy_data);
 | |
|     }
 | |
| 
 | |
|     if (exif_size > 0) {
 | |
|         WebPData exif = { exif_bytes, exif_size };
 | |
|         WebPMuxSetChunk(mux, "EXIF", &exif, copy_data);
 | |
|     }
 | |
| 
 | |
|     WebPMuxAssemble(mux, &output_data);
 | |
|     WebPMuxDelete(mux);
 | |
| 
 | |
|     output = (uint8_t*)output_data.bytes;
 | |
|     ret_size = output_data.size;
 | |
|     if (ret_size > 0) {
 | |
|         PyObject *ret = PyBytes_FromStringAndSize((char*)output, ret_size);
 | |
|         WebPDataClear(&output_data);
 | |
|         return ret;
 | |
|     }
 | |
|     }
 | |
| #endif
 | |
|     Py_RETURN_NONE;
 | |
| }
 | |
| 
 | |
| 
 | |
| PyObject* WebPDecode_wrapper(PyObject* self, PyObject* args)
 | |
| {
 | |
|     PyBytesObject *webp_string;
 | |
|     uint8_t *webp;
 | |
|     Py_ssize_t size;
 | |
|     PyObject *ret, *bytes, *pymode, *icc_profile = Py_None, *exif = Py_None;
 | |
|     WebPDecoderConfig config;
 | |
|     VP8StatusCode vp8_status_code = VP8_STATUS_OK;
 | |
|     char* mode = "RGB";
 | |
| 
 | |
|     if (!PyArg_ParseTuple(args, "S", &webp_string)) {
 | |
|         Py_RETURN_NONE;
 | |
|     }
 | |
| 
 | |
|     if (!WebPInitDecoderConfig(&config)) {
 | |
|         Py_RETURN_NONE;
 | |
|     }
 | |
| 
 | |
|     PyBytes_AsStringAndSize((PyObject *) webp_string, (char**)&webp, &size);
 | |
| 
 | |
|     vp8_status_code = WebPGetFeatures(webp, size, &config.input);
 | |
|     if (vp8_status_code == VP8_STATUS_OK) {
 | |
|         // If we don't set it, we don't get alpha.
 | |
|         // Initialized to MODE_RGB
 | |
|         if (config.input.has_alpha) {
 | |
|             config.output.colorspace = MODE_RGBA;
 | |
|             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);
 | |
|         WebPMuxGetFrame(mux, 1, &image);
 | |
|         webp = (uint8_t*)image.bitstream.bytes;
 | |
|         size = image.bitstream.size;
 | |
| 
 | |
|         vp8_status_code = WebPDecode(webp, size, &config);
 | |
| 
 | |
|         WebPMuxGetChunk(mux, "ICCP", &icc_profile_data);
 | |
|         if (icc_profile_data.size > 0) {
 | |
|             icc_profile = PyBytes_FromStringAndSize((const char*)icc_profile_data.bytes, icc_profile_data.size);
 | |
|         }
 | |
| 
 | |
|         WebPMuxGetChunk(mux, "EXIF", &exif_data);
 | |
|         if (exif_data.size > 0) {
 | |
|             exif = PyBytes_FromStringAndSize((const char*)exif_data.bytes, exif_data.size);
 | |
|         }
 | |
| 
 | |
|         WebPMuxDelete(mux);
 | |
|         }
 | |
| #endif
 | |
|     }
 | |
| 
 | |
|     if (vp8_status_code != VP8_STATUS_OK) {
 | |
|         WebPFreeDecBuffer(&config.output);
 | |
|         Py_RETURN_NONE;
 | |
|     }
 | |
| 
 | |
|     if (config.output.colorspace < MODE_YUV) {
 | |
|         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,
 | |
|                                           config.output.u.YUVA.y_size);
 | |
|     }
 | |
| 
 | |
| #if PY_VERSION_HEX >= 0x03000000
 | |
|     pymode = PyUnicode_FromString(mode);
 | |
| #else
 | |
|     pymode = PyString_FromString(mode);
 | |
| #endif
 | |
|     ret = Py_BuildValue("SiiSSS", bytes, config.output.width,
 | |
|                         config.output.height, pymode, icc_profile, exif);
 | |
|     WebPFreeDecBuffer(&config.output);
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| // 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){
 | |
|     return Py_BuildValue("i", WebPGetDecoderVersion());
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * The version of webp that ships with (0.1.3) Ubuntu 12.04 doesn't handle alpha well.
 | |
|  * Files that are valid with 0.3 are reported as being invalid.
 | |
|  */
 | |
| PyObject* WebPDecoderBuggyAlpha_wrapper(PyObject* self, PyObject* args){
 | |
|     return Py_BuildValue("i", WebPGetDecoderVersion()==0x0103);
 | |
| }
 | |
| 
 | |
| static PyMethodDef webpMethods[] =
 | |
| {
 | |
|     {"WebPEncode", WebPEncode_wrapper, METH_VARARGS, "WebPEncode"},
 | |
|     {"WebPDecode", WebPDecode_wrapper, METH_VARARGS, "WebPDecode"},
 | |
|     {"WebPDecoderVersion", WebPDecoderVersion_wrapper, METH_VARARGS, "WebPVersion"},
 | |
|     {"WebPDecoderBuggyAlpha", WebPDecoderBuggyAlpha_wrapper, METH_VARARGS, "WebPDecoderBuggyAlpha"},
 | |
|     {NULL, NULL}
 | |
| };
 | |
| 
 | |
| void addMuxFlagToModule(PyObject* m) {
 | |
| #ifdef HAVE_WEBPMUX
 | |
|     PyModule_AddObject(m, "HAVE_WEBPMUX", Py_True);
 | |
| #else
 | |
|     PyModule_AddObject(m, "HAVE_WEBPMUX", Py_False);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| 
 | |
| #if PY_VERSION_HEX >= 0x03000000
 | |
| PyMODINIT_FUNC
 | |
| PyInit__webp(void) {
 | |
|     PyObject* m;
 | |
| 
 | |
|     static PyModuleDef module_def = {
 | |
|         PyModuleDef_HEAD_INIT,
 | |
|         "_webp",            /* m_name */
 | |
|         NULL,               /* m_doc */
 | |
|         -1,                 /* m_size */
 | |
|         webpMethods,        /* m_methods */
 | |
|     };
 | |
| 
 | |
|     m = PyModule_Create(&module_def);
 | |
|     addMuxFlagToModule(m);
 | |
|     return m;
 | |
| }
 | |
| #else
 | |
| PyMODINIT_FUNC
 | |
| init_webp(void)
 | |
| {
 | |
|     PyObject* m = Py_InitModule("_webp", webpMethods);
 | |
|     addMuxFlagToModule(m);
 | |
| }
 | |
| #endif
 |