bool save_WEBP(const std::string& file_name, const Texture_data_adapter& adapter) { const Texture_description& description = adapter.description(); if (Data_format::R8G8B8A8_UNorm_sRGB != description.format) { return false; } std::ofstream stream(file_name, std::ios::binary); if (!stream) { return false; } Texture_description::Data data; adapter.query_image(data, 0, 0, 0); uint8_t* output; size_t num_bytes = WebPEncodeLosslessRGBA(reinterpret_cast<uint8_t*>(data.buffer), data.dimensions.x, data.dimensions.y, data.row_pitch, &output); if (!num_bytes) { return false; } stream.write(reinterpret_cast<char*>(output), num_bytes); free(output); return true; }
uint8_t* webpEncodeLosslessRGBA( const uint8_t* rgba, int width, int height, int stride, size_t* output_size ) { uint8_t* output = NULL; *output_size = WebPEncodeLosslessRGBA(rgba, width, height, stride, &output); return output; }
size_t webpEncodeLosslessRGBA( const uint8_t* rgba, int width, int height, int stride, uint8_t** output ) { return WebPEncodeLosslessRGBA(rgba, width, height, stride, output); }
/*! * pixWriteMemWebP() * * Input: &encdata (<return> webp encoded data of pixs) * &encsize (<return> size of webp encoded data) * pixs (any depth, cmapped OK) * quality (0 - 100; default ~80) * lossless (use 1 for lossless; 0 for lossy) * Return: 0 if OK, 1 on error * * Notes: * (1) Lossless and lossy encoding are entirely different in webp. * @quality applies to lossy, and is ignored for lossless. * (2) The input image is converted to RGB if necessary. If spp == 3, * we set the alpha channel to fully opaque (255), and * WebPEncodeRGBA() then removes the alpha chunk when encoding, * setting the internal header field has_alpha to 0. */ l_int32 pixWriteMemWebP(l_uint8 **pencdata, size_t *pencsize, PIX *pixs, l_int32 quality, l_int32 lossless) { l_int32 w, h, d, wpl, stride; l_uint32 *data; PIX *pix1, *pix2; PROCNAME("pixWriteMemWebP"); if (!pencdata) return ERROR_INT("&encdata not defined", procName, 1); *pencdata = NULL; if (!pencsize) return ERROR_INT("&encsize not defined", procName, 1); *pencsize = 0; if (!pixs) return ERROR_INT("&pixs not defined", procName, 1); if (lossless == 0 && (quality < 0 || quality > 100)) return ERROR_INT("quality not in [0 ... 100]", procName, 1); if ((pix1 = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR)) == NULL) return ERROR_INT("failure to remove color map", procName, 1); /* Convert to rgb if not 32 bpp; pix2 must not be a clone of pixs. */ if (pixGetDepth(pix1) != 32) pix2 = pixConvertTo32(pix1); else pix2 = pixCopy(NULL, pix1); pixDestroy(&pix1); pixGetDimensions(pix2, &w, &h, &d); if (w <= 0 || h <= 0 || d != 32) { pixDestroy(&pix2); return ERROR_INT("pix2 not 32 bpp or of 0 size", procName, 1); } /* If spp == 3, need to set alpha layer to opaque (all 1s). */ if (pixGetSpp(pix2) == 3) pixSetComponentArbitrary(pix2, L_ALPHA_CHANNEL, 255); /* Webp encoder assumes big-endian byte order for RGBA components */ pixEndianByteSwap(pix2); wpl = pixGetWpl(pix2); data = pixGetData(pix2); stride = wpl * 4; if (lossless) { *pencsize = WebPEncodeLosslessRGBA((uint8_t *)data, w, h, stride, pencdata); } else { *pencsize = WebPEncodeRGBA((uint8_t *)data, w, h, stride, quality, pencdata); } pixDestroy(&pix2); if (*pencsize == 0) { free(pencdata); *pencdata = NULL; return ERROR_INT("webp encoding failed", procName, 1); } return 0; }
virtual void HandleMessage(const pp::Var& var_message) { if (!var_message.is_dictionary ()) { return; } pp::VarDictionary::VarDictionary dic = pp::VarDictionary::VarDictionary (var_message); pp::Var s_rgba= dic.Get("rgba"); pp::Var s_width = dic.Get("width"); pp::Var s_height = dic.Get("height"); pp::Var s_quality= dic.Get("quality"); pp::Var id = dic.Get("id"); if (!s_rgba.is_array_buffer()) { PostMessage(ErrorMsg("ArrayBuffer no find")); return; } if( !s_width.is_int ()) { PostMessage(ErrorMsg("width is not int")); return; } int width = s_width.AsInt (); if (!s_height.is_int ()) { PostMessage(ErrorMsg("height is not int")); return; } int height = s_height.AsInt (); double quality = 80.0f; bool lossless = false; if (s_quality.is_string()) { if (s_quality.AsString() == "lossless") { lossless = true; } }else if (s_quality.is_number()) { double q = s_quality.AsDouble(); if (q <= 100.0 && q >= 0 ) { quality = (float)q; } } std::unique_ptr<pp::VarArrayBuffer::VarArrayBuffer> array_buffer_var(new pp::VarArrayBuffer::VarArrayBuffer(s_rgba)); uint8_t* data = static_cast<uint8_t *>(array_buffer_var->Map()); int byte_length = static_cast<int>(array_buffer_var->ByteLength()); if (byte_length != (width * height * 4)) { PostMessage(ErrorMsg("ArrayBuffer length error :"+ std::to_string(byte_length))); return; } std::shared_ptr<uint8_t> outdata(new uint8_t[byte_length]()); uint8_t * r_outdata = outdata.get(); size_t ret; if (lossless) { ret = WebPEncodeLosslessRGBA(data,width,height,width*4,&r_outdata); }else{ ret = WebPEncodeRGBA(data,width,height,width*4,quality,&r_outdata); } if (ret == 0) { PostMessage(ErrorMsg("encoder error ")); return; } pp::VarArrayBuffer::VarArrayBuffer data_value = pp::VarArrayBuffer::VarArrayBuffer (ret); uint8_t* r_data_value = static_cast<uint8_t*>(data_value.Map()); for (uint32_t i = 0; i < ret; ++i) { r_data_value[i] = r_outdata[i]; } data_value.Unmap(); pp::VarDictionary::VarDictionary ret_msg = pp::VarDictionary::VarDictionary (); pp::Var id_key = pp::Var::Var("id"); ret_msg.Set (id_key,id); pp::Var data_key = pp::Var::Var("data"); ret_msg.Set (data_key,data_value); PostMessage(ret_msg); }
PyObject* WebPEncode_wrapper(PyObject* self, PyObject* args) { int width; int height; int lossless; 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#iiifss#s#", (char**)&rgb, &size, &width, &height, &lossless, &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; } if (lossless) { ret_size = WebPEncodeLosslessRGBA(rgb, width, height, 4* width, &output); } else { 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; } if (lossless) { ret_size = WebPEncodeLosslessRGB(rgb, width, height, 3* width, &output); } else { 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 { /* 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) */ int i_icc_size = (int)icc_size; int i_exif_size = (int)exif_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 }; WebPMuxError err; int dbg = 0; 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 (dbg) { /* was getting %ld icc_size == 0, icc_size>0 was true */ fprintf(stderr, "icc size %d, %d \n", i_icc_size, i_icc_size > 0); } if (i_icc_size > 0) { if (dbg) { 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 (dbg) { fprintf(stderr, "exif size %d \n", i_exif_size); } if (i_exif_size > 0) { 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"); } } WebPMuxAssemble(mux, &output_data); WebPMuxDelete(mux); free(output); ret_size = output_data.size; if (ret_size > 0) { PyObject *ret = PyBytes_FromStringAndSize((char*)output_data.bytes, ret_size); WebPDataClear(&output_data); return ret; } } #endif Py_RETURN_NONE; }
DEFINE_FUNC_5(webp_encode_argb, data_buffer_value, width_value, height_value, lossless_value, quality_factor_value) { int width = 0; int height = 0; float quality_factor = 100; int lossless = 1; int stride = 0; uint8_t* abgr = NULL; uint8_t* rgba = NULL; uint8_t* output = NULL; int output_size = 0; int pixels_size; int bytes_size; buffer data_buffer; if (val_is_int(width_value)) width = val_int(width_value); if (val_is_int(height_value)) height = val_int(height_value); if (val_is_bool(lossless_value)) lossless = val_bool(lossless_value); if (val_is_float(quality_factor_value)) quality_factor = val_float(quality_factor_value); stride = width * 4; pixels_size = width * height; bytes_size = pixels_size * 4; if (!val_is_buffer(data_buffer_value)) { val_throw(alloc_string("webp_encode_argb: Expected to be a buffer")); return alloc_null(); } data_buffer = val_to_buffer(data_buffer_value); if (bytes_size != buffer_size(data_buffer)) { val_throw(alloc_string("webp_encode_argb: Invalid buffer size")); return alloc_null(); } //if () abgr = (uint8_t *)buffer_data(data_buffer); rgba = (uint8_t *)malloc(bytes_size); uint8_t* _abgr = abgr; uint8_t* _rgba = rgba; int _pixels_size = pixels_size; while (_pixels_size-- > 0) { //_rgba[0] = _abgr[3]; _rgba[0] = _abgr[1]; _rgba[1] = _abgr[2]; _rgba[2] = _abgr[3]; _rgba[3] = _abgr[0]; _abgr += 4; _rgba += 4; } if (lossless) { output_size = WebPEncodeLosslessRGBA( rgba, //abgr, width, height, stride, &output ); } else { output_size = WebPEncodeRGBA( rgba, //abgr, width, height, stride, quality_factor, &output ); } printf("output_size: (%d, %d, %d) : %d\n", width, height, stride, output_size); buffer output_buffer = alloc_buffer_len(0); buffer_append_sub(output_buffer, (char *)output, output_size); buffer_set_size(output_buffer, output_size); if (output != NULL) free(output); if (rgba != NULL) free(rgba); return buffer_val(output_buffer); }
/*! * \brief pixWriteMemWebP() * * \param[out] pencdata webp encoded data of pixs * \param[out] pencsize size of webp encoded data * \param[in] pixs any depth, cmapped OK * \param[in] quality 0 - 100; default ~80 * \param[in] lossless use 1 for lossless; 0 for lossy * \return 0 if OK, 1 on error * * <pre> * Notes: * (1) Lossless and lossy encoding are entirely different in webp. * %quality applies to lossy, and is ignored for lossless. * (2) The input image is converted to RGB if necessary. If spp == 3, * we set the alpha channel to fully opaque (255), and * WebPEncodeRGBA() then removes the alpha chunk when encoding, * setting the internal header field has_alpha to 0. * </pre> */ l_ok pixWriteMemWebP(l_uint8 **pencdata, size_t *pencsize, PIX *pixs, l_int32 quality, l_int32 lossless) { l_int32 w, h, d, wpl, stride; l_uint32 *data; PIX *pix1, *pix2; PROCNAME("pixWriteMemWebP"); if (!pencdata) return ERROR_INT("&encdata not defined", procName, 1); *pencdata = NULL; if (!pencsize) return ERROR_INT("&encsize not defined", procName, 1); *pencsize = 0; if (!pixs) return ERROR_INT("&pixs not defined", procName, 1); if (lossless == 0 && (quality < 0 || quality > 100)) return ERROR_INT("quality not in [0 ... 100]", procName, 1); if ((pix1 = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR)) == NULL) return ERROR_INT("failure to remove color map", procName, 1); /* Convert to rgb if not 32 bpp; pix2 must not be a clone of pixs. */ if (pixGetDepth(pix1) != 32) pix2 = pixConvertTo32(pix1); else pix2 = pixCopy(NULL, pix1); pixDestroy(&pix1); pixGetDimensions(pix2, &w, &h, &d); if (w <= 0 || h <= 0 || d != 32) { pixDestroy(&pix2); return ERROR_INT("pix2 not 32 bpp or of 0 size", procName, 1); } /* If spp == 3, need to set alpha layer to opaque (all 1s). */ if (pixGetSpp(pix2) == 3) pixSetComponentArbitrary(pix2, L_ALPHA_CHANNEL, 255); /* The WebP API expects data in RGBA order. The pix stores * in host-dependent order with R as the MSB and A as the LSB. * On little-endian machines, the bytes in the word must * be swapped; e.g., R goes from byte 0 (LSB) to byte 3 (MSB). * No swapping is necessary for big-endians. */ pixEndianByteSwap(pix2); wpl = pixGetWpl(pix2); data = pixGetData(pix2); stride = wpl * 4; if (lossless) { *pencsize = WebPEncodeLosslessRGBA((uint8_t *)data, w, h, stride, pencdata); } else { *pencsize = WebPEncodeRGBA((uint8_t *)data, w, h, stride, quality, pencdata); } pixDestroy(&pix2); if (*pencsize == 0) { free(*pencdata); *pencdata = NULL; return ERROR_INT("webp encoding failed", procName, 1); } return 0; }