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