Blame gdk-pixbuf/gdk-pixdata.c

Packit a4058c
/* GdkPixbuf library - GdkPixdata - functions for inlined pixbuf handling
Packit a4058c
 * Copyright (C) 1999, 2001 Tim Janik
Packit a4058c
 *
Packit a4058c
 * This library is free software; you can redistribute it and/or
Packit a4058c
 * modify it under the terms of the GNU Lesser General Public
Packit a4058c
 * License as published by the Free Software Foundation; either
Packit a4058c
 * version 2 of the License, or (at your option) any later version.
Packit a4058c
 *
Packit a4058c
 * This library is distributed in the hope that it will be useful,
Packit a4058c
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit a4058c
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit a4058c
 * Lesser General Public License for more details.
Packit a4058c
 *
Packit a4058c
 * You should have received a copy of the GNU Lesser General Public
Packit a4058c
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit a4058c
 */
Packit a4058c
#include "config.h"
Packit a4058c
Packit a4058c
#include "gdk-pixbuf-private.h"
Packit a4058c
#include "gdk-pixdata.h"
Packit a4058c
#include <string.h>
Packit a4058c
Packit a4058c
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
Packit a4058c
Packit a4058c
/**
Packit a4058c
 * SECTION:inline
Packit a4058c
 * @Short_description: Functions for inlined pixbuf handling.
Packit a4058c
 * @Title: Inline data
Packit a4058c
 * 
Packit a4058c
 * Using #GdkPixdata, images can be compiled into an application,
Packit a4058c
 * making it unnecessary to refer to external image files at runtime.
Packit a4058c
 * GdkPixBuf includes a utility named gdk-pixbuf-csource, which
Packit a4058c
 * can be used to convert image files into #GdkPixdata structures suitable
Packit a4058c
 * for inclusion in C sources. To convert the #GdkPixdata structures back 
Packit a4058c
 * into #GdkPixbufs, use gdk_pixbuf_from_pixdata.
Packit a4058c
 *
Packit a4058c
 * #GdkPixdata should not be used any more. #GResource should be used to save
Packit a4058c
 * the original compressed images inside the program's binary.
Packit a4058c
 */
Packit a4058c
Packit a4058c
#define APPEND g_string_append_printf
Packit a4058c
Packit a4058c
/* --- functions --- */
Packit a4058c
static guint
Packit a4058c
pixdata_get_length (const GdkPixdata *pixdata)
Packit a4058c
{
Packit a4058c
  guint bpp, length;
Packit a4058c
Packit a4058c
  if ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB)
Packit a4058c
    bpp = 3;
Packit a4058c
  else if ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA)
Packit a4058c
    bpp = 4;
Packit a4058c
  else
Packit a4058c
    return 0;	/* invalid format */
Packit a4058c
  switch (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK)
Packit a4058c
    {
Packit a4058c
      guint8 *rle_buffer;
Packit a4058c
      guint max_length;
Packit a4058c
    case GDK_PIXDATA_ENCODING_RAW:
Packit a4058c
      length = pixdata->rowstride * pixdata->height;
Packit a4058c
      break;
Packit a4058c
    case GDK_PIXDATA_ENCODING_RLE:
Packit a4058c
      /* need an RLE walk to determine size */
Packit a4058c
      max_length = pixdata->rowstride * pixdata->height;
Packit a4058c
      rle_buffer = pixdata->pixel_data;
Packit a4058c
      length = 0;
Packit a4058c
      while (length < max_length)
Packit a4058c
	{
Packit a4058c
	  guint chunk_length = *(rle_buffer++);
Packit a4058c
Packit a4058c
	  if (chunk_length & 128)
Packit a4058c
	    {
Packit a4058c
	      chunk_length = chunk_length - 128;
Packit a4058c
	      if (!chunk_length)	/* RLE data corrupted */
Packit a4058c
		return 0;
Packit a4058c
	      length += chunk_length * bpp;
Packit a4058c
	      rle_buffer += bpp;
Packit a4058c
	    }
Packit a4058c
	  else
Packit a4058c
	    {
Packit a4058c
	      if (!chunk_length)        /* RLE data corrupted */
Packit a4058c
		return 0;
Packit a4058c
	      chunk_length *= bpp;
Packit a4058c
	      length += chunk_length;
Packit a4058c
	      rle_buffer += chunk_length;
Packit a4058c
	    }
Packit a4058c
	}
Packit a4058c
      length = rle_buffer - pixdata->pixel_data;
Packit a4058c
      break;
Packit a4058c
    default:
Packit a4058c
      length = 0;
Packit a4058c
      break;
Packit a4058c
    }
Packit a4058c
  return length;
Packit a4058c
}
Packit a4058c
Packit a4058c
/**
Packit a4058c
 * gdk_pixdata_serialize:
Packit a4058c
 * @pixdata: a valid #GdkPixdata structure to serialize.
Packit a4058c
 * @stream_length_p: location to store the resulting stream length in.
Packit a4058c
 *
Packit a4058c
 * Serializes a #GdkPixdata structure into a byte stream.
Packit a4058c
 * The byte stream consists of a straightforward writeout of the
Packit a4058c
 * #GdkPixdata fields in network byte order, plus the @pixel_data
Packit a4058c
 * bytes the structure points to.
Packit a4058c
 *
Packit a4058c
 * Return value: (array length=stream_length_p) (transfer full): A
Packit a4058c
 * newly-allocated string containing the serialized #GdkPixdata
Packit a4058c
 * structure.
Packit a4058c
 *
Packit a4058c
 * Deprecated: 2.32: Use #GResource instead.
Packit a4058c
 **/
Packit a4058c
guint8* /* free result */
Packit a4058c
gdk_pixdata_serialize (const GdkPixdata *pixdata,
Packit a4058c
		       guint            *stream_length_p)
Packit a4058c
{
Packit a4058c
  guint8 *stream, *s;
Packit a4058c
  guint32 *istream;
Packit a4058c
  guint length;
Packit a4058c
Packit a4058c
  /* check args passing */
Packit a4058c
  g_return_val_if_fail (pixdata != NULL, NULL);
Packit a4058c
  g_return_val_if_fail (stream_length_p != NULL, NULL);
Packit a4058c
  /* check pixdata contents */
Packit a4058c
  g_return_val_if_fail (pixdata->magic == GDK_PIXBUF_MAGIC_NUMBER, NULL);
Packit a4058c
  g_return_val_if_fail (pixdata->width > 0, NULL);
Packit a4058c
  g_return_val_if_fail (pixdata->height > 0, NULL);
Packit a4058c
  g_return_val_if_fail (pixdata->rowstride >= pixdata->width, NULL);
Packit a4058c
  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ||
Packit a4058c
			(pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA, NULL);
Packit a4058c
  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_SAMPLE_WIDTH_MASK) == GDK_PIXDATA_SAMPLE_WIDTH_8, NULL);
Packit a4058c
  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RAW ||
Packit a4058c
			(pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RLE, NULL);
Packit a4058c
  g_return_val_if_fail (pixdata->pixel_data != NULL, NULL);
Packit a4058c
Packit a4058c
  length = pixdata_get_length (pixdata);
Packit a4058c
Packit a4058c
  /* check length field */
