io-gif.c, io-png.c: Actually put the licencing terms in the code now...
io-xpm.c: XPM parser baed off of gdk's, but this does something with the
transparent colors.
/*
- * io-png.c: GdkPixBuf I/O for GIF files.
+ * io-gif.c: GdkPixBuf I/O for GIF files.
* ...second verse, same as the first...
*
- * Author:
- * Mark Crichton <crichton@gimp.org>
+ * Copyright (C) 1999 Mark Crichton
+ * Author: Mark Crichton <crichton@gimp.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Cambridge, MA 02139, USA.
*
*/
+
#include <config.h>
#include <stdio.h>
#include <glib.h>
/* Shared library entry point */
GdkPixBuf *image_load(FILE * f)
{
- gint fn, is_trans, done;
- gint t_color = -1;
- gint w, h, i, j;
- art_u8 *pixels, *tmpptr;
- GifFileType *gif;
- GifRowType *rows;
- GifRecordType rec;
- ColorMapObject *cmap;
- int intoffset[] = {0, 4, 2, 1};
- int intjump[] = {8, 8, 4, 2};
-
- GdkPixBuf *pixbuf;
-
- g_return_val_if_fail(f != NULL, NULL);
-
- fn = fileno(f);
- gif = DGifOpenFileHandle(fn);
-
- if (!gif) {
- g_error("DGifOpenFilehandle FAILED");
+ gint fn, is_trans, done;
+ gint t_color = -1;
+ gint w, h, i, j;
+ art_u8 *pixels, *tmpptr;
+ GifFileType *gif;
+ GifRowType *rows;
+ GifRecordType rec;
+ ColorMapObject *cmap;
+ int intoffset[] =
+ {0, 4, 2, 1};
+ int intjump[] =
+ {8, 8, 4, 2};
+
+ GdkPixBuf *pixbuf;
+
+ g_return_val_if_fail(f != NULL, NULL);
+
+ fn = fileno(f);
+ gif = DGifOpenFileHandle(fn);
+
+ if (!gif) {
+ g_error("DGifOpenFilehandle FAILED");
+ PrintGifError();
+ return NULL;
+ }
+ /* Now we do the ungodly mess of loading a GIF image
+ * I used to remember when I liked this file format...
+ * of course, I still coded in assembler then.
+ * This comes from gdk_imlib, with some cleanups.
+ */
+
+ do {
+ if (DGifGetRecordType(gif, &rec) == GIF_ERROR) {
+ PrintGifError();
+ rec = TERMINATE_RECORD_TYPE;
+ }
+ if ((rec == IMAGE_DESC_RECORD_TYPE) && (!done)) {
+ if (DGifGetImageDesc(gif) == GIF_ERROR) {
PrintGifError();
+ rec = TERMINATE_RECORD_TYPE;
+ }
+ w = gif->Image.Width;
+ h = gif->Image.Height;
+ rows = g_malloc(h * sizeof(GifRowType *));
+ if (!rows) {
+ DGifCloseFile(gif);
return NULL;
- }
- /* Now we do the ungodly mess of loading a GIF image
- * I used to remember when I liked this file format...
- * of course, I still coded in assembler then.
- * This comes from gdk_imlib, with some cleanups.
- */
-
- do {
- if (DGifGetRecordType(gif, &rec) == GIF_ERROR) {
- PrintGifError();
- rec = TERMINATE_RECORD_TYPE;
+ }
+ for (i = 0; i < h; i++) {
+ rows[i] = g_malloc(w * sizeof(GifPixelType));
+ if (!rows[i]) {
+ DGifCloseFile(gif);
+ for (i = 0; i < h; i++)
+ if (rows[i])
+ g_free(rows[i]);
+ free(rows);
+ return NULL;
}
- if ((rec == IMAGE_DESC_RECORD_TYPE) && (!done)) {
- if (DGifGetImageDesc(gif) == GIF_ERROR) {
- PrintGifError();
- rec = TERMINATE_RECORD_TYPE;
- }
- w = gif->Image.Width;
- h = gif->Image.Height;
- rows = g_malloc(h * sizeof(GifRowType *));
- if (!rows) {
- DGifCloseFile(gif);
- return NULL;
- }
- for (i = 0; i < h; i++) {
- rows[i] = g_malloc(w * sizeof(GifPixelType));
- if (!rows[i]) {
- DGifCloseFile(gif);
- for (i = 0; i < h; i++)
- if (rows[i])
- g_free(rows[i]);
- free(rows);
- return NULL;
- }
- }
- if (gif->Image.Interlace) {
- for (i = 0; i < 4; i++) {
- for (j = intoffset[i]; j < h; j += intjump[i])
- DGifGetLine(gif, rows[j], w);
- }
- } else {
- for (i = 0; i < h; i++)
- DGifGetLine(gif, rows[i], w);
- }
- done = TRUE;
- } else if (rec == EXTENSION_RECORD_TYPE) {
- gint ext_code;
- GifByteType *ext;
-
- DGifGetExtension(gif, &ext_code, &ext);
- while (ext) {
- if ((ext_code == GRAPHICS_EXT_FUNC_CODE) &&
- (ext[1] & 1) && (t_color < 0)) {
- is_trans = TRUE;
- t_color = (gint) ext[4];
- }
- ext = NULL;
- DGifGetExtensionNext(gif, &ext);
- }
+ }
+ if (gif->Image.Interlace) {
+ for (i = 0; i < 4; i++) {
+ for (j = intoffset[i]; j < h; j += intjump[i])
+ DGifGetLine(gif, rows[j], w);
}
- }
- while (rec != TERMINATE_RECORD_TYPE);
-
- /* Ok, we're loaded, now to convert from indexed -> RGB
- * with alpha if necessary
- */
-
- if (is_trans)
- pixels = art_alloc(h * w * 4);
- else
- pixels = art_alloc(h * w * 3);
- tmpptr = pixels;
-
- if (!pixels)
- return NULL;
-
- /* The meat of the transformation */
- /* Get the right palette */
- cmap = (gif->Image.ColorMap ? gif->Image.ColorMap : gif->SColorMap);
-
- /* Unindex the data, and pack it in RGB(A) order.
- * Note for transparent GIFs, the alpha is set to 0
- * for the transparent color, and 0xFF for everything else.
- * I think that's right...
- */
-
- for (i = 0; i < h; i++) {
- for (j = 0; j < w; j++) {
- tmpptr[0] = cmap->Colors[rows[i][j]].Red;
- tmpptr[1] = cmap->Colors[rows[i][j]].Green;
- tmpptr[2] = cmap->Colors[rows[i][j]].Blue;
- if (is_trans && (rows[i][j] == t_color))
- tmpptr[3] = 0;
- else
- tmpptr[3] = 0xFF;
- tmpptr += (is_trans ? 3 : 4);
+ } else {
+ for (i = 0; i < h; i++)
+ DGifGetLine(gif, rows[i], w);
+ }
+ done = TRUE;
+ } else if (rec == EXTENSION_RECORD_TYPE) {
+ gint ext_code;
+ GifByteType *ext;
+
+ DGifGetExtension(gif, &ext_code, &ext);
+ while (ext) {
+ if ((ext_code == GRAPHICS_EXT_FUNC_CODE) &&
+ (ext[1] & 1) && (t_color < 0)) {
+ is_trans = TRUE;
+ t_color = (gint) ext[4];
}
+ ext = NULL;
+ DGifGetExtensionNext(gif, &ext);
+ }
+ }
+ }
+ while (rec != TERMINATE_RECORD_TYPE);
+
+ /* Ok, we're loaded, now to convert from indexed -> RGB
+ * with alpha if necessary
+ */
+
+ if (is_trans)
+ pixels = art_alloc(h * w * 4);
+ else
+ pixels = art_alloc(h * w * 3);
+ tmpptr = pixels;
+
+ if (!pixels)
+ return NULL;
+
+ /* The meat of the transformation */
+ /* Get the right palette */
+ cmap = (gif->Image.ColorMap ? gif->Image.ColorMap : gif->SColorMap);
+
+ /* Unindex the data, and pack it in RGB(A) order.
+ * Note for transparent GIFs, the alpha is set to 0
+ * for the transparent color, and 0xFF for everything else.
+ * I think that's right...
+ */
+
+ for (i = 0; i < h; i++) {
+ for (j = 0; j < w; j++) {
+ tmpptr[0] = cmap->Colors[rows[i][j]].Red;
+ tmpptr[1] = cmap->Colors[rows[i][j]].Green;
+ tmpptr[2] = cmap->Colors[rows[i][j]].Blue;
+ if (is_trans && (rows[i][j] == t_color))
+ tmpptr[3] = 0;
+ else
+ tmpptr[3] = 0xFF;
+ tmpptr += (is_trans ? 3 : 4);
}
+ }
- /* Ok, now stuff the GdkPixBuf with goodies */
+ /* Ok, now stuff the GdkPixBuf with goodies */
- pixbuf = g_new(GdkPixBuf, 1);
+ pixbuf = g_new(GdkPixBuf, 1);
- if (is_trans)
- pixbuf->art_pixbuf = art_pixbuf_new_rgba(pixels, w, h, (w * 4));
- else
- pixbuf->art_pixbuf = art_pixbuf_new_rgb(pixels, w, h, (w * 3));
+ if (is_trans)
+ pixbuf->art_pixbuf = art_pixbuf_new_rgba(pixels, w, h, (w * 4));
+ else
+ pixbuf->art_pixbuf = art_pixbuf_new_rgb(pixels, w, h, (w * 3));
- /* Ok, I'm anal...shoot me */
- if (!(pixbuf->art_pixbuf))
- return NULL;
- pixbuf->ref_count = 0;
- pixbuf->unref_func = NULL;
+ /* Ok, I'm anal...shoot me */
+ if (!(pixbuf->art_pixbuf))
+ return NULL;
+ pixbuf->ref_count = 0;
+ pixbuf->unref_func = NULL;
- return pixbuf;
+ return pixbuf;
}
/*
* io-png.c: GdkPixBuf I/O for PNG files.
+ * Copyright (C) 1999 Mark Crichton
+ * Author: Mark Crichton <crichton@gimp.org>
*
- * Author:
- * Mark Crichton <crichton@gimp.org>
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Cambridge, MA 02139, USA.
*
*/
#include <config.h>
/* Shared library entry point */
GdkPixBuf *image_load(FILE * f)
{
- png_structp png_ptr;
- png_infop info_ptr, end_info;
- gint i, depth, ctype, inttype, passes, bpp; /* bpp = BYTES/pixel */
- png_uint_32 w, h, x, y;
- png_bytepp rows;
- art_u8 *pixels, *temp, *rowdata;
- GdkPixBuf *pixbuf;
-
- g_return_val_if_fail (f != NULL, NULL);
-
- png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL,
- NULL);
-
- info_ptr = png_create_info_struct (png_ptr);
- if (!info_ptr) {
- png_destroy_read_struct(&png_ptr, NULL, NULL);
- return NULL;
- }
+ png_structp png_ptr;
+ png_infop info_ptr, end_info;
+ gint i, depth, ctype, inttype, passes, bpp; /* bpp = BYTES/pixel */
+ png_uint_32 w, h, x, y;
+ png_bytepp rows;
+ art_u8 *pixels, *temp, *rowdata;
+ GdkPixBuf *pixbuf;
+
+ g_return_val_if_fail(f != NULL, NULL);
+
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL,
+ NULL);
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr) {
+ png_destroy_read_struct(&png_ptr, NULL, NULL);
+ return NULL;
+ }
+ end_info = png_create_info_struct(png_ptr);
+ if (!end_info) {
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ return NULL;
+ }
+ if (setjmp(png_ptr->jmpbuf)) {
+ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+ return NULL;
+ }
+ png_init_io(png_ptr, f);
+ png_read_info(png_ptr, info_ptr);
- end_info = png_create_info_struct (png_ptr);
- if (!end_info) {
- png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
- return NULL;
- }
+ png_get_IHDR(png_ptr, info_ptr, &w, &h, &depth, &ctype, &inttype,
+ NULL, NULL);
- if (setjmp(png_ptr->jmpbuf)) {
- png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
- return NULL;
- }
+ /* Ok, we want to work with 24 bit images.
+ * However, PNG can vary depth per channel.
+ * So, we use the png_set_expand function to expand
+ * everything into a format libart expects.
+ * We also use png_set_strip_16 to reduce down to 8 bit/chan.
+ */
- png_init_io(png_ptr, f);
- png_read_info(png_ptr, info_ptr);
+ if (ctype == PNG_COLOR_TYPE_PALETTE && depth <= 8)
+ png_set_expand(png_ptr);
- png_get_IHDR(png_ptr, info_ptr, &w, &h, &depth, &ctype, &inttype,
- NULL, NULL);
+ if (ctype == PNG_COLOR_TYPE_GRAY && depth < 8)
+ png_set_expand(png_ptr);
- /* Ok, we want to work with 24 bit images.
- * However, PNG can vary depth per channel.
- * So, we use the png_set_expand function to expand
- * everything into a format libart expects.
- * We also use png_set_strip_16 to reduce down to 8 bit/chan.
- */
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+ png_set_expand(png_ptr);
- if (ctype == PNG_COLOR_TYPE_PALETTE && depth <= 8)
- png_set_expand(png_ptr);
+ if (depth == 16)
+ png_set_strip_16(png_ptr);
- if (ctype == PNG_COLOR_TYPE_GRAY && depth < 8)
- png_set_expand(png_ptr);
+ /* We also have png "packing" bits into bytes if < 8 */
+ if (depth < 8)
+ png_set_packing(png_ptr);
- if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
- png_set_expand(png_ptr);
+ /* Lastly, if the PNG is greyscale, convert to RGB */
+ if (ctype == PNG_COLOR_TYPE_GRAY || ctype == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_gray_to_rgb(png_ptr);
- if (depth == 16)
- png_set_strip_16(png_ptr);
+ /* ...and if we're interlaced... */
+ passes = png_set_interlace_handling(png_ptr);
- /* We also have png "packing" bits into bytes if < 8 */
- if (depth < 8)
- png_set_packing(png_ptr);
+ /* Update our info structs */
+ png_read_update_info(png_ptr, info_ptr);
- /* Lastly, if the PNG is greyscale, convert to RGB */
- if (ctype == PNG_COLOR_TYPE_GRAY || ctype == PNG_COLOR_TYPE_GRAY_ALPHA)
- png_set_gray_to_rgb(png_ptr);
+ /* Allocate some memory and set up row array */
+ /* This "inhales vigirously"... */
+ if (ctype & PNG_COLOR_MASK_ALPHA)
+ bpp = 4;
+ else
+ bpp = 3;
- /* ...and if we're interlaced... */
- passes = png_set_interlace_handling(png_ptr);
+ pixels = art_alloc(w * h * bpp);
+ rows = g_malloc(h * sizeof(png_bytep));
- /* Update our info structs */
- png_read_update_info(png_ptr, info_ptr);
+ if ((!pixels) || (!rows)) {
+ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+ return NULL;
+ }
+ /* Icky code, but it has to be done... */
+ for (i = 0; i < h; i++) {
+ if ((rows[i] = g_malloc(w * sizeof(art_u8) * bpp)) == NULL) {
+ int n;
+ for (n = 0; n < i; n++)
+ g_free(rows[i]);
+ g_free(rows);
+ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+ return NULL;
+ }
+ }
- /* Allocate some memory and set up row array */
- /* This "inhales vigirously"... */
- if (ctype & PNG_COLOR_MASK_ALPHA)
- bpp = 4;
- else
- bpp = 3;
+ /* And we FINALLY get here... */
+ png_read_image(png_ptr, rows);
+ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
- pixels = art_alloc(w*h*bpp);
- rows = g_malloc(h*sizeof(png_bytep));
+ /* Now stuff the bytes into pixels & free rows[y] */
- if ((!pixels) || (!rows)) {
- png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
- return NULL;
- }
+ temp = pixels;
- /* Icky code, but it has to be done... */
- for (i = 0; i < h; i++) {
- if ((rows[i] = g_malloc(w*sizeof(art_u8)*bpp)) == NULL) {
- int n;
- for (n = 0; n < i; n++)
- g_free(rows[i]);
- g_free(rows);
- png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
- return NULL;
- }
- }
-
- /* And we FINALLY get here... */
- png_read_image(png_ptr, rows);
- png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
-
- /* Now stuff the bytes into pixels & free rows[y] */
-
- temp = pixels;
-
- for (y = 0; y < h; y++) {
- (png_bytep)rowdata = rows[y];
- for (x = 0; x < w; x++) {
- temp[0] = rowdata[(x*bpp)];
- temp[1] = rowdata[(x*bpp)+1];
- temp[2] = rowdata[(x*bpp)+2];
- if (bpp == 4)
- temp[3] = rowdata[(x*bpp)+3];
- temp += bpp;
- }
- g_free(rows[y]);
+ for (y = 0; y < h; y++) {
+ (png_bytep) rowdata = rows[y];
+ for (x = 0; x < w; x++) {
+ temp[0] = rowdata[(x * bpp)];
+ temp[1] = rowdata[(x * bpp) + 1];
+ temp[2] = rowdata[(x * bpp) + 2];
+ if (bpp == 4)
+ temp[3] = rowdata[(x * bpp) + 3];
+ temp += bpp;
}
- g_free(rows);
+ g_free(rows[y]);
+ }
+ g_free(rows);
- /* Return the GdkPixBuf */
- pixbuf = g_new(GdkPixBuf, 1);
+ /* Return the GdkPixBuf */
+ pixbuf = g_new(GdkPixBuf, 1);
- if (ctype & PNG_COLOR_MASK_ALPHA)
- pixbuf->art_pixbuf = art_pixbuf_new_rgba (pixels, w, h, (w*4));
- else
- pixbuf->art_pixbuf = art_pixbuf_new_rgb (pixels, w, h, (w*3));
+ if (ctype & PNG_COLOR_MASK_ALPHA)
+ pixbuf->art_pixbuf = art_pixbuf_new_rgba(pixels, w, h, (w * 4));
+ else
+ pixbuf->art_pixbuf = art_pixbuf_new_rgb(pixels, w, h, (w * 3));
- /* Ok, I'm anal...shoot me */
- if (!(pixbuf->art_pixbuf))
- return NULL;
- pixbuf->ref_count = 0;
- pixbuf->unref_func = NULL;
+ /* Ok, I'm anal...shoot me */
+ if (!(pixbuf->art_pixbuf))
+ return NULL;
+ pixbuf->ref_count = 0;
+ pixbuf->unref_func = NULL;
- return pixbuf;
+ return pixbuf;
}
--- /dev/null
+/*
+ * io-xpm.c: GdkPixBuf I/O for XPM files.
+ * Copyright (C) 1999 Mark Crichton
+ * Author: Mark Crichton <crichton@gimp.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <glib.h>
+
+/* We need gdk.h since we might need to parse X color names */
+#include <gdk/gdk.h>
+
+#include "gdk-pixbuf.h"
+/*#include "gdk-pixbuf-io.h" */
+
+/* I have must have done something to deserve this.
+ * XPM is such a crappy format to handle.
+ * This code is an ugly hybred from gdkpixmap.c
+ * modified to respect transparent colors.
+ * It's still a mess, though.
+ */
+
+enum buf_op {
+ op_header,
+ op_cmap,
+ op_body
+};
+
+typedef struct {
+ gchar *color_string;
+ GdkColor color;
+ gint transparent;
+} _XPMColor;
+
+struct file_handle {
+ FILE *infile;
+ gchar *buffer;
+ guint buffer_size;
+};
+
+struct mem_handle {
+ gchar **data;
+ int offset;
+};
+
+static gint
+ xpm_seek_string(FILE * infile,
+ const gchar * str,
+ gint skip_comments)
+{
+ char instr[1024];
+
+ while (!feof(infile)) {
+ fscanf(infile, "%1023s", instr);
+ if (skip_comments == TRUE && strcmp(instr, "/*") == 0) {
+ fscanf(infile, "%1023s", instr);
+ while (!feof(infile) && strcmp(instr, "*/") != 0)
+ fscanf(infile, "%1023s", instr);
+ fscanf(infile, "%1023s", instr);
+ }
+ if (strcmp(instr, str) == 0)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gint
+ xpm_seek_char(FILE * infile,
+ gchar c)
+{
+ gint b, oldb;
+
+ while ((b = getc(infile)) != EOF) {
+ if (c != b && b == '/') {
+ b = getc(infile);
+ if (b == EOF)
+ return FALSE;
+ else if (b == '*') { /* we have a comment */
+ b = -1;
+ do {
+ oldb = b;
+ b = getc(infile);
+ if (b == EOF)
+ return FALSE;
+ }
+ while (!(oldb == '*' && b == '/'));
+ }
+ } else if (c == b)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gint
+ xpm_read_string(FILE * infile,
+ gchar ** buffer,
+ guint * buffer_size)
+{
+ gint c;
+ guint cnt = 0, bufsiz, ret = FALSE;
+ gchar *buf;
+
+ buf = *buffer;
+ bufsiz = *buffer_size;
+ if (buf == NULL) {
+ bufsiz = 10 * sizeof(gchar);
+ buf = g_new(gchar, bufsiz);
+ }
+ do
+ c = getc(infile);
+ while (c != EOF && c != '"');
+
+ if (c != '"')
+ goto out;
+
+ while ((c = getc(infile)) != EOF) {
+ if (cnt == bufsiz) {
+ guint new_size = bufsiz * 2;
+ if (new_size > bufsiz)
+ bufsiz = new_size;
+ else
+ goto out;
+
+ buf = (gchar *) g_realloc(buf, bufsiz);
+ buf[bufsiz - 1] = '\0';
+ }
+ if (c != '"')
+ buf[cnt++] = c;
+ else {
+ buf[cnt] = 0;
+ ret = TRUE;
+ break;
+ }
+ }
+
+ out:
+ buf[bufsiz - 1] = '\0'; /* ensure null termination for errors */
+ *buffer = buf;
+ *buffer_size = bufsiz;
+ return ret;
+}
+
+static gchar *
+ xpm_skip_whitespaces(gchar * buffer)
+{
+ gint32 index = 0;
+
+ while (buffer[index] != 0 && (buffer[index] == 0x20 || buffer[index] == 0x09))
+ index++;
+
+ return &buffer[index];
+}
+
+static gchar *
+ xpm_skip_string(gchar * buffer)
+{
+ gint32 index = 0;
+
+ while (buffer[index] != 0 && buffer[index] != 0x20 && buffer[index] != 0x09)
+ index++;
+
+ return &buffer[index];
+}
+
+/* Xlib crashed once at a color name lengths around 125 */
+#define MAX_COLOR_LEN 120
+
+static gchar *
+ xpm_extract_color(gchar * buffer)
+{
+ gint counter, numnames;
+ gchar *ptr = NULL, ch, temp[128];
+ gchar color[MAX_COLOR_LEN], *retcol;
+ gint space;
+ counter = 0;
+ while (ptr == NULL) {
+ if (buffer[counter] == 'c') {
+ ch = buffer[counter + 1];
+ if (ch == 0x20 || ch == 0x09)
+ ptr = &buffer[counter + 1];
+ } else if (buffer[counter] == 0)
+ return NULL;
+
+ counter++;
+ }
+ ptr = xpm_skip_whitespaces(ptr);
+
+ if (ptr[0] == 0)
+ return NULL;
+ else if (ptr[0] == '#') {
+ counter = 1;
+ while (ptr[counter] != 0 &&
+ ((ptr[counter] >= '0' && ptr[counter] <= '9') ||
+ (ptr[counter] >= 'a' && ptr[counter] <= 'f') ||
+ (ptr[counter] >= 'A' && ptr[counter] <= 'F')))
+ counter++;
+ retcol = g_new(gchar, counter + 1);
+ strncpy(retcol, ptr, counter);
+
+ retcol[counter] = 0;
+
+ return retcol;
+ }
+ color[0] = 0;
+ numnames = 0;
+
+ space = MAX_COLOR_LEN - 1;
+ while (space > 0) {
+ sscanf(ptr, "%127s", temp);
+
+ if (((gint) ptr[0] == 0) ||
+ (strcmp("s", temp) == 0) || (strcmp("m", temp) == 0) ||
+ (strcmp("g", temp) == 0) || (strcmp("g4", temp) == 0)) {
+ break;
+ } else {
+ if (numnames > 0) {
+ space -= 1;
+ strcat(color, " ");
+ }
+ strncat(color, temp, space);
+ space -= MIN(space, strlen(temp));
+ ptr = xpm_skip_string(ptr);
+ ptr = xpm_skip_whitespaces(ptr);
+ numnames++;
+ }
+ }
+
+ retcol = g_strdup(color);
+ return retcol;
+}
+
+
+/* (almost) direct copy from gdkpixmap.c... loads an XPM from a file */
+
+static gchar *
+ file_buffer(enum buf_op op, gpointer handle)
+{
+ struct file_handle *h = handle;
+
+ switch (op) {
+ case op_header:
+ if (xpm_seek_string(h->infile, "XPM", FALSE) != TRUE)
+ break;
+
+ if (xpm_seek_char(h->infile, '{') != TRUE)
+ break;
+ /* Fall through to the next xpm_seek_char. */
+
+ case op_cmap:
+ xpm_seek_char(h->infile, '"');
+ fseek(h->infile, -1, SEEK_CUR);
+ /* Fall through to the xpm_read_string. */
+
+ case op_body:
+ xpm_read_string(h->infile, &h->buffer, &h->buffer_size);
+ return h->buffer;
+ }
+ return NULL;
+}
+
+/* This reads from memory */
+static gchar *
+ mem_buffer(enum buf_op op, gpointer handle)
+{
+ struct mem_handle *h = handle;
+ switch (op) {
+ case op_header:
+ case op_cmap:
+ case op_body:
+ if (h->data[h->offset])
+ return h->data[h->offset++];
+ }
+ return NULL;
+}
+
+/* This function does all the work. */
+
+static GdkPixBuf *
+ _pixbuf_create_from_xpm(gchar * (*get_buf) (enum buf_op op, gpointer handle),
+ gpointer handle)
+{
+ gint w, h, n_col, cpp;
+ gint cnt, xcnt, ycnt, wbytes, n, ns;
+ gint is_trans = FALSE;
+ gchar *buffer, *name_buf;
+ gchar pixel_str[32];
+ GHashTable *color_hash;
+ _XPMColor *colors, *color, *fallbackcolor;
+ art_u8 *pixels, *pixtmp;
+ GdkPixBuf *pixbuf;
+
+ buffer = (*get_buf) (op_header, handle);
+ if (!buffer) {
+ g_warning("No XPM header found");
+ return NULL;
+ }
+ sscanf(buffer, "%d %d %d %d", &w, &h, &n_col, &cpp);
+ if (cpp >= 32) {
+ g_warning("XPM has more than 31 chars per pixel.");
+ return NULL;
+ }
+ /* The hash is used for fast lookups of color from chars */
+ color_hash = g_hash_table_new(g_str_hash, g_str_equal);
+
+ name_buf = g_new(gchar, n_col * (cpp + 1));
+ colors = g_new(_XPMColor, n_col);
+
+ for (cnt = 0; cnt < n_col; cnt++) {
+ gchar *color_name;
+
+ buffer = (*get_buf) (op_cmap, handle);
+ if (!buffer) {
+ g_warning("Can't load XPM colormap");
+ g_free(name_buf);
+ g_free(colors);
+ return NULL;
+ }
+ color = &colors[cnt];
+ color->color_string = &name_buf[cnt * (cpp + 1)];
+ strncpy(color->color_string, buffer, cpp);
+ color->color_string[cpp] = 0;
+ buffer += strlen(color->color_string);
+ color->transparent = FALSE;
+
+ color_name = xpm_extract_color(buffer);
+
+ if ((!color_name) || (g_strcasecmp(color_name, "None") == 0)
+ || (gdk_color_parse(color_name, &color->color) == FALSE)) {
+ color->transparent = TRUE;
+ is_trans = TRUE;
+ }
+ g_free(color_name);
+ g_hash_table_insert(color_hash, color->color_string, color);
+
+ if (cnt == 0)
+ fallbackcolor = color;
+ }
+
+ if (is_trans)
+ pixels = art_alloc(w * h * 4);
+ else
+ pixels = art_alloc(w * h * 3);
+
+ if (!pixels) {
+ g_warning("XPM: Cannot alloc ArtBuf");
+ g_hash_table_destroy(color_hash);
+ g_free(colors);
+ g_free(name_buf);
+ return NULL;
+ }
+ wbytes = w * cpp;
+ pixtmp = pixels;
+
+ for (ycnt = 0; ycnt < h; ycnt++) {
+ buffer = (*get_buf) (op_body, handle);
+ if ((!buffer) || (strlen(buffer) < wbytes))
+ continue;
+ for (n = 0, cnt = 0, xcnt = 0; n < wbytes; n += cpp, xcnt++) {
+ strncpy(pixel_str, &buffer[n], cpp);
+ pixel_str[cpp] = 0;
+ ns = 0;
+
+ color = g_hash_table_lookup(color_hash, pixel_str);
+
+ /* Bad XPM...punt */
+ if (!color)
+ color = fallbackcolor;
+
+ pixtmp[0] = color->color.red;
+ pixtmp[1] = color->color.green;
+ pixtmp[2] = color->color.blue;
+ if ((is_trans) && (color->transparent)) {
+ pixtmp[3] = 0;
+ pixtmp++;
+ } else if (is_trans) {
+ pixtmp[3] = 0xFF;
+ pixtmp++;
+ }
+ pixtmp += 3;
+ }
+ }
+ /* Ok, now stuff the GdkPixBuf with goodies */
+
+ pixbuf = g_new(GdkPixBuf, 1);
+
+ if (is_trans)
+ pixbuf->art_pixbuf = art_pixbuf_new_rgba(pixels, w, h, (w * 4));
+ else
+ pixbuf->art_pixbuf = art_pixbuf_new_rgb(pixels, w, h, (w * 3));
+
+ /* Ok, I'm anal...shoot me */
+ if (!(pixbuf->art_pixbuf))
+ return NULL;
+ pixbuf->ref_count = 0;
+ pixbuf->unref_func = NULL;
+
+ g_hash_table_destroy(color_hash);
+ g_free(colors);
+ g_free(name_buf);
+
+ return pixbuf;
+}
+
+/* Shared library entry point for file loading */
+GdkPixBuf *image_load(FILE * f)
+{
+ GdkPixBuf *pixbuf;
+ struct file_handler h;
+
+ g_return_val_if_fail(f != NULL, NULL);
+
+ h = g_new(file_handler, 1);
+ h.infile = f;
+ pixbuf = _pixbuf_create_from_xpm(file_buffer, &h);
+ g_free(h);
+
+ return pixbuf;
+}