[goffice] Ensure that GOPixbuf keeps the original data around. [#745297]
- From: Jean Bréfort <jbrefort src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [goffice] Ensure that GOPixbuf keeps the original data around. [#745297]
- Date: Sat, 28 Feb 2015 19:05:17 +0000 (UTC)
commit ea67f35a2a16d7ba61572d9e35ebe98efdcc94e9
Author: Jean Brefort <jean brefort normalesup org>
Date: Sat Feb 28 20:04:59 2015 +0100
Ensure that GOPixbuf keeps the original data around. [#745297]
ChangeLog | 7 ++
NEWS | 1 +
goffice/utils/go-image.c | 8 +--
goffice/utils/go-pixbuf.c | 154 ++++++++++++++++++++++++++++++++++-----------
goffice/utils/go-pixbuf.h | 4 +-
5 files changed, 129 insertions(+), 45 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index d72b96d..f8ca46e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2015-02-28 Jean Brefort <jean brefort normalesup org>
+
+ * goffice/utils/go-image.c (go_image_new_from_data): ensure that GOPixbuf
+ keeps the original data around. [#745297]
+ * goffice/utils/go-pixbuf.c: ditto.
+ * goffice/utils/go-pixbuf.h: ditto.
+
2015-02-27 Morten Welinder <terra gnome org>
* goffice/utils/go-pixbuf.c (go_pixbuf_load_data): Set
diff --git a/NEWS b/NEWS
index 2c91c20..5d860b4 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,7 @@ goffice 0.10.21:
Jean:
* Ignore invalid values while checking data order. [#744200]
+ * Ensure that GOPixbuf keeps the original data around. [#745297]
Morten:
* Fix problem with linear solver.
diff --git a/goffice/utils/go-image.c b/goffice/utils/go-image.c
index d80a5fd..8c46650 100644
--- a/goffice/utils/go-image.c
+++ b/goffice/utils/go-image.c
@@ -663,13 +663,7 @@ go_image_new_from_data (char const *type, guint8 const *data, gsize length, char
} else if (!strcmp (type, "eps")) {
image = go_spectre_new_from_data (data, length, error);
} else {
- GdkPixbufLoader *loader = gdk_pixbuf_loader_new_with_type (type, error);
- if (loader) {
- if (gdk_pixbuf_loader_write (loader, data, length, error))
- image = go_pixbuf_new_from_pixbuf (gdk_pixbuf_loader_get_pixbuf (loader));
- gdk_pixbuf_loader_close (loader, error);
- g_object_unref (loader);
- }
+ image = go_pixbuf_new_from_data (type, data, length, error);
}
if (image == NULL) {
#ifdef GOFFICE_WITH_GTK
diff --git a/goffice/utils/go-pixbuf.c b/goffice/utils/go-pixbuf.c
index 6091d22..001b854 100644
--- a/goffice/utils/go-pixbuf.c
+++ b/goffice/utils/go-pixbuf.c
@@ -34,6 +34,9 @@ struct _GOPixbuf {
unsigned rowstride;
GdkPixbuf *pixbuf;
cairo_surface_t *surface;
+ guint8 *cairo_pixels;
+ gsize length;
+ char *type;
};
typedef GOImageClass GOPixbufClass;
@@ -42,7 +45,8 @@ static GObjectClass *parent_klass;
enum {
PIXBUF_PROP_0,
- PIXBUF_PROP_PIXBUF
+ PIXBUF_PROP_PIXBUF,
+ PIXBUF_PROP_TYPE
};
static void
@@ -51,10 +55,10 @@ pixbuf_to_cairo (GOPixbuf *pixbuf)
unsigned char *src, *dst;
GOImage *image = GO_IMAGE (pixbuf);
- g_return_if_fail (GO_IS_PIXBUF (pixbuf) && image->data && pixbuf->pixbuf);
+ g_return_if_fail (GO_IS_PIXBUF (pixbuf) && pixbuf->cairo_pixels && pixbuf->pixbuf);
src = gdk_pixbuf_get_pixels (pixbuf->pixbuf);
- dst = image->data;
+ dst = pixbuf->cairo_pixels;
g_return_if_fail (gdk_pixbuf_get_rowstride (pixbuf->pixbuf) == (int) pixbuf->rowstride);
@@ -67,10 +71,10 @@ cairo_to_pixbuf (GOPixbuf *pixbuf)
unsigned char *src, *dst;
GOImage *image = GO_IMAGE (pixbuf);
- g_return_if_fail (GO_IS_PIXBUF (pixbuf) && image->data && pixbuf->pixbuf);
+ g_return_if_fail (GO_IS_PIXBUF (pixbuf) && pixbuf->cairo_pixels && pixbuf->pixbuf);
dst = gdk_pixbuf_get_pixels (pixbuf->pixbuf);
- src = image->data;
+ src = pixbuf->cairo_pixels;
g_return_if_fail (gdk_pixbuf_get_rowstride (pixbuf->pixbuf) == (int) pixbuf->rowstride);
@@ -83,18 +87,16 @@ go_pixbuf_save (GOImage *image, GsfXMLOut *output)
GOPixbuf *pixbuf;
g_return_if_fail (GO_IS_PIXBUF (image));
pixbuf = GO_PIXBUF (image);
- gsf_xml_out_add_int (output, "rowstride", pixbuf->rowstride);
- if (!image->data) {
- image->data = g_try_new0 (guint8, image->height * pixbuf->rowstride);
- if (image->data == NULL) {
- g_critical ("go_pixbuf_save: assertion `image->data != NULL' failed");
- return;
- }
- pixbuf_to_cairo (pixbuf);
+ if (pixbuf->type == NULL) {
+ pixbuf->type = g_strdup ("png");
+ g_free (image->data); /* just in case, but the pointer should be NULL */
+ gdk_pixbuf_save_to_buffer (pixbuf->pixbuf, (gchar **) &image->data,
+ &image->data_length, pixbuf->type, NULL,
+ "compression", 9, NULL);
}
- gsf_xml_out_add_base64
- (output, NULL,
- image->data, image->height * pixbuf->rowstride);
+ gsf_xml_out_add_cstr_unchecked (output, "image-type", pixbuf->type);
+ gsf_xml_out_add_base64 (output, NULL,
+ image->data, image->data_length);
}
static void
@@ -106,7 +108,40 @@ go_pixbuf_load_attr (GOImage *image, xmlChar const *attr_name, xmlChar const *at
long l = strtol (attr_value, NULL, 10);
g_return_if_fail (l > 0 && l < G_MAXINT);
pixbuf->rowstride = l;
+ } else if (!strcmp (attr_name, "image-type"))
+ pixbuf->type = g_strdup (attr_value);
+}
+
+static void
+go_pixbuf_create_pixbuf (GOPixbuf *pixbuf, GError **error)
+{
+ GOImage *image = GO_IMAGE (pixbuf);
+ GdkPixbufLoader *loader = gdk_pixbuf_loader_new_with_type (pixbuf->type, NULL);
+ if (loader) {
+ if (gdk_pixbuf_loader_write (loader, image->data, image->data_length, error))
+ g_object_set (pixbuf,
+ "pixbuf", gdk_pixbuf_loader_get_pixbuf (loader),
+ NULL);
+ gdk_pixbuf_loader_close (loader, error);
+ g_object_unref (loader);
+ }
+}
+
+static void
+go_pixbuf_restore_data (GOPixbuf *pixbuf)
+{
+ GOImage *image = GO_IMAGE (pixbuf);
+ if (pixbuf->pixbuf == NULL) {
+ if (image->width == 0 || image->height == 0 || pixbuf->cairo_pixels == NULL)
+ return;
+ pixbuf->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
+ image->width, image->height);
+ cairo_to_pixbuf (pixbuf);
}
+ if (image->data == NULL && pixbuf->pixbuf && pixbuf->type)
+ gdk_pixbuf_save_to_buffer (pixbuf->pixbuf, (gchar **) &image->data,
+ &image->data_length, pixbuf->type, NULL,
+ NULL);
}
static void
@@ -114,24 +149,37 @@ go_pixbuf_load_data (GOImage *image, GsfXMLIn *xin)
{
size_t length, expected;
int stride;
+ GOPixbuf *pixbuf = GO_PIXBUF (image);
stride = go_pixbuf_get_rowstride (GO_PIXBUF (image));
- g_return_if_fail (stride > 0);
-
length = gsf_base64_decode_simple (xin->content->str, strlen(xin->content->str));
- expected = image->height * (size_t)stride;
- if (expected != length)
- g_critical ("Invalid image size, expected %" G_GSIZE_FORMAT " bytes, got %" G_GSIZE_FORMAT,
- expected, length);
- image->data = g_try_malloc (expected);
- image->data_length = expected;
- if (image->data == NULL) {
- g_critical ("go_pixbuf_load_data: assertion `image->data != NULL' failed");
- return;
+ if (stride > 0) {
+ /* load raw pixels */
+ expected = image->height * (size_t)stride;
+ if (expected != length)
+ g_critical ("Invalid image size, expected %" G_GSIZE_FORMAT " bytes, got %"
G_GSIZE_FORMAT,
+ expected, length);
+ pixbuf->cairo_pixels = g_try_malloc (expected);
+ pixbuf->length = expected;
+ if (pixbuf->cairo_pixels == NULL) {
+ g_critical ("go_pixbuf_load_data: assertion `pixbuf->cairo_pixels != NULL' failed");
+ return;
+ }
+ memcpy (pixbuf->cairo_pixels, xin->content->str, MIN (length, expected));
+ if (length < expected) /* fill with 0 */
+ memset (pixbuf->cairo_pixels + length, 0, expected - length);
+ go_pixbuf_restore_data (pixbuf);
+ } else {
+ image->data = g_try_malloc (length);
+ image->data_length = length;
+ if (image->data == NULL) {
+ g_critical ("go_pixbuf_load_data: assertion `image->data != NULL' failed");
+ return;
+ }
+ memcpy (image->data, xin->content->str, length);
+ /* create the pixbuf */
+ go_pixbuf_create_pixbuf (pixbuf, NULL);
}
- memcpy (image->data, xin->content->str, MIN (length, expected));
- if (length < expected) /* fill with 0 */
- memset (image->data + length, 0, expected - length);
}
static void
@@ -140,16 +188,16 @@ go_pixbuf_draw (GOImage *image, cairo_t *cr)
GOPixbuf *pixbuf = GO_PIXBUF (image);
g_return_if_fail (pixbuf);
if (pixbuf->surface == NULL) {
- if (image->data == NULL) {
+ if (pixbuf->cairo_pixels == NULL) {
/* image built from a pixbuf */
- image->data = g_try_new0 (guint8, image->height * pixbuf->rowstride);
- if (image->data == NULL) {
+ pixbuf->cairo_pixels = g_try_new0 (guint8, image->height * pixbuf->rowstride);
+ if (pixbuf->cairo_pixels == NULL) {
g_critical ("go_pixbuf_load_data: assertion `image->data != NULL' failed");
return;
}
pixbuf_to_cairo (pixbuf);
}
- pixbuf->surface = cairo_image_surface_create_for_data (image->data,
+ pixbuf->surface = cairo_image_surface_create_for_data (pixbuf->cairo_pixels,
CAIRO_FORMAT_ARGB32,
image->width,
image->height,
@@ -168,7 +216,7 @@ go_pixbuf_get_pixbuf (GOImage *image)
GOPixbuf *pixbuf = GO_PIXBUF (image);
g_return_val_if_fail (pixbuf, NULL);
if (!pixbuf->pixbuf) {
- if (image->width == 0 || image->height == 0 || image->data == NULL)
+ if (image->width == 0 || image->height == 0 || pixbuf->cairo_pixels == NULL)
return NULL;
pixbuf->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
image->width, image->height);
@@ -243,12 +291,19 @@ go_pixbuf_set_property (GObject *obj, guint param_id,
if (pixbuf->pixbuf)
g_object_unref (pixbuf->pixbuf);
pixbuf->pixbuf = pix;
- g_free (image->data); /* this should be in GOPixbuf */
- image->data = NULL; /* this should be in GOPixbuf */
_go_image_changed (image, gdk_pixbuf_get_width (pix), gdk_pixbuf_get_height (pix));
pixbuf->rowstride = gdk_pixbuf_get_rowstride (pix); /* this should be in GOPixbuf */
}
break;
+ case PIXBUF_PROP_TYPE: {
+ char const *type = g_value_get_string (value);
+ if (pixbuf->type && !strcmp (type, pixbuf->type))
+ break;
+ g_return_if_fail (pixbuf->type == NULL);
+ pixbuf->type = g_strdup (type);
+ go_pixbuf_restore_data (pixbuf);
+ }
+ break;
default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
return; /* NOTE : RETURN */
@@ -265,6 +320,9 @@ go_pixbuf_get_property (GObject *obj, guint param_id,
case PIXBUF_PROP_PIXBUF:
g_value_set_object (value, pixbuf->pixbuf);
break;
+ case PIXBUF_PROP_TYPE:
+ g_value_set_string (value, pixbuf->type);
+ break;
default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
return; /* NOTE : RETURN */
@@ -279,6 +337,7 @@ go_pixbuf_finalize (GObject *obj)
g_object_unref (pixbuf->pixbuf);
if (pixbuf->surface)
cairo_surface_destroy (pixbuf->surface);
+ g_free (pixbuf->type);
(parent_klass->finalize) (obj);
}
@@ -304,6 +363,12 @@ go_pixbuf_class_init (GObjectClass *klass)
g_param_spec_object ("pixbuf", _("Pixbuf"),
_("GdkPixbuf object from which the GOPixbuf is
built"),
GDK_TYPE_PIXBUF, G_PARAM_READWRITE));
+ g_object_class_install_property (klass, PIXBUF_PROP_TYPE,
+ g_param_spec_string ("image-type",
+ N_("Image type"),
+ N_("Type of image"),
+ NULL,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
}
GSF_CLASS (GOPixbuf, go_pixbuf,
@@ -317,6 +382,21 @@ go_pixbuf_new_from_pixbuf (GdkPixbuf *pixbuf)
return g_object_new (GO_TYPE_PIXBUF, "pixbuf", pixbuf, NULL);
}
+GOImage *
+go_pixbuf_new_from_data (char const *type, guint8 const *data, gsize length, GError **error)
+{
+ GOImage *image = g_object_new (GO_TYPE_PIXBUF, NULL);
+ image->data = g_memdup (data, length);
+ image->data_length = length;
+ g_object_set (image, "image-type", type, NULL);
+ go_pixbuf_create_pixbuf (GO_PIXBUF (image), error);
+ if (*error != NULL) {
+ g_object_unref (image);
+ return NULL;
+ }
+ return image;
+}
+
int
go_pixbuf_get_rowstride (GOPixbuf *pixbuf)
{
diff --git a/goffice/utils/go-pixbuf.h b/goffice/utils/go-pixbuf.h
index bd57c24..7657a22 100644
--- a/goffice/utils/go-pixbuf.h
+++ b/goffice/utils/go-pixbuf.h
@@ -33,7 +33,9 @@ G_BEGIN_DECLS
GType go_pixbuf_get_type (void);
-GOImage *go_pixbuf_new_from_pixbuf (GdkPixbuf *pixbuf);
+GOImage *go_pixbuf_new_from_pixbuf (GdkPixbuf *pixbuf);
+GOImage *go_pixbuf_new_from_data (char const *type, guint8 const *data,
+ gsize length, GError **error);
int go_pixbuf_get_rowstride (GOPixbuf *pixbuf);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]