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; }
/* * 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; }
int ReadPNG(const uint8_t* const data, size_t data_size, struct WebPPicture* const pic, int keep_alpha, struct Metadata* const metadata) { volatile png_structp png = NULL; volatile png_infop info = NULL; volatile png_infop end_info = NULL; PNGReadContext context = { NULL, 0, 0 }; int color_type, bit_depth, interlaced; int has_alpha; int num_passes; int p; volatile int ok = 0; png_uint_32 width, height, y; int64_t stride; uint8_t* volatile rgb = NULL; if (data == NULL || data_size == 0 || pic == NULL) return 0; context.data = data; context.data_size = data_size; png = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL, NULL, MallocFunc, FreeFunc); if (png == NULL) goto End; png_set_error_fn(png, 0, error_function, NULL); if (setjmp(png_jmpbuf(png))) { Error: MetadataFree(metadata); goto End; } info = png_create_info_struct(png); if (info == NULL) goto Error; end_info = png_create_info_struct(png); if (end_info == NULL) goto Error; png_set_read_fn(png, &context, ReadFunc); png_read_info(png, info); if (!png_get_IHDR(png, info, &width, &height, &bit_depth, &color_type, &interlaced, NULL, NULL)) goto Error; png_set_strip_16(png); png_set_packing(png); if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png); } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { if (bit_depth < 8) { png_set_expand_gray_1_2_4_to_8(png); } png_set_gray_to_rgb(png); } if (png_get_valid(png, info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png); has_alpha = 1; } else { has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA); } // Apply gamma correction if needed. { double image_gamma = 1 / 2.2, screen_gamma = 2.2; int srgb_intent; if (png_get_sRGB(png, info, &srgb_intent) || png_get_gAMA(png, info, &image_gamma)) { png_set_gamma(png, screen_gamma, image_gamma); } } if (!keep_alpha) { png_set_strip_alpha(png); has_alpha = 0; } num_passes = png_set_interlace_handling(png); png_read_update_info(png, info); stride = (int64_t)(has_alpha ? 4 : 3) * width * sizeof(*rgb); if (stride != (int)stride || !ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) { goto Error; } rgb = (uint8_t*)malloc((size_t)stride * height); if (rgb == NULL) goto Error; for (p = 0; p < num_passes; ++p) { png_bytep row = rgb; for (y = 0; y < height; ++y) { png_read_rows(png, &row, NULL, 1); row += stride; } } png_read_end(png, end_info); if (metadata != NULL && !ExtractMetadataFromPNG(png, info, end_info, metadata)) { fprintf(stderr, "Error extracting PNG metadata!\n"); goto Error; } pic->width = (int)width; pic->height = (int)height; ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, (int)stride) : WebPPictureImportRGB(pic, rgb, (int)stride); if (!ok) { goto Error; } End: if (png != NULL) { png_destroy_read_struct((png_structpp)&png, (png_infopp)&info, (png_infopp)&end_info); } free(rgb); return ok; }
int ReadPNG(FILE* in_file, WebPPicture* const pic, int keep_alpha, Metadata* const metadata) { png_structp png; png_infop info = NULL; png_infop end_info = NULL; int color_type, bit_depth, interlaced; int has_alpha; int num_passes; int p; int ok = 0; png_uint_32 width, height, y; int stride; uint8_t* rgb = NULL; png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (png == NULL) { goto End; } png_set_error_fn(png, 0, error_function, NULL); if (setjmp(png_jmpbuf(png))) { Error: MetadataFree(metadata); png_destroy_read_struct(&png, &info, &end_info); goto End; } info = png_create_info_struct(png); if (info == NULL) goto Error; end_info = png_create_info_struct(png); if (end_info == NULL) goto Error; png_init_io(png, in_file); png_read_info(png, info); if (!png_get_IHDR(png, info, &width, &height, &bit_depth, &color_type, &interlaced, NULL, NULL)) goto Error; png_set_strip_16(png); png_set_packing(png); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { if (bit_depth < 8) { png_set_expand_gray_1_2_4_to_8(png); } png_set_gray_to_rgb(png); } if (png_get_valid(png, info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png); has_alpha = 1; } else { has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA); } if (!keep_alpha) { png_set_strip_alpha(png); has_alpha = 0; } num_passes = png_set_interlace_handling(png); png_read_update_info(png, info); stride = (has_alpha ? 4 : 3) * width * sizeof(*rgb); rgb = (uint8_t*)malloc(stride * height); if (rgb == NULL) goto Error; for (p = 0; p < num_passes; ++p) { for (y = 0; y < height; ++y) { png_bytep row = rgb + y * stride; png_read_rows(png, &row, NULL, 1); } } png_read_end(png, end_info); if (metadata != NULL && !ExtractMetadataFromPNG(png, info, end_info, metadata)) { fprintf(stderr, "Error extracting PNG metadata!\n"); goto Error; } png_destroy_read_struct(&png, &info, &end_info); pic->width = width; pic->height = height; ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, stride) : WebPPictureImportRGB(pic, rgb, stride); if (!ok) { goto Error; } End: free(rgb); return ok; }
int ReadWebP(const uint8_t* const data, size_t data_size, WebPPicture* const pic, int keep_alpha, Metadata* const metadata) { int ok = 0; VP8StatusCode status = VP8_STATUS_OK; WebPDecoderConfig config; WebPDecBuffer* const output_buffer = &config.output; WebPBitstreamFeatures* const bitstream = &config.input; if (data == NULL || data_size == 0 || pic == NULL) return 0; // TODO(jzern): add Exif/XMP/ICC extraction. if (metadata != NULL) { fprintf(stderr, "Warning: metadata extraction from WebP is unsupported.\n"); } if (!WebPInitDecoderConfig(&config)) { fprintf(stderr, "Library version mismatch!\n"); return 0; } status = WebPGetFeatures(data, data_size, bitstream); if (status != VP8_STATUS_OK) { PrintWebPError("input data", status); return 0; } { const int has_alpha = keep_alpha && bitstream->has_alpha; if (pic->use_argb) { output_buffer->colorspace = has_alpha ? MODE_RGBA : MODE_RGB; } else { output_buffer->colorspace = has_alpha ? MODE_YUVA : MODE_YUV; } status = DecodeWebP(data, data_size, 0, &config); if (status == VP8_STATUS_OK) { pic->width = output_buffer->width; pic->height = output_buffer->height; if (pic->use_argb) { const uint8_t* const rgba = output_buffer->u.RGBA.rgba; const int stride = output_buffer->u.RGBA.stride; ok = has_alpha ? WebPPictureImportRGBA(pic, rgba, stride) : WebPPictureImportRGB(pic, rgba, stride); } else { pic->colorspace = has_alpha ? WEBP_YUV420A : WEBP_YUV420; ok = WebPPictureAlloc(pic); if (!ok) { status = VP8_STATUS_OUT_OF_MEMORY; } else { const WebPYUVABuffer* const yuva = &output_buffer->u.YUVA; const int uv_width = (pic->width + 1) >> 1; const int uv_height = (pic->height + 1) >> 1; ImgIoUtilCopyPlane(yuva->y, yuva->y_stride, pic->y, pic->y_stride, pic->width, pic->height); ImgIoUtilCopyPlane(yuva->u, yuva->u_stride, pic->u, pic->uv_stride, uv_width, uv_height); ImgIoUtilCopyPlane(yuva->v, yuva->v_stride, pic->v, pic->uv_stride, uv_width, uv_height); if (has_alpha) { ImgIoUtilCopyPlane(yuva->a, yuva->a_stride, pic->a, pic->a_stride, pic->width, pic->height); } } } } }
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; }
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; }
static int ReadPNG(FILE* in_file, WebPPicture* const pic, int keep_alpha) { png_structp png; png_infop info; int color_type, bit_depth, interlaced; int has_alpha; int num_passes; int p; int ok = 0; png_uint_32 width, height, y; int stride; uint8_t* rgb = NULL; png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (png == NULL) { goto End; } png_set_error_fn(png, 0, error_function, NULL); if (setjmp(png_jmpbuf(png))) { Error: png_destroy_read_struct(&png, NULL, NULL); if (rgb) free(rgb); goto End; } info = png_create_info_struct(png); if (info == NULL) goto Error; png_init_io(png, in_file); png_read_info(png, info); if (!png_get_IHDR(png, info, &width, &height, &bit_depth, &color_type, &interlaced, NULL, NULL)) goto Error; png_set_strip_16(png); png_set_packing(png); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); if (color_type == PNG_COLOR_TYPE_GRAY) { if (bit_depth < 8) { png_set_expand_gray_1_2_4_to_8(png); } png_set_gray_to_rgb(png); } if (png_get_valid(png, info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png); has_alpha = 1; } else { has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA); } if (!keep_alpha) { png_set_strip_alpha(png); has_alpha = 0; } #ifdef WEBP_EXPERIMENTAL_FEATURES if (has_alpha) { pic->colorspace |= WEBP_CSP_ALPHA_BIT; } #endif num_passes = png_set_interlace_handling(png); png_read_update_info(png, info); stride = (has_alpha ? 4 : 3) * width * sizeof(*rgb); rgb = (uint8_t*)malloc(stride * height); if (rgb == NULL) goto Error; for (p = 0; p < num_passes; ++p) { for (y = 0; y < height; ++y) { png_bytep row = rgb + y * stride; png_read_rows(png, &row, NULL, 1); } } png_read_end(png, info); png_destroy_read_struct(&png, &info, NULL); pic->width = width; pic->height = height; ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, stride) : WebPPictureImportRGB(pic, rgb, stride); free(rgb); End: return ok; }
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; }
static int ReadJPEG(FILE* in_file, WebPPicture* const pic) { int ok = 0; int stride, width, height; uint8_t* rgb = NULL; uint8_t* row_ptr = NULL; struct jpeg_decompress_struct dinfo; struct my_error_mgr jerr; JSAMPARRAY buffer; dinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; if (setjmp (jerr.setjmp_buffer)) { Error: jpeg_destroy_decompress(&dinfo); goto End; } jpeg_create_decompress(&dinfo); jpeg_stdio_src(&dinfo, in_file); jpeg_read_header(&dinfo, TRUE); dinfo.out_color_space = JCS_RGB; dinfo.dct_method = JDCT_IFAST; dinfo.do_fancy_upsampling = TRUE; jpeg_start_decompress(&dinfo); if (dinfo.output_components != 3) { goto Error; } width = dinfo.output_width; height = dinfo.output_height; stride = dinfo.output_width * dinfo.output_components * sizeof(*rgb); rgb = (uint8_t*)malloc(stride * height); if (rgb == NULL) { goto End; } row_ptr = rgb; buffer = (*dinfo.mem->alloc_sarray) ((j_common_ptr) &dinfo, JPOOL_IMAGE, stride, 1); if (buffer == NULL) { goto End; } while (dinfo.output_scanline < dinfo.output_height) { if (jpeg_read_scanlines(&dinfo, buffer, 1) != 1) { goto End; } memcpy(row_ptr, buffer[0], stride); row_ptr += stride; } jpeg_finish_decompress (&dinfo); jpeg_destroy_decompress (&dinfo); // WebP conversion. pic->width = width; pic->height = height; ok = WebPPictureImportRGB(pic, rgb, stride); End: if (rgb) { free(rgb); } return ok; }
static HRESULT ReadPictureWithWIC(const char* filename, WebPPicture* const pic, int keep_alpha) { HRESULT hr = S_OK; IWICBitmapFrameDecode* pFrame = NULL; IWICFormatConverter* pConverter = NULL; IWICImagingFactory* pFactory = NULL; IWICBitmapDecoder* pDecoder = NULL; IStream* pStream = NULL; UINT frameCount = 0; UINT width, height = 0; BYTE* rgb = NULL; WICPixelFormatGUID srcPixelFormat = { 0 }; GUID srcContainerFormat = { 0 }; const GUID* alphaContainers[] = { &GUID_ContainerFormatBmp, &GUID_ContainerFormatPng, &GUID_ContainerFormatTiff }; int has_alpha = 0; int i, stride; IFS(CoInitialize(NULL)); IFS(CoCreateInstance(MAKE_REFGUID(CLSID_WICImagingFactory), NULL, CLSCTX_INPROC_SERVER, MAKE_REFGUID(IID_IWICImagingFactory), (LPVOID*)&pFactory)); if (hr == REGDB_E_CLASSNOTREG) { printf("Couldn't access Windows Imaging Component (are you running \n"); printf("Windows XP SP3 or newer?). Most formats not available.\n"); printf("Use -s for the available YUV input.\n"); } // Prepare for image decoding. IFS(OpenInputStream(filename, &pStream)); IFS(IWICImagingFactory_CreateDecoderFromStream(pFactory, pStream, NULL, WICDecodeMetadataCacheOnDemand, &pDecoder)); IFS(IWICBitmapDecoder_GetFrameCount(pDecoder, &frameCount)); if (SUCCEEDED(hr) && frameCount == 0) { printf("No frame found in input file.\n"); hr = E_FAIL; } IFS(IWICBitmapDecoder_GetFrame(pDecoder, 0, &pFrame)); IFS(IWICBitmapFrameDecode_GetPixelFormat(pFrame, &srcPixelFormat)); IFS(IWICBitmapDecoder_GetContainerFormat(pDecoder, &srcContainerFormat)); has_alpha = keep_alpha; for (i = 0; has_alpha && i < sizeof(alphaContainers)/sizeof(alphaContainers[0]); ++i) { if (IsEqualGUID(&srcContainerFormat, alphaContainers[i])) { has_alpha = IsEqualGUID(&srcPixelFormat, &GUID_WICPixelFormat32bppRGBA) || IsEqualGUID(&srcPixelFormat, &GUID_WICPixelFormat32bppBGRA); break; } } // Prepare for pixel format conversion (if necessary). IFS(IWICImagingFactory_CreateFormatConverter(pFactory, &pConverter)); IFS(IWICFormatConverter_Initialize(pConverter, (IWICBitmapSource*)pFrame, has_alpha ? MAKE_REFGUID(GUID_WICPixelFormat32bppRGBA) : MAKE_REFGUID(GUID_WICPixelFormat24bppRGB), WICBitmapDitherTypeNone, NULL, 0.0, WICBitmapPaletteTypeCustom)); // Decode. IFS(IWICFormatConverter_GetSize(pConverter, &width, &height)); stride = (has_alpha ? 4 : 3) * width * sizeof(*rgb); if (SUCCEEDED(hr)) { rgb = (BYTE*)malloc(stride * height); if (rgb == NULL) hr = E_OUTOFMEMORY; } IFS(IWICFormatConverter_CopyPixels(pConverter, NULL, stride, stride * height, rgb)); // WebP conversion. if (SUCCEEDED(hr)) { int ok; #ifdef WEBP_EXPERIMENTAL_FEATURES if (has_alpha) { pic->colorspace |= WEBP_CSP_ALPHA_BIT; } #endif pic->width = width; pic->height = height; ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, stride) : WebPPictureImportRGB(pic, rgb, stride); if (!ok) hr = E_FAIL; } // Cleanup. if (pConverter != NULL) IUnknown_Release(pConverter); if (pFrame != NULL) IUnknown_Release(pFrame); if (pDecoder != NULL) IUnknown_Release(pDecoder); if (pFactory != NULL) IUnknown_Release(pFactory); if (pStream != NULL) IUnknown_Release(pStream); free(rgb); return hr; }
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); }
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; }
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 ReadJPEG(FILE* in_file, WebPPicture* const pic, Metadata* const metadata) { int ok = 0; int stride, width, height; struct jpeg_decompress_struct dinfo; struct my_error_mgr jerr; uint8_t* rgb = NULL; JSAMPROW buffer[1]; dinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; if (setjmp(jerr.setjmp_buffer)) { Error: MetadataFree(metadata); jpeg_destroy_decompress(&dinfo); goto End; } jpeg_create_decompress(&dinfo); jpeg_stdio_src(&dinfo, in_file); if (metadata != NULL) SaveMetadataMarkers(&dinfo); jpeg_read_header(&dinfo, TRUE); dinfo.out_color_space = JCS_RGB; dinfo.dct_method = JDCT_IFAST; dinfo.do_fancy_upsampling = TRUE; jpeg_start_decompress(&dinfo); if (dinfo.output_components != 3) { goto Error; } width = dinfo.output_width; height = dinfo.output_height; stride = dinfo.output_width * dinfo.output_components * sizeof(*rgb); rgb = (uint8_t*)malloc(stride * height); if (rgb == NULL) { goto End; } buffer[0] = (JSAMPLE*)rgb; while (dinfo.output_scanline < dinfo.output_height) { if (jpeg_read_scanlines(&dinfo, buffer, 1) != 1) { goto End; } buffer[0] += stride; } if (metadata != NULL) { ok = ExtractMetadataFromJPEG(&dinfo, metadata); if (!ok) { fprintf(stderr, "Error extracting JPEG metadata!\n"); goto Error; } } jpeg_finish_decompress(&dinfo); jpeg_destroy_decompress(&dinfo); // WebP conversion. pic->width = width; pic->height = height; ok = WebPPictureImportRGB(pic, rgb, stride); if (!ok) goto Error; End: free(rgb); return ok; }
/* 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; }