Packit a4058c
  g_return_val_if_fail (length != 0, NULL);
Packit a4058c
  
Packit a4058c
  stream = g_malloc (GDK_PIXDATA_HEADER_LENGTH + length);
Packit a4058c
  istream = (guint32*) stream;
Packit a4058c
Packit a4058c
  /* store header */
Packit a4058c
  *istream++ = g_htonl (GDK_PIXBUF_MAGIC_NUMBER);
Packit a4058c
  *istream++ = g_htonl (GDK_PIXDATA_HEADER_LENGTH + length);
Packit a4058c
  *istream++ = g_htonl (pixdata->pixdata_type);
Packit a4058c
  *istream++ = g_htonl (pixdata->rowstride);
Packit a4058c
  *istream++ = g_htonl (pixdata->width);
Packit a4058c
  *istream++ = g_htonl (pixdata->height);
Packit a4058c
Packit a4058c
  /* copy pixel data */
Packit a4058c
  s = (guint8*) istream;
Packit a4058c
  memcpy (s, pixdata->pixel_data, length);
Packit a4058c
  s += length;
Packit a4058c
Packit a4058c
  *stream_length_p = GDK_PIXDATA_HEADER_LENGTH + length;
Packit a4058c
  g_assert (s - stream == *stream_length_p);	/* paranoid */
Packit a4058c
Packit a4058c
  return stream;
Packit a4058c
}
Packit a4058c
Packit a4058c
#define	return_header_corrupt(error)	{ \
Packit a4058c
  g_set_error_literal (error, GDK_PIXBUF_ERROR, \
Packit a4058c
                       GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Image header corrupt")); \
Packit a4058c
  return FALSE; \
Packit a4058c
}
Packit a4058c
#define	return_invalid_format(error)	{ \
Packit a4058c
  g_set_error_literal (error, GDK_PIXBUF_ERROR, \
Packit a4058c
                       GDK_PIXBUF_ERROR_UNKNOWN_TYPE, _("Image format unknown")); \
Packit a4058c
  return FALSE; \
Packit a4058c
}
Packit a4058c
#define	return_pixel_corrupt(error)	{ \
Packit a4058c
  g_set_error_literal (error, GDK_PIXBUF_ERROR, \
Packit a4058c
                       GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Image pixel data corrupt")); \
Packit a4058c
  return FALSE; \
Packit a4058c
}
Packit a4058c
Packit a4058c
static inline const guint8 *
Packit a4058c
get_uint32 (const guint8 *stream, guint *result)
Packit a4058c
{
Packit a4058c
  *result = (stream[0] << 24) + (stream[1] << 16) + (stream[2] << 8) + stream[3];
Packit a4058c
  return stream + 4;
Packit a4058c
}
Packit a4058c
Packit a4058c
/**
Packit a4058c
 * gdk_pixdata_deserialize:
Packit a4058c
 * @pixdata: a #GdkPixdata structure to be filled in.
Packit a4058c
 * @stream_length: length of the stream used for deserialization.
Packit a4058c
 * @stream: (array length=stream_length): stream of bytes containing a
Packit a4058c
 *   serialized #GdkPixdata structure.
Packit a4058c
 * @error: #GError location to indicate failures (maybe %NULL to ignore errors).
Packit a4058c
 *
Packit a4058c
 * Deserializes (reconstruct) a #GdkPixdata structure from a byte stream.
Packit a4058c
 * The byte stream consists of a straightforward writeout of the
Packit a4058c
 * #GdkPixdata fields in network byte order, plus the @pixel_data
Packit a4058c
 * bytes the structure points to.
Packit a4058c
 * The @pixdata contents are reconstructed byte by byte and are checked
Packit a4058c
 * for validity. This function may fail with %GDK_PIXBUF_ERROR_CORRUPT_IMAGE
Packit a4058c
 * or %GDK_PIXBUF_ERROR_UNKNOWN_TYPE.
Packit a4058c
 *
Packit a4058c
 * Return value: Upon successful deserialization %TRUE is returned,
Packit a4058c
 * %FALSE otherwise.
Packit a4058c
 *
Packit a4058c
 * Deprecated: 2.32: Use #GResource instead.
Packit a4058c
 **/
Packit a4058c
gboolean
Packit a4058c
gdk_pixdata_deserialize (GdkPixdata   *pixdata,
Packit a4058c
			 guint         stream_length,
Packit a4058c
			 const guint8 *stream,
Packit a4058c
			 GError	     **error)
Packit a4058c
{
Packit a4058c
  guint color_type, sample_width, encoding;
Packit a4058c
Packit a4058c
  g_return_val_if_fail (pixdata != NULL, FALSE);
Packit a4058c
  if (stream_length < GDK_PIXDATA_HEADER_LENGTH)
Packit a4058c
    return_header_corrupt (error);
Packit a4058c
  g_return_val_if_fail (stream != NULL, FALSE);
Packit a4058c
Packit a4058c
Packit a4058c
  /* deserialize header */
Packit a4058c
  stream = get_uint32 (stream, &pixdata->magic);
Packit a4058c
  stream = get_uint32 (stream, (guint32 *)&pixdata->length);
Packit a4058c
  if (pixdata->magic != GDK_PIXBUF_MAGIC_NUMBER || pixdata->length < GDK_PIXDATA_HEADER_LENGTH)
Packit a4058c
    return_header_corrupt (error);
Packit a4058c
  stream = get_uint32 (stream, &pixdata->pixdata_type);
Packit a4058c
  stream = get_uint32 (stream, &pixdata->rowstride);
Packit a4058c
  stream = get_uint32 (stream, &pixdata->width);
Packit a4058c
  stream = get_uint32 (stream, &pixdata->height);
Packit a4058c
  if (pixdata->width < 1 || pixdata->height < 1 ||
Packit a4058c
      pixdata->rowstride < pixdata->width)
Packit a4058c
    return_header_corrupt (error);
Packit a4058c
  color_type = pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK;
Packit a4058c
  sample_width = pixdata->pixdata_type & GDK_PIXDATA_SAMPLE_WIDTH_MASK;
Packit a4058c
  encoding = pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK;
Packit a4058c
  if ((color_type != GDK_PIXDATA_COLOR_TYPE_RGB &&
Packit a4058c
       color_type != GDK_PIXDATA_COLOR_TYPE_RGBA) ||
Packit a4058c
      sample_width != GDK_PIXDATA_SAMPLE_WIDTH_8 ||
Packit a4058c
      (encoding != GDK_PIXDATA_ENCODING_RAW &&
Packit a4058c
       encoding != GDK_PIXDATA_ENCODING_RLE))
Packit a4058c
    return_invalid_format (error);
Packit a4058c
Packit a4058c
  /* deserialize pixel data */
Packit a4058c
  if (stream_length < pixdata->length - GDK_PIXDATA_HEADER_LENGTH)
Packit a4058c
    return_pixel_corrupt (error);
Packit a4058c
  pixdata->pixel_data = (guint8 *)stream;
Packit a4058c
Packit a4058c
  return TRUE;
Packit a4058c
}
Packit a4058c
Packit a4058c
static gboolean
Packit a4058c
diff2_rgb (guint8 *ip)
Packit a4058c
{
Packit a4058c
  return ip[0] != ip[3] || ip[1] != ip[4] || ip[2] != ip[5];
Packit a4058c
}
Packit a4058c
Packit a4058c
static gboolean
Packit a4058c
diff2_rgba (guint8 *ip)
Packit a4058c
{
Packit a4058c
  return ip[0] != ip[4] || ip[1] != ip[5] || ip[2] != ip[6] || ip[3] != ip[7];
Packit a4058c
}
Packit a4058c
Packit a4058c
static guint8*			/* dest buffer bound */
Packit a4058c
rl_encode_rgbx (guint8 *bp,	/* dest buffer */
Packit a4058c
		guint8 *ip,	/* image pointer */
Packit a4058c
		guint8 *limit,	/* image upper bound */
Packit a4058c
		guint   n_ch)
