4
* Copyright (C) 2011 Jean Brefort (jean.brefort@normalesup.org)
6
* This program is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public License as
8
* published by the Free Software Foundation; either version 2 of the
9
* License, or (at your option) version 3.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
22
#include <goffice/goffice-config.h>
23
#include "go-pixbuf.h"
25
#include <goffice/goffice-priv.h>
26
#include <gsf/gsf-utils.h>
27
#include <gsf/gsf-impl-utils.h>
28
#include <glib/gi18n-lib.h>
30
/* GOPixbuf implementation */
36
cairo_surface_t *surface;
39
typedef GOImageClass GOPixbufClass;
41
static GObjectClass *parent_klass;
49
pixbuf_to_cairo (GOPixbuf *pixbuf)
51
unsigned char *src, *dst;
52
GOImage *image = GO_IMAGE (pixbuf);
54
g_return_if_fail (GO_IS_PIXBUF (pixbuf) && image->data && pixbuf->pixbuf);
56
src = gdk_pixbuf_get_pixels (pixbuf->pixbuf);
59
g_return_if_fail (gdk_pixbuf_get_rowstride (pixbuf->pixbuf) == (int) pixbuf->rowstride);
61
go_cairo_convert_data_from_pixbuf (dst, src, image->width, image->height, pixbuf->rowstride);
65
cairo_to_pixbuf (GOPixbuf *pixbuf)
67
unsigned char *src, *dst;
68
GOImage *image = GO_IMAGE (pixbuf);
70
g_return_if_fail (GO_IS_PIXBUF (pixbuf) && image->data && pixbuf->pixbuf);
72
dst = gdk_pixbuf_get_pixels (pixbuf->pixbuf);
75
g_return_if_fail (gdk_pixbuf_get_rowstride (pixbuf->pixbuf) == (int) pixbuf->rowstride);
77
go_cairo_convert_data_to_pixbuf (dst, src, image->width, image->height, pixbuf->rowstride);
81
go_pixbuf_save (GOImage *image, GsfXMLOut *output)
84
g_return_if_fail (GO_IS_PIXBUF (image));
85
pixbuf = GO_PIXBUF (image);
86
gsf_xml_out_add_int (output, "rowstride", pixbuf->rowstride);
88
image->data = g_new0 (guint8, image->height * pixbuf->rowstride);
89
g_return_if_fail (image->data !=NULL);
90
pixbuf_to_cairo (pixbuf);
92
gsf_xml_out_add_base64
94
image->data, image->height * pixbuf->rowstride);
98
go_pixbuf_load_attr (GOImage *image, xmlChar const *attr_name, xmlChar const *attr_value)
100
GOPixbuf *pixbuf = GO_PIXBUF (image);
101
g_return_if_fail (pixbuf);
102
if (!strcmp (attr_name, "rowstride"))
103
pixbuf->rowstride = strtol (attr_value, NULL, 10);
107
go_pixbuf_load_data (GOImage *image, GsfXMLIn *xin)
109
size_t length, expected;
110
length = gsf_base64_decode_simple (xin->content->str, strlen(xin->content->str));
111
expected = image->height * go_pixbuf_get_rowstride (GO_PIXBUF (image));
112
if (expected != length)
113
g_critical ("Invalid image size, expected %lu bytes, got %lu", expected, length);
114
image->data = g_malloc (expected);
115
g_return_if_fail (image->data !=NULL);
116
memcpy (image->data, xin->content->str, (length < expected)? length: expected);
117
if (length < expected) /* fill with 0 */
118
memset (image->data + length, 0, expected - length);
122
go_pixbuf_draw (GOImage *image, cairo_t *cr)
124
GOPixbuf *pixbuf = GO_PIXBUF (image);
125
g_return_if_fail (pixbuf);
126
if (pixbuf->surface == NULL) {
127
if (image->data == NULL) {
128
/* image built from a pixbuf */
129
image->data = g_new0 (guint8, image->height * pixbuf->rowstride);
130
g_return_if_fail (image->data !=NULL);
131
pixbuf_to_cairo (pixbuf);
133
pixbuf->surface = cairo_image_surface_create_for_data (image->data,
140
cairo_set_source_surface (cr, pixbuf->surface, 0., 0.);
141
cairo_rectangle (cr, 0., 0., image->width, image->height);
147
go_pixbuf_get_pixbuf (GOImage *image)
149
GOPixbuf *pixbuf = GO_PIXBUF (image);
150
g_return_val_if_fail (pixbuf, NULL);
151
if (!pixbuf->pixbuf) {
152
if (image->width == 0 || image->height == 0 || image->data == NULL)
154
pixbuf->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
155
image->width, image->height);
156
cairo_to_pixbuf (pixbuf);
158
return g_object_ref (pixbuf->pixbuf);
162
go_pixbuf_get_scaled_pixbuf (GOImage *image, int width, int height)
164
GOPixbuf *pixbuf = GO_PIXBUF (image);
165
g_return_val_if_fail (pixbuf, NULL);
166
if (!pixbuf->pixbuf) {
167
if (image->width == 0 || image->height == 0 || image->data == NULL)
169
pixbuf->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
170
image->width, image->height);
171
cairo_to_pixbuf (pixbuf);
173
return gdk_pixbuf_scale_simple (pixbuf->pixbuf, width, height, GDK_INTERP_HYPER);
177
go_pixbuf_differ (GOImage *first, GOImage *second)
179
void *pixels1, *pixels2;
181
GOPixbuf *pfirst = GO_PIXBUF (first), *psecond = GO_PIXBUF (second);
183
go_pixbuf_get_pixbuf (first);
184
if (!psecond->pixbuf)
185
go_pixbuf_get_pixbuf (second);
186
if (!pfirst->pixbuf || !psecond->pixbuf)
187
return TRUE; /* this should not happen */
188
if (gdk_pixbuf_get_n_channels (pfirst->pixbuf) != gdk_pixbuf_get_n_channels (psecond->pixbuf))
190
if (gdk_pixbuf_get_colorspace (pfirst->pixbuf) != gdk_pixbuf_get_colorspace (psecond->pixbuf))
192
if (gdk_pixbuf_get_bits_per_sample (pfirst->pixbuf) != gdk_pixbuf_get_bits_per_sample (psecond->pixbuf))
194
if (gdk_pixbuf_get_has_alpha (pfirst->pixbuf) != gdk_pixbuf_get_has_alpha (psecond->pixbuf))
196
if (gdk_pixbuf_get_width (pfirst->pixbuf) != gdk_pixbuf_get_width (psecond->pixbuf))
198
if (gdk_pixbuf_get_height (pfirst->pixbuf) != gdk_pixbuf_get_height (psecond->pixbuf))
200
if (gdk_pixbuf_get_rowstride (pfirst->pixbuf) != gdk_pixbuf_get_rowstride (psecond->pixbuf))
202
pixels1 = gdk_pixbuf_get_pixels (pfirst->pixbuf);
203
pixels2 = gdk_pixbuf_get_pixels (psecond->pixbuf);
204
size = gdk_pixbuf_get_rowstride (pfirst->pixbuf) * gdk_pixbuf_get_height (pfirst->pixbuf);
205
return memcmp (pixels1, pixels2, size);
209
go_pixbuf_set_property (GObject *obj, guint param_id,
210
GValue const *value, GParamSpec *pspec)
212
GOPixbuf *pixbuf = GO_PIXBUF (obj);
213
GOImage *image = GO_IMAGE (obj);
216
case PIXBUF_PROP_PIXBUF: {
217
GdkPixbuf *pix = GDK_PIXBUF (g_value_get_object (value));
218
if (!GDK_IS_PIXBUF (pix))
220
if (!gdk_pixbuf_get_has_alpha (pix))
221
pix = gdk_pixbuf_add_alpha (pix, FALSE, 0, 0, 0);
225
g_object_unref (pixbuf->pixbuf);
226
pixbuf->pixbuf = pix;
227
g_free (image->data); /* this should be in GOPixbuf */
228
image->data = NULL; /* this should be in GOPixbuf */
229
_go_image_changed (image, gdk_pixbuf_get_width (pix), gdk_pixbuf_get_height (pix));
230
pixbuf->rowstride = gdk_pixbuf_get_rowstride (pix); /* this should be in GOPixbuf */
234
default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
235
return; /* NOTE : RETURN */
240
go_pixbuf_get_property (GObject *obj, guint param_id,
241
GValue *value, GParamSpec *pspec)
243
GOPixbuf *pixbuf = GO_PIXBUF (obj);
246
case PIXBUF_PROP_PIXBUF:
247
g_value_set_object (value, pixbuf->pixbuf);
250
default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
251
return; /* NOTE : RETURN */
256
go_pixbuf_finalize (GObject *obj)
258
GOPixbuf *pixbuf = GO_PIXBUF (obj);
260
g_object_unref (pixbuf->pixbuf);
262
cairo_surface_destroy (pixbuf->surface);
263
(parent_klass->finalize) (obj);
267
go_pixbuf_class_init (GObjectClass *klass)
269
GOImageClass *image_klass = (GOImageClass *) klass;
271
klass->finalize = go_pixbuf_finalize;
272
klass->set_property = go_pixbuf_set_property;
273
klass->get_property = go_pixbuf_get_property;
274
parent_klass = g_type_class_peek_parent (klass);
276
image_klass->save = go_pixbuf_save;
277
image_klass->load_attr = go_pixbuf_load_attr;
278
image_klass->load_data = go_pixbuf_load_data;
279
image_klass->get_pixbuf = go_pixbuf_get_pixbuf;
280
image_klass->get_scaled_pixbuf = go_pixbuf_get_scaled_pixbuf;
281
image_klass->draw = go_pixbuf_draw;
282
image_klass->differ = go_pixbuf_differ;
284
g_object_class_install_property (klass, PIXBUF_PROP_PIXBUF,
285
g_param_spec_object ("pixbuf", _("Pixbuf"),
286
_("GdkPixbuf object from which the GOPixbuf is built"),
287
GDK_TYPE_PIXBUF, G_PARAM_READWRITE));
290
GSF_CLASS (GOPixbuf, go_pixbuf,
291
go_pixbuf_class_init, NULL,
296
go_pixbuf_new_from_pixbuf (GdkPixbuf *pixbuf)
298
return g_object_new (GO_TYPE_PIXBUF, "pixbuf", pixbuf, NULL);
302
go_pixbuf_get_rowstride (GOPixbuf *pixbuf)
304
g_return_val_if_fail (GO_IS_PIXBUF (pixbuf), 0);
305
return pixbuf->rowstride;