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