Packit a4058c
{
Packit a4058c
  gboolean (*diff2_pix) (guint8 *) = n_ch > 3 ? diff2_rgba : diff2_rgb;
Packit a4058c
  guint8 *ilimit = limit - n_ch;
Packit a4058c
Packit a4058c
  while (ip < limit)
Packit a4058c
    {
Packit a4058c
      g_assert (ip < ilimit); /* paranoid */
Packit a4058c
Packit a4058c
      if (diff2_pix (ip))
Packit a4058c
	{
Packit a4058c
	  guint8 *s_ip = ip;
Packit a4058c
	  guint l = 1;
Packit a4058c
Packit a4058c
	  ip += n_ch;
Packit a4058c
	  while (l < 127 && ip < ilimit && diff2_pix (ip))
Packit a4058c
	    { ip += n_ch; l += 1; }
Packit a4058c
	  if (ip == ilimit && l < 127)
Packit a4058c
	    { ip += n_ch; l += 1; }
Packit a4058c
	  *(bp++) = l;
Packit a4058c
	  memcpy (bp, s_ip, l * n_ch);
Packit a4058c
	  bp += l * n_ch;
Packit a4058c
	}
Packit a4058c
      else
Packit a4058c
	{
Packit a4058c
	  guint l = 2;
Packit a4058c
Packit a4058c
	  ip += n_ch;
Packit a4058c
	  while (l < 127 && ip < ilimit && !diff2_pix (ip))
Packit a4058c
	    { ip += n_ch; l += 1; }
Packit a4058c
	  *(bp++) = l | 128;
Packit a4058c
	  memcpy (bp, ip, n_ch);
Packit a4058c
	  ip += n_ch;
Packit a4058c
	  bp += n_ch;
Packit a4058c
	}
Packit a4058c
      if (ip == ilimit)
Packit a4058c
	{
Packit a4058c
	  *(bp++) = 1;
Packit a4058c
	  memcpy (bp, ip, n_ch);
Packit a4058c
	  ip += n_ch;
Packit a4058c
	  bp += n_ch;
Packit a4058c
	}
Packit a4058c
    }
Packit a4058c
Packit a4058c
  return bp;
Packit a4058c
}
Packit a4058c
Packit a4058c
/* Used as the destroy notification function for gdk_pixbuf_new() */
Packit a4058c
static void
Packit a4058c
free_buffer (guchar *pixels, gpointer data)
Packit a4058c
{
Packit a4058c
	g_free (pixels);
Packit a4058c
}
Packit a4058c
Packit a4058c
/**
Packit a4058c
 * gdk_pixdata_from_pixbuf: (skip)
Packit a4058c
 * @pixdata: a #GdkPixdata to fill.
Packit a4058c
 * @pixbuf: the data to fill @pixdata with.
Packit a4058c
 * @use_rle: whether to use run-length encoding for the pixel data.
Packit a4058c
 *
Packit a4058c
 * Converts a #GdkPixbuf to a #GdkPixdata. If @use_rle is %TRUE, the
Packit a4058c
 * pixel data is run-length encoded into newly-allocated memory and a 
Packit a4058c
 * pointer to that memory is returned. 
Packit a4058c
 *
Packit a4058c
 * Returns: (nullable): If @use_rle is %TRUE, a pointer to the
Packit a4058c
 *   newly-allocated memory for the run-length encoded pixel data,
Packit a4058c
 *   otherwise %NULL.
Packit a4058c
 *
Packit a4058c
 * Deprecated: 2.32: Use #GResource instead.
Packit a4058c
 **/
Packit a4058c
gpointer
Packit a4058c
gdk_pixdata_from_pixbuf (GdkPixdata      *pixdata,
Packit a4058c
			 const GdkPixbuf *pixbuf,
Packit a4058c
			 gboolean         use_rle)
