static bool encodePixels(IntSize imageSize, const unsigned char* pixels, bool premultiplied, int quality, Vector<unsigned char>* output) { if (imageSize.width() <= 0 || imageSize.width() > WEBP_MAX_DIMENSION) return false; if (imageSize.height() <= 0 || imageSize.height() > WEBP_MAX_DIMENSION) return false; WebPConfig config; if (!WebPConfigInit(&config)) return false; WebPPicture picture; if (!WebPPictureInit(&picture)) return false; picture.width = imageSize.width(); picture.height = imageSize.height(); if (premultiplied && !platformPremultipliedImportPicture(pixels, &picture)) return false; if (!premultiplied && !importPictureRGBX<false>(pixels, &picture)) return false; picture.custom_ptr = output; picture.writer = &writeOutput; config.quality = quality; config.method = 3; bool success = WebPEncode(&config, &picture); WebPPictureFree(&picture); return success; }
static size_t encode(const uint8_t* rgba, int width, int height, uint8_t** output) { WebPPicture pic; WebPConfig config; WebPMemoryWriter wrt; int ok; if (!WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, 100) || !WebPPictureInit(&pic)) { return 0; } config.lossless = true; config.method = 6; pic.use_argb = true; pic.width = width; pic.height = height; pic.writer = WebPMemoryWrite; pic.custom_ptr = &wrt; WebPMemoryWriterInit(&wrt); ok = WebPPictureImportRGBA(&pic, rgba, width * 4) && WebPEncode(&config, &pic); WebPPictureFree(&pic); if (!ok) return 0; *output = wrt.mem; return wrt.size; }
bool WebpOutput::write_scanline (int y, int z, TypeDesc format, const void *data, stride_t xstride) { if (y > m_spec.height) { error ("Attempt to write too many scanlines to %s", m_filename.c_str()); close (); return false; } std::vector<uint8_t> scratch; data = to_native_scanline (format, data, xstride, scratch, m_dither, y, z); memcpy(&m_uncompressed_image[y*m_scanline_size], data, m_scanline_size); if (y == m_spec.height - 1) { if (m_spec.nchannels == 4) { WebPPictureImportRGBA(&m_webp_picture, &m_uncompressed_image[0], m_scanline_size); } else { WebPPictureImportRGB(&m_webp_picture, &m_uncompressed_image[0], m_scanline_size); } if (!WebPEncode(&m_webp_config, &m_webp_picture)) { error ("Failed to encode %s as WebP image", m_filename.c_str()); close(); return false; } } return true; }
static gboolean export_webp (GeglOperation *operation, GeglBuffer *input, const GeglRectangle *result, GOutputStream *stream) { GeglProperties *o = GEGL_PROPERTIES (operation); WebPConfig config; WebPPicture picture; const Babl *format; gint status; g_return_val_if_fail (stream != NULL, FALSE); if (!WebPConfigInit (&config) || !WebPPictureInit (&picture)) { g_warning ("could not initialize WebP encoder"); return FALSE; } if (!WebPConfigPreset (&config, WEBP_PRESET_DEFAULT, o->quality)) { g_warning("could not load WebP default preset"); return FALSE; } picture.width = result->width; picture.height = result->height; format = babl_format ("R'G'B'A u8"); if (!WebPValidateConfig (&config)) { g_warning ("WebP encoder configuration is invalid"); return FALSE; } picture.writer = write_to_stream; picture.custom_ptr = stream; if (save_RGBA (&picture, input, result, format)) { g_warning ("could not pass pixels data to WebP encoder"); return FALSE; } status = WebPEncode (&config, &picture); WebPPictureFree (&picture); return status ? TRUE : FALSE; }
static int EncodeFrame(const WebPConfig* const config, WebPPicture* const pic, WebPData* const encoded_data) { WebPMemoryWriter memory; pic->use_argb = 1; pic->writer = WebPMemoryWrite; pic->custom_ptr = &memory; WebPMemoryWriterInit(&memory); if (!WebPEncode(config, pic)) { return 0; } encoded_data->bytes = memory.mem; encoded_data->size = memory.size; return 1; }
static int libwebp_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame, int *got_packet) { LibWebPContext *s = avctx->priv_data; WebPPicture *pic = NULL; AVFrame *alt_frame = NULL; WebPMemoryWriter mw = { 0 }; int ret = ff_libwebp_get_frame(avctx, s, frame, &alt_frame, &pic); if (ret < 0) goto end; WebPMemoryWriterInit(&mw); pic->custom_ptr = &mw; pic->writer = WebPMemoryWrite; ret = WebPEncode(&s->config, pic); if (!ret) { av_log(avctx, AV_LOG_ERROR, "WebPEncode() failed with error: %d\n", pic->error_code); ret = ff_libwebp_error_to_averror(pic->error_code); goto end; } ret = ff_alloc_packet(pkt, mw.size); if (ret < 0) goto end; memcpy(pkt->data, mw.mem, mw.size); pkt->flags |= AV_PKT_FLAG_KEY; *got_packet = 1; end: #if (WEBP_ENCODER_ABI_VERSION > 0x0203) WebPMemoryWriterClear(&mw); #else free(mw.mem); /* must use free() according to libwebp documentation */ #endif WebPPictureFree(pic); av_freep(&pic); av_frame_free(&alt_frame); return ret; }
/* * Finish off an encoded strip by flushing it. */ static int TWebPPostEncode(TIFF* tif) { static const char module[] = "WebPPostEncode"; int64_t stride; WebPState *sp = EncoderState(tif); assert(sp != NULL); assert(sp->state == LSTATE_INIT_ENCODE); stride = (int64_t)sp->sPicture.width * sp->nSamples; #if WEBP_ENCODER_ABI_VERSION >= 0x0100 if (sp->nSamples == 4) { if (!WebPPictureImportRGBA(&sp->sPicture, sp->pBuffer, (int)stride)) { TIFFErrorExt(tif->tif_clientdata, module, "WebPPictureImportRGBA() failed" ); return 0; } } else #endif if (!WebPPictureImportRGB(&sp->sPicture, sp->pBuffer, (int)stride)) { TIFFErrorExt(tif->tif_clientdata, module, "WebPPictureImportRGB() failed"); return 0; } if (!WebPEncode(&sp->sEncoderConfig, &sp->sPicture)) { #if WEBP_ENCODER_ABI_VERSION >= 0x0100 const char* pszErrorMsg = NULL; switch(sp->sPicture.error_code) { case VP8_ENC_ERROR_OUT_OF_MEMORY: pszErrorMsg = "Out of memory"; break; case VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY: pszErrorMsg = "Out of memory while flushing bits"; break; case VP8_ENC_ERROR_NULL_PARAMETER: pszErrorMsg = "A pointer parameter is NULL"; break; case VP8_ENC_ERROR_INVALID_CONFIGURATION: pszErrorMsg = "Configuration is invalid"; break; case VP8_ENC_ERROR_BAD_DIMENSION: pszErrorMsg = "Picture has invalid width/height"; break; case VP8_ENC_ERROR_PARTITION0_OVERFLOW: pszErrorMsg = "Partition is bigger than 512k. Try using less " "SEGMENTS, or increase PARTITION_LIMIT value"; break; case VP8_ENC_ERROR_PARTITION_OVERFLOW: pszErrorMsg = "Partition is bigger than 16M"; break; case VP8_ENC_ERROR_BAD_WRITE: pszErrorMsg = "Error while fludshing bytes"; break; case VP8_ENC_ERROR_FILE_TOO_BIG: pszErrorMsg = "File is bigger than 4G"; break; case VP8_ENC_ERROR_USER_ABORT: pszErrorMsg = "User interrupted"; break; default: TIFFErrorExt(tif->tif_clientdata, module, "WebPEncode returned an unknown error code: %d", sp->sPicture.error_code); pszErrorMsg = "Unknown WebP error type."; break; } TIFFErrorExt(tif->tif_clientdata, module, "WebPEncode() failed : %s", pszErrorMsg); #else TIFFErrorExt(tif->tif_clientdata, module, "Error in WebPEncode()"); #endif return 0; } sp->sPicture.custom_ptr = NULL; if (!TIFFFlushData1(tif)) { TIFFErrorExt(tif->tif_clientdata, module, "Error flushing TIFF WebP encoder."); return 0; } return 1; }
static MagickBooleanType WriteWEBPImage(const ImageInfo *image_info, Image *image) { int webp_status; MagickBooleanType status; register const PixelPacket *__restrict__ p; register ssize_t x; register unsigned char *__restrict__ q; ssize_t y; unsigned char *pixels; WebPConfig configure; WebPPicture picture; WebPAuxStats statistics; /* Open output image file. */ assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickSignature); assert(image != (Image *) NULL); assert(image->signature == MagickSignature); if (image->debug != MagickFalse) (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); if (status == MagickFalse) return(status); if (WebPPictureInit(&picture) == 0) ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); picture.writer=WebPWriter; picture.custom_ptr=(void *) image; picture.stats=(&statistics); picture.width=(int) image->columns; picture.height=(int) image->rows; if (image->quality != UndefinedCompressionQuality) configure.quality=(float) image->quality; if (WebPConfigInit(&configure) == 0) ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); /* Future: set custom configuration parameters here. */ if (WebPValidateConfig(&configure) == 0) ThrowWriterException(ResourceLimitError,"UnableToEncodeImageFile"); /* Allocate memory for pixels. */ pixels=(unsigned char *) AcquireQuantumMemory(image->columns, (image->matte != MagickFalse ? 4 : 3)*image->rows*sizeof(*pixels)); if (pixels == (unsigned char *) NULL) ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); /* Convert image to WebP raster pixels. */ q=pixels; for (y=0; y < (ssize_t) image->rows; y++) { p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception); if (p == (PixelPacket *) NULL) break; for (x=0; x < (ssize_t) image->columns; x++) { *q++=ScaleQuantumToChar(GetRedPixelComponent(p)); *q++=ScaleQuantumToChar(GetGreenPixelComponent(p)); *q++=ScaleQuantumToChar(GetBluePixelComponent(p)); if (image->matte != MagickFalse) *q++=ScaleQuantumToChar((Quantum) (QuantumRange- (image->matte != MagickFalse ? GetOpacityPixelComponent(p) : OpaqueOpacity))); p++; } status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, image->rows); if (status == MagickFalse) break; } if (image->matte == MagickFalse) webp_status=WebPPictureImportRGB(&picture,pixels,3*picture.width); else webp_status=WebPPictureImportRGBA(&picture,pixels,4*picture.width); pixels=(unsigned char *) RelinquishMagickMemory(pixels); webp_status=WebPEncode(&configure,&picture); (void) CloseBlob(image); return(webp_status == 0 ? MagickFalse : MagickTrue); }
/** Encode a FIBITMAP to a WebP image @param hmem Memory output stream, containing on return the encoded image @param dib The FIBITMAP to encode @param flags FreeImage save flags @return Returns TRUE if successfull, returns FALSE otherwise */ static BOOL EncodeImage(FIMEMORY *hmem, FIBITMAP *dib, int flags) { WebPPicture picture; // Input buffer WebPConfig config; // Coding parameters BOOL bIsFlipped = FALSE; try { const unsigned width = FreeImage_GetWidth(dib); const unsigned height = FreeImage_GetHeight(dib); const unsigned bpp = FreeImage_GetBPP(dib); const unsigned pitch = FreeImage_GetPitch(dib); // check image type FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); if( !((image_type == FIT_BITMAP) && ((bpp == 24) || (bpp == 32))) ) { throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; } // check format limits if(MAX(width, height) > WEBP_MAX_DIMENSION) { FreeImage_OutputMessageProc(s_format_id, "Unsupported image size: width x height = %d x %d", width, height); return FALSE; } // Initialize output I/O if(WebPPictureInit(&picture) == 1) { picture.writer = WebP_MemoryWriter; picture.custom_ptr = hmem; picture.width = (int)width; picture.height = (int)height; } else { throw "Couldn't initialize WebPPicture"; } // --- Set encoding parameters --- // Initialize encoding parameters to default values WebPConfigInit(&config); // quality/speed trade-off (0=fast, 6=slower-better) config.method = 6; if((flags & WEBP_LOSSLESS) == WEBP_LOSSLESS) { // lossless encoding config.lossless = 1; picture.use_argb = 1; } else if((flags & 0x7F) > 0) { // lossy encoding config.lossless = 0; // quality is between 1 (smallest file) and 100 (biggest) - default to 75 config.quality = (float)(flags & 0x7F); if(config.quality > 100) { config.quality = 100; } } // validate encoding parameters if(WebPValidateConfig(&config) == 0) { throw "Failed to initialize encoder"; } // --- Perform encoding --- // Invert dib scanlines bIsFlipped = FreeImage_FlipVertical(dib); // convert dib buffer to output stream const BYTE *bits = FreeImage_GetBits(dib); #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR switch(bpp) { case 24: WebPPictureImportBGR(&picture, bits, pitch); break; case 32: WebPPictureImportBGRA(&picture, bits, pitch); break; } #else switch(bpp) { case 24: WebPPictureImportRGB(&picture, bits, pitch); break; case 32: WebPPictureImportRGBA(&picture, bits, pitch); break; } #endif // FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR if(!WebPEncode(&config, &picture)) { throw "Failed to encode image"; } WebPPictureFree(&picture); if(bIsFlipped) { // invert dib scanlines FreeImage_FlipVertical(dib); } return TRUE; } catch (const char* text) { WebPPictureFree(&picture); if(bIsFlipped) { // invert dib scanlines FreeImage_FlipVertical(dib); } if(NULL != text) { FreeImage_OutputMessageProc(s_format_id, text); } } return FALSE; }
int webp_encode(const char *in_file, const char *out_file, const FfiWebpEncodeConfig *encode_config) { int return_value = -1; FILE *out = NULL; int keep_alpha = 1; WebPPicture picture; WebPConfig config; // OPTIONS BEGIN if (encode_config->lossless == 0 || encode_config->lossless == 1){ config.lossless = encode_config->lossless; } if (encode_config->quality >= 0 && encode_config->quality <= 100){ config.quality = encode_config->quality; } if (encode_config->method >= 0 && encode_config->method <= 6){ config.method = encode_config->method; } if (encode_config->target_size > 0){ config.target_size = encode_config->target_size; } if (encode_config->target_PSNR > 0){ config.target_PSNR = encode_config->target_PSNR; } if (encode_config->segments >= 0 && encode_config->segments <= 4){ config.segments = encode_config->segments; } if (encode_config->sns_strength >= 0 && encode_config->sns_strength <= 100){ config.sns_strength = encode_config->sns_strength; } if (encode_config->filter_strength >= 0 && encode_config->filter_strength <= 100){ config.filter_strength = encode_config->filter_strength; } if (encode_config->filter_sharpness >= 0 && encode_config->filter_sharpness <= 7){ config.filter_sharpness = encode_config->filter_sharpness; } if (encode_config->filter_type == 0 || encode_config->filter_type == 1){ config.filter_type = encode_config->filter_type; } if (encode_config->autofilter == 0 || encode_config->autofilter == 1){ config.autofilter = encode_config->autofilter; } if (encode_config->alpha_compression == 0 || encode_config->alpha_compression == 1){ config.alpha_compression = encode_config->alpha_compression; } if (encode_config->alpha_filtering >= 0 && encode_config->alpha_filtering <= 2){ config.alpha_filtering = encode_config->alpha_filtering; } if (encode_config->alpha_quality >= 0 && encode_config->alpha_quality <= 100){ config.alpha_quality = encode_config->alpha_quality; } if (encode_config->pass >= 0 && encode_config->pass <= 10){ config.pass = encode_config->pass; } if (encode_config->show_compressed >= 0){ config.show_compressed = encode_config->show_compressed; } if (encode_config->preprocessing == 0 || encode_config->preprocessing == 1){ config.preprocessing = encode_config->preprocessing; } if (encode_config->partitions >= 0 && encode_config->partitions <= 3){ config.partitions = encode_config->partitions; } if (encode_config->partition_limit >= 0 && encode_config->partition_limit <= 100){ config.partition_limit = encode_config->partition_limit; } if ((encode_config->width | encode_config->height) > 0){ picture.width = encode_config->width; picture.height = encode_config->height; } // OPTIONS END if (!WebPPictureInit(&picture) || !WebPConfigInit(&config)) { //fprintf(stderr, "Error! Version mismatch!\n"); return 1; } if (!WebPValidateConfig(&config)) { //fprintf(stderr, "Error! Invalid configuration.\n"); return_value = 2; goto Error; } if (!UtilReadPicture(in_file, &picture, keep_alpha)) { //fprintf(stderr, "Error! Cannot read input picture file '%s'\n", in_file); return_value = 3; goto Error; } out = fopen(out_file, "wb"); if (out == NULL) { //fprintf(stderr, "Error! Cannot open output file '%s'\n", out_file); return_value = 4; goto Error; } picture.writer = EncodeWriter; picture.custom_ptr = (void*)out; if ((encode_config->crop_w | encode_config->crop_h) > 0){ if (!WebPPictureView(&picture, encode_config->crop_x, encode_config->crop_y, encode_config->crop_w, encode_config->crop_h, &picture)) { //fprintf(stderr, "Error! Cannot crop picture\n"); return_value = 5; goto Error; } } if ((encode_config->resize_w | encode_config->resize_h) > 0) { if (!WebPPictureRescale(&picture, encode_config->resize_w, encode_config->resize_h)) { //fprintf(stderr, "Error! Cannot resize picture\n"); return_value = 6; goto Error; } } if (picture.extra_info_type > 0) { AllocExtraInfo(&picture); } if (!WebPEncode(&config, &picture)) { //fprintf(stderr, "Error! Cannot encode picture as WebP\n"); return_value = 7; goto Error; } return_value = 0; Error: free(picture.extra_info); WebPPictureFree(&picture); if (out != NULL) { fclose(out); } return return_value; }
GDALDataset * WEBPDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS, int bStrict, char ** papszOptions, GDALProgressFunc pfnProgress, void * pProgressData ) { int nBands = poSrcDS->GetRasterCount(); int nXSize = poSrcDS->GetRasterXSize(); int nYSize = poSrcDS->GetRasterYSize(); /* -------------------------------------------------------------------- */ /* WEBP library initialization */ /* -------------------------------------------------------------------- */ WebPPicture sPicture; if (!WebPPictureInit(&sPicture)) { CPLError(CE_Failure, CPLE_AppDefined, "WebPPictureInit() failed"); return NULL; } /* -------------------------------------------------------------------- */ /* Some some rudimentary checks */ /* -------------------------------------------------------------------- */ if( nXSize > 16383 || nYSize > 16383 ) { CPLError( CE_Failure, CPLE_NotSupported, "WEBP maximum image dimensions are 16383 x 16383."); return NULL; } if( nBands != 3 ) { CPLError( CE_Failure, CPLE_NotSupported, "WEBP driver doesn't support %d bands. Must be 3 (RGB) bands.", nBands ); return NULL; } GDALDataType eDT = poSrcDS->GetRasterBand(1)->GetRasterDataType(); if( eDT != GDT_Byte ) { CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported, "WEBP driver doesn't support data type %s. " "Only eight bit byte bands supported.", GDALGetDataTypeName( poSrcDS->GetRasterBand(1)->GetRasterDataType()) ); if (bStrict) return NULL; } /* -------------------------------------------------------------------- */ /* What options has the user selected? */ /* -------------------------------------------------------------------- */ float fQuality = 75.0f; const char* pszQUALITY = CSLFetchNameValue(papszOptions, "QUALITY"); if( pszQUALITY != NULL ) { fQuality = (float) atof(pszQUALITY); if( fQuality < 0.0f || fQuality > 100.0f ) { CPLError( CE_Failure, CPLE_IllegalArg, "%s=%s is not a legal value.", "QUALITY", pszQUALITY); return NULL; } } WebPPreset nPreset = WEBP_PRESET_DEFAULT; const char* pszPRESET = CSLFetchNameValueDef(papszOptions, "PRESET", "DEFAULT"); if (EQUAL(pszPRESET, "DEFAULT")) nPreset = WEBP_PRESET_DEFAULT; else if (EQUAL(pszPRESET, "PICTURE")) nPreset = WEBP_PRESET_PICTURE; else if (EQUAL(pszPRESET, "PHOTO")) nPreset = WEBP_PRESET_PHOTO; else if (EQUAL(pszPRESET, "PICTURE")) nPreset = WEBP_PRESET_PICTURE; else if (EQUAL(pszPRESET, "DRAWING")) nPreset = WEBP_PRESET_DRAWING; else if (EQUAL(pszPRESET, "ICON")) nPreset = WEBP_PRESET_ICON; else if (EQUAL(pszPRESET, "TEXT")) nPreset = WEBP_PRESET_TEXT; else { CPLError( CE_Failure, CPLE_IllegalArg, "%s=%s is not a legal value.", "PRESET", pszPRESET ); return NULL; } WebPConfig sConfig; if (!WebPConfigInitInternal(&sConfig, nPreset, fQuality, WEBP_ENCODER_ABI_VERSION)) { CPLError(CE_Failure, CPLE_AppDefined, "WebPConfigInit() failed"); return NULL; } #define FETCH_AND_SET_OPTION_INT(name, fieldname, minval, maxval) \ { \ const char* pszVal = CSLFetchNameValue(papszOptions, name); \ if (pszVal != NULL) \ { \ sConfig.fieldname = atoi(pszVal); \ if (sConfig.fieldname < minval || sConfig.fieldname > maxval) \ { \ CPLError( CE_Failure, CPLE_IllegalArg, \ "%s=%s is not a legal value.", name, pszVal ); \ return NULL; \ } \ } \ } FETCH_AND_SET_OPTION_INT("TARGETSIZE", target_size, 0, INT_MAX); const char* pszPSNR = CSLFetchNameValue(papszOptions, "PSNR"); if (pszPSNR) { sConfig.target_PSNR = atof(pszPSNR); if (sConfig.target_PSNR < 0) { CPLError( CE_Failure, CPLE_IllegalArg, "PSNR=%s is not a legal value.", pszPSNR ); return NULL; } } FETCH_AND_SET_OPTION_INT("METHOD", method, 0, 6); FETCH_AND_SET_OPTION_INT("SEGMENTS", segments, 1, 4); FETCH_AND_SET_OPTION_INT("SNS_STRENGTH", sns_strength, 0, 100); FETCH_AND_SET_OPTION_INT("FILTER_STRENGTH", filter_strength, 0, 100); FETCH_AND_SET_OPTION_INT("FILTER_SHARPNESS", filter_sharpness, 0, 7); FETCH_AND_SET_OPTION_INT("FILTER_TYPE", filter_type, 0, 1); FETCH_AND_SET_OPTION_INT("AUTOFILTER", autofilter, 0, 1); FETCH_AND_SET_OPTION_INT("PASS", pass, 1, 10); FETCH_AND_SET_OPTION_INT("PREPROCESSING", preprocessing, 0, 1); FETCH_AND_SET_OPTION_INT("PARTITIONS", partitions, 0, 3); if (!WebPValidateConfig(&sConfig)) { CPLError(CE_Failure, CPLE_AppDefined, "WebPValidateConfig() failed"); return NULL; } /* -------------------------------------------------------------------- */ /* Allocate memory */ /* -------------------------------------------------------------------- */ GByte *pabyBuffer; pabyBuffer = (GByte *) VSIMalloc( 3 * nXSize * nYSize ); if (pabyBuffer == NULL) { return NULL; } /* -------------------------------------------------------------------- */ /* Create the dataset. */ /* -------------------------------------------------------------------- */ VSILFILE *fpImage; fpImage = VSIFOpenL( pszFilename, "wb" ); if( fpImage == NULL ) { CPLError( CE_Failure, CPLE_OpenFailed, "Unable to create WEBP file %s.\n", pszFilename ); VSIFree(pabyBuffer); return NULL; } /* -------------------------------------------------------------------- */ /* WEBP library settings */ /* -------------------------------------------------------------------- */ sPicture.colorspace = 0; sPicture.width = nXSize; sPicture.height = nYSize; sPicture.writer = WEBPDatasetWriter; sPicture.custom_ptr = fpImage; if (!WebPPictureAlloc(&sPicture)) { CPLError(CE_Failure, CPLE_AppDefined, "WebPPictureAlloc() failed"); VSIFree(pabyBuffer); VSIFCloseL( fpImage ); return NULL; } /* -------------------------------------------------------------------- */ /* Acquire source imagery. */ /* -------------------------------------------------------------------- */ CPLErr eErr = CE_None; eErr = poSrcDS->RasterIO( GF_Read, 0, 0, nXSize, nYSize, pabyBuffer, nXSize, nYSize, GDT_Byte, 3, NULL, 3, 3 * nXSize, 1 ); /* -------------------------------------------------------------------- */ /* Import and write to file */ /* -------------------------------------------------------------------- */ if (eErr == CE_None && !WebPPictureImportRGB(&sPicture, pabyBuffer, 3 * nXSize)) { CPLError(CE_Failure, CPLE_AppDefined, "WebPPictureImportRGB() failed"); eErr = CE_Failure; } if (eErr == CE_None && !WebPEncode(&sConfig, &sPicture)) { CPLError(CE_Failure, CPLE_AppDefined, "WebPEncode() failed"); eErr = CE_Failure; } /* -------------------------------------------------------------------- */ /* Cleanup and close. */ /* -------------------------------------------------------------------- */ CPLFree( pabyBuffer ); WebPPictureFree(&sPicture); VSIFCloseL( fpImage ); if( eErr != CE_None ) { VSIUnlink( pszFilename ); return NULL; } /* -------------------------------------------------------------------- */ /* Re-open dataset, and copy any auxilary pam information. */ /* -------------------------------------------------------------------- */ GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly); /* If outputing to stdout, we can't reopen it, so we'll return */ /* a fake dataset to make the caller happy */ CPLPushErrorHandler(CPLQuietErrorHandler); WEBPDataset *poDS = (WEBPDataset*) WEBPDataset::Open( &oOpenInfo ); CPLPopErrorHandler(); if( poDS ) { poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT ); return poDS; } return NULL; }
int encodeWEBP(Vbitmap *vbitmap, Ychannel *channelout, YmagineFormatOptions *options) { int rc = YMAGINE_ERROR; #if HAVE_WEBP WebPConfig config; WebPPicture picture; WebPPreset preset = WEBP_PRESET_PHOTO; // One of DEFAULT, PICTURE, PHOTO, DRAWING, ICON or TEXT int width; int height; int pitch; int quality; const unsigned char *pixels; int colormode; /* * List of encoding options for WebP config * int lossless; // Lossless encoding (0=lossy(default), 1=lossless). * float quality; // between 0 (smallest file) and 100 (biggest) * int method; // quality/speed trade-off (0=fast, 6=slower-better) * * WebPImageHint image_hint; // Hint for image type (lossless only for now). * * // Parameters related to lossy compression only: * int target_size; // if non-zero, set the desired target size in bytes. * // Takes precedence over the 'compression' parameter. * float target_PSNR; // if non-zero, specifies the minimal distortion to * // try to achieve. Takes precedence over target_size. * int segments; // maximum number of segments to use, in [1..4] * int sns_strength; // Spatial Noise Shaping. 0=off, 100=maximum. * int filter_strength; // range: [0 = off .. 100 = strongest] * int filter_sharpness; // range: [0 = off .. 7 = least sharp] * int filter_type; // filtering type: 0 = simple, 1 = strong (only used * // if filter_strength > 0 or autofilter > 0) * int autofilter; // Auto adjust filter's strength [0 = off, 1 = on] * int alpha_compression; // Algorithm for encoding the alpha plane (0 = none, * // 1 = compressed with WebP lossless). Default is 1. * int alpha_filtering; // Predictive filtering method for alpha plane. * // 0: none, 1: fast, 2: best. Default if 1. * int alpha_quality; // Between 0 (smallest size) and 100 (lossless). * // Default is 100. * int pass; // number of entropy-analysis passes (in [1..10]). * * int show_compressed; // if true, export the compressed picture back. * // In-loop filtering is not applied. * int preprocessing; // preprocessing filter (0=none, 1=segment-smooth) * int partitions; // log2(number of token partitions) in [0..3] * // Default is set to 0 for easier progressive decoding. * int partition_limit; // quality degradation allowed to fit the 512k limit on * // prediction modes coding (0: no degradation, * // 100: maximum possible degradation). */ colormode = VbitmapColormode(vbitmap); if (colormode != VBITMAP_COLOR_RGBA && colormode != VBITMAP_COLOR_RGB) { ALOGD("currently only support RGB, RGBA webp encoding"); return rc; } quality = YmagineFormatOptions_normalizeQuality(options); if (!WebPConfigPreset(&config, preset, (float) quality)) { return YMAGINE_ERROR; // version error } if (options && options->accuracy >= 0) { int method = options->accuracy / 15; if (method > 6) { method = 6; } config.method = method; } if (!WebPValidateConfig(&config)) { // parameter ranges verification failed return YMAGINE_ERROR; } rc = VbitmapLock(vbitmap); if (rc < 0) { ALOGE("AndroidBitmap_lockPixels() failed"); return YMAGINE_ERROR; } width = VbitmapWidth(vbitmap); height = VbitmapHeight(vbitmap); pitch = VbitmapPitch(vbitmap); pixels = VbitmapBuffer(vbitmap); if (WebPPictureInit(&picture)) { picture.use_argb = 1; picture.width = width; picture.height = height; picture.writer = WebPYchannelWrite; picture.custom_ptr = channelout; if (colormode == VBITMAP_COLOR_RGBA) { WebPPictureImportRGBA(&picture, pixels, pitch); } else { WebPPictureImportRGB(&picture, pixels, pitch); } WebPEncode(&config, &picture); WebPPictureFree(&picture); } VbitmapUnlock(vbitmap); rc = YMAGINE_OK; #endif return rc; }
GDALDataset * WEBPDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS, int bStrict, char ** papszOptions, GDALProgressFunc pfnProgress, void * pProgressData ) { int nBands = poSrcDS->GetRasterCount(); int nXSize = poSrcDS->GetRasterXSize(); int nYSize = poSrcDS->GetRasterYSize(); /* -------------------------------------------------------------------- */ /* WEBP library initialization */ /* -------------------------------------------------------------------- */ WebPPicture sPicture; if (!WebPPictureInit(&sPicture)) { CPLError(CE_Failure, CPLE_AppDefined, "WebPPictureInit() failed"); return NULL; } /* -------------------------------------------------------------------- */ /* Some some rudimentary checks */ /* -------------------------------------------------------------------- */ if( nXSize > 16383 || nYSize > 16383 ) { CPLError( CE_Failure, CPLE_NotSupported, "WEBP maximum image dimensions are 16383 x 16383."); return NULL; } if( nBands != 3 #if WEBP_ENCODER_ABI_VERSION >= 0x0100 && nBands != 4 #endif ) { CPLError( CE_Failure, CPLE_NotSupported, "WEBP driver doesn't support %d bands. Must be 3 (RGB) " #if WEBP_ENCODER_ABI_VERSION >= 0x0100 "or 4 (RGBA) " #endif "bands.", nBands ); return NULL; } GDALDataType eDT = poSrcDS->GetRasterBand(1)->GetRasterDataType(); if( eDT != GDT_Byte ) { CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported, "WEBP driver doesn't support data type %s. " "Only eight bit byte bands supported.", GDALGetDataTypeName( poSrcDS->GetRasterBand(1)->GetRasterDataType()) ); if (bStrict) return NULL; } /* -------------------------------------------------------------------- */ /* What options has the user selected? */ /* -------------------------------------------------------------------- */ float fQuality = 75.0f; const char* pszQUALITY = CSLFetchNameValue(papszOptions, "QUALITY"); if( pszQUALITY != NULL ) { fQuality = (float) CPLAtof(pszQUALITY); if( fQuality < 0.0f || fQuality > 100.0f ) { CPLError( CE_Failure, CPLE_IllegalArg, "%s=%s is not a legal value.", "QUALITY", pszQUALITY); return NULL; } } WebPPreset nPreset = WEBP_PRESET_DEFAULT; const char* pszPRESET = CSLFetchNameValueDef(papszOptions, "PRESET", "DEFAULT"); if (EQUAL(pszPRESET, "DEFAULT")) nPreset = WEBP_PRESET_DEFAULT; else if (EQUAL(pszPRESET, "PICTURE")) nPreset = WEBP_PRESET_PICTURE; else if (EQUAL(pszPRESET, "PHOTO")) nPreset = WEBP_PRESET_PHOTO; else if (EQUAL(pszPRESET, "PICTURE")) nPreset = WEBP_PRESET_PICTURE; else if (EQUAL(pszPRESET, "DRAWING")) nPreset = WEBP_PRESET_DRAWING; else if (EQUAL(pszPRESET, "ICON")) nPreset = WEBP_PRESET_ICON; else if (EQUAL(pszPRESET, "TEXT")) nPreset = WEBP_PRESET_TEXT; else { CPLError( CE_Failure, CPLE_IllegalArg, "%s=%s is not a legal value.", "PRESET", pszPRESET ); return NULL; } WebPConfig sConfig; if (!WebPConfigInitInternal(&sConfig, nPreset, fQuality, WEBP_ENCODER_ABI_VERSION)) { CPLError(CE_Failure, CPLE_AppDefined, "WebPConfigInit() failed"); return NULL; } #define FETCH_AND_SET_OPTION_INT(name, fieldname, minval, maxval) \ { \ const char* pszVal = CSLFetchNameValue(papszOptions, name); \ if (pszVal != NULL) \ { \ sConfig.fieldname = atoi(pszVal); \ if (sConfig.fieldname < minval || sConfig.fieldname > maxval) \ { \ CPLError( CE_Failure, CPLE_IllegalArg, \ "%s=%s is not a legal value.", name, pszVal ); \ return NULL; \ } \ } \ } FETCH_AND_SET_OPTION_INT("TARGETSIZE", target_size, 0, INT_MAX); const char* pszPSNR = CSLFetchNameValue(papszOptions, "PSNR"); if (pszPSNR) { sConfig.target_PSNR = CPLAtof(pszPSNR); if (sConfig.target_PSNR < 0) { CPLError( CE_Failure, CPLE_IllegalArg, "PSNR=%s is not a legal value.", pszPSNR ); return NULL; } } FETCH_AND_SET_OPTION_INT("METHOD", method, 0, 6); FETCH_AND_SET_OPTION_INT("SEGMENTS", segments, 1, 4); FETCH_AND_SET_OPTION_INT("SNS_STRENGTH", sns_strength, 0, 100); FETCH_AND_SET_OPTION_INT("FILTER_STRENGTH", filter_strength, 0, 100); FETCH_AND_SET_OPTION_INT("FILTER_SHARPNESS", filter_sharpness, 0, 7); FETCH_AND_SET_OPTION_INT("FILTER_TYPE", filter_type, 0, 1); FETCH_AND_SET_OPTION_INT("AUTOFILTER", autofilter, 0, 1); FETCH_AND_SET_OPTION_INT("PASS", pass, 1, 10); FETCH_AND_SET_OPTION_INT("PREPROCESSING", preprocessing, 0, 1); FETCH_AND_SET_OPTION_INT("PARTITIONS", partitions, 0, 3); #if WEBP_ENCODER_ABI_VERSION >= 0x0002 FETCH_AND_SET_OPTION_INT("PARTITION_LIMIT", partition_limit, 0, 100); #endif #if WEBP_ENCODER_ABI_VERSION >= 0x0100 sConfig.lossless = CSLFetchBoolean(papszOptions, "LOSSLESS", FALSE); if (sConfig.lossless) sPicture.use_argb = 1; #endif if (!WebPValidateConfig(&sConfig)) { CPLError(CE_Failure, CPLE_AppDefined, "WebPValidateConfig() failed"); return NULL; } /* -------------------------------------------------------------------- */ /* Allocate memory */ /* -------------------------------------------------------------------- */ GByte *pabyBuffer; pabyBuffer = (GByte *) VSIMalloc( nBands * nXSize * nYSize ); if (pabyBuffer == NULL) { return NULL; } /* -------------------------------------------------------------------- */ /* Create the dataset. */ /* -------------------------------------------------------------------- */ VSILFILE *fpImage; fpImage = VSIFOpenL( pszFilename, "wb" ); if( fpImage == NULL ) { CPLError( CE_Failure, CPLE_OpenFailed, "Unable to create WEBP file %s.\n", pszFilename ); VSIFree(pabyBuffer); return NULL; } WebPUserData sUserData; sUserData.fp = fpImage; sUserData.pfnProgress = pfnProgress ? pfnProgress : GDALDummyProgress; sUserData.pProgressData = pProgressData; /* -------------------------------------------------------------------- */ /* WEBP library settings */ /* -------------------------------------------------------------------- */ sPicture.width = nXSize; sPicture.height = nYSize; sPicture.writer = WEBPDatasetWriter; sPicture.custom_ptr = &sUserData; #if WEBP_ENCODER_ABI_VERSION >= 0x0100 sPicture.progress_hook = WEBPDatasetProgressHook; #endif if (!WebPPictureAlloc(&sPicture)) { CPLError(CE_Failure, CPLE_AppDefined, "WebPPictureAlloc() failed"); VSIFree(pabyBuffer); VSIFCloseL( fpImage ); return NULL; } /* -------------------------------------------------------------------- */ /* Acquire source imagery. */ /* -------------------------------------------------------------------- */ CPLErr eErr = CE_None; eErr = poSrcDS->RasterIO( GF_Read, 0, 0, nXSize, nYSize, pabyBuffer, nXSize, nYSize, GDT_Byte, nBands, NULL, nBands, nBands * nXSize, 1, NULL ); /* -------------------------------------------------------------------- */ /* Import and write to file */ /* -------------------------------------------------------------------- */ #if WEBP_ENCODER_ABI_VERSION >= 0x0100 if (eErr == CE_None && nBands == 4) { if (!WebPPictureImportRGBA(&sPicture, pabyBuffer, nBands * nXSize)) { CPLError(CE_Failure, CPLE_AppDefined, "WebPPictureImportRGBA() failed"); eErr = CE_Failure; } } else #endif if (eErr == CE_None && !WebPPictureImportRGB(&sPicture, pabyBuffer, nBands * nXSize)) { CPLError(CE_Failure, CPLE_AppDefined, "WebPPictureImportRGB() failed"); eErr = CE_Failure; } if (eErr == CE_None && !WebPEncode(&sConfig, &sPicture)) { const char* pszErrorMsg = NULL; #if WEBP_ENCODER_ABI_VERSION >= 0x0100 switch(sPicture.error_code) { case VP8_ENC_ERROR_OUT_OF_MEMORY: pszErrorMsg = "Out of memory"; break; case VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY: pszErrorMsg = "Out of memory while flushing bits"; break; case VP8_ENC_ERROR_NULL_PARAMETER: pszErrorMsg = "A pointer parameter is NULL"; break; case VP8_ENC_ERROR_INVALID_CONFIGURATION: pszErrorMsg = "Configuration is invalid"; break; case VP8_ENC_ERROR_BAD_DIMENSION: pszErrorMsg = "Picture has invalid width/height"; break; case VP8_ENC_ERROR_PARTITION0_OVERFLOW: pszErrorMsg = "Partition is bigger than 512k. Try using less SEGMENTS, or increase PARTITION_LIMIT value"; break; case VP8_ENC_ERROR_PARTITION_OVERFLOW: pszErrorMsg = "Partition is bigger than 16M"; break; case VP8_ENC_ERROR_BAD_WRITE: pszErrorMsg = "Error while flusing bytes"; break; case VP8_ENC_ERROR_FILE_TOO_BIG: pszErrorMsg = "File is bigger than 4G"; break; case VP8_ENC_ERROR_USER_ABORT: pszErrorMsg = "User interrupted"; break; default: break; } #endif if (pszErrorMsg) CPLError(CE_Failure, CPLE_AppDefined, "WebPEncode() failed : %s", pszErrorMsg); else CPLError(CE_Failure, CPLE_AppDefined, "WebPEncode() failed"); eErr = CE_Failure; } /* -------------------------------------------------------------------- */ /* Cleanup and close. */ /* -------------------------------------------------------------------- */ CPLFree( pabyBuffer ); WebPPictureFree(&sPicture); VSIFCloseL( fpImage ); if( eErr != CE_None ) { VSIUnlink( pszFilename ); return NULL; } /* -------------------------------------------------------------------- */ /* Re-open dataset, and copy any auxiliary pam information. */ /* -------------------------------------------------------------------- */ GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly); /* If outputing to stdout, we can't reopen it, so we'll return */ /* a fake dataset to make the caller happy */ CPLPushErrorHandler(CPLQuietErrorHandler); WEBPDataset *poDS = (WEBPDataset*) WEBPDataset::Open( &oOpenInfo ); CPLPopErrorHandler(); if( poDS ) { poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT ); return poDS; } return NULL; }
bool QWebpHandler::write(const QImage &image) { if (image.isNull()) { qWarning() << "source image is null."; return false; } QImage srcImage = image; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN if (srcImage.format() != QImage::Format_ARGB32) srcImage = srcImage.convertToFormat(QImage::Format_ARGB32); #else /* Q_BIG_ENDIAN */ if (srcImage.format() != QImage::Format_RGBA8888) srcImage = srcImage.convertToFormat(QImage::Format_RGBA8888); #endif WebPPicture picture; WebPConfig config; if (!WebPPictureInit(&picture) || !WebPConfigInit(&config)) { qWarning() << "failed to init webp picture and config"; return false; } picture.width = srcImage.width(); picture.height = srcImage.height(); picture.use_argb = 1; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN if (!WebPPictureImportBGRA(&picture, srcImage.bits(), srcImage.bytesPerLine())) { #else /* Q_BIG_ENDIAN */ if (!WebPPictureImportRGBA(&picture, srcImage.bits(), srcImage.bytesPerLine())) { #endif qWarning() << "failed to import image data to webp picture."; WebPPictureFree(&picture); return false; } config.lossless = m_lossless; config.quality = m_quality; picture.writer = pictureWriter; picture.custom_ptr = device(); if (!WebPEncode(&config, &picture)) { qWarning() << "failed to encode webp picture, error code: " << picture.error_code; WebPPictureFree(&picture); return false; } WebPPictureFree(&picture); return true; } QVariant QWebpHandler::option(ImageOption option) const { if (!supportsOption(option) || !ensureScanned()) return QVariant(); switch (option) { case Quality: return m_quality; case Size: return QSize(m_width, m_height); case Animation: return (m_flags & ANIMATION_FLAG) == ANIMATION_FLAG; default: return QVariant(); } } void QWebpHandler::setOption(ImageOption option, const QVariant &value) { switch (option) { case Quality: m_quality = qBound(0, value.toInt(), 100); m_lossless = (m_quality >= 100); return; default: break; } return QImageIOHandler::setOption(option, value); } bool QWebpHandler::supportsOption(ImageOption option) const { return option == Quality || option == Size || option == Animation; } QByteArray QWebpHandler::name() const { return QByteArrayLiteral("webp"); } int QWebpHandler::imageCount() const { if (!ensureScanned()) return 0; if ((m_flags & ANIMATION_FLAG) == 0) return 1; return m_frameCount; } int QWebpHandler::currentImageNumber() const { if (!ensureScanned()) return 0; return m_iter.frame_num; } QRect QWebpHandler::currentImageRect() const { if (!ensureScanned()) return QRect(); return QRect(m_iter.x_offset, m_iter.y_offset, m_iter.width, m_iter.height); } bool QWebpHandler::jumpToImage(int imageNumber) { if (!ensureScanned()) return false; WebPDemuxReleaseIterator(&m_iter); return WebPDemuxGetFrame(m_demuxer, imageNumber, &m_iter); } bool QWebpHandler::jumpToNextImage() { if (!ensureScanned()) return false; return WebPDemuxNextFrame(&m_iter); } int QWebpHandler::loopCount() const { if (!ensureScanned() || (m_flags & ANIMATION_FLAG) == 0) return 0; return m_loop; } int QWebpHandler::nextImageDelay() const { if (!ensureScanned()) return 0; return m_iter.duration; }
static GstFlowReturn gst_webp_enc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame) { GstWebpEnc *enc = GST_WEBP_ENC (encoder); GstBuffer *out_buffer = NULL; GstVideoFrame vframe; GST_LOG_OBJECT (enc, "got new frame"); gst_webp_set_picture_params (enc); if (!gst_video_frame_map (&vframe, &enc->input_state->info, frame->input_buffer, GST_MAP_READ)) return GST_FLOW_ERROR; if (!enc->use_argb) { enc->webp_picture.y = GST_VIDEO_FRAME_COMP_DATA (&vframe, 0); enc->webp_picture.u = GST_VIDEO_FRAME_COMP_DATA (&vframe, 1); enc->webp_picture.v = GST_VIDEO_FRAME_COMP_DATA (&vframe, 2); enc->webp_picture.y_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, 0); enc->webp_picture.uv_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, 1); } else { switch (enc->rgb_format) { case GST_VIDEO_FORMAT_RGB: WebPPictureImportRGB (&enc->webp_picture, GST_VIDEO_FRAME_COMP_DATA (&vframe, 0), GST_VIDEO_FRAME_COMP_STRIDE (&vframe, 0)); break; case GST_VIDEO_FORMAT_RGBA: WebPPictureImportRGBA (&enc->webp_picture, GST_VIDEO_FRAME_COMP_DATA (&vframe, 0), GST_VIDEO_FRAME_COMP_STRIDE (&vframe, 0)); break; default: break; } } if (WebPEncode (&enc->webp_config, &enc->webp_picture)) { WebPPictureFree (&enc->webp_picture); out_buffer = gst_buffer_new_allocate (NULL, enc->webp_writer.size, NULL); if (!out_buffer) { GST_ERROR_OBJECT (enc, "Failed to create output buffer"); return GST_FLOW_ERROR; } gst_buffer_fill (out_buffer, 0, enc->webp_writer.mem, enc->webp_writer.size); free (enc->webp_writer.mem); } else { GST_ERROR_OBJECT (enc, "Failed to encode WebPPicture"); return GST_FLOW_ERROR; } gst_video_frame_unmap (&vframe); frame->output_buffer = out_buffer; return gst_video_encoder_finish_frame (encoder, frame); }
static gboolean real_save_webp (GdkPixbuf *pixbuf, gchar **keys, gchar **values, GError **error, gboolean to_callback, FILE *f, save_context *context) { WebPPicture picture; WebPConfig config; gint w, h, rowstride, has_alpha, rc; guchar *pixels; if (!WebPPictureInit(&picture) || !WebPConfigInit(&config)) { g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, "WebP encoder version mismatch."); return FALSE; } if (keys && *keys) { gchar **kiter = keys; gchar **viter = values; while (*kiter) { if (strncmp (*kiter, "quality", 7) == 0) { float quality = (float) g_ascii_strtod (*viter, NULL); if (quality < 0 || quality > 100) { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, "WebP quality must be a value between 0 and 100."); return FALSE; } config.quality = quality; } else if (strncmp (*kiter, "preset", 6) == 0) { WebPPreset preset; if (strncmp (*viter, "default", 7) == 0) { preset = WEBP_PRESET_DEFAULT; } else if (strncmp (*viter, "photo", 5) == 0) { preset = WEBP_PRESET_PHOTO; } else if (strncmp (*viter, "picture", 7) == 0) { preset = WEBP_PRESET_PICTURE; } else if (strncmp (*viter, "drawing", 7) == 0) { preset = WEBP_PRESET_DRAWING; } else if (strncmp (*viter, "icon", 4) == 0) { preset = WEBP_PRESET_ICON; } else if (strncmp (*viter, "text", 4) == 0) { preset = WEBP_PRESET_TEXT; } else { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, "WebP encoder invalid preset."); return FALSE; } if (WebPConfigPreset (&config, preset, config.quality) == 0) { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, "Could not initialize decoder with preset."); return FALSE; } } ++kiter; ++viter; } } if (WebPValidateConfig (&config) != 1) { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, "Invalid encoding configuration"); return FALSE; } w = gdk_pixbuf_get_width (pixbuf); h = gdk_pixbuf_get_height (pixbuf); rowstride = gdk_pixbuf_get_rowstride (pixbuf); has_alpha = gdk_pixbuf_get_has_alpha (pixbuf); pixels = gdk_pixbuf_get_pixels (pixbuf); picture.width = w; picture.height = h; if (has_alpha) { rc = WebPPictureImportRGBA (&picture, pixels, rowstride); } else { rc = WebPPictureImportRGB (&picture, pixels, rowstride); } if (rc == 0) { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, "Failed to allocate picture"); return FALSE; } if (to_callback) { picture.writer = save_callback; picture.custom_ptr = (void*) context; } else { picture.writer = write_file; picture.custom_ptr = (void*) f; } if (WebPEncode(&config, &picture) == 0) { fprintf(stderr, "Error! Cannot encode picture as WebP\n"); } return TRUE; }
status_t WebPTranslator::_TranslateFromBits(BPositionIO* stream, BMessage* ioExtension, uint32 outType, BPositionIO* target) { if (!outType) outType = WEBP_IMAGE_FORMAT; if (outType != WEBP_IMAGE_FORMAT) return B_NO_TRANSLATOR; TranslatorBitmap bitsHeader; status_t status; status = identify_bits_header(stream, NULL, &bitsHeader); if (status != B_OK) return status; if (bitsHeader.colors == B_CMAP8) { // TODO: support whatever colospace by intermediate colorspace conversion printf("Error! Colorspace not supported\n"); return B_NO_TRANSLATOR; } int32 bitsBytesPerPixel = 0; switch (bitsHeader.colors) { case B_RGB32: case B_RGB32_BIG: case B_RGBA32: case B_RGBA32_BIG: case B_CMY32: case B_CMYA32: case B_CMYK32: bitsBytesPerPixel = 4; break; case B_RGB24: case B_RGB24_BIG: case B_CMY24: bitsBytesPerPixel = 3; break; case B_RGB16: case B_RGB16_BIG: case B_RGBA15: case B_RGBA15_BIG: case B_RGB15: case B_RGB15_BIG: bitsBytesPerPixel = 2; break; case B_CMAP8: case B_GRAY8: bitsBytesPerPixel = 1; break; default: return B_ERROR; } if (bitsBytesPerPixel < 3) { // TODO support return B_NO_TRANSLATOR; } WebPPicture picture; WebPConfig config; if (!WebPPictureInit(&picture) || !WebPConfigInit(&config)) { printf("Error! Version mismatch!\n"); return B_ERROR; } WebPPreset preset = (WebPPreset)fSettings->SetGetInt32(WEBP_SETTING_PRESET); config.quality = (float)fSettings->SetGetInt32(WEBP_SETTING_QUALITY); if (!WebPConfigPreset(&config, (WebPPreset)preset, config.quality)) { printf("Error! Could initialize configuration with preset."); return B_ERROR; } config.method = fSettings->SetGetInt32(WEBP_SETTING_METHOD); config.preprocessing = fSettings->SetGetBool(WEBP_SETTING_PREPROCESSING); if (!WebPValidateConfig(&config)) { printf("Error! Invalid configuration.\n"); return B_ERROR; } picture.width = bitsHeader.bounds.IntegerWidth() + 1; picture.height = bitsHeader.bounds.IntegerHeight() + 1; int stride = bitsHeader.rowBytes; int bitsSize = picture.height * stride; uint8* bits = (uint8*)malloc(bitsSize); if (bits == NULL) return B_NO_MEMORY; if (stream->Read(bits, bitsSize) != bitsSize) { free(bits); return B_IO_ERROR; } if (!WebPPictureImportBGRA(&picture, bits, stride)) { printf("Error! WebPEncode() failed!\n"); free(bits); return B_ERROR; } free(bits); picture.writer = _EncodedWriter; picture.custom_ptr = target; picture.stats = NULL; if (!WebPEncode(&config, &picture)) { printf("Error! WebPEncode() failed!\n"); status = B_NO_TRANSLATOR; } else status = B_OK; WebPPictureFree(&picture); return status; }
static gboolean _cairo_surface_write_as_webp (cairo_surface_t *image, char **buffer, gsize *buffer_size, char **keys, char **values, GError **error) { gboolean lossless; int quality; int method; WebPConfig config; CairoWebpData *cairo_webp_data; WebPPicture pic; lossless = TRUE; quality = 75; method = 4; if (keys && *keys) { char **kiter = keys; char **viter = values; while (*kiter) { if (strcmp (*kiter, "lossless") == 0) { if (*viter == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Must specify a value for the 'lossless' option"); return FALSE; } lossless = atoi (*viter); if (lossless < 0 || lossless > 1) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Invalid value set for the 'lossless' option of the WebP saver"); return FALSE; } } else if (strcmp (*kiter, "quality") == 0) { if (*viter == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Must specify a quality value to the WebP saver"); return FALSE; } quality = atoi (*viter); if (quality < 0 || quality > 100) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Unsupported quality value passed to the WebP saver"); return FALSE; } } else if (strcmp (*kiter, "method") == 0) { if (*viter == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Must specify a method value to the WebP saver"); return FALSE; } method = atoi (*viter); if (method < 0 || method > 6) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Unsupported method value passed to the WebP saver"); return FALSE; } } else { g_warning ("Bad option name '%s' passed to the WebP saver", *kiter); return FALSE; } ++kiter; ++viter; } } if (! WebPConfigInit (&config)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Version error"); return FALSE; } config.lossless = lossless; config.quality = quality; config.method = method; if (! WebPValidateConfig (&config)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Config error"); return FALSE; } cairo_webp_data = g_new0 (CairoWebpData, 1); cairo_webp_data->error = error; cairo_webp_data->buffer_data = gth_buffer_data_new (); cairo_webp_data->success = FALSE; WebPPictureInit (&pic); pic.width = cairo_image_surface_get_width (image); pic.height = cairo_image_surface_get_height (image); pic.writer = cairo_webp_writer_func; pic.custom_ptr = cairo_webp_data; pic.use_argb = TRUE; if (_WebPPictureImportCairoSurface (&pic, image)) { int ok = WebPEncode (&config, &pic); WebPPictureFree (&pic); if (cairo_webp_data->success && ! ok) { g_set_error (cairo_webp_data->error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Encoding error: %d", pic.error_code); cairo_webp_data->success = FALSE; } } else { g_set_error (cairo_webp_data->error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Memory error"); cairo_webp_data->success = FALSE; } if (cairo_webp_data->success) gth_buffer_data_get (cairo_webp_data->buffer_data, buffer, buffer_size); _cairo_webp_data_destroy (cairo_webp_data); return TRUE; }
/** * Convert bitmap object from Android code to WebP format. Save to file. */ jint Java_com_tbliss_android_seniorproject_webpconv_WebPConv_doConvJniGraphics2( JNIEnv* env, jobject javaThis, jobject jbitmap, jfloat jqualityFactor, jstring filename) { int ret = 0; float cqualityFactor; int stride, width, height; void* pixels; // pointer to address of bitmap int outputSize = 0; AndroidBitmapInfo bitmapInfo; uint8_t* outputPointer; uint8_t* cbitmapPointer; WebPConfig config; WebPMemoryWriter wrt; size_t dataWritten = 0; int bytesWritten = 0; FILE* fileout = NULL; const char* fname = (*env)->GetStringUTFChars(env, filename, NULL); // Get Bitmap info (height/width/stride) if ((ret = AndroidBitmap_getInfo(env, jbitmap, &bitmapInfo)) < 0){ LOGV("Could not get Bitmap info. error=%d", ret); return 0; } width = (int)bitmapInfo.width; height = (int)bitmapInfo.height; stride = (int)bitmapInfo.stride; // width * 4 LOGV("Bitmap: width=%d, height=%d, stride=%d, format=%d", width, height, stride, bitmapInfo.format); // Lock Bitmap pixels if ((ret = AndroidBitmap_lockPixels(env, jbitmap, &pixels)) < 0) { LOGV("AndroidBitmap_lockPixels() failed ! error=%d", ret); return 0; } cbitmapPointer = (uint8_t*)pixels; outputSize = stride * height; LOGV("output_size: %d", outputSize); outputPointer = (uint8_t*) malloc(outputSize); cqualityFactor = (float)jqualityFactor; // Setup a config if (!WebPConfigPreset(&config, WEBP_PRESET_PICTURE, cqualityFactor)) { LOGV("WebPConfigPreset failed"); return 0; // version error } // ... additional tuning config.method = 1; LOGV("config.method = %d", config.method); if (WebPValidateConfig(&config) != 1) { LOGV("Error with config"); } // Setup the input data WebPPicture pic; if (!WebPPictureInit(&pic)) { LOGV("WebPPictureInit failed"); return 0; // version error } pic.width = width; pic.height = height; if (!WebPPictureImportRGBA(&pic, cbitmapPointer, stride)) { LOGV("WebPPictureImportRGB failed"); return 0; } // Set up a byte-output write method. WebPMemoryWriter, for instance. pic.writer = MyMemoryWriter; pic.custom_ptr = &wrt; //InitMemoryWriter(&wrt); wrt.mem = &outputPointer; wrt.size = &dataWritten; wrt.max_size = outputSize; // Compress! ret = WebPEncode(&config, &pic); // ok = 0 => error occurred! if (!ret) { LOGV("ret == 0, WebPEncode fail"); } WebPPictureFree(&pic); // must be called independently of the 'ok' result. // Write to phone fileout = fopen(fname, "wb"); if(!fileout){ LOGV("cannot open output file %s", fname); return 0; } bytesWritten = fwrite(outputPointer, 1, dataWritten, fileout); LOGV("bytesWritten: %d", bytesWritten); // Unlock pixels of Bitmap fclose(fileout); AndroidBitmap_unlockPixels(env, jbitmap); free(outputPointer); (*env)->ReleaseStringUTFChars(env, filename, fname); return dataWritten; }
/* Save a layer from an image */ gboolean save_layer(gint32 drawable_ID, WebPWriterFunction writer, void *custom_ptr, #ifdef WEBP_0_5 gboolean animation, WebPAnimEncoder *enc, int frame_timestamp, #endif WebPSaveParams *params, GError **error) { gboolean status = FALSE; gint bpp; gint width; gint height; GimpImageType drawable_type; WebPConfig config; WebPPicture picture; guchar *buffer = NULL; #ifdef GIMP_2_9 GeglBuffer *geglbuffer; GeglRectangle extent; #else GimpDrawable *drawable = NULL; GimpPixelRgn region; #endif /* Retrieve the image data */ bpp = gimp_drawable_bpp(drawable_ID); width = gimp_drawable_width(drawable_ID); height = gimp_drawable_height(drawable_ID); drawable_type = gimp_drawable_type(drawable_ID); /* Initialize the WebP configuration with a preset and fill in the * remaining values */ WebPConfigPreset(&config, webp_preset_by_name(params->preset), params->quality); config.lossless = params->lossless; config.method = 6; /* better quality */ config.alpha_quality = params->alpha_quality; /* Prepare the WebP structure */ WebPPictureInit(&picture); picture.use_argb = 1; picture.width = width; picture.height = height; picture.writer = writer; picture.custom_ptr = custom_ptr; picture.progress_hook = webp_file_progress; do { /* Attempt to allocate a buffer of the appropriate size */ buffer = (guchar *)g_malloc(bpp * width * height); if(!buffer) { g_set_error(error, G_FILE_ERROR, 0, "Unable to allocate buffer for layer"); break; } #ifdef GIMP_2_9 /* Obtain the buffer and get its extent */ geglbuffer = gimp_drawable_get_buffer(drawable_ID); extent = *gegl_buffer_get_extent(geglbuffer); /* Read the layer buffer into our buffer */ gegl_buffer_get(geglbuffer, &extent, 1.0, NULL, buffer, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); g_object_unref(geglbuffer); #else /* Get the drawable */ drawable = gimp_drawable_get(drawable_ID); /* Obtain the pixel region for the drawable */ gimp_pixel_rgn_init(®ion, drawable, 0, 0, width, height, FALSE, FALSE); /* Read the region into the buffer */ gimp_pixel_rgn_get_rect(®ion, buffer, 0, 0, width, height); gimp_drawable_detach(drawable); #endif /* Use the appropriate function to import the data from the buffer */ if(drawable_type == GIMP_RGB_IMAGE) { WebPPictureImportRGB(&picture, buffer, width * bpp); } else { WebPPictureImportRGBA(&picture, buffer, width * bpp); } #ifdef WEBP_0_5 if (animation == TRUE) { if (!WebPAnimEncoderAdd(enc, &picture, frame_timestamp, &config)) { g_set_error(error, G_FILE_ERROR, picture.error_code, "WebP error: '%s'", webp_error_string(picture.error_code)); break; } } else { #endif if(!WebPEncode(&config, &picture)) { g_set_error(error, G_FILE_ERROR, picture.error_code, "WebP error: '%s'", webp_error_string(picture.error_code)); break; } #ifdef WEBP_0_5 } #endif /* Everything succeeded */ status = TRUE; } while(0); /* Free the buffer */ if (buffer) { free(buffer); } return status; }