Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correct GdkPixbuf byte length and simplify decoder #2

Merged
merged 2 commits into from Oct 23, 2014
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
99 changes: 32 additions & 67 deletions io-webp.c
Expand Up @@ -42,7 +42,6 @@ typedef struct {
GdkPixbuf *pixbuf;
gboolean got_header;
WebPIDecoder *idec;
guchar *decbuf;
gint last_y;
GError **error;
} WebPContext;
Expand Down Expand Up @@ -148,56 +147,20 @@ gdk_pixbuf__webp_image_stop_load (gpointer context, GError **error)
if (data->idec) {
WebPIDelete (data->idec);
}
if (data->decbuf) {
g_free (data->decbuf);
}
return TRUE;
}

// Modified WebPINewRGB() that takes a WebPDecoderConfig argument, which we
// currently need for scaling options.
static WebPIDecoder *
new_rgb_decoder (WEBP_CSP_MODE mode, uint8_t* output_buffer,
size_t output_buffer_size, int output_stride,
WebPDecoderConfig *config)
{
const int is_external_memory = (output_buffer != NULL);

if (mode >= MODE_YUV) return NULL;
if (!is_external_memory) {
// Overwrite parameters to sane values.
output_buffer_size = 0;
output_stride = 0;
} else {
// A buffer was passed. Validate the other params.
if (output_stride == 0 || output_buffer_size == 0) {
return NULL;
}
}

config->output.colorspace = mode;
config->output.is_external_memory = is_external_memory;
config->output.u.RGBA.rgba = output_buffer;
config->output.u.RGBA.stride = output_stride;
config->output.u.RGBA.size = output_buffer_size;
return WebPIDecode (NULL, 0, config);
}

static gboolean
gdk_pixbuf__webp_image_load_increment (gpointer context,
const guchar *buf, guint size,
GError **error)
{
gint w, h, stride, scaled_w, scaled_h;
gint w, h, stride;
WebPContext *data = (WebPContext *) context;
g_return_val_if_fail(data != NULL, FALSE);

if (!data->got_header) {
gint rc;
WebPBitstreamFeatures features;
gboolean use_alpha = TRUE;

rc = WebPGetInfo (buf, size, &w, &h);
gint rc = WebPGetInfo (buf, size, &w, &h);
if (rc == 0) {
g_set_error (error,
GDK_PIXBUF_ERROR,
Expand All @@ -207,21 +170,24 @@ gdk_pixbuf__webp_image_load_increment (gpointer context,
}
data->got_header = TRUE;

scaled_w = w;
scaled_h = h;
memset (&data->config, 0, sizeof data->config);
if (data->size_func) {
gint scaled_w = w;
gint scaled_h = h;

(* data->size_func) (&scaled_w, &scaled_h,
data->user_data);
if (scaled_w != w || scaled_h != h) {
data->config.options.use_scaling = TRUE;
data->config.options.scaled_width = scaled_w;
data->config.options.scaled_height = scaled_h;
w = scaled_w;
h = scaled_h;
}
w = scaled_w;
h = scaled_h;
}

WebPBitstreamFeatures features;
gboolean use_alpha = TRUE;

/* Take the safe route and only disable the alpha channel when
we're sure that there is not any. */
if (WebPGetFeatures (buf, size, &features) == VP8_STATUS_OK
Expand All @@ -234,22 +200,29 @@ gdk_pixbuf__webp_image_load_increment (gpointer context,
8,
w,
h);
stride = gdk_pixbuf_get_rowstride (data->pixbuf);

data->decbuf = g_try_malloc (h * stride);
if (!data->decbuf) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
"Cannot allocate memory for decoded image data.");
return FALSE;
}

data->idec = new_rgb_decoder (use_alpha ? MODE_RGBA : MODE_RGB,
data->decbuf,
h * stride,
stride,
&data->config);
guint pixbuf_length;
stride = gdk_pixbuf_get_rowstride (data->pixbuf);
guchar *pixbuf_data = gdk_pixbuf_get_pixels_with_length (data->pixbuf,
&pixbuf_length);

/* Initialise the picture to transparent black. */
memset (pixbuf_data, 0x00, pixbuf_length);

data->config.output.colorspace = use_alpha ? MODE_RGBA : MODE_RGB;
data->config.output.is_external_memory = TRUE;
data->config.output.u.RGBA.rgba = pixbuf_data;
data->config.output.u.RGBA.stride = stride;

/* XXX: this may not be true: the last row doesn't strictly have
to include stride padding, even though it does in case of
gdk_pixbuf_new(), looking at its source. There is an explicit
check in libwebp that requires that the following value equals
stride times height, however, even though it is fairly unlikely
that anyone would actually want to write into the padding. */
data->config.output.u.RGBA.size = h * stride;

data->idec = WebPIDecode (NULL, 0, &data->config);
if (!data->idec) {
g_set_error (error,
GDK_PIXBUF_ERROR,
Expand Down Expand Up @@ -287,14 +260,6 @@ gdk_pixbuf__webp_image_load_increment (gpointer context,
return FALSE;
}

/* Copy decoder output to pixbuf */
gint y, row_offset = 0;
guchar *dptr;
dptr = gdk_pixbuf_get_pixels (data->pixbuf);
for (y = 0; y < data->last_y; ++y, row_offset += stride) {
g_memmove (dptr + row_offset, dec_output + row_offset, stride);
}

if (data->update_func) {
(* data->update_func) (data->pixbuf, 0, 0,
w,
Expand Down