Packit a4058c
{
Packit a4058c
  gpointer free_me = NULL;
Packit a4058c
  guint height, rowstride, encoding, bpp, length;
Packit a4058c
  guint8 *img_buffer;
Packit a4058c
Packit a4058c
  g_return_val_if_fail (pixdata != NULL, NULL);
Packit a4058c
  g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
Packit a4058c
  g_return_val_if_fail (pixbuf->bits_per_sample == 8, NULL);
Packit a4058c
  g_return_val_if_fail ((pixbuf->n_channels == 3 && !pixbuf->has_alpha) ||
Packit a4058c
			(pixbuf->n_channels == 4 && pixbuf->has_alpha), NULL);
Packit a4058c
  g_return_val_if_fail (pixbuf->rowstride >= pixbuf->width, NULL);
Packit a4058c
Packit a4058c
  height = pixbuf->height;
Packit a4058c
  rowstride = pixbuf->rowstride;
Packit a4058c
  bpp = pixbuf->has_alpha ? 4 : 3;
Packit a4058c
  encoding = use_rle && ((rowstride / bpp | height) > 1) ? GDK_PIXDATA_ENCODING_RLE : GDK_PIXDATA_ENCODING_RAW;
Packit a4058c
Packit a4058c
  if (encoding == GDK_PIXDATA_ENCODING_RLE)
Packit a4058c
    {
Packit a4058c
      guint pad, n_bytes = rowstride * height;
Packit a4058c
      guint8 *img_buffer_end, *data;
Packit a4058c
      GdkPixbuf *buf = NULL;
Packit a4058c
Packit a4058c
      if (n_bytes % bpp != 0) 
Packit a4058c
	{
Packit a4058c
	  rowstride = pixbuf->width * bpp;
Packit a4058c
	  n_bytes = rowstride * height;
Packit a4058c
	  data = g_malloc (n_bytes);
Packit a4058c
	  buf = gdk_pixbuf_new_from_data (data,
Packit a4058c
					  GDK_COLORSPACE_RGB,
Packit a4058c
					  pixbuf->has_alpha, 8,
Packit a4058c
					  pixbuf->width,
Packit a4058c
					  pixbuf->height,
Packit a4058c
					  rowstride,
Packit a4058c
					  free_buffer, NULL);
Packit a4058c
	  gdk_pixbuf_copy_area (pixbuf, 0, 0, pixbuf->width, pixbuf->height,
Packit a4058c
				buf, 0, 0);
Packit a4058c
	}
Packit a4058c
      else
Packit a4058c
	buf = (GdkPixbuf *)pixbuf;
Packit a4058c
      pad = rowstride;
Packit a4058c
      pad = MAX (pad, 130 + n_bytes / 127);
Packit a4058c
      data = g_new (guint8, pad + n_bytes);
Packit a4058c
      free_me = data;
Packit a4058c
      img_buffer = data;
Packit a4058c
      img_buffer_end = rl_encode_rgbx (img_buffer,
Packit a4058c
				       buf->pixels, buf->pixels + n_bytes,
Packit a4058c
				       bpp);
Packit a4058c
      length = img_buffer_end - img_buffer;
Packit a4058c
      if (buf != pixbuf)
Packit a4058c
	g_object_unref (buf);
Packit a4058c
    }
Packit a4058c
  else
Packit a4058c
    {
Packit a4058c
      img_buffer = pixbuf->pixels;
Packit a4058c
      length = rowstride * height;
Packit a4058c
    }
Packit a4058c
Packit a4058c
  pixdata->magic = GDK_PIXBUF_MAGIC_NUMBER;
Packit a4058c
  pixdata->length = GDK_PIXDATA_HEADER_LENGTH + length;
Packit a4058c
  pixdata->pixdata_type = pixbuf->has_alpha ? GDK_PIXDATA_COLOR_TYPE_RGBA : GDK_PIXDATA_COLOR_TYPE_RGB;
Packit a4058c
  pixdata->pixdata_type |= GDK_PIXDATA_SAMPLE_WIDTH_8;
Packit a4058c
  pixdata->pixdata_type |= encoding;
Packit a4058c
  pixdata->rowstride = rowstride;
Packit a4058c
  pixdata->width = pixbuf->width;
Packit a4058c
  pixdata->height = height;
Packit a4058c
  pixdata->pixel_data = img_buffer;
Packit a4058c
Packit a4058c
  return free_me;
Packit a4058c
}
Packit a4058c
Packit a4058c
/* From glib's gmem.c */
Packit a4058c
#define SIZE_OVERFLOWS(a,b) (G_UNLIKELY ((b) > 0 && (a) > G_MAXSIZE / (b)))
Packit a4058c
Packit a4058c
#define RLE_OVERRUN(offset) (rle_buffer_limit == NULL ? FALSE : rle_buffer + (offset) > rle_buffer_limit)
Packit a4058c
Packit a4058c
/**
Packit a4058c
 * gdk_pixbuf_from_pixdata:
Packit a4058c
 * @pixdata: a #GdkPixdata to convert into a #GdkPixbuf.
Packit a4058c
 * @copy_pixels: whether to copy raw pixel data; run-length encoded
Packit a4058c
 *     pixel data is always copied.
Packit a4058c
 * @error: location to store possible errors.
Packit a4058c
 * 
Packit a4058c
 * Converts a #GdkPixdata to a #GdkPixbuf. If @copy_pixels is %TRUE or
Packit a4058c
 * if the pixel data is run-length-encoded, the pixel data is copied into
Packit a4058c
 * newly-allocated memory; otherwise it is reused.
Packit a4058c
 *
Packit a4058c
 * Returns: (transfer full): a new #GdkPixbuf.
Packit a4058c
 * Deprecated: 2.32: Use #GResource instead.
Packit a4058c
 **/
Packit a4058c
GdkPixbuf*
Packit a4058c
gdk_pixbuf_from_pixdata (const GdkPixdata *pixdata,
Packit a4058c
			 gboolean          copy_pixels,
Packit a4058c
			 GError          **error)
Packit a4058c
{
Packit a4058c
  guint encoding, bpp;
Packit a4058c
  guint8 *data = NULL;
Packit a4058c
Packit a4058c
  g_return_val_if_fail (pixdata != NULL, NULL);
Packit a4058c
  g_return_val_if_fail (pixdata->width > 0, NULL);
Packit a4058c
  g_return_val_if_fail (pixdata->height > 0, NULL);
Packit a4058c
  g_return_val_if_fail (pixdata->rowstride >= pixdata->width, NULL);
Packit a4058c
  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ||
Packit a4058c
			(pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA, NULL);
Packit a4058c
  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_SAMPLE_WIDTH_MASK) == GDK_PIXDATA_SAMPLE_WIDTH_8, NULL);
Packit a4058c
  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RAW ||
Packit a4058c
			(pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RLE, NULL);
Packit a4058c
  g_return_val_if_fail (pixdata->pixel_data != NULL, NULL);
