1 /* GdkPixbuf library - GdkPixdata - functions for inlined pixbuf handling
2 * Copyright (C) 1999, 2001 Tim Janik
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
16 */
17 #include "config.h"
18
19 #include "gdk-pixbuf-private.h"
20 #include "gdk-pixdata.h"
21 #include <string.h>
22
23 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
24
25 /**
26 * SECTION:inline
27 * @Short_description: Functions for inlined pixbuf handling.
28 * @Title: Inline data
29 *
30 * Using #GdkPixdata, images can be compiled into an application,
31 * making it unnecessary to refer to external image files at runtime.
32 * GdkPixBuf includes a utility named gdk-pixbuf-csource, which
33 * can be used to convert image files into #GdkPixdata structures suitable
34 * for inclusion in C sources. To convert the #GdkPixdata structures back
35 * into #GdkPixbufs, use gdk_pixbuf_from_pixdata.
36 *
37 * #GdkPixdata should not be used any more. #GResource should be used to save
38 * the original compressed images inside the program's binary.
39 */
40
41 #define APPEND g_string_append_printf
42
43 /* --- functions --- */
44 static guint
pixdata_get_length(const GdkPixdata * pixdata)45 pixdata_get_length (const GdkPixdata *pixdata)
46 {
47 guint bpp, length;
48
49 if ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB)
50 bpp = 3;
51 else if ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA)
52 bpp = 4;
53 else
54 return 0; /* invalid format */
55 switch (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK)
56 {
57 guint8 *rle_buffer;
58 guint max_length;
59 case GDK_PIXDATA_ENCODING_RAW:
60 length = pixdata->rowstride * pixdata->height;
61 break;
62 case GDK_PIXDATA_ENCODING_RLE:
63 /* need an RLE walk to determine size */
64 max_length = pixdata->rowstride * pixdata->height;
65 rle_buffer = pixdata->pixel_data;
66 length = 0;
67 while (length < max_length)
68 {
69 guint chunk_length = *(rle_buffer++);
70
71 if (chunk_length & 128)
72 {
73 chunk_length = chunk_length - 128;
74 if (!chunk_length) /* RLE data corrupted */
75 return 0;
76 length += chunk_length * bpp;
77 rle_buffer += bpp;
78 }
79 else
80 {
81 if (!chunk_length) /* RLE data corrupted */
82 return 0;
83 chunk_length *= bpp;
84 length += chunk_length;
85 rle_buffer += chunk_length;
86 }
87 }
88 length = rle_buffer - pixdata->pixel_data;
89 break;
90 default:
91 length = 0;
92 break;
93 }
94 return length;
95 }
96
97 /**
98 * gdk_pixdata_serialize:
99 * @pixdata: a valid #GdkPixdata structure to serialize.
100 * @stream_length_p: location to store the resulting stream length in.
101 *
102 * Serializes a #GdkPixdata structure into a byte stream.
103 * The byte stream consists of a straightforward writeout of the
104 * #GdkPixdata fields in network byte order, plus the @pixel_data
105 * bytes the structure points to.
106 *
107 * Return value: (array length=stream_length_p) (transfer full): A
108 * newly-allocated string containing the serialized #GdkPixdata
109 * structure.
110 *
111 * Deprecated: 2.32: Use #GResource instead.
112 **/
113 guint8* /* free result */
gdk_pixdata_serialize(const GdkPixdata * pixdata,guint * stream_length_p)114 gdk_pixdata_serialize (const GdkPixdata *pixdata,
115 guint *stream_length_p)
116 {
117 guint8 *stream, *s;
118 guint32 *istream;
119 guint length;
120
121 /* check args passing */
122 g_return_val_if_fail (pixdata != NULL, NULL);
123 g_return_val_if_fail (stream_length_p != NULL, NULL);
124 /* check pixdata contents */
125 g_return_val_if_fail (pixdata->magic == GDK_PIXBUF_MAGIC_NUMBER, NULL);
126 g_return_val_if_fail (pixdata->width > 0, NULL);
127 g_return_val_if_fail (pixdata->height > 0, NULL);
128 g_return_val_if_fail (pixdata->rowstride >= pixdata->width, NULL);
129 g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ||
130 (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA, NULL);
131 g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_SAMPLE_WIDTH_MASK) == GDK_PIXDATA_SAMPLE_WIDTH_8, NULL);
132 g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RAW ||
133 (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RLE, NULL);
134 g_return_val_if_fail (pixdata->pixel_data != NULL, NULL);
135
136 length = pixdata_get_length (pixdata);
137
138 /* check length field */
139 g_return_val_if_fail (length != 0, NULL);
140
141 stream = g_malloc (GDK_PIXDATA_HEADER_LENGTH + length);
142 istream = (guint32*) stream;
143
144 /* store header */
145 *istream++ = g_htonl (GDK_PIXBUF_MAGIC_NUMBER);
146 *istream++ = g_htonl (GDK_PIXDATA_HEADER_LENGTH + length);
147 *istream++ = g_htonl (pixdata->pixdata_type);
148 *istream++ = g_htonl (pixdata->rowstride);
149 *istream++ = g_htonl (pixdata->width);
150 *istream++ = g_htonl (pixdata->height);
151
152 /* copy pixel data */
153 s = (guint8*) istream;
154 memcpy (s, pixdata->pixel_data, length);
155 s += length;
156
157 *stream_length_p = GDK_PIXDATA_HEADER_LENGTH + length;
158 g_assert (s - stream == *stream_length_p); /* paranoid */
159
160 return stream;
161 }
162
163 #define return_header_corrupt(error) { \
164 g_set_error_literal (error, GDK_PIXBUF_ERROR, \
165 GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Image header corrupt")); \
166 return FALSE; \
167 }
168 #define return_invalid_format(error) { \
169 g_set_error_literal (error, GDK_PIXBUF_ERROR, \
170 GDK_PIXBUF_ERROR_UNKNOWN_TYPE, _("Image format unknown")); \
171 return FALSE; \
172 }
173 #define return_pixel_corrupt(error) { \
174 g_set_error_literal (error, GDK_PIXBUF_ERROR, \
175 GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Image pixel data corrupt")); \
176 return FALSE; \
177 }
178
179 static inline const guint8 *
get_uint32(const guint8 * stream,guint * result)180 get_uint32 (const guint8 *stream, guint *result)
181 {
182 *result = (stream[0] << 24) + (stream[1] << 16) + (stream[2] << 8) + stream[3];
183 return stream + 4;
184 }
185
186 /**
187 * gdk_pixdata_deserialize:
188 * @pixdata: a #GdkPixdata structure to be filled in.
189 * @stream_length: length of the stream used for deserialization.
190 * @stream: (array length=stream_length): stream of bytes containing a
191 * serialized #GdkPixdata structure.
192 * @error: #GError location to indicate failures (maybe %NULL to ignore errors).
193 *
194 * Deserializes (reconstruct) a #GdkPixdata structure from a byte stream.
195 * The byte stream consists of a straightforward writeout of the
196 * #GdkPixdata fields in network byte order, plus the @pixel_data
197 * bytes the structure points to.
198 * The @pixdata contents are reconstructed byte by byte and are checked
199 * for validity. This function may fail with %GDK_PIXBUF_ERROR_CORRUPT_IMAGE
200 * or %GDK_PIXBUF_ERROR_UNKNOWN_TYPE.
201 *
202 * Return value: Upon successful deserialization %TRUE is returned,
203 * %FALSE otherwise.
204 *
205 * Deprecated: 2.32: Use #GResource instead.
206 **/
207 gboolean
gdk_pixdata_deserialize(GdkPixdata * pixdata,guint stream_length,const guint8 * stream,GError ** error)208 gdk_pixdata_deserialize (GdkPixdata *pixdata,
209 guint stream_length,
210 const guint8 *stream,
211 GError **error)
212 {
213 guint color_type, sample_width, encoding;
214
215 g_return_val_if_fail (pixdata != NULL, FALSE);
216 if (stream_length < GDK_PIXDATA_HEADER_LENGTH)
217 return_header_corrupt (error);
218 g_return_val_if_fail (stream != NULL, FALSE);
219
220
221 /* deserialize header */
222 stream = get_uint32 (stream, &pixdata->magic);
223 stream = get_uint32 (stream, (guint32 *)&pixdata->length);
224 if (pixdata->magic != GDK_PIXBUF_MAGIC_NUMBER || pixdata->length < GDK_PIXDATA_HEADER_LENGTH)
225 return_header_corrupt (error);
226 stream = get_uint32 (stream, &pixdata->pixdata_type);
227 stream = get_uint32 (stream, &pixdata->rowstride);
228 stream = get_uint32 (stream, &pixdata->width);
229 stream = get_uint32 (stream, &pixdata->height);
230 if (pixdata->width < 1 || pixdata->height < 1 ||
231 pixdata->rowstride < pixdata->width)
232 return_header_corrupt (error);
233 color_type = pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK;
234 sample_width = pixdata->pixdata_type & GDK_PIXDATA_SAMPLE_WIDTH_MASK;
235 encoding = pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK;
236 if ((color_type != GDK_PIXDATA_COLOR_TYPE_RGB &&
237 color_type != GDK_PIXDATA_COLOR_TYPE_RGBA) ||
238 sample_width != GDK_PIXDATA_SAMPLE_WIDTH_8 ||
239 (encoding != GDK_PIXDATA_ENCODING_RAW &&
240 encoding != GDK_PIXDATA_ENCODING_RLE))
241 return_invalid_format (error);
242
243 /* deserialize pixel data */
244 if (stream_length < pixdata->length - GDK_PIXDATA_HEADER_LENGTH)
245 return_pixel_corrupt (error);
246 pixdata->pixel_data = (guint8 *)stream;
247
248 return TRUE;
249 }
250
251 static gboolean
diff2_rgb(const guint8 * ip)252 diff2_rgb (const guint8 *ip)
253 {
254 return ip[0] != ip[3] || ip[1] != ip[4] || ip[2] != ip[5];
255 }
256
257 static gboolean
diff2_rgba(const guint8 * ip)258 diff2_rgba (const guint8 *ip)
259 {
260 return ip[0] != ip[4] || ip[1] != ip[5] || ip[2] != ip[6] || ip[3] != ip[7];
261 }
262
263 static guint8 * /* dest buffer bound */
rl_encode_rgbx(guint8 * bp,const guint8 * ip,const guint8 * limit,guint n_ch)264 rl_encode_rgbx (guint8 *bp, /* dest buffer */
265 const guint8 *ip, /* image pointer */
266 const guint8 *limit, /* image upper bound */
267 guint n_ch)
268 {
269 gboolean (*diff2_pix) (const guint8 *) = n_ch > 3 ? diff2_rgba : diff2_rgb;
270 const guint8 *ilimit = limit - n_ch;
271
272 while (ip < limit)
273 {
274 g_assert (ip < ilimit); /* paranoid */
275
276 if (diff2_pix (ip))
277 {
278 const guint8 *s_ip = ip;
279 guint l = 1;
280
281 ip += n_ch;
282 while (l < 127 && ip < ilimit && diff2_pix (ip))
283 { ip += n_ch; l += 1; }
284 if (ip == ilimit && l < 127)
285 { ip += n_ch; l += 1; }
286 *(bp++) = l;
287 memcpy (bp, s_ip, l * n_ch);
288 bp += l * n_ch;
289 }
290 else
291 {
292 guint l = 2;
293
294 ip += n_ch;
295 while (l < 127 && ip < ilimit && !diff2_pix (ip))
296 { ip += n_ch; l += 1; }
297 *(bp++) = l | 128;
298 memcpy (bp, ip, n_ch);
299 ip += n_ch;
300 bp += n_ch;
301 }
302 if (ip == ilimit)
303 {
304 *(bp++) = 1;
305 memcpy (bp, ip, n_ch);
306 ip += n_ch;
307 bp += n_ch;
308 }
309 }
310
311 return bp;
312 }
313
314 /* Used as the destroy notification function for gdk_pixbuf_new() */
315 static void
free_buffer(guchar * pixels,gpointer data)316 free_buffer (guchar *pixels, gpointer data)
317 {
318 g_free (pixels);
319 }
320
321 /**
322 * gdk_pixdata_from_pixbuf: (skip)
323 * @pixdata: a #GdkPixdata to fill.
324 * @pixbuf: the data to fill @pixdata with.
325 * @use_rle: whether to use run-length encoding for the pixel data.
326 *
327 * Converts a #GdkPixbuf to a #GdkPixdata. If @use_rle is %TRUE, the
328 * pixel data is run-length encoded into newly-allocated memory and a
329 * pointer to that memory is returned.
330 *
331 * Returns: (nullable): If @use_rle is %TRUE, a pointer to the
332 * newly-allocated memory for the run-length encoded pixel data,
333 * otherwise %NULL.
334 *
335 * Deprecated: 2.32: Use #GResource instead.
336 **/
337 gpointer
gdk_pixdata_from_pixbuf(GdkPixdata * pixdata,const GdkPixbuf * pixbuf,gboolean use_rle)338 gdk_pixdata_from_pixbuf (GdkPixdata *pixdata,
339 const GdkPixbuf *pixbuf,
340 gboolean use_rle)
341 {
342 gpointer free_me = NULL;
343 guint height, rowstride, encoding, bpp, length;
344 const guint8 *pixels = NULL;
345 guint8 *img_buffer;
346
347 g_return_val_if_fail (pixdata != NULL, NULL);
348 g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
349 g_return_val_if_fail (pixbuf->bits_per_sample == 8, NULL);
350 g_return_val_if_fail ((pixbuf->n_channels == 3 && !pixbuf->has_alpha) ||
351 (pixbuf->n_channels == 4 && pixbuf->has_alpha), NULL);
352 g_return_val_if_fail (pixbuf->rowstride >= pixbuf->width, NULL);
353
354 height = pixbuf->height;
355 rowstride = pixbuf->rowstride;
356 bpp = pixbuf->has_alpha ? 4 : 3;
357 encoding = use_rle && ((rowstride / bpp | height) > 1) ? GDK_PIXDATA_ENCODING_RLE : GDK_PIXDATA_ENCODING_RAW;
358
359 if (encoding == GDK_PIXDATA_ENCODING_RLE)
360 {
361 guint pad, n_bytes = rowstride * height;
362 guint8 *img_buffer_end, *data;
363 GdkPixbuf *buf = NULL;
364
365 if (n_bytes % bpp != 0)
366 {
367 rowstride = pixbuf->width * bpp;
368 n_bytes = rowstride * height;
369 data = g_malloc (n_bytes);
370 buf = gdk_pixbuf_new_from_data (data,
371 GDK_COLORSPACE_RGB,
372 pixbuf->has_alpha, 8,
373 pixbuf->width,
374 pixbuf->height,
375 rowstride,
376 free_buffer, NULL);
377 gdk_pixbuf_copy_area (pixbuf, 0, 0, pixbuf->width, pixbuf->height,
378 buf, 0, 0);
379 }
380 else
381 buf = (GdkPixbuf *)pixbuf;
382
383 pixels = gdk_pixbuf_read_pixels (buf);
384 pad = rowstride;
385 pad = MAX (pad, 130 + n_bytes / 127);
386 data = g_new (guint8, pad + n_bytes);
387 free_me = data;
388 img_buffer = data;
389 img_buffer_end = rl_encode_rgbx (img_buffer,
390 pixels, pixels + n_bytes,
391 bpp);
392 length = img_buffer_end - img_buffer;
393 if (buf != pixbuf)
394 g_object_unref (buf);
395 }
396 else
397 {
398 img_buffer = (guint8 *) gdk_pixbuf_read_pixels (pixbuf);
399 length = rowstride * height;
400 }
401
402 pixdata->magic = GDK_PIXBUF_MAGIC_NUMBER;
403 pixdata->length = GDK_PIXDATA_HEADER_LENGTH + length;
404 pixdata->pixdata_type = pixbuf->has_alpha ? GDK_PIXDATA_COLOR_TYPE_RGBA : GDK_PIXDATA_COLOR_TYPE_RGB;
405 pixdata->pixdata_type |= GDK_PIXDATA_SAMPLE_WIDTH_8;
406 pixdata->pixdata_type |= encoding;
407 pixdata->rowstride = rowstride;
408 pixdata->width = pixbuf->width;
409 pixdata->height = height;
410 pixdata->pixel_data = img_buffer;
411
412 return free_me;
413 }
414
415 /* From glib's gmem.c */
416 #define SIZE_OVERFLOWS(a,b) (G_UNLIKELY ((b) > 0 && (a) > G_MAXSIZE / (b)))
417
418 #define RLE_OVERRUN(offset) (rle_buffer_limit == NULL ? FALSE : rle_buffer + (offset) > rle_buffer_limit)
419
420 /**
421 * gdk_pixbuf_from_pixdata:
422 * @pixdata: a #GdkPixdata to convert into a #GdkPixbuf.
423 * @copy_pixels: whether to copy raw pixel data; run-length encoded
424 * pixel data is always copied.
425 * @error: location to store possible errors.
426 *
427 * Converts a #GdkPixdata to a #GdkPixbuf. If @copy_pixels is %TRUE or
428 * if the pixel data is run-length-encoded, the pixel data is copied into
429 * newly-allocated memory; otherwise it is reused.
430 *
431 * Returns: (transfer full): a new #GdkPixbuf.
432 * Deprecated: 2.32: Use #GResource instead.
433 **/
434 GdkPixbuf*
gdk_pixbuf_from_pixdata(const GdkPixdata * pixdata,gboolean copy_pixels,GError ** error)435 gdk_pixbuf_from_pixdata (const GdkPixdata *pixdata,
436 gboolean copy_pixels,
437 GError **error)
438 {
439 guint encoding, bpp;
440 guint8 *data = NULL;
441
442 g_return_val_if_fail (pixdata != NULL, NULL);
443 g_return_val_if_fail (pixdata->width > 0, NULL);
444 g_return_val_if_fail (pixdata->height > 0, NULL);
445 g_return_val_if_fail (pixdata->rowstride >= pixdata->width, NULL);
446 g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ||
447 (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA, NULL);
448 g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_SAMPLE_WIDTH_MASK) == GDK_PIXDATA_SAMPLE_WIDTH_8, NULL);
449 g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RAW ||
450 (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RLE, NULL);
451 g_return_val_if_fail (pixdata->pixel_data != NULL, NULL);
452
453 bpp = (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ? 3 : 4;
454 encoding = pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK;
455
456 g_debug ("gdk_pixbuf_from_pixdata() called on:");
457 g_debug ("\tEncoding %s", encoding == GDK_PIXDATA_ENCODING_RAW ? "raw" : "rle");
458 g_debug ("\tDimensions: %d x %d", pixdata->width, pixdata->height);
459 g_debug ("\tRowstride: %d, Length: %d", pixdata->rowstride, pixdata->length);
460 g_debug ("\tCopy pixels == %s", copy_pixels ? "true" : "false");
461
462 if (encoding == GDK_PIXDATA_ENCODING_RLE)
463 copy_pixels = TRUE;
464
465 /* Sanity check the length and dimensions */
466 if (SIZE_OVERFLOWS (pixdata->height, pixdata->rowstride))
467 {
468 g_set_error_literal (error, GDK_PIXBUF_ERROR,
469 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
470 _("Image pixel data corrupt"));
471 return NULL;
472 }
473
474 if (encoding == GDK_PIXDATA_ENCODING_RAW &&
475 pixdata->length >= 1 &&
476 pixdata->length < pixdata->height * pixdata->rowstride - GDK_PIXDATA_HEADER_LENGTH)
477 {
478 g_set_error_literal (error, GDK_PIXBUF_ERROR,
479 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
480 _("Image pixel data corrupt"));
481 return NULL;
482 }
483
484 if (copy_pixels)
485 {
486 data = g_try_malloc_n (pixdata->height, pixdata->rowstride);
487 if (!data)
488 {
489 g_set_error (error, GDK_PIXBUF_ERROR,
490 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
491 g_dngettext(GETTEXT_PACKAGE,
492 "failed to allocate image buffer of %u byte",
493 "failed to allocate image buffer of %u bytes",
494 pixdata->rowstride * pixdata->height),
495 pixdata->rowstride * pixdata->height);
496 return NULL;
497 }
498 }
499 if (encoding == GDK_PIXDATA_ENCODING_RLE)
500 {
501 const guint8 *rle_buffer = pixdata->pixel_data;
502 guint8 *rle_buffer_limit = NULL;
503 guint8 *image_buffer = data;
504 guint8 *image_limit = data + pixdata->rowstride * pixdata->height;
505 gboolean check_overrun = FALSE;
506
507 if (pixdata->length >= 1)
508 rle_buffer_limit = pixdata->pixel_data + pixdata->length - GDK_PIXDATA_HEADER_LENGTH;
509
510 while (image_buffer < image_limit &&
511 (rle_buffer_limit != NULL || rle_buffer > rle_buffer_limit))
512 {
513 guint length;
514
515 if (RLE_OVERRUN(1))
516 {
517 check_overrun = TRUE;
518 break;
519 }
520
521 length = *(rle_buffer++);
522
523 if (length & 128)
524 {
525 length = length - 128;
526 check_overrun = image_buffer + length * bpp > image_limit;
527 if (check_overrun)
528 length = (image_limit - image_buffer) / bpp;
529 if (RLE_OVERRUN(bpp < 4 ? 3 : 4))
530 {
531 check_overrun = TRUE;
532 break;
533 }
534 if (bpp < 4) /* RGB */
535 do
536 {
537 memcpy (image_buffer, rle_buffer, 3);
538 image_buffer += 3;
539 }
540 while (--length);
541 else /* RGBA */
542 do
543 {
544 memcpy (image_buffer, rle_buffer, 4);
545 image_buffer += 4;
546 }
547 while (--length);
548 if (RLE_OVERRUN(bpp))
549 {
550 check_overrun = TRUE;
551 break;
552 }
553 rle_buffer += bpp;
554 }
555 else
556 {
557 length *= bpp;
558 check_overrun = image_buffer + length > image_limit;
559 if (check_overrun)
560 length = image_limit - image_buffer;
561 if (RLE_OVERRUN(length))
562 {
563 check_overrun = TRUE;
564 break;
565 }
566 memcpy (image_buffer, rle_buffer, length);
567 image_buffer += length;
568 rle_buffer += length;
569 }
570 }
571 if (check_overrun)
572 {
573 g_free (data);
574 g_set_error_literal (error, GDK_PIXBUF_ERROR,
575 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
576 _("Image pixel data corrupt"));
577 return NULL;
578 }
579 }
580 else if (copy_pixels)
581 memcpy (data, pixdata->pixel_data, pixdata->rowstride * pixdata->height);
582 else
583 data = pixdata->pixel_data;
584
585 return gdk_pixbuf_new_from_data (data, GDK_COLORSPACE_RGB,
586 (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA,
587 8, pixdata->width, pixdata->height, pixdata->rowstride,
588 copy_pixels ? (GdkPixbufDestroyNotify) g_free : NULL, data);
589 }
590
591 typedef struct {
592 /* config */
593 gboolean dump_stream;
594 gboolean dump_struct;
595 gboolean dump_macros;
596 gboolean dump_gtypes;
597 gboolean dump_rle_decoder;
598 const gchar *static_prefix;
599 const gchar *const_prefix;
600 /* runtime */
601 GString *gstring;
602 guint pos;
603 gboolean pad;
604 } CSourceData;
605
606 static inline void
save_uchar(CSourceData * cdata,guint8 d)607 save_uchar (CSourceData *cdata,
608 guint8 d)
609 {
610 GString *gstring = cdata->gstring;
611
612 if (cdata->pos > 70)
613 {
614 if (cdata->dump_struct || cdata->dump_stream)
615 {
616 g_string_append (gstring, "\"\n \"");
617 cdata->pos = 3;
618 cdata->pad = FALSE;
619 }
620 if (cdata->dump_macros)
621 {
622 g_string_append (gstring, "\" \\\n \"");
623 cdata->pos = 3;
624 cdata->pad = FALSE;
625 }
626 }
627 if (d < 33 || d > 126 || d == '?')
628 {
629 APPEND (gstring, "\\%o", d);
630 cdata->pos += 1 + 1 + (d > 7) + (d > 63);
631 cdata->pad = d < 64;
632 return;
633 }
634 if (d == '\\')
635 {
636 g_string_append (gstring, "\\\\");
637 cdata->pos += 2;
638 }
639 else if (d == '"')
640 {
641 g_string_append (gstring, "\\\"");
642 cdata->pos += 2;
643 }
644 else if (cdata->pad && d >= '0' && d <= '9')
645 {
646 g_string_append (gstring, "\"\"");
647 g_string_append_c (gstring, d);
648 cdata->pos += 3;
649 }
650 else
651 {
652 g_string_append_c (gstring, d);
653 cdata->pos += 1;
654 }
655 cdata->pad = FALSE;
656 return;
657 }
658
659 static inline void
save_rle_decoder(GString * gstring,const gchar * macro_name,const gchar * s_uint,const gchar * s_uint_8,guint n_ch)660 save_rle_decoder (GString *gstring,
661 const gchar *macro_name,
662 const gchar *s_uint,
663 const gchar *s_uint_8,
664 guint n_ch)
665 {
666 APPEND (gstring, "#define %s_RUN_LENGTH_DECODE(image_buf, rle_data, size, bpp) do \\\n",
667 macro_name);
668 APPEND (gstring, "{ %s __bpp; %s *__ip; const %s *__il, *__rd; \\\n", s_uint, s_uint_8, s_uint_8);
669 APPEND (gstring, " __bpp = (bpp); __ip = (image_buf); __il = __ip + (size) * __bpp; \\\n");
670
671 APPEND (gstring, " __rd = (rle_data); if (__bpp > 3) { /* RGBA */ \\\n");
672
673 APPEND (gstring, " while (__ip < __il) { %s __l = *(__rd++); \\\n", s_uint);
674 APPEND (gstring, " if (__l & 128) { __l = __l - 128; \\\n");
675 APPEND (gstring, " do { memcpy (__ip, __rd, 4); __ip += 4; } while (--__l); __rd += 4; \\\n");
676 APPEND (gstring, " } else { __l *= 4; memcpy (__ip, __rd, __l); \\\n");
677 APPEND (gstring, " __ip += __l; __rd += __l; } } \\\n");
678
679 APPEND (gstring, " } else { /* RGB */ \\\n");
680
681 APPEND (gstring, " while (__ip < __il) { %s __l = *(__rd++); \\\n", s_uint);
682 APPEND (gstring, " if (__l & 128) { __l = __l - 128; \\\n");
683 APPEND (gstring, " do { memcpy (__ip, __rd, 3); __ip += 3; } while (--__l); __rd += 3; \\\n");
684 APPEND (gstring, " } else { __l *= 3; memcpy (__ip, __rd, __l); \\\n");
685 APPEND (gstring, " __ip += __l; __rd += __l; } } \\\n");
686
687 APPEND (gstring, " } } while (0)\n");
688 }
689
690 /**
691 * gdk_pixdata_to_csource:
692 * @pixdata: a #GdkPixdata to convert to C source.
693 * @name: used for naming generated data structures or macros.
694 * @dump_type: a #GdkPixdataDumpType determining the kind of C
695 * source to be generated.
696 *
697 * Generates C source code suitable for compiling images directly
698 * into programs.
699 *
700 * gdk-pixbuf ships with a program called
701 * [gdk-pixbuf-csource][gdk-pixbuf-csource], which offers a command
702 * line interface to this function.
703 *
704 * Returns: a newly-allocated string containing the C source form
705 * of @pixdata.
706 * Deprecated: 2.32: Use #GResource instead.
707 **/
708 GString*
gdk_pixdata_to_csource(GdkPixdata * pixdata,const gchar * name,GdkPixdataDumpType dump_type)709 gdk_pixdata_to_csource (GdkPixdata *pixdata,
710 const gchar *name,
711 GdkPixdataDumpType dump_type)
712 {
713 CSourceData cdata = { 0, };
714 gchar *s_uint_8;
715 guint bpp, width, height, rowstride;
716 gboolean rle_encoded;
717 gchar *macro_name;
718 guint8 *img_buffer, *img_buffer_end, *stream = NULL;
719 guint stream_length;
720 GString *gstring;
721
722 /* check args passing */
723 g_return_val_if_fail (pixdata != NULL, NULL);
724 g_return_val_if_fail (name != NULL, NULL);
725 /* check pixdata contents */
726 g_return_val_if_fail (pixdata->magic == GDK_PIXBUF_MAGIC_NUMBER, NULL);
727 g_return_val_if_fail (pixdata->width > 0, NULL);
728 g_return_val_if_fail (pixdata->height > 0, NULL);
729 g_return_val_if_fail (pixdata->rowstride >= pixdata->width, NULL);
730 g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ||
731 (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA, NULL);
732 g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_SAMPLE_WIDTH_MASK) == GDK_PIXDATA_SAMPLE_WIDTH_8, NULL);
733 g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RAW ||
734 (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RLE, NULL);
735 g_return_val_if_fail (pixdata->pixel_data != NULL, NULL);
736
737 img_buffer = pixdata->pixel_data;
738 if (pixdata->length < 1)
739 img_buffer_end = img_buffer + pixdata_get_length (pixdata);
740 else
741 img_buffer_end = img_buffer + pixdata->length - GDK_PIXDATA_HEADER_LENGTH;
742 g_return_val_if_fail (img_buffer < img_buffer_end, NULL);
743
744 bpp = (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ? 3 : 4;
745 width = pixdata->width;
746 height = pixdata->height;
747 rowstride = pixdata->rowstride;
748 rle_encoded = (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_RLE) > 0;
749 macro_name = g_ascii_strup (name, -1);
750
751 cdata.dump_macros = (dump_type & GDK_PIXDATA_DUMP_MACROS) > 0;
752 cdata.dump_struct = (dump_type & GDK_PIXDATA_DUMP_PIXDATA_STRUCT) > 0;
753 cdata.dump_stream = !cdata.dump_macros && !cdata.dump_struct;
754 g_return_val_if_fail (cdata.dump_macros + cdata.dump_struct + cdata.dump_stream == 1, NULL);
755
756 cdata.dump_gtypes = (dump_type & GDK_PIXDATA_DUMP_CTYPES) == 0;
757 cdata.dump_rle_decoder = (dump_type & GDK_PIXDATA_DUMP_RLE_DECODER) > 0;
758 cdata.static_prefix = (dump_type & GDK_PIXDATA_DUMP_STATIC) ? "static " : "";
759 cdata.const_prefix = (dump_type & GDK_PIXDATA_DUMP_CONST) ? "const " : "";
760 gstring = g_string_new (NULL);
761 cdata.gstring = gstring;
762
763 if (!cdata.dump_macros && cdata.dump_gtypes)
764 s_uint_8 = "guint8 ";
765 else if (!cdata.dump_macros)
766 s_uint_8 = "unsigned char";
767 else if (cdata.dump_macros && cdata.dump_gtypes)
768 s_uint_8 = "guint8";
769 else /* cdata.dump_macros && !cdata.dump_gtypes */
770 s_uint_8 = "unsigned char";
771
772 /* initial comment
773 */
774 APPEND (gstring,
775 "/* GdkPixbuf %s C-Source image dump %s*/\n\n",
776 bpp > 3 ? "RGBA" : "RGB",
777 rle_encoded ? "1-byte-run-length-encoded " : "");
778
779 /* dump RLE decoder for structures
780 */
781 if (cdata.dump_rle_decoder && cdata.dump_struct)
782 save_rle_decoder (gstring,
783 macro_name,
784 cdata.dump_gtypes ? "guint" : "unsigned int",
785 cdata.dump_gtypes ? "guint8" : "unsigned char",
786 bpp);
787
788 /* format & size blurbs
789 */
790 if (cdata.dump_macros)
791 {
792 APPEND (gstring, "#define %s_ROWSTRIDE (%u)\n",
793 macro_name, rowstride);
794 APPEND (gstring, "#define %s_WIDTH (%u)\n",
795 macro_name, width);
796 APPEND (gstring, "#define %s_HEIGHT (%u)\n",
797 macro_name, height);
798 APPEND (gstring, "#define %s_BYTES_PER_PIXEL (%u) /* 3:RGB, 4:RGBA */\n",
799 macro_name, bpp);
800 }
801 if (cdata.dump_struct)
802 {
803 APPEND (gstring, "%s%sGdkPixdata %s = {\n",
804 cdata.static_prefix, cdata.const_prefix, name);
805 APPEND (gstring, " 0x%x, /* Pixbuf magic: 'GdkP' */\n",
806 GDK_PIXBUF_MAGIC_NUMBER);
807 APPEND (gstring, " %d + %lu, /* header length + pixel_data length */\n",
808 GDK_PIXDATA_HEADER_LENGTH,
809 rle_encoded ? (glong)(img_buffer_end - img_buffer) : (glong)rowstride * height);
810 APPEND (gstring, " 0x%x, /* pixdata_type */\n",
811 pixdata->pixdata_type);
812 APPEND (gstring, " %u, /* rowstride */\n",
813 rowstride);
814 APPEND (gstring, " %u, /* width */\n",
815 width);
816 APPEND (gstring, " %u, /* height */\n",
817 height);
818 APPEND (gstring, " /* pixel_data: */\n");
819 }
820 if (cdata.dump_stream)
821 {
822 guint pix_length = img_buffer_end - img_buffer;
823
824
825 stream = gdk_pixdata_serialize (pixdata, &stream_length);
826 img_buffer = stream;
827 img_buffer_end = stream + stream_length;
828
829 APPEND (gstring, "#ifdef __SUNPRO_C\n");
830 APPEND (gstring, "#pragma align 4 (%s)\n", name);
831 APPEND (gstring, "#endif\n");
832
833 APPEND (gstring, "#ifdef __GNUC__\n");
834 APPEND (gstring, "%s%s%s %s[] __attribute__ ((__aligned__ (4))) = \n",
835 cdata.static_prefix, cdata.const_prefix,
836 cdata.dump_gtypes ? "guint8" : "unsigned char",
837 name);
838 APPEND (gstring, "#else\n");
839 APPEND (gstring, "%s%s%s %s[] = \n",
840 cdata.static_prefix, cdata.const_prefix,
841 cdata.dump_gtypes ? "guint8" : "unsigned char",
842 name);
843 APPEND (gstring, "#endif\n");
844
845 APPEND (gstring, "{ \"\"\n /* Pixbuf magic (0x%x) */\n \"",
846 GDK_PIXBUF_MAGIC_NUMBER);
847 cdata.pos = 3;
848 save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
849 save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
850 APPEND (gstring, "\"\n /* length: header (%d) + pixel_data (%u) */\n \"",
851 GDK_PIXDATA_HEADER_LENGTH,
852 rle_encoded ? pix_length : rowstride * height);
853 cdata.pos = 3;
854 save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
855 save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
856 APPEND (gstring, "\"\n /* pixdata_type (0x%x) */\n \"",
857 pixdata->pixdata_type);
858 cdata.pos = 3;
859 save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
860 save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
861 APPEND (gstring, "\"\n /* rowstride (%u) */\n \"",
862 rowstride);
863 cdata.pos = 3;
864 save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
865 save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
866 APPEND (gstring, "\"\n /* width (%u) */\n \"", width);
867 cdata.pos = 3;
868 save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
869 save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
870 APPEND (gstring, "\"\n /* height (%u) */\n \"", height);
871 cdata.pos = 3;
872 save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
873 save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
874 APPEND (gstring, "\"\n /* pixel_data: */\n");
875 }
876
877 /* pixel_data intro
878 */
879 if (cdata.dump_macros)
880 {
881 APPEND (gstring, "#define %s_%sPIXEL_DATA ((%s*) \\\n",
882 macro_name,
883 rle_encoded ? "RLE_" : "",
884 s_uint_8);
885 APPEND (gstring, " \"");
886 cdata.pos = 2;
887 }
888 if (cdata.dump_struct)
889 {
890 APPEND (gstring, " \"");
891 cdata.pos = 3;
892 }
893 if (cdata.dump_stream)
894 {
895 APPEND (gstring, " \"");
896 cdata.pos = 3;
897 }
898
899 /* pixel_data
900 */
901 do
902 save_uchar (&cdata, *img_buffer++);
903 while (img_buffer < img_buffer_end);
904
905 /* pixel_data trailer
906 */
907 if (cdata.dump_macros)
908 APPEND (gstring, "\")\n\n");
909 if (cdata.dump_struct)
910 APPEND (gstring, "\",\n};\n\n");
911 if (cdata.dump_stream)
912 APPEND (gstring, "\"};\n\n");
913
914 /* dump RLE decoder for macros
915 */
916 if (cdata.dump_rle_decoder && cdata.dump_macros)
917 save_rle_decoder (gstring,
918 macro_name,
919 cdata.dump_gtypes ? "guint" : "unsigned int",
920 cdata.dump_gtypes ? "guint8" : "unsigned char",
921 bpp);
922
923 /* cleanup
924 */
925 g_free (stream);
926 g_free (macro_name);
927
928 return gstring;
929 }
930
931 /**
932 * gdk_pixbuf_new_from_inline:
933 * @data_length: Length in bytes of the @data argument or -1 to
934 * disable length checks
935 * @data: (array length=data_length): Byte data containing a
936 * serialized #GdkPixdata structure
937 * @copy_pixels: Whether to copy the pixel data, or use direct pointers
938 * @data for the resulting pixbuf
939 * @error: #GError return location, may be %NULL to ignore errors
940 *
941 * Create a #GdkPixbuf from a flat representation that is suitable for
942 * storing as inline data in a program. This is useful if you want to
943 * ship a program with images, but don't want to depend on any
944 * external files.
945 *
946 * gdk-pixbuf ships with a program called [gdk-pixbuf-csource][gdk-pixbuf-csource],
947 * which allows for conversion of #GdkPixbufs into such a inline representation.
948 * In almost all cases, you should pass the `--raw` option to
949 * `gdk-pixbuf-csource`. A sample invocation would be:
950 *
951 * |[
952 * gdk-pixbuf-csource --raw --name=myimage_inline myimage.png
953 * ]|
954 *
955 * For the typical case where the inline pixbuf is read-only static data,
956 * you don't need to copy the pixel data unless you intend to write to
957 * it, so you can pass %FALSE for @copy_pixels. (If you pass `--rle` to
958 * `gdk-pixbuf-csource`, a copy will be made even if @copy_pixels is %FALSE,
959 * so using this option is generally a bad idea.)
960 *
961 * If you create a pixbuf from const inline data compiled into your
962 * program, it's probably safe to ignore errors and disable length checks,
963 * since things will always succeed:
964 * |[
965 * pixbuf = gdk_pixbuf_new_from_inline (-1, myimage_inline, FALSE, NULL);
966 * ]|
967 *
968 * For non-const inline data, you could get out of memory. For untrusted
969 * inline data located at runtime, you could have corrupt inline data in
970 * addition.
971 *
972 * Return value: A newly-created #GdkPixbuf structure with a reference,
973 * count of 1, or %NULL if an error occurred.
974 *
975 * Deprecated: 2.32: Use #GResource instead.
976 **/
977 GdkPixbuf*
gdk_pixbuf_new_from_inline(gint data_length,const guint8 * data,gboolean copy_pixels,GError ** error)978 gdk_pixbuf_new_from_inline (gint data_length,
979 const guint8 *data,
980 gboolean copy_pixels,
981 GError **error)
982 {
983 GdkPixdata pixdata;
984
985 if (data_length != -1)
986 g_return_val_if_fail (data_length > GDK_PIXDATA_HEADER_LENGTH, NULL);
987 g_return_val_if_fail (data != NULL, NULL);
988
989 if (!gdk_pixdata_deserialize (&pixdata, data_length, data, error))
990 return NULL;
991
992 return gdk_pixbuf_from_pixdata (&pixdata, copy_pixels, error);
993 }
994