Ejemplo n.º 1
0
inline int import_image_data(T2 const& image,
                             WebPPicture & pic,
                             bool alpha)
{
    // Reason for copy: https://github.com/mapnik/mapnik/issues/2024
    // TODO - figure out way to pass view pixels directly to webp importer
    image_data_32 im(image.width(),image.height());
    for (unsigned y = 0; y < image.height(); ++y)
    {
        typename T2::pixel_type const * row_from = image.getRow(y);
        image_data_32::pixel_type * row_to = im.getRow(y);
        for (unsigned x = 0; x < image.width(); ++x)
        {
            row_to[x] = row_from[x];
        }
    }
    int stride = sizeof(typename T2::pixel_type) * im.width();
    if (alpha)
    {
        return WebPPictureImportRGBA(&pic, im.getBytes(), stride);
    }
    else
    {
#if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1
        return WebPPictureImportRGBX(&pic, im.getBytes(), stride);
#else
        return WebPPictureImportRGBA(&pic, im.getBytes(), stride);
#endif
    }
}
Ejemplo n.º 2
0
inline int import_image(T2 const& im_in,
                             WebPPicture & pic,
                             bool alpha)
{
    image<typename T2::pixel> const& data = im_in.data();
    std::size_t width = im_in.width();
    std::size_t height = im_in.height();
    std::size_t stride = sizeof(typename T2::pixel_type) * width;
    if (data.width() == width &&
        data.height() == height)
    {
        if (alpha)
        {
            return WebPPictureImportRGBA(&pic, data.bytes(), static_cast<int>(stride));
        }
        else
        {
    #if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1
            return WebPPictureImportRGBX(&pic, data.bytes(), static_cast<int>(stride));
    #else
            return WebPPictureImportRGBA(&pic, data.bytes(), static_cast<int>(stride));
    #endif
        }
    }
    else
    {
        // need to copy: https://github.com/mapnik/mapnik/issues/2024
        image_rgba8 im(width,height);
        for (unsigned y = 0; y < height; ++y)
        {
            typename T2::pixel_type const * row_from = im_in.get_row(y);
            image_rgba8::pixel_type * row_to = im.get_row(y);
            std::copy(row_from, row_from + width, row_to);
        }
        if (alpha)
        {
            return WebPPictureImportRGBA(&pic, im.bytes(), static_cast<int>(stride));
        }
        else
        {
    #if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1
            return WebPPictureImportRGBX(&pic, im.bytes(), static_cast<int>(stride));
    #else
            return WebPPictureImportRGBA(&pic, im.bytes(), static_cast<int>(stride));
    #endif
        }
    }
}
Ejemplo n.º 3
0
int ReadTIFF(const char* const filename,
             WebPPicture* const pic, int keep_alpha,
             Metadata* const metadata) {
  TIFF* const tif = TIFFOpen(filename, "r");
  uint32 width, height;
  uint32* raster;
  int ok = 0;
  tdir_t dircount;

  if (tif == NULL) {
    fprintf(stderr, "Error! Cannot open TIFF file '%s'\n", filename);
    return 0;
  }

  dircount = TIFFNumberOfDirectories(tif);
  if (dircount > 1) {
    fprintf(stderr, "Warning: multi-directory TIFF files are not supported.\n"
                    "Only the first will be used, %d will be ignored.\n",
                    dircount - 1);
  }

  if (!(TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width) &&
        TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height))) {
    fprintf(stderr, "Error! Cannot retrieve TIFF image dimensions.\n");
    return 0;
  }
  raster = (uint32*)_TIFFmalloc(width * height * sizeof(*raster));
  if (raster != NULL) {
    if (TIFFReadRGBAImageOriented(tif, width, height, raster,
                                  ORIENTATION_TOPLEFT, 1)) {
      const int stride = width * sizeof(*raster);
      pic->width = width;
      pic->height = height;
      // TIFF data is ABGR
#ifdef WORDS_BIGENDIAN
      TIFFSwabArrayOfLong(raster, width * height);
#endif
      ok = keep_alpha
         ? WebPPictureImportRGBA(pic, (const uint8_t*)raster, stride)
         : WebPPictureImportRGBX(pic, (const uint8_t*)raster, stride);
    }
    _TIFFfree(raster);
  } else {
    fprintf(stderr, "Error allocating TIFF RGBA memory!\n");
  }

  if (ok) {
    if (metadata != NULL) {
      ok = ExtractMetadataFromTIFF(tif, metadata);
      if (!ok) {
        fprintf(stderr, "Error extracting TIFF metadata!\n");
        MetadataFree(metadata);
        WebPPictureFree(pic);
      }
    }
  }

  TIFFClose(tif);
  return ok;
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 5
0
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;    
}
Ejemplo n.º 6
0
inline int import_image_data(T2 const& image,
                             WebPPicture & pic,
                             bool alpha)
{
    ImageData<typename T2::pixel_type> const& data = image.data();
    int stride = sizeof(typename T2::pixel_type) * image.width();
    if (data.width() == image.width() &&
        data.height() == image.height())
    {
        if (alpha)
        {
            return WebPPictureImportRGBA(&pic, data.getBytes(), stride);
        }
        else
        {
    #if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1
            return WebPPictureImportRGBX(&pic, data.getBytes(), stride);
    #else
            return WebPPictureImportRGBA(&pic, data.getBytes(), stride);
    #endif
        }
    }
    else
    {
        // need to copy: https://github.com/mapnik/mapnik/issues/2024
        image_data_32 im(image.width(),image.height());
        for (unsigned y = 0; y < image.height(); ++y)
        {
            typename T2::pixel_type const * row_from = image.getRow(y);
            image_data_32::pixel_type * row_to = im.getRow(y);
            std::memcpy(row_to,row_from,stride);
        }
        if (alpha)
        {
            return WebPPictureImportRGBA(&pic, im.getBytes(), stride);
        }
        else
        {
    #if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1
            return WebPPictureImportRGBX(&pic, im.getBytes(), stride);
    #else
            return WebPPictureImportRGBA(&pic, im.getBytes(), stride);
    #endif
        }
    }
}
Ejemplo n.º 7
0
inline int import_image(image_rgba8 const& im,
                             WebPPicture & pic,
                             bool alpha)
{
    std::size_t stride = sizeof(image_rgba8::pixel_type) * im.width();
    if (alpha)
    {
        return WebPPictureImportRGBA(&pic, im.bytes(), static_cast<int>(stride));
    }
    else
    {
#if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1
        return WebPPictureImportRGBX(&pic, im.bytes(), static_cast<int>(stride));
#else
        return WebPPictureImportRGBA(&pic, im.bytes(), static_cast<int>(stride));
#endif
    }
}
Ejemplo n.º 8
0
inline int import_image_data(image_data_32 const& im,
                             WebPPicture & pic,
                             bool alpha)
{
    int stride = sizeof(image_data_32::pixel_type) * im.width();
    if (alpha)
    {
        return WebPPictureImportRGBA(&pic, im.getBytes(), stride);
    }
    else
    {
#if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1
        return WebPPictureImportRGBX(&pic, im.getBytes(), stride);
#else
        return WebPPictureImportRGBA(&pic, im.getBytes(), stride);
#endif
    }
}
Ejemplo n.º 9
0
int ReadTIFF(const char* const filename,
             WebPPicture* const pic, int keep_alpha) {
  TIFF* const tif = TIFFOpen(filename, "r");
  uint32 width, height;
  uint32* raster;
  int ok = 0;
  int dircount = 1;

  if (tif == NULL) {
    fprintf(stderr, "Error! Cannot open TIFF file '%s'\n", filename);
    return 0;
  }

  while (TIFFReadDirectory(tif)) ++dircount;

  if (dircount > 1) {
    fprintf(stderr, "Warning: multi-directory TIFF files are not supported.\n"
                    "Only the first will be used, %d will be ignored.\n",
                    dircount - 1);
  }

  TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
  TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
  raster = (uint32*)_TIFFmalloc(width * height * sizeof(*raster));
  if (raster != NULL) {
    if (TIFFReadRGBAImageOriented(tif, width, height, raster,
                                  ORIENTATION_TOPLEFT, 1)) {
      const int stride = width * sizeof(*raster);
      pic->width = width;
      pic->height = height;
      // TIFF data is ABGR
#ifdef __BIG_ENDIAN__
      TIFFSwabArrayOfLong(raster, width * height);
#endif
      ok = keep_alpha
         ? WebPPictureImportRGBA(pic, (const uint8_t*)raster, stride)
         : WebPPictureImportRGBX(pic, (const uint8_t*)raster, stride);
    }
    _TIFFfree(raster);
  } else {
    fprintf(stderr, "Error allocating TIFF RGBA memory!\n");
  }

  if (ok && keep_alpha == 2) {
    WebPCleanupTransparentArea(pic);
  }

  TIFFClose(tif);
  return ok;
}
Ejemplo n.º 10
0
static gint
save_RGBA (WebPPicture         *picture,
           GeglBuffer          *input,
           const GeglRectangle *result,
           const Babl          *format)
{
  gint bytes_per_pixel, bytes_per_row;
  uint8_t *buffer;

  bytes_per_pixel = babl_format_get_bytes_per_pixel (format);
  bytes_per_row = bytes_per_pixel * result->width;

  buffer = g_try_new (uint8_t, bytes_per_row * result->height);

  g_assert (buffer != NULL);

  gegl_buffer_get (input, result, 1.0, format, buffer,
                   GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);

  WebPPictureImportRGBA (picture, buffer, bytes_per_row);

  g_free (buffer);
  return 0;
}
Ejemplo n.º 11
0
Archivo: _webp.c Proyecto: dvska/Pillow
PyObject* _anim_encoder_add(PyObject* self, PyObject* args)
{
    uint8_t* rgb;
    Py_ssize_t size;
    int timestamp;
    int width;
    int height;
    char* mode;
    int lossless;
    float quality_factor;
    int method;
    WebPConfig config;
    WebPAnimEncoderObject* encp = (WebPAnimEncoderObject*)self;
    WebPAnimEncoder* enc = encp->enc;
    WebPPicture* frame = &(encp->frame);

    if (!PyArg_ParseTuple(args, "z#iiisifi",
        (char**)&rgb, &size, &timestamp, &width, &height, &mode,
        &lossless, &quality_factor, &method)) {
        return NULL;
    }

    // Check for NULL frame, which sets duration of final frame
    if (!rgb) {
        WebPAnimEncoderAdd(enc, NULL, timestamp, NULL);
        Py_RETURN_NONE;
    }

    // Setup config for this frame
    if (!WebPConfigInit(&config)) {
        PyErr_SetString(PyExc_RuntimeError, "failed to initialize config!");
        return NULL;
    }
    config.lossless = lossless;
    config.quality = quality_factor;
    config.method = method;

    // Validate the config
    if (!WebPValidateConfig(&config)) {
        PyErr_SetString(PyExc_ValueError, "invalid configuration");
        return NULL;
    }

    // Populate the frame with raw bytes passed to us
    frame->width = width;
    frame->height = height;
    frame->use_argb = 1; // Don't convert RGB pixels to YUV
    if (strcmp(mode, "RGBA")==0) {
        WebPPictureImportRGBA(frame, rgb, 4 * width);
    } else if (strcmp(mode, "RGBX")==0) {
        WebPPictureImportRGBX(frame, rgb, 4 * width);
    }

    // Add the frame to the encoder
    if (!WebPAnimEncoderAdd(enc, frame, timestamp, &config)) {
        PyErr_SetString(PyExc_RuntimeError, WebPAnimEncoderGetError(enc));
        return NULL;
    }

    Py_RETURN_NONE;
}
Ejemplo n.º 12
0
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;
}
Ejemplo n.º 13
0
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);
          }
        }
      }
    }
  }
Ejemplo n.º 14
0
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);
}
Ejemplo n.º 15
0
/**
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 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);
}
Ejemplo n.º 17
0
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;
}
Ejemplo n.º 18
0
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;
}
Ejemplo n.º 19
0
/**
 * 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;
}
Ejemplo n.º 20
0
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;
}
Ejemplo n.º 21
0
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;
}
Ejemplo n.º 22
0
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;
}
Ejemplo n.º 23
0
/*
* 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;
}
Ejemplo n.º 24
0
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;
}
Ejemplo n.º 25
0
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;
}
Ejemplo n.º 26
0
/* 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(&region,
                            drawable,
                            0, 0,
                            width,
                            height,
                            FALSE, FALSE);

        /* Read the region into the buffer */
        gimp_pixel_rgn_get_rect(&region,
                                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;
}