Packit a4058c
Packit a4058c
  bpp = (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ? 3 : 4;
Packit a4058c
  encoding = pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK;
Packit a4058c
Packit a4058c
  g_debug ("gdk_pixbuf_from_pixdata() called on:");
Packit a4058c
  g_debug ("\tEncoding %s", encoding == GDK_PIXDATA_ENCODING_RAW ? "raw" : "rle");
Packit a4058c
  g_debug ("\tDimensions: %d x %d", pixdata->width, pixdata->height);
Packit a4058c
  g_debug ("\tRowstride: %d, Length: %d", pixdata->rowstride, pixdata->length);
Packit a4058c
  g_debug ("\tCopy pixels == %s", copy_pixels ? "true" : "false");
Packit a4058c
Packit a4058c
  if (encoding == GDK_PIXDATA_ENCODING_RLE)
Packit a4058c
    copy_pixels = TRUE;
Packit a4058c
Packit a4058c
  /* Sanity check the length and dimensions */
Packit a4058c
  if (SIZE_OVERFLOWS (pixdata->height, pixdata->rowstride))
Packit a4058c
    {
Packit a4058c
      g_set_error_literal (error, GDK_PIXBUF_ERROR,
Packit a4058c
                           GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
Packit a4058c
                           _("Image pixel data corrupt"));
Packit a4058c
      return NULL;
Packit a4058c
    }
Packit a4058c
Packit a4058c
  if (encoding == GDK_PIXDATA_ENCODING_RAW &&
Packit a4058c
      pixdata->length >= 1 &&
Packit a4058c
      pixdata->length < pixdata->height * pixdata->rowstride - GDK_PIXDATA_HEADER_LENGTH)
Packit a4058c
    {
Packit a4058c
      g_set_error_literal (error, GDK_PIXBUF_ERROR,
Packit a4058c
                           GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
Packit a4058c
                           _("Image pixel data corrupt"));
Packit a4058c
      return NULL;
Packit a4058c
    }
Packit a4058c
Packit a4058c
  if (copy_pixels)
Packit a4058c
    {
Packit a4058c
      data = g_try_malloc_n (pixdata->height, pixdata->rowstride);
Packit a4058c
      if (!data)
Packit a4058c
	{
Packit a4058c
	  g_set_error (error, GDK_PIXBUF_ERROR,
Packit a4058c
		       GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
Packit a4058c
		       g_dngettext(GETTEXT_PACKAGE,
Packit a4058c
				   "failed to allocate image buffer of %u byte",
Packit a4058c
				   "failed to allocate image buffer of %u bytes",
Packit a4058c
				   pixdata->rowstride * pixdata->height),
Packit a4058c
		       pixdata->rowstride * pixdata->height);
Packit a4058c
	  return NULL;
Packit a4058c
	}
Packit a4058c
    }
Packit a4058c
  if (encoding == GDK_PIXDATA_ENCODING_RLE)
Packit a4058c
    {
Packit a4058c
      const guint8 *rle_buffer = pixdata->pixel_data;
Packit a4058c
      guint8 *rle_buffer_limit = NULL;
Packit a4058c
      guint8 *image_buffer = data;
Packit a4058c
      guint8 *image_limit = data + pixdata->rowstride * pixdata->height;
Packit a4058c
      gboolean check_overrun = FALSE;
Packit a4058c
Packit a4058c
      if (pixdata->length >= 1)
Packit a4058c
        rle_buffer_limit = pixdata->pixel_data + pixdata->length - GDK_PIXDATA_HEADER_LENGTH;
Packit a4058c
Packit a4058c
      while (image_buffer < image_limit &&
Packit a4058c
             (rle_buffer_limit != NULL || rle_buffer > rle_buffer_limit))
Packit a4058c
	{
Packit a4058c
	  guint length;
Packit a4058c
Packit a4058c
	  if (RLE_OVERRUN(1))
Packit a4058c
	    {
Packit a4058c
	      check_overrun = TRUE;
Packit a4058c
	      break;
Packit a4058c
	    }
Packit a4058c
Packit a4058c
	  length = *(rle_buffer++);
Packit a4058c
Packit a4058c
	  if (length & 128)
Packit a4058c
	    {
Packit a4058c
	      length = length - 128;
Packit a4058c
	      check_overrun = image_buffer + length * bpp > image_limit;
Packit a4058c
	      if (check_overrun)
Packit a4058c
		length = (image_limit - image_buffer) / bpp;
Packit a4058c
	      if (RLE_OVERRUN(bpp < 4 ? 3 : 4))
Packit a4058c
	        {
Packit a4058c
	          check_overrun = TRUE;
Packit a4058c
	          break;
Packit a4058c
	        }
Packit a4058c
	      if (bpp < 4)	/* RGB */
Packit a4058c
		do
Packit a4058c
		  {
Packit a4058c
		    memcpy (image_buffer, rle_buffer, 3);
Packit a4058c
		    image_buffer += 3;
Packit a4058c
		  }
Packit a4058c
		while (--length);
Packit a4058c
	      else		/* RGBA */
Packit a4058c
		do
Packit a4058c
		  {
Packit a4058c
		    memcpy (image_buffer, rle_buffer, 4);
Packit a4058c
		    image_buffer += 4;
Packit a4058c
		  }
Packit a4058c
		while (--length);
Packit a4058c
	      if (RLE_OVERRUN(bpp))
Packit a4058c
	        {
Packit a4058c
	          check_overrun = TRUE;
Packit a4058c
	          break;
Packit a4058c
		}
Packit a4058c
	      rle_buffer += bpp;
Packit a4058c
	    }
Packit a4058c
	  else
Packit a4058c
	    {
Packit a4058c
	      length *= bpp;
Packit a4058c
	      check_overrun = image_buffer + length > image_limit;
Packit a4058c
	      if (check_overrun)
Packit a4058c
		length = image_limit - image_buffer;
Packit a4058c
	      if (RLE_OVERRUN(length))
Packit a4058c
	        {
Packit a4058c
	          check_overrun = TRUE;
Packit a4058c
	          break;
Packit a4058c
		}
Packit a4058c
	      memcpy (image_buffer, rle_buffer, length);
Packit a4058c
	      image_buffer += length;
Packit a4058c
	      rle_buffer += length;
Packit a4058c
	    }
Packit a4058c
	}
Packit a4058c
      if (check_overrun)
Packit a4058c
	{
Packit a4058c
	  g_free (data);
Packit a4058c
	  g_set_error_literal (error, GDK_PIXBUF_ERROR,
Packit a4058c
                               GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
Packit a4058c
                               _("Image pixel data corrupt"));
Packit a4058c
	  return NULL;
Packit a4058c
	}
Packit a4058c
    }
Packit a4058c
  else if (copy_pixels)
Packit a4058c
    memcpy (data, pixdata->pixel_data, pixdata->rowstride * pixdata->height);
Packit a4058c
  else
Packit a4058c
    data = pixdata->pixel_data;
Packit a4058c
Packit a4058c
  return gdk_pixbuf_new_from_data (data, GDK_COLORSPACE_RGB,
Packit a4058c
				   (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA,
Packit a4058c
				   8, pixdata->width, pixdata->height, pixdata->rowstride,
Packit a4058c
				   copy_pixels ? (GdkPixbufDestroyNotify) g_free : NULL, data);
Packit a4058c
}
Packit a4058c
Packit a4058c
typedef struct {
Packit a4058c
  /* config */
Packit a4058c
  gboolean     dump_stream;
Packit a4058c
  gboolean     dump_struct;
Packit a4058c
  gboolean     dump_macros;
Packit a4058c
  gboolean     dump_gtypes;
Packit a4058c
  gboolean     dump_rle_decoder;
Packit a4058c
  const gchar *static_prefix;
Packit a4058c
  const gchar *const_prefix;
Packit a4058c
  /* runtime */
Packit a4058c
  GString *gstring;
Packit a4058c
  guint    pos;
Packit a4058c
  gboolean pad;
Packit a4058c
} CSourceData;
Packit a4058c
Packit a4058c
static inline void
Packit a4058c
save_uchar (CSourceData *cdata,
Packit a4058c
	    guint8       d)
Packit a4058c
{
Packit a4058c
  GString *gstring = cdata->gstring;
Packit a4058c
Packit a4058c
  if (cdata->pos > 70)
Packit a4058c
    {
Packit a4058c
      if (cdata->dump_struct || cdata->dump_stream)
Packit a4058c
	{
Packit a4058c
	  g_string_append (gstring, "\"\n  \"");
Packit a4058c
	  cdata->pos = 3;
Packit a4058c
	  cdata->pad = FALSE;
Packit a4058c
	}
Packit a4058c
      if (cdata->dump_macros)
Packit a4058c
	{
Packit a4058c
	  g_string_append (gstring, "\" \\\n  \"");
Packit a4058c
	  cdata->pos = 3;
Packit a4058c
	  cdata->pad = FALSE;
Packit a4058c
	}
Packit a4058c
    }
Packit a4058c
  if (d < 33 || d > 126 || d == '?')
Packit a4058c
    {
Packit a4058c
      APPEND (gstring, "\\%o", d);
Packit a4058c
      cdata->pos += 1 + 1 + (d > 7) + (d > 63);
Packit a4058c
      cdata->pad = d < 64;
Packit a4058c
      return;
Packit a4058c
    }
Packit a4058c
  if (d == '\\')
Packit a4058c
    {
Packit a4058c
      g_string_append (gstring, "\\\\");
Packit a4058c
      cdata->pos += 2;
Packit a4058c
    }
Packit a4058c
  else if (d == '"')
Packit a4058c
    {
Packit a4058c
      g_string_append (gstring, "\\\"");
Packit a4058c
      cdata->pos += 2;
Packit a4058c
    }
Packit a4058c
  else if (cdata->pad && d >= '0' && d <= '9')
Packit a4058c
    {
Packit a4058c
      g_string_append (gstring, "\"\"");
Packit a4058c
      g_string_append_c (gstring, d);
Packit a4058c
      cdata->pos += 3;
Packit a4058c
    }
Packit a4058c
  else
Packit a4058c
    {
Packit a4058c
      g_string_append_c (gstring, d);
Packit a4058c
      cdata->pos += 1;
Packit a4058c
    }
Packit a4058c
  cdata->pad = FALSE;
Packit a4058c
  return;
Packit a4058c
}
Packit a4058c
Packit a4058c
static inline void
Packit a4058c
save_rle_decoder (GString     *gstring,
Packit a4058c
		  const gchar *macro_name,
Packit a4058c
		  const gchar *s_uint,
Packit a4058c
		  const gchar *s_uint_8,
Packit a4058c
		  guint        n_ch)
Packit a4058c
{
Packit a4058c
  APPEND (gstring, "#define %s_RUN_LENGTH_DECODE(image_buf, rle_data, size, bpp) do \\\n",
Packit a4058c
	  macro_name);
Packit a4058c
  APPEND (gstring, "{ %s __bpp; %s *__ip; const %s *__il, *__rd; \\\n", s_uint, s_uint_8, s_uint_8);
Packit a4058c
  APPEND (gstring, "  __bpp = (bpp); __ip = (image_buf); __il = __ip + (size) * __bpp; \\\n");
Packit a4058c
  
Packit a4058c
  APPEND (gstring, "  __rd = (rle_data); if (__bpp > 3) { /* RGBA */ \\\n");
Packit a4058c
  
Packit a4058c
  APPEND (gstring, "    while (__ip < __il) { %s __l = *(__rd++); \\\n", s_uint);
Packit a4058c
  APPEND (gstring, "      if (__l & 128) { __l = __l - 128; \\\n");
Packit a4058c
  APPEND (gstring, "        do { memcpy (__ip, __rd, 4); __ip += 4; } while (--__l); __rd += 4; \\\n");
Packit a4058c
  APPEND (gstring, "      } else { __l *= 4; memcpy (__ip, __rd, __l); \\\n");
Packit a4058c
  APPEND (gstring, "               __ip += __l; __rd += __l; } } \\\n");
Packit a4058c
  
Packit a4058c
  APPEND (gstring, "  } else { /* RGB */ \\\n");
Packit a4058c
  
Packit a4058c
  APPEND (gstring, "    while (__ip < __il) { %s __l = *(__rd++); \\\n", s_uint);
Packit a4058c
  APPEND (gstring, "      if (__l & 128) { __l = __l - 128; \\\n");
Packit a4058c
  APPEND (gstring, "        do { memcpy (__ip, __rd, 3); __ip += 3; } while (--__l); __rd += 3; \\\n");
Packit a4058c
  APPEND (gstring, "      } else { __l *= 3; memcpy (__ip, __rd, __l); \\\n");
Packit a4058c
  APPEND (gstring, "               __ip += __l; __rd += __l; } } \\\n");
Packit a4058c
  
Packit a4058c
  APPEND (gstring, "  } } while (0)\n");
Packit a4058c
}
Packit a4058c
Packit a4058c
/**
Packit a4058c
 * gdk_pixdata_to_csource:
Packit a4058c
 * @pixdata: a #GdkPixdata to convert to C source.
Packit a4058c
 * @name: used for naming generated data structures or macros.
Packit a4058c
 * @dump_type: a #GdkPixdataDumpType determining the kind of C
Packit a4058c
 *   source to be generated.
Packit a4058c
 *
Packit a4058c
 * Generates C source code suitable for compiling images directly 
Packit a4058c
 * into programs. 
Packit a4058c
 *
Packit a4058c
 * gdk-pixbuf ships with a program called
Packit a4058c
 * [gdk-pixbuf-csource][gdk-pixbuf-csource], which offers a command
Packit a4058c
 * line interface to this function.
Packit a4058c
 *
Packit a4058c
 * Returns: a newly-allocated string containing the C source form
Packit a4058c
 *   of @pixdata.
Packit a4058c
 * Deprecated: 2.32: Use #GResource instead.
Packit a4058c
 **/
Packit a4058c
GString*
Packit a4058c
gdk_pixdata_to_csource (GdkPixdata        *pixdata,
Packit a4058c
			const gchar	  *name,
Packit a4058c
			GdkPixdataDumpType dump_type)
Packit a4058c
{
Packit a4058c
  CSourceData cdata = { 0, };
Packit a4058c
  gchar *s_uint_8;
Packit a4058c
  guint bpp, width, height, rowstride;
Packit a4058c
  gboolean rle_encoded;
Packit a4058c
  gchar *macro_name;
Packit a4058c
  guint8 *img_buffer, *img_buffer_end, *stream = NULL;
Packit a4058c
  guint stream_length;
Packit a4058c
  GString *gstring;
Packit a4058c
  
Packit a4058c
  /* check args passing */
Packit a4058c
  g_return_val_if_fail (pixdata != NULL, NULL);
Packit a4058c
  g_return_val_if_fail (name != NULL, NULL);
Packit a4058c
  /* check pixdata contents */
Packit a4058c
  g_return_val_if_fail (pixdata->magic == GDK_PIXBUF_MAGIC_NUMBER, NULL);
Packit a4058c
  g_return_val_if_fail (pixdata->width > 0, NULL);
Packit a4058c
  g_return_val_if_fail (pixdata->height > 0, NULL);
Packit a4058c
  g_return_val_if_fail (pixdata->rowstride >= pixdata->width, NULL);
Packit a4058c
  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ||
Packit a4058c
			(pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGBA, NULL);
Packit a4058c
  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_SAMPLE_WIDTH_MASK) == GDK_PIXDATA_SAMPLE_WIDTH_8, NULL);
