CPLErr WEBPDataset::Uncompress() { if (bHasBeenUncompressed) return eUncompressErrRet; bHasBeenUncompressed = TRUE; eUncompressErrRet = CE_Failure; // To avoid excessive memory allocation attempts // Normally WebP images are no larger than 16383x16383*4 ~= 1 GB if( nRasterXSize > INT_MAX / (nRasterYSize * nBands) ) { CPLError(CE_Failure, CPLE_NotSupported, "Too large image"); return CE_Failure; } pabyUncompressed = reinterpret_cast<GByte*>( VSIMalloc3(nRasterXSize, nRasterYSize, nBands ) ); if (pabyUncompressed == nullptr) return CE_Failure; VSIFSeekL(fpImage, 0, SEEK_END); vsi_l_offset nSizeLarge = VSIFTellL(fpImage); if( nSizeLarge != static_cast<vsi_l_offset>( static_cast<uint32_t>( nSizeLarge ) ) ) return CE_Failure; VSIFSeekL(fpImage, 0, SEEK_SET); uint32_t nSize = static_cast<uint32_t>( nSizeLarge ); uint8_t* pabyCompressed = reinterpret_cast<uint8_t*>( VSIMalloc(nSize) ); if (pabyCompressed == nullptr) return CE_Failure; VSIFReadL(pabyCompressed, 1, nSize, fpImage); uint8_t* pRet; if (nBands == 4) pRet = WebPDecodeRGBAInto( pabyCompressed, static_cast<uint32_t>( nSize ), static_cast<uint8_t*>( pabyUncompressed), nRasterXSize * nRasterYSize * nBands, nRasterXSize * nBands ); else pRet = WebPDecodeRGBInto( pabyCompressed, static_cast<uint32_t>( nSize ), static_cast<uint8_t*>( pabyUncompressed ), nRasterXSize * nRasterYSize * nBands, nRasterXSize * nBands ); VSIFree(pabyCompressed); if (pRet == nullptr) { CPLError(CE_Failure, CPLE_AppDefined, "WebPDecodeRGBInto() failed"); return CE_Failure; } eUncompressErrRet = CE_None; return CE_None; }
void LoadWEBP(const char *filename, unsigned char **pic, int *width, int *height, byte alphaByte) { byte *out; int len; int stride; int size; union { byte *b; void *v; } fbuffer; /* read compressed data */ len = ri.FS_ReadFile((char *)filename, &fbuffer.v); if(!fbuffer.b || len < 0) { return; } /* validate data and query image size */ if( !WebPGetInfo( fbuffer.b, len, width, height ) ) return; stride = *width * sizeof( color4ub_t ); size = *height * stride; out = ri.Z_Malloc( size ); if( !WebPDecodeRGBAInto( fbuffer.b, len, out, size, stride ) ) { ri.Free( out ); return; } ri.FS_FreeFile(fbuffer.v); *pic = out; }
Error webp_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p_buffer_len) { ERR_FAIL_NULL_V(p_image, ERR_INVALID_PARAMETER); WebPBitstreamFeatures features; if (WebPGetFeatures(p_buffer, p_buffer_len, &features) != VP8_STATUS_OK) { // ERR_EXPLAIN("Error decoding WEBP image"); ERR_FAIL_V(ERR_FILE_CORRUPT); } PoolVector<uint8_t> dst_image; int datasize = features.width * features.height * (features.has_alpha ? 4 : 3); dst_image.resize(datasize); PoolVector<uint8_t>::Write dst_w = dst_image.write(); bool errdec = false; if (features.has_alpha) { errdec = WebPDecodeRGBAInto(p_buffer, p_buffer_len, dst_w.ptr(), datasize, 4 * features.width) == NULL; } else { errdec = WebPDecodeRGBInto(p_buffer, p_buffer_len, dst_w.ptr(), datasize, 3 * features.width) == NULL; } dst_w = PoolVector<uint8_t>::Write(); //ERR_EXPLAIN("Error decoding webp!"); ERR_FAIL_COND_V(errdec, ERR_FILE_CORRUPT); p_image->create(features.width, features.height, 0, features.has_alpha ? Image::FORMAT_RGBA8 : Image::FORMAT_RGB8, dst_image); return OK; }
CPLErr WEBPDataset::Uncompress() { if (bHasBeenUncompressed) return eUncompressErrRet; bHasBeenUncompressed = TRUE; eUncompressErrRet = CE_Failure; pabyUncompressed = reinterpret_cast<GByte*>( VSIMalloc3(nRasterXSize, nRasterYSize, nBands ) ); if (pabyUncompressed == NULL) return CE_Failure; VSIFSeekL(fpImage, 0, SEEK_END); vsi_l_offset nSizeLarge = VSIFTellL(fpImage); if( nSizeLarge != static_cast<vsi_l_offset>( static_cast<uint32_t>( nSizeLarge ) ) ) return CE_Failure; VSIFSeekL(fpImage, 0, SEEK_SET); uint32_t nSize = static_cast<uint32_t>( nSizeLarge ); uint8_t* pabyCompressed = reinterpret_cast<uint8_t*>( VSIMalloc(nSize) ); if (pabyCompressed == NULL) return CE_Failure; VSIFReadL(pabyCompressed, 1, nSize, fpImage); uint8_t* pRet; if (nBands == 4) pRet = WebPDecodeRGBAInto( pabyCompressed, static_cast<uint32_t>( nSize ), static_cast<uint8_t*>( pabyUncompressed), nRasterXSize * nRasterYSize * nBands, nRasterXSize * nBands ); else pRet = WebPDecodeRGBInto( pabyCompressed, static_cast<uint32_t>( nSize ), static_cast<uint8_t*>( pabyUncompressed ), nRasterXSize * nRasterYSize * nBands, nRasterXSize * nBands ); VSIFree(pabyCompressed); if (pRet == NULL) { CPLError(CE_Failure, CPLE_AppDefined, "WebPDecodeRGBInto() failed"); return CE_Failure; } eUncompressErrRet = CE_None; return CE_None; }
PremultipliedImage decodeWebP(const uint8_t* data, size_t size) { int width = 0, height = 0; if (WebPGetInfo(data, size, &width, &height) == 0) { throw std::runtime_error("failed to retrieve WebP basic header information"); } int stride = width * 4; size_t webpSize = stride * height; auto webp = std::make_unique<uint8_t[]>(webpSize); if (!WebPDecodeRGBAInto(data, size, webp.get(), webpSize, stride)) { throw std::runtime_error("failed to decode WebP data"); } UnassociatedImage image { size_t(width), size_t(height), std::move(webp) }; return util::premultiply(std::move(image)); }
/*! * \brief pixReadMemWebP() * * \param[in] filedata webp compressed data in memory * \param[in] filesize number of bytes in data * \return pix 32 bpp, or NULL on error * * <pre> * Notes: * (1) When the encoded data only has 3 channels (no alpha), * WebPDecodeRGBAInto() generates a raster of 32-bit pixels, with * the alpha channel set to opaque (255). * (2) We don't need to use the gnu runtime functions like fmemopen() * for redirecting data from a stream to memory, because * the webp library has been written with memory-to-memory * functions at the lowest level (which is good!). And, in * any event, fmemopen() doesn't work with l_binaryReadStream(). * </pre> */ PIX * pixReadMemWebP(const l_uint8 *filedata, size_t filesize) { l_uint8 *out = NULL; l_int32 w, h, has_alpha, wpl, stride; l_uint32 *data; size_t size; PIX *pix; WebPBitstreamFeatures features; PROCNAME("pixReadMemWebP"); if (!filedata) return (PIX *)ERROR_PTR("filedata not defined", procName, NULL); if (WebPGetFeatures(filedata, filesize, &features)) return (PIX *)ERROR_PTR("Invalid WebP file", procName, NULL); w = features.width; h = features.height; has_alpha = features.has_alpha; /* Write from compressed Y,U,V arrays to pix raster data */ pix = pixCreate(w, h, 32); pixSetInputFormat(pix, IFF_WEBP); if (has_alpha) pixSetSpp(pix, 4); data = pixGetData(pix); wpl = pixGetWpl(pix); stride = wpl * 4; size = stride * h; out = WebPDecodeRGBAInto(filedata, filesize, (uint8_t *)data, size, stride); if (out == NULL) { /* error: out should also point to data */ pixDestroy(&pix); return (PIX *)ERROR_PTR("WebP decode failed", procName, NULL); } /* 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(pix); return pix; }
std::auto_ptr<Image> WebPFormat::read(byte_source* src, ImageFactory* factory, const options_map& opts) { std::vector<byte> data = full_data(*src); int w, h; int ok = WebPGetInfo(&data[0], data.size(), &w, &h); if (!ok) { throw CannotReadError("imread.imread._webp: File does not validate as WebP"); } std::auto_ptr<Image> output(factory->create(8, h, w, 4)); const int stride = w*4; const uint8_t* p = WebPDecodeRGBAInto( &data[0], data.size(), output->rowp_as<byte>(0), h*stride, stride); if (p != output->rowp_as<uint8_t>(0)) { throw CannotReadError("imread.imread._webp: Error in decoding file"); } return output; }
CPLErr WEBPDataset::Uncompress() { if (bHasBeenUncompressed) return eUncompressErrRet; bHasBeenUncompressed = TRUE; eUncompressErrRet = CE_Failure; pabyUncompressed = (GByte*)VSIMalloc3(nRasterXSize, nRasterYSize, nBands); if (pabyUncompressed == NULL) return CE_Failure; VSIFSeekL(fpImage, 0, SEEK_END); vsi_l_offset nSize = VSIFTellL(fpImage); if (nSize != (vsi_l_offset)(uint32_t)nSize) return CE_Failure; VSIFSeekL(fpImage, 0, SEEK_SET); uint8_t* pabyCompressed = (uint8_t*)VSIMalloc(nSize); if (pabyCompressed == NULL) return CE_Failure; VSIFReadL(pabyCompressed, 1, nSize, fpImage); uint8_t* pRet; if (nBands == 4) pRet = WebPDecodeRGBAInto(pabyCompressed, (uint32_t)nSize, (uint8_t*)pabyUncompressed, nRasterXSize * nRasterYSize * nBands, nRasterXSize * nBands); else pRet = WebPDecodeRGBInto(pabyCompressed, (uint32_t)nSize, (uint8_t*)pabyUncompressed, nRasterXSize * nRasterYSize * nBands, nRasterXSize * nBands); VSIFree(pabyCompressed); if (pRet == NULL) { CPLError(CE_Failure, CPLE_AppDefined, "WebPDecodeRGBInto() failed"); return CE_Failure; } eUncompressErrRet = CE_None; return CE_None; }
/*! * pixReadMemWebP() * * Input: filedata (webp compressed data in memory) * filesize (number of bytes in data) * Return: pix (32 bpp), or null on error * * Notes: * (1) When the encoded data only has 3 channels (no alpha), * WebPDecodeRGBAInto() generates a raster of 32-bit pixels, with * the alpha channel set to opaque (255). * (2) We don't need to use the gnu runtime functions like fmemopen() * for redirecting data from a stream to memory, because * the webp library has been written with memory-to-memory * functions at the lowest level (which is good!). And, in * any event, fmemopen() doesn't work with l_binaryReadStream(). */ PIX * pixReadMemWebP(const l_uint8 *filedata, size_t filesize) { l_uint8 *out = NULL; l_int32 w, h, has_alpha, wpl, stride; l_uint32 *data; size_t size; PIX *pix; WebPBitstreamFeatures features; PROCNAME("pixReadMemWebP"); if (!filedata) return (PIX *)ERROR_PTR("filedata not defined", procName, NULL); if (WebPGetFeatures(filedata, filesize, &features)) return (PIX *)ERROR_PTR("Invalid WebP file", procName, NULL); w = features.width; h = features.height; has_alpha = features.has_alpha; /* Write from compressed Y,U,V arrays to pix raster data */ pix = pixCreate(w, h, 32); if (has_alpha) pixSetSpp(pix, 4); data = pixGetData(pix); wpl = pixGetWpl(pix); stride = wpl * 4; size = stride * h; out = WebPDecodeRGBAInto(filedata, filesize, (uint8_t *)data, size, stride); if (out == NULL) { /* error: out should also point to data */ pixDestroy(&pix); return (PIX *)ERROR_PTR("WebP decode failed", procName, NULL); } /* WebP decoder emits opposite byte order for RGBA components */ pixEndianByteSwap(pix); return pix; }
static Ref<Image> _webp_lossy_unpack(const PoolVector<uint8_t> &p_buffer) { int size = p_buffer.size() - 4; ERR_FAIL_COND_V(size <= 0, Ref<Image>()); PoolVector<uint8_t>::Read r = p_buffer.read(); ERR_FAIL_COND_V(r[0] != 'W' || r[1] != 'E' || r[2] != 'B' || r[3] != 'P', Ref<Image>()); WebPBitstreamFeatures features; if (WebPGetFeatures(&r[4], size, &features) != VP8_STATUS_OK) { ERR_EXPLAIN("Error unpacking WEBP image:"); ERR_FAIL_V(Ref<Image>()); } /* print_line("width: "+itos(features.width)); print_line("height: "+itos(features.height)); print_line("alpha: "+itos(features.has_alpha)); */ PoolVector<uint8_t> dst_image; int datasize = features.width * features.height * (features.has_alpha ? 4 : 3); dst_image.resize(datasize); PoolVector<uint8_t>::Write dst_w = dst_image.write(); bool errdec = false; if (features.has_alpha) { errdec = WebPDecodeRGBAInto(&r[4], size, dst_w.ptr(), datasize, 4 * features.width) == NULL; } else { errdec = WebPDecodeRGBInto(&r[4], size, dst_w.ptr(), datasize, 3 * features.width) == NULL; } //ERR_EXPLAIN("Error decoding webp! - "+p_file); ERR_FAIL_COND_V(errdec, Ref<Image>()); dst_w = PoolVector<uint8_t>::Write(); Ref<Image> img = memnew(Image(features.width, features.height, 0, features.has_alpha ? Image::FORMAT_RGBA8 : Image::FORMAT_RGB8, dst_image)); return img; }
int ImageFormatWEBP::load(const char *name, int& width, int& height, int& format) { printf("ImageFormatWEBP::load\n"); // Open File FILE* file = fopen(name,"rb"); if (file == 0) { printf("ImageFormatWEBP::load(): can't open file '%s'\n",name); return 0; } // init width / height / format value to 0 width = 0; height = 0; format = 0; // size of file fseek(file,0,SEEK_END); const long data_size = ftell(file); fseek(file,0,SEEK_SET); unsigned char * img_data = new unsigned char[data_size]; fread(img_data,data_size,1,file); fclose(file); // Get header info int webpinfo = WebPGetInfo(img_data, data_size, &width, &height); if (webpinfo == 0) { printf("ImageFormatWEBP::load(): wrong header in \"%s\" file\n",name); delete img_data; return 0; } // Get betstream WebPBitstreamFeatures features; VP8StatusCode status = WebPGetFeatures(img_data, data_size, &features); if (status != VP8_STATUS_OK) { printf("ImageFormatWEBP::load(): bad bitstream in \"%s\" file, error:\"%d\"\n",name,status); delete img_data; return 0; } format = features.has_alpha ? 4 : 3; int data_decoded_size = width * height * format; // raw data image container unsigned char * img_data_decoded = new unsigned char[data_decoded_size]; memset(img_data_decoded,0x00,data_decoded_size); // decode image inside container (RGB and RGBA) if (format == 3 ) { if ( WebPDecodeRGBInto(img_data, data_size, img_data_decoded, data_decoded_size, width * format) == NULL ) { printf("ImageFormatWEBP::load(): can't decode RGB \"%s\" file\n",name); delete img_data; delete img_data_decoded; return 0; } } else { if ( WebPDecodeRGBAInto(img_data, data_size, img_data_decoded, data_decoded_size, width * format) == NULL ) { printf("ImageFormatWEBP::load(): can't decode RGBA \"%s\" file\n",name); delete img_data; delete img_data_decoded; return 0; } } // create temporary file for glue code javascript FILE* raw = fopen(kTempararyName,"wb"); if (raw) { fwrite(img_data_decoded,data_decoded_size ,1 , raw); fclose(raw); } delete img_data; delete img_data_decoded; return 1; }