]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/gdk-pixdata.c
use gdk_pixbuf_new_from_stream(). fixed up item factory so inlined pixbufs
[~andy/gtk] / gdk-pixbuf / gdk-pixdata.c
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, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 #include "gdk-pixdata.h"
20
21 #include "gdk-pixbuf-private.h"
22 #include "gdk-pixbuf-i18n.h"
23
24
25 /* --- functions --- */
26 static guint
27 pixdata_get_length (const GdkPixdata *pixdata)
28 {
29   guint bpp, length;
30
31   if ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB)
32     bpp = 3;
33   else if ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA)
34     bpp = 4;
35   else
36     return 0;   /* invalid format */
37   switch (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK)
38     {
39       guint8 *rle_buffer;
40       guint max_length;
41     case GDK_PIXDATA_ENCODING_RAW:
42       length = pixdata->rowstride * pixdata->height;
43       break;
44     case GDK_PIXDATA_ENCODING_RLE:
45       /* need an RLE walk to determine size */
46       max_length = pixdata->rowstride * pixdata->height;
47       rle_buffer = pixdata->pixel_data;
48       length = 0;
49       while (length < max_length)
50         {
51           guint chunk_length = *(rle_buffer++);
52
53           if (chunk_length & 128)
54             {
55               chunk_length = chunk_length - 128;
56               if (!chunk_length)        /* RLE data corrupted */
57                 return 0;
58               length += chunk_length * bpp;
59               rle_buffer += bpp;
60             }
61           else
62             {
63               if (!chunk_length)        /* RLE data corrupted */
64                 return 0;
65               chunk_length *= bpp;
66               length += chunk_length;
67               rle_buffer += chunk_length;
68             }
69         }
70       length = rle_buffer - pixdata->pixel_data;
71       break;
72     default:
73       length = 0;
74       break;
75     }
76   return length;
77 }
78
79 /**
80  * gdk_pixdata_serialize:
81  * @pixdata: A valid GdkPixdata structure to serialize
82  * @stream_length_p: Location to store the resulting stream length in
83  *
84  * Serialize a #GdkPixdata structure into a byte stream.
85  * The byte stream consists of a straight forward write out of the
86  * #GdkPixdata fields in network byte order, plus the pixel_data
87  * bytes the structure points to.
88  *
89  * Return value: A newly-allocated string containing the serialized
90  * GdkPixdata structure
91  **/
92 guint8* /* free result */
93 gdk_pixdata_serialize (const GdkPixdata *pixdata,
94                        guint            *stream_length_p)
95 {
96   guint8 *stream, *s;
97   guint32 *istream;
98   guint length;
99
100   /* check args passing */
101   g_return_val_if_fail (pixdata != NULL, NULL);
102   g_return_val_if_fail (stream_length_p != NULL, NULL);
103   /* check pixdata contents */
104   g_return_val_if_fail (pixdata->magic == GDK_PIXBUF_MAGIC_NUMBER, NULL);
105   g_return_val_if_fail (pixdata->width > 0, NULL);
106   g_return_val_if_fail (pixdata->height > 0, NULL);
107   g_return_val_if_fail (pixdata->rowstride >= pixdata->width, NULL);
108   g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ||
109                         (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA, NULL);
110   g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_SAMPLE_WIDTH_MASK) == GDK_PIXDATA_SAMPLE_WIDTH_8, NULL);
111   g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RAW ||
112                         (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RLE, NULL);
113   g_return_val_if_fail (pixdata->pixel_data != NULL, NULL);
114
115   length = pixdata_get_length (pixdata);
116
117   /* check length field */
118   g_return_val_if_fail (length != 0, NULL);
119   
120   stream = g_malloc (GDK_PIXDATA_HEADER_LENGTH + length);
121   istream = (guint32*) stream;
122
123   /* store header */
124   *istream++ = g_htonl (GDK_PIXBUF_MAGIC_NUMBER);
125   *istream++ = g_htonl (GDK_PIXDATA_HEADER_LENGTH + length);
126   *istream++ = g_htonl (pixdata->pixdata_type);
127   *istream++ = g_htonl (pixdata->rowstride);
128   *istream++ = g_htonl (pixdata->width);
129   *istream++ = g_htonl (pixdata->height);
130
131   /* copy pixel data */
132   s = (guint8*) istream;
133   memcpy (s, pixdata->pixel_data, length);
134   s += length;
135
136   *stream_length_p = GDK_PIXDATA_HEADER_LENGTH + length;
137   g_assert (s - stream == *stream_length_p);    /* paranoid */
138
139   return stream;
140 }
141
142 #define return_header_corrupt(error)    { \
143   g_set_error (error, GDK_PIXBUF_ERROR, \
144                GDK_PIXBUF_ERROR_HEADER_CORRUPT, _("Image header corrupt")); \
145   return FALSE; \
146 }
147 #define return_invalid_format(error)    { \
148   g_set_error (error, GDK_PIXBUF_ERROR, \
149                GDK_PIXBUF_ERROR_UNKNOWN_FORMAT, _("Image format unknown")); \
150   return FALSE; \
151 }
152 #define return_pixel_corrupt(error)     { \
153   g_set_error (error, GDK_PIXBUF_ERROR, \
154                GDK_PIXBUF_ERROR_PIXEL_CORRUPT, _("Image pixel data corrupt")); \
155   return FALSE; \
156 }
157
158 /**
159  * gdk_pixdata_deserialize:
160  * @pixdata: A GdkPixdata structure to be filled in
161  * @stream_length: Length of the stream used for deserialization
162  * @stream: Stream of bytes containing a serialized pixdata structure
163  * @error: GError location to indicate failures (maybe NULL to ignore errors)
164  *
165  * Deserialize (reconstruct) a #GdkPixdata structure from a byte stream.
166  * The byte stream consists of a straight forward write out of the
167  * #GdkPixdata fields in network byte order, plus the pixel_data
168  * bytes the structure points to.
169  * The pixdata contents are reconstructed byte by byte and are checked
170  * for validity, due to the checks, this function may prematurely abort
171  * with errors, such as #GDK_PIXBUF_ERROR_HEADER_CORRUPT,
172  * #GDK_PIXBUF_ERROR_PIXEL_CORRUPT or #GDK_PIXBUF_ERROR_UNKNOWN_FORMAT.
173  *
174  * Return value: Upon successfull deserialization #TRUE is returned,
175  * #FALSE otherwise
176  **/
177 gboolean
178 gdk_pixdata_deserialize (GdkPixdata   *pixdata,
179                          guint         stream_length,
180                          const guint8 *stream,
181                          GError      **error)
182 {
183   guint32 *istream;
184   guint color_type, sample_width, encoding;
185
186   g_return_val_if_fail (pixdata != NULL, FALSE);
187   if (stream_length < GDK_PIXDATA_HEADER_LENGTH)
188     return_header_corrupt (error);
189   g_return_val_if_fail (stream != NULL, FALSE);
190
191
192   /* deserialize header */
193   istream = (guint32*) stream;
194   pixdata->magic = g_ntohl (*istream++);
195   pixdata->length = g_ntohl (*istream++);
196   if (pixdata->magic != GDK_PIXBUF_MAGIC_NUMBER || pixdata->length < GDK_PIXDATA_HEADER_LENGTH)
197     return_header_corrupt (error);
198   pixdata->pixdata_type = g_ntohl (*istream++);
199   pixdata->rowstride = g_ntohl (*istream++);
200   pixdata->width = g_ntohl (*istream++);
201   pixdata->height = g_ntohl (*istream++);
202   if (pixdata->width < 1 || pixdata->height < 1 ||
203       pixdata->rowstride < pixdata->width)
204     return_header_corrupt (error);
205   color_type = pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK;
206   sample_width = pixdata->pixdata_type & GDK_PIXDATA_SAMPLE_WIDTH_MASK;
207   encoding = pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK;
208   if ((color_type != GDK_PIXDATA_COLOR_TYPE_RGB &&
209        color_type != GDK_PIXDATA_COLOR_TYPE_RGBA) ||
210       sample_width != GDK_PIXDATA_SAMPLE_WIDTH_8 ||
211       (encoding != GDK_PIXDATA_ENCODING_RAW &&
212        encoding != GDK_PIXDATA_ENCODING_RLE))
213     return_invalid_format (error);
214
215   /* deserialize pixel data */
216   if (stream_length < pixdata->length - GDK_PIXDATA_HEADER_LENGTH)
217     return_pixel_corrupt (error);
218   pixdata->pixel_data = (guint8*) istream;
219
220   return TRUE;
221 }
222
223 static gboolean
224 diff2_rgb (guint8 *ip)
225 {
226   return ip[0] != ip[3] || ip[1] != ip[4] || ip[2] != ip[5];
227 }
228
229 static gboolean
230 diff2_rgba (guint8 *ip)
231 {
232   return ip[0] != ip[4] || ip[1] != ip[5] || ip[2] != ip[6] || ip[3] != ip[7];
233 }
234
235 static guint8*                  /* dest buffer bound */
236 rl_encode_rgbx (guint8 *bp,     /* dest buffer */
237                 guint8 *ip,     /* image pointer */
238                 guint8 *limit,  /* image upper bound */
239                 guint   n_ch)
240 {
241   gboolean (*diff2_pix) (guint8 *) = n_ch > 3 ? diff2_rgba : diff2_rgb;
242   guint8 *ilimit = limit - n_ch;
243
244   while (ip < limit)
245     {
246       g_assert (ip < ilimit); /* paranoid */
247
248       if (diff2_pix (ip))
249         {
250           guint8 *s_ip = ip;
251           guint l = 1;
252
253           ip += n_ch;
254           while (l < 127 && ip < ilimit && diff2_pix (ip))
255             { ip += n_ch; l += 1; }
256           if (ip == ilimit && l < 127)
257             { ip += n_ch; l += 1; }
258           *(bp++) = l;
259           memcpy (bp, s_ip, l * n_ch);
260           bp += l * n_ch;
261         }
262       else
263         {
264           guint l = 2;
265
266           ip += n_ch;
267           while (l < 127 && ip < ilimit && !diff2_pix (ip))
268             { ip += n_ch; l += 1; }
269           *(bp++) = l | 128;
270           memcpy (bp, ip, n_ch);
271           ip += n_ch;
272           bp += n_ch;
273         }
274       if (ip == ilimit)
275         {
276           *(bp++) = 1;
277           memcpy (bp, ip, n_ch);
278           ip += n_ch;
279           bp += n_ch;
280         }
281     }
282
283   return bp;
284 }
285
286 gpointer
287 gdk_pixdata_from_pixbuf (GdkPixdata      *pixdata,
288                          const GdkPixbuf *pixbuf,
289                          gboolean         use_rle)
290 {
291   gpointer free_me = NULL;
292   guint height, rowstride, encoding, bpp, length;
293   guint8 *img_buffer;
294
295   g_return_val_if_fail (pixdata != NULL, NULL);
296   g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
297   g_return_val_if_fail (pixbuf->bits_per_sample == 8, NULL);
298   g_return_val_if_fail ((pixbuf->n_channels == 3 && !pixbuf->has_alpha) ||
299                         (pixbuf->n_channels == 4 && pixbuf->has_alpha), NULL);
300   g_return_val_if_fail (pixbuf->rowstride >= pixbuf->width, NULL);
301
302   height = pixbuf->height;
303   rowstride = pixbuf->rowstride;
304   encoding = use_rle ? GDK_PIXDATA_ENCODING_RLE : GDK_PIXDATA_ENCODING_RAW;
305   bpp = pixbuf->has_alpha ? 4 : 3;
306
307   if (encoding == GDK_PIXDATA_ENCODING_RLE)
308     {
309       guint pad, n_bytes = rowstride * height;
310       guint8 *img_buffer_end, *data;
311
312       pad = rowstride;
313       pad = MAX (pad, 130 + n_bytes / 127);
314       data = g_new (guint8, pad + n_bytes);
315       free_me = data;
316       img_buffer = data;
317       img_buffer_end = rl_encode_rgbx (img_buffer,
318                                        pixbuf->pixels, pixbuf->pixels + n_bytes,
319                                        bpp);
320       length = img_buffer_end - img_buffer;
321     }
322   else
323     {
324       img_buffer = pixbuf->pixels;
325       length = rowstride * height;
326     }
327
328   pixdata->magic = GDK_PIXBUF_MAGIC_NUMBER;
329   pixdata->length = GDK_PIXDATA_HEADER_LENGTH + length;
330   pixdata->pixdata_type = pixbuf->has_alpha ? GDK_PIXDATA_COLOR_TYPE_RGBA : GDK_PIXDATA_COLOR_TYPE_RGB;
331   pixdata->pixdata_type |= GDK_PIXDATA_SAMPLE_WIDTH_8;
332   pixdata->pixdata_type |= encoding;
333   pixdata->rowstride = rowstride;
334   pixdata->width = pixbuf->width;
335   pixdata->height = height;
336   pixdata->pixel_data = img_buffer;
337
338   return free_me;
339 }
340
341 GdkPixbuf*
342 gdk_pixbuf_from_pixdata (const GdkPixdata *pixdata,
343                          gboolean          copy_pixels,
344                          GError          **error)
345 {
346   guint encoding, bpp;
347   guint8 *data = NULL;
348
349   g_return_val_if_fail (pixdata != NULL, NULL);
350   g_return_val_if_fail (pixdata->width > 0, NULL);
351   g_return_val_if_fail (pixdata->height > 0, NULL);
352   g_return_val_if_fail (pixdata->rowstride >= pixdata->width, NULL);
353   g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ||
354                         (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA, NULL);
355   g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_SAMPLE_WIDTH_MASK) == GDK_PIXDATA_SAMPLE_WIDTH_8, NULL);
356   g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RAW ||
357                         (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RLE, NULL);
358   g_return_val_if_fail (pixdata->pixel_data != NULL, NULL);
359
360   bpp = (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ? 3 : 4;
361   encoding = pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK;
362   if (encoding == GDK_PIXDATA_ENCODING_RLE)
363     copy_pixels = TRUE;
364   if (copy_pixels)
365     {
366       data = g_try_malloc (pixdata->rowstride * pixdata->height);
367       if (!data)
368         {
369           g_set_error (error, GDK_PIXBUF_ERROR,
370                        GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
371                        _("failed to allocate imagge buffer of %u bytes"),
372                        pixdata->rowstride * pixdata->height);
373           return NULL;
374         }
375     }
376   if (encoding == GDK_PIXDATA_ENCODING_RLE)
377     {
378       const guint8 *rle_buffer = pixdata->pixel_data;
379       guint8 *image_buffer = data;
380       guint8 *image_limit = data + pixdata->rowstride * pixdata->height;
381       gboolean check_overrun = FALSE;
382
383       while (image_buffer < image_limit)
384         {
385           guint length = *(rle_buffer++);
386
387           if (length & 128)
388             {
389               length = length - 128;
390               check_overrun = image_buffer + length * bpp > image_limit;
391               if (check_overrun)
392                 length = (image_limit - image_buffer) / bpp;
393               if (bpp < 4)      /* RGB */
394                 do
395                   {
396                     memcpy (image_buffer, rle_buffer, 3);
397                     image_buffer += 3;
398                   }
399                 while (--length);
400               else              /* RGBA */
401                 do
402                   {
403                     memcpy (image_buffer, rle_buffer, 4);
404                     image_buffer += 4;
405                   }
406                 while (--length);
407               rle_buffer += bpp;
408             }
409           else
410             {
411               length *= bpp;
412               check_overrun = image_buffer + length > image_limit;
413               if (check_overrun)
414                 length = image_limit - image_buffer;
415               memcpy (image_buffer, rle_buffer, length);
416               image_buffer += length;
417               rle_buffer += length;
418             }
419         }
420       if (check_overrun)
421         {
422           g_free (data);
423           g_set_error (error, GDK_PIXBUF_ERROR,
424                        GDK_PIXBUF_ERROR_PIXEL_CORRUPT,
425                        _("Image pixel data corrupt"));
426           return NULL;
427         }
428     }
429   else if (copy_pixels)
430     memcpy (data, pixdata->pixel_data, pixdata->rowstride * pixdata->height);
431   else
432     data = pixdata->pixel_data;
433
434   return gdk_pixbuf_new_from_data (data, GDK_COLORSPACE_RGB,
435                                    (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA,
436                                    8, pixdata->width, pixdata->height, pixdata->rowstride,
437                                    copy_pixels ? (GdkPixbufDestroyNotify) g_free : NULL, data);
438 }
439
440 typedef struct {
441   /* config */
442   gboolean     dump_stream;
443   gboolean     dump_struct;
444   gboolean     dump_macros;
445   gboolean     dump_gtypes;
446   gboolean     dump_rle_decoder;
447   const gchar *static_prefix;
448   const gchar *const_prefix;
449   /* runtime */
450   GString *gstring;
451   guint    pos;
452   gboolean pad;
453 } CSourceData;
454
455 static inline void
456 save_uchar (CSourceData *cdata,
457             guint8       d)
458 {
459   GString *gstring = cdata->gstring;
460
461   if (cdata->pos > 70)
462     {
463       if (cdata->dump_struct || cdata->dump_stream)
464         {
465           g_string_append (gstring, "\"\n  \"");
466           cdata->pos = 3;
467           cdata->pad = FALSE;
468         }
469       if (cdata->dump_macros)
470         {
471           g_string_append (gstring, "\" \\\n  \"");
472           cdata->pos = 3;
473           cdata->pad = FALSE;
474         }
475     }
476   if (d < 33 || d > 126)
477     {
478       g_string_printfa (gstring, "\\%o", d);
479       cdata->pos += 1 + 1 + (d > 7) + (d > 63);
480       cdata->pad = d < 64;
481       return;
482     }
483   if (d == '\\')
484     {
485       g_string_append (gstring, "\\\\");
486       cdata->pos += 2;
487     }
488   else if (d == '"')
489     {
490       g_string_append (gstring, "\\\"");
491       cdata->pos += 2;
492     }
493   else if (cdata->pad && d >= '0' && d <= '9')
494     {
495       g_string_append (gstring, "\"\"");
496       g_string_append_c (gstring, d);
497       cdata->pos += 3;
498     }
499   else
500     {
501       g_string_append_c (gstring, d);
502       cdata->pos += 1;
503     }
504   cdata->pad = FALSE;
505   return;
506 }
507
508 static inline void
509 save_rle_decoder (GString     *gstring,
510                   const gchar *macro_name,
511                   const gchar *s_uint,
512                   const gchar *s_uint_8,
513                   guint        n_ch)
514 {
515   g_string_printfa (gstring, "#define %s_RUN_LENGTH_DECODE(image_buf, rle_data, size, bpp) do \\\n",
516                     macro_name);
517   g_string_printfa (gstring, "{ %s __bpp; %s *__ip; const %s *__il, *__rd; \\\n", s_uint, s_uint_8, s_uint_8);
518   g_string_printfa (gstring, "  __bpp = (bpp); __ip = (image_buf); __il = __ip + (size) * __bpp; \\\n");
519   
520   g_string_printfa (gstring, "  __rd = (rle_data); if (__bpp > 3) { /* RGBA */ \\\n");
521   
522   g_string_printfa (gstring, "    while (__ip < __il) { %s __l = *(__rd++); \\\n", s_uint);
523   g_string_printfa (gstring, "      if (__l & 128) { __l = __l - 128; \\\n");
524   g_string_printfa (gstring, "        do { memcpy (__ip, __rd, 4); __ip += 4; } while (--__l); __rd += 4; \\\n");
525   g_string_printfa (gstring, "      } else { __l *= 4; memcpy (__ip, __rd, __l); \\\n");
526   g_string_printfa (gstring, "               __ip += __l; __rd += __l; } } \\\n");
527   
528   g_string_printfa (gstring, "  } else { /* RGB */ \\\n");
529   
530   g_string_printfa (gstring, "    while (__ip < __il) { %s __l = *(__rd++); \\\n", s_uint);
531   g_string_printfa (gstring, "      if (__l & 128) { __l = __l - 128; \\\n");
532   g_string_printfa (gstring, "        do { memcpy (__ip, __rd, 3); __ip += 3; } while (--__l); __rd += 3; \\\n");
533   g_string_printfa (gstring, "      } else { __l *= 3; memcpy (__ip, __rd, __l); \\\n");
534   g_string_printfa (gstring, "               __ip += __l; __rd += __l; } } \\\n");
535   
536   g_string_printfa (gstring, "  } } while (0)\n");
537 }
538
539 GString*
540 gdk_pixdata_to_csource (GdkPixdata        *pixdata,
541                         const gchar       *name,
542                         GdkPixdataDumpType dump_type)
543 {
544   CSourceData cdata = { 0, };
545   gchar *s_uint_8, *s_uint_32, *s_uint, *s_char, *s_null;
546   guint bpp, width, height, rowstride;
547   gboolean rle_encoded;
548   gchar *macro_name;
549   guint8 *img_buffer, *img_buffer_end, *stream;
550   guint stream_length;
551   GString *gstring;
552   
553   /* check args passing */
554   g_return_val_if_fail (pixdata != NULL, NULL);
555   g_return_val_if_fail (name != NULL, NULL);
556   /* check pixdata contents */
557   g_return_val_if_fail (pixdata->magic == GDK_PIXBUF_MAGIC_NUMBER, NULL);
558   g_return_val_if_fail (pixdata->width > 0, NULL);
559   g_return_val_if_fail (pixdata->height > 0, NULL);
560   g_return_val_if_fail (pixdata->rowstride >= pixdata->width, NULL);
561   g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ||
562                         (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA, NULL);
563   g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_SAMPLE_WIDTH_MASK) == GDK_PIXDATA_SAMPLE_WIDTH_8, NULL);
564   g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RAW ||
565                         (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RLE, NULL);
566   g_return_val_if_fail (pixdata->pixel_data != NULL, NULL);
567
568   img_buffer = pixdata->pixel_data;
569   if (pixdata->length < 1)
570     img_buffer_end = img_buffer + pixdata_get_length (pixdata);
571   else
572     img_buffer_end = img_buffer + pixdata->length - GDK_PIXDATA_HEADER_LENGTH;
573   g_return_val_if_fail (img_buffer < img_buffer_end, NULL);
574
575   bpp = (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ? 3 : 4;
576   width = pixdata->width;
577   height = pixdata->height;
578   rowstride = pixdata->rowstride;
579   rle_encoded = (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_RLE) > 0;
580   macro_name = g_strdup (name);
581   g_strup (macro_name);
582
583   cdata.dump_macros = (dump_type & GDK_PIXDATA_DUMP_MACROS) > 0;
584   cdata.dump_struct = (dump_type & GDK_PIXDATA_DUMP_PIXDATA_STRUCT) > 0;
585   cdata.dump_stream = !cdata.dump_macros && !cdata.dump_struct;
586   g_return_val_if_fail (cdata.dump_macros + cdata.dump_struct + cdata.dump_stream == 1, NULL);
587
588   cdata.dump_gtypes = (dump_type & GDK_PIXDATA_DUMP_CTYPES) == 0;
589   cdata.dump_rle_decoder = (dump_type & GDK_PIXDATA_DUMP_RLE_DECODER) > 0;
590   cdata.static_prefix = (dump_type & GDK_PIXDATA_DUMP_STATIC) ? "static " : "";
591   cdata.const_prefix = (dump_type & GDK_PIXDATA_DUMP_CONST) ? "const " : "";
592   gstring = g_string_new ("");
593   cdata.gstring = gstring;
594
595   if (!cdata.dump_macros && cdata.dump_gtypes)
596     {
597       s_uint_8 =  "guint8 ";
598       s_uint_32 = "guint32";
599       s_uint =    "guint  ";
600       s_char =    "gchar  ";
601       s_null =    "NULL";
602     }
603   else if (!cdata.dump_macros)
604     {
605       s_uint_8 =  "unsigned char";
606       s_uint_32 = "unsigned int ";
607       s_uint =    "unsigned int ";
608       s_char =    "char         ";
609       s_null =    "(char*) 0";
610     }
611   else if (cdata.dump_macros && cdata.dump_gtypes)
612     {
613       s_uint_8 =  "guint8";
614       s_uint_32 = "guint32";
615       s_uint  =   "guint";
616       s_char =    "gchar";
617       s_null =    "NULL";
618     }
619   else /* cdata.dump_macros && !cdata.dump_gtypes */
620     {
621       s_uint_8 =  "unsigned char";
622       s_uint_32 = "unsigned int";
623       s_uint =    "unsigned int";
624       s_char =    "char";
625       s_null =    "(char*) 0";
626     }
627
628   /* initial comment
629    */
630   g_string_printfa (gstring,
631                     "/* GdkPixbuf %s C-Source image dump %s*/\n\n",
632                     bpp > 3 ? "RGBA" : "RGB",
633                     rle_encoded ? "1-byte-run-length-encoded " : "");
634
635   /* dump RLE decoder for structures
636    */
637   if (cdata.dump_rle_decoder && cdata.dump_struct)
638     save_rle_decoder (gstring,
639                       macro_name,
640                       cdata.dump_gtypes ? "guint" : "unsigned int",
641                       cdata.dump_gtypes ? "guint8" : "unsigned char",
642                       bpp);
643
644   /* format & size blurbs
645    */
646   if (cdata.dump_macros)
647     {
648       g_string_printfa (gstring, "#define %s_ROWSTRIDE (%u)\n",
649                         macro_name, rowstride);
650       g_string_printfa (gstring, "#define %s_WIDTH (%u)\n",
651                         macro_name, width);
652       g_string_printfa (gstring, "#define %s_HEIGHT (%u)\n",
653                         macro_name, height);
654       g_string_printfa (gstring, "#define %s_BYTES_PER_PIXEL (%u) /* 3:RGB, 4:RGBA */\n",
655                         macro_name, bpp);
656     }
657   if (cdata.dump_struct)
658     {
659       g_string_printfa (gstring, "%s%sGdkPixdata %s = {\n",
660                         cdata.static_prefix, cdata.const_prefix, name);
661       g_string_printfa (gstring, "  0x%x, /* Pixbuf magic: 'GdkP' */\n",
662                         GDK_PIXBUF_MAGIC_NUMBER);
663       g_string_printfa (gstring, "  %u + %u, /* header length + pixel_data length */\n",
664                         GDK_PIXDATA_HEADER_LENGTH,
665                         rle_encoded ? img_buffer_end - img_buffer : rowstride * height);
666       g_string_printfa (gstring, "  0x%x, /* pixdata_type */\n",
667                         pixdata->pixdata_type);
668       g_string_printfa (gstring, "  %u, /* rowstride */\n",
669                         rowstride);
670       g_string_printfa (gstring, "  %u, /* width */\n",
671                         width);
672       g_string_printfa (gstring, "  %u, /* height */\n",
673                         height);
674       g_string_printfa (gstring, "  /* pixel_data: */\n");
675     }
676   if (cdata.dump_stream)
677     {
678       guint pix_length = img_buffer_end - img_buffer;
679       
680       stream = gdk_pixdata_serialize (pixdata, &stream_length);
681       img_buffer_end = stream + stream_length;
682
683       g_string_printfa (gstring, "%s%s%s %s[] = \n",
684                         cdata.static_prefix, cdata.const_prefix,
685                         cdata.dump_gtypes ? "guint8" : "unsigned char",
686                         name);
687       g_string_printfa (gstring, "( \"\"\n  /* Pixbuf magic (0x%x) */\n  \"",
688                         GDK_PIXBUF_MAGIC_NUMBER);
689       cdata.pos = 3;
690       save_uchar (&cdata, *stream++); save_uchar (&cdata, *stream++);
691       save_uchar (&cdata, *stream++); save_uchar (&cdata, *stream++);
692       g_string_printfa (gstring, "\"\n  /* length: header (%u) + pixel_data (%u) */\n  \"",
693                         GDK_PIXDATA_HEADER_LENGTH,
694                         rle_encoded ? pix_length : rowstride * height);
695       cdata.pos = 3;
696       save_uchar (&cdata, *stream++); save_uchar (&cdata, *stream++);
697       save_uchar (&cdata, *stream++); save_uchar (&cdata, *stream++);
698       g_string_printfa (gstring, "\"\n  /* pixdata_type (0x%x) */\n  \"",
699                         pixdata->pixdata_type);
700       cdata.pos = 3;
701       save_uchar (&cdata, *stream++); save_uchar (&cdata, *stream++);
702       save_uchar (&cdata, *stream++); save_uchar (&cdata, *stream++);
703       g_string_printfa (gstring, "\"\n  /* rowstride (%u) */\n  \"",
704                         rowstride);
705       cdata.pos = 3;
706       save_uchar (&cdata, *stream++); save_uchar (&cdata, *stream++);
707       save_uchar (&cdata, *stream++); save_uchar (&cdata, *stream++);
708       g_string_printfa (gstring, "\"\n  /* width (%u) */\n  \"", width);
709       cdata.pos = 3;
710       save_uchar (&cdata, *stream++); save_uchar (&cdata, *stream++);
711       save_uchar (&cdata, *stream++); save_uchar (&cdata, *stream++);
712       g_string_printfa (gstring, "\"\n  /* height (%u) */\n  \"", height);
713       cdata.pos = 3;
714       save_uchar (&cdata, *stream++); save_uchar (&cdata, *stream++);
715       save_uchar (&cdata, *stream++); save_uchar (&cdata, *stream++);
716       g_string_printfa (gstring, "\"\n  /* pixel_data: */\n");
717       img_buffer = stream;
718     }
719
720   /* pixel_data intro
721    */
722   if (cdata.dump_macros)
723     {
724       g_string_printfa (gstring, "#define %s_%sPIXEL_DATA ((%s*) \\\n",
725                         macro_name,
726                         rle_encoded ? "RLE_" : "",
727                         s_uint_8);
728       g_string_printfa (gstring, "  \"");
729       cdata.pos = 2;
730     }
731   if (cdata.dump_struct)
732     {
733       g_string_printfa (gstring, "  \"");
734       cdata.pos = 3;
735     }
736   if (cdata.dump_stream)
737     {
738       g_string_printfa (gstring, "  \"");
739       cdata.pos = 3;
740     }
741     
742   /* pixel_data
743    */
744   do
745     save_uchar (&cdata, *img_buffer++);
746   while (img_buffer < img_buffer_end);
747
748   /* pixel_data trailer
749    */
750   if (cdata.dump_macros)
751     g_string_printfa (gstring, "\")\n\n");
752   if (cdata.dump_struct)
753     g_string_printfa (gstring, "\",\n};\n\n");
754   if (cdata.dump_stream)
755     g_string_printfa (gstring, "\");\n\n");
756
757   /* dump RLE decoder for macros
758    */
759   if (cdata.dump_rle_decoder && cdata.dump_macros)
760     save_rle_decoder (gstring,
761                       macro_name,
762                       cdata.dump_gtypes ? "guint" : "unsigned int",
763                       cdata.dump_gtypes ? "guint8" : "unsigned char",
764                       bpp);
765
766   /* cleanup
767    */
768   g_free (macro_name);
769   
770   return gstring;
771 }
772
773 /**
774  * gdk_pixbuf_new_from_stream:
775  * @stream_length: Length in bytes of the @stream argument
776  * @stream: Byte stream containing a serialized GdkPixdata structure
777  * @copy_pixels: Whether to copy the pixels data, or keep direct pointers into the
778  *               stream data for the resulting pixbuf
779  * @error: GError return location, may be NULL to ignore errors
780  *
781  * Create a #GdkPixbuf from a serialized GdkPixdata structure.
782  * Gtk+ ships with a program called gdk-pixbuf-csource which allowes
783  * for conversion of #GdkPixbufs into various kinds of C sources.
784  * This is useful if you want to ship a program with images, but
785  * don't want to depend on any external files.
786  *
787  * Since the inline pixbuf is read-only static data, you
788  * don't need to copy it unless you intend to write to it.
789  * For deserialization of streams that are run length encoded, the
790  * decoded data is always a copy of the input stream.
791  *
792  * If you create a pixbuf from const inline data compiled into your
793  * program, it's probably safe to ignore errors, since things will
794  * always succeed.  For non-const inline data, you could get out of
795  * memory. For untrusted inline data located at runtime, you could
796  * have corrupt inline data in addition.
797  *
798  * Return value: A newly-created #GdkPixbuf structure with a reference count of
799  * 1, or NULL If error is set.
800  **/
801 GdkPixbuf*
802 gdk_pixbuf_new_from_stream (gint          stream_length,
803                             const guint8 *stream,
804                             gboolean      copy_pixels,
805                             GError      **error)
806 {
807   GdkPixdata pixdata;
808
809   if (stream_length != -1)
810     g_return_val_if_fail (stream_length > GDK_PIXDATA_HEADER_LENGTH, NULL);
811   g_return_val_if_fail (stream != NULL, NULL);
812
813   if (!gdk_pixdata_deserialize (&pixdata, stream_length, stream, error))
814     return NULL;
815
816   return gdk_pixbuf_from_pixdata (&pixdata, copy_pixels, error);
817 }