Packit a4058c
  g_return_val_if_fail ((pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RAW ||
Packit a4058c
			(pixdata->pixdata_type & GDK_PIXDATA_ENCODING_MASK) == GDK_PIXDATA_ENCODING_RLE, NULL);
Packit a4058c
  g_return_val_if_fail (pixdata->pixel_data != NULL, NULL);
Packit a4058c
Packit a4058c
  img_buffer = pixdata->pixel_data;
Packit a4058c
  if (pixdata->length < 1)
Packit a4058c
    img_buffer_end = img_buffer + pixdata_get_length (pixdata);
Packit a4058c
  else
Packit a4058c
    img_buffer_end = img_buffer + pixdata->length - GDK_PIXDATA_HEADER_LENGTH;
Packit a4058c
  g_return_val_if_fail (img_buffer < img_buffer_end, NULL);
Packit a4058c
Packit a4058c
  bpp = (pixdata->pixdata_type & GDK_PIXDATA_COLOR_TYPE_MASK) == GDK_PIXDATA_COLOR_TYPE_RGB ? 3 : 4;
Packit a4058c
  width = pixdata->width;
Packit a4058c
  height = pixdata->height;
Packit a4058c
  rowstride = pixdata->rowstride;
Packit a4058c
  rle_encoded = (pixdata->pixdata_type & GDK_PIXDATA_ENCODING_RLE) > 0;
Packit a4058c
  macro_name = g_ascii_strup (name, -1);
Packit a4058c
Packit a4058c
  cdata.dump_macros = (dump_type & GDK_PIXDATA_DUMP_MACROS) > 0;
Packit a4058c
  cdata.dump_struct = (dump_type & GDK_PIXDATA_DUMP_PIXDATA_STRUCT) > 0;
Packit a4058c
  cdata.dump_stream = !cdata.dump_macros && !cdata.dump_struct;
Packit a4058c
  g_return_val_if_fail (cdata.dump_macros + cdata.dump_struct + cdata.dump_stream == 1, NULL);
Packit a4058c
Packit a4058c
  cdata.dump_gtypes = (dump_type & GDK_PIXDATA_DUMP_CTYPES) == 0;
Packit a4058c
  cdata.dump_rle_decoder = (dump_type & GDK_PIXDATA_DUMP_RLE_DECODER) > 0;
Packit a4058c
  cdata.static_prefix = (dump_type & GDK_PIXDATA_DUMP_STATIC) ? "static " : "";
Packit a4058c
  cdata.const_prefix = (dump_type & GDK_PIXDATA_DUMP_CONST) ? "const " : "";
Packit a4058c
  gstring = g_string_new (NULL);
Packit a4058c
  cdata.gstring = gstring;
Packit a4058c
Packit a4058c
  if (!cdata.dump_macros && cdata.dump_gtypes)
Packit a4058c
    s_uint_8 =  "guint8 ";
Packit a4058c
  else if (!cdata.dump_macros)
Packit a4058c
    s_uint_8 =  "unsigned char";
Packit a4058c
  else if (cdata.dump_macros && cdata.dump_gtypes)
Packit a4058c
    s_uint_8 =  "guint8";
Packit a4058c
  else /* cdata.dump_macros && !cdata.dump_gtypes */
Packit a4058c
    s_uint_8 =  "unsigned char";
Packit a4058c
Packit a4058c
  /* initial comment
Packit a4058c
   */
Packit a4058c
  APPEND (gstring,
Packit a4058c
	  "/* GdkPixbuf %s C-Source image dump %s*/\n\n",
Packit a4058c
	  bpp > 3 ? "RGBA" : "RGB",
Packit a4058c
	  rle_encoded ? "1-byte-run-length-encoded " : "");
Packit a4058c
  
Packit a4058c
  /* dump RLE decoder for structures
Packit a4058c
   */
Packit a4058c
  if (cdata.dump_rle_decoder && cdata.dump_struct)
Packit a4058c
    save_rle_decoder (gstring,
Packit a4058c
		      macro_name,
Packit a4058c
		      cdata.dump_gtypes ? "guint" : "unsigned int",
Packit a4058c
		      cdata.dump_gtypes ? "guint8" : "unsigned char",
Packit a4058c
		      bpp);
Packit a4058c
Packit a4058c
  /* format & size blurbs
Packit a4058c
   */
Packit a4058c
  if (cdata.dump_macros)
Packit a4058c
    {
Packit a4058c
      APPEND (gstring, "#define %s_ROWSTRIDE (%u)\n",
Packit a4058c
	      macro_name, rowstride);
Packit a4058c
      APPEND (gstring, "#define %s_WIDTH (%u)\n",
Packit a4058c
	      macro_name, width);
Packit a4058c
      APPEND (gstring, "#define %s_HEIGHT (%u)\n",
Packit a4058c
	      macro_name, height);
Packit a4058c
      APPEND (gstring, "#define %s_BYTES_PER_PIXEL (%u) /* 3:RGB, 4:RGBA */\n",
Packit a4058c
	      macro_name, bpp);
Packit a4058c
    }
Packit a4058c
  if (cdata.dump_struct)
Packit a4058c
    {
Packit a4058c
      APPEND (gstring, "%s%sGdkPixdata %s = {\n",
Packit a4058c
	      cdata.static_prefix, cdata.const_prefix, name);
Packit a4058c
      APPEND (gstring, "  0x%x, /* Pixbuf magic: 'GdkP' */\n",
Packit a4058c
	      GDK_PIXBUF_MAGIC_NUMBER);
Packit a4058c
      APPEND (gstring, "  %d + %lu, /* header length + pixel_data length */\n",
Packit a4058c
	      GDK_PIXDATA_HEADER_LENGTH,
Packit a4058c
	      rle_encoded ? (glong)(img_buffer_end - img_buffer) : (glong)rowstride * height);
Packit a4058c
      APPEND (gstring, "  0x%x, /* pixdata_type */\n",
Packit a4058c
	      pixdata->pixdata_type);
Packit a4058c
      APPEND (gstring, "  %u, /* rowstride */\n",
Packit a4058c
	      rowstride);
Packit a4058c
      APPEND (gstring, "  %u, /* width */\n",
Packit a4058c
	      width);
Packit a4058c
      APPEND (gstring, "  %u, /* height */\n",
Packit a4058c
	      height);
Packit a4058c
      APPEND (gstring, "  /* pixel_data: */\n");
Packit a4058c
    }
Packit a4058c
  if (cdata.dump_stream)
Packit a4058c
    {
Packit a4058c
      guint pix_length = img_buffer_end - img_buffer;
Packit a4058c
Packit a4058c
Packit a4058c
      stream = gdk_pixdata_serialize (pixdata, &stream_length);
Packit a4058c
      img_buffer = stream;
Packit a4058c
      img_buffer_end = stream + stream_length;
Packit a4058c
Packit a4058c
      APPEND (gstring, "#ifdef __SUNPRO_C\n");
Packit a4058c
      APPEND (gstring, "#pragma align 4 (%s)\n", name);   
Packit a4058c
      APPEND (gstring, "#endif\n");
Packit a4058c
Packit a4058c
      APPEND (gstring, "#ifdef __GNUC__\n");
Packit a4058c
      APPEND (gstring, "%s%s%s %s[] __attribute__ ((__aligned__ (4))) = \n",
Packit a4058c
	      cdata.static_prefix, cdata.const_prefix,
Packit a4058c
	      cdata.dump_gtypes ? "guint8" : "unsigned char",
Packit a4058c
	      name);
Packit a4058c
      APPEND (gstring, "#else\n");
Packit a4058c
      APPEND (gstring, "%s%s%s %s[] = \n",
Packit a4058c
	      cdata.static_prefix, cdata.const_prefix,
Packit a4058c
	      cdata.dump_gtypes ? "guint8" : "unsigned char",
Packit a4058c
	      name);
Packit a4058c
      APPEND (gstring, "#endif\n");
Packit a4058c
Packit a4058c
      APPEND (gstring, "{ \"\"\n  /* Pixbuf magic (0x%x) */\n  \"",
Packit a4058c
	      GDK_PIXBUF_MAGIC_NUMBER);
Packit a4058c
      cdata.pos = 3;
Packit a4058c
      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
Packit a4058c
      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
Packit a4058c
      APPEND (gstring, "\"\n  /* length: header (%d) + pixel_data (%u) */\n  \"",
Packit a4058c
	      GDK_PIXDATA_HEADER_LENGTH,
Packit a4058c
	      rle_encoded ? pix_length : rowstride * height);
Packit a4058c
      cdata.pos = 3;
Packit a4058c
      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
Packit a4058c
      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
Packit a4058c
      APPEND (gstring, "\"\n  /* pixdata_type (0x%x) */\n  \"",
Packit a4058c
	      pixdata->pixdata_type);
Packit a4058c
      cdata.pos = 3;
Packit a4058c
      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
Packit a4058c
      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
Packit a4058c
      APPEND (gstring, "\"\n  /* rowstride (%u) */\n  \"",
Packit a4058c
	      rowstride);
Packit a4058c
      cdata.pos = 3;
Packit a4058c
      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
Packit a4058c
      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
Packit a4058c
      APPEND (gstring, "\"\n  /* width (%u) */\n  \"", width);
Packit a4058c
      cdata.pos = 3;
Packit a4058c
      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
Packit a4058c
      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
Packit a4058c
      APPEND (gstring, "\"\n  /* height (%u) */\n  \"", height);
Packit a4058c
      cdata.pos = 3;
Packit a4058c
      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
Packit a4058c
      save_uchar (&cdata, *img_buffer++); save_uchar (&cdata, *img_buffer++);
Packit a4058c
      APPEND (gstring, "\"\n  /* pixel_data: */\n");
Packit a4058c
    }
Packit a4058c
Packit a4058c
  /* pixel_data intro
Packit a4058c
   */
Packit a4058c
  if (cdata.dump_macros)
Packit a4058c
    {
Packit a4058c
      APPEND (gstring, "#define %s_%sPIXEL_DATA ((%s*) \\\n",
Packit a4058c
	      macro_name,
Packit a4058c
	      rle_encoded ? "RLE_" : "",
Packit a4058c
	      s_uint_8);
Packit a4058c
      APPEND (gstring, "  \"");
Packit a4058c
      cdata.pos = 2;
Packit a4058c
    }
Packit a4058c
  if (cdata.dump_struct)
Packit a4058c
    {
Packit a4058c
      APPEND (gstring, "  \"");
Packit a4058c
      cdata.pos = 3;
Packit a4058c
    }
Packit a4058c
  if (cdata.dump_stream)
Packit a4058c
    {
Packit a4058c
      APPEND (gstring, "  \"");
Packit a4058c
      cdata.pos = 3;
Packit a4058c
    }
Packit a4058c
    
Packit a4058c
  /* pixel_data
Packit a4058c
   */
Packit a4058c
  do
Packit a4058c
    save_uchar (&cdata, *img_buffer++);
Packit a4058c
  while (img_buffer < img_buffer_end);
Packit a4058c
Packit a4058c
  /* pixel_data trailer
Packit a4058c
   */
Packit a4058c
  if (cdata.dump_macros)
Packit a4058c
    APPEND (gstring, "\")\n\n");
Packit a4058c
  if (cdata.dump_struct)
Packit a4058c
    APPEND (gstring, "\",\n};\n\n");
Packit a4058c
  if (cdata.dump_stream)
Packit a4058c
    APPEND (gstring, "\"};\n\n");
Packit a4058c
Packit a4058c
  /* dump RLE decoder for macros
Packit a4058c
   */
Packit a4058c
  if (cdata.dump_rle_decoder && cdata.dump_macros)
Packit a4058c
    save_rle_decoder (gstring,
Packit a4058c
		      macro_name,
Packit a4058c
		      cdata.dump_gtypes ? "guint" : "unsigned int",
Packit a4058c
		      cdata.dump_gtypes ? "guint8" : "unsigned char",
Packit a4058c
		      bpp);
Packit a4058c
Packit a4058c
  /* cleanup
Packit a4058c
   */
Packit a4058c
  g_free (stream);
Packit a4058c
  g_free (macro_name);
Packit a4058c
    
Packit a4058c
  return gstring;
Packit a4058c
}
Packit a4058c
Packit a4058c
/**
Packit a4058c
 * gdk_pixbuf_new_from_inline:
Packit a4058c
 * @data_length: Length in bytes of the @data argument or -1 to 
Packit a4058c
 *    disable length checks
Packit a4058c
 * @data: (array length=data_length): Byte data containing a
Packit a4058c
 *    serialized #GdkPixdata structure
Packit a4058c
 * @copy_pixels: Whether to copy the pixel data, or use direct pointers
Packit a4058c
 *               @data for the resulting pixbuf
Packit a4058c
 * @error: #GError return location, may be %NULL to ignore errors
Packit a4058c
 *
Packit a4058c
 * Create a #GdkPixbuf from a flat representation that is suitable for
Packit a4058c
 * storing as inline data in a program. This is useful if you want to
Packit a4058c
 * ship a program with images, but don't want to depend on any
Packit a4058c
 * external files.
Packit a4058c
 *
Packit a4058c
 * gdk-pixbuf ships with a program called [gdk-pixbuf-csource][gdk-pixbuf-csource],
Packit a4058c
 * which allows for conversion of #GdkPixbufs into such a inline representation.
Packit a4058c
 * In almost all cases, you should pass the `--raw` option to
Packit a4058c
 * `gdk-pixbuf-csource`. A sample invocation would be:
Packit a4058c
 *
Packit a4058c
 * |[
Packit a4058c
 *  gdk-pixbuf-csource --raw --name=myimage_inline myimage.png
Packit a4058c
 * ]|
Packit a4058c
 * 
Packit a4058c
 * For the typical case where the inline pixbuf is read-only static data,
Packit a4058c
 * you don't need to copy the pixel data unless you intend to write to
Packit a4058c
 * it, so you can pass %FALSE for @copy_pixels.  (If you pass `--rle` to
Packit a4058c
 * `gdk-pixbuf-csource`, a copy will be made even if @copy_pixels is %FALSE,
Packit a4058c
 * so using this option is generally a bad idea.)
Packit a4058c
 *
Packit a4058c
 * If you create a pixbuf from const inline data compiled into your
Packit a4058c
 * program, it's probably safe to ignore errors and disable length checks, 
Packit a4058c
 * since things will always succeed:
Packit a4058c
 * |[
Packit a4058c
 * pixbuf = gdk_pixbuf_new_from_inline (-1, myimage_inline, FALSE, NULL);
Packit a4058c
 * ]|
Packit a4058c
 *
Packit a4058c
 * For non-const inline data, you could get out of memory. For untrusted 
Packit a4058c
 * inline data located at runtime, you could have corrupt inline data in 
Packit a4058c
 * addition.
Packit a4058c
 *
Packit a4058c
 * Return value: A newly-created #GdkPixbuf structure with a reference,
Packit a4058c
 *   count of 1, or %NULL if an error occurred.
Packit a4058c
 *
Packit a4058c
 * Deprecated: 2.32: Use #GResource instead.
Packit a4058c
 **/
Packit a4058c
GdkPixbuf*
Packit a4058c
gdk_pixbuf_new_from_inline (gint          data_length,
Packit a4058c
			    const guint8 *data,
Packit a4058c
			    gboolean      copy_pixels,
Packit a4058c
			    GError      **error)
Packit a4058c
{
Packit a4058c
  GdkPixdata pixdata;
Packit a4058c
Packit a4058c
  if (data_length != -1)
Packit a4058c
    g_return_val_if_fail (data_length > GDK_PIXDATA_HEADER_LENGTH, NULL);
Packit a4058c
  g_return_val_if_fail (data != NULL, NULL);
Packit a4058c
Packit a4058c
  if (!gdk_pixdata_deserialize (&pixdata, data_length, data, error))
Packit a4058c
    return NULL;
Packit a4058c
Packit a4058c
  return gdk_pixbuf_from_pixdata (&pixdata, copy_pixels, error);
Packit a4058c
}