PCX support for gdk-pixbuf



Well, I figured I'd dump the PCX loader on you guys too - I'll be moving
these to tmp file less progressive loaders this week as I port my
modeler to gnome.  This prob isn't useful as the TGA, unless you do a
lot of quakeforge development.  =)


cheers,
Terry

-- 
 ---------------------------------------------------
| GooseEgg    http://gooseegg.sourceforge.net       |
| QuakeForge  http://www.quakeforge.net             |
| Personal    http://www.westga.edu/~stu7440        |
|                                                   |
|      Death is running Debian GNU/Linux            |
 ---------------------------------------------------

/* -*- Mode: C; tab-width: 3; indent-tabs-mode: t; c-basic-offset: 3 -*- */
/* GdkPixbuf library - PCX image loader
 *
 * Copyright (C) 2001 Mongoose
 *
 * Authors: Terry 'Mongoose' Hendrix II <stu7440 westga edu>
 *
 * 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,
 * Boston, MA 02111-1307, USA.
 */

#include <config.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <setjmp.h>
#include "gdk-pixbuf-private.h"
#include "gdk-pixbuf-io.h"

#define MONGOOSE_PCX

#ifdef MONGOOSE_PCX
#define PCX_FATAL_ERR  -1
#define PCX_SUSPEND     0
#define PCX_OK          1


typedef struct pcx_header_s
{
	guchar signature;
	guchar version;
	guchar encoding;
	guchar bytes_per_pixel;
	gushort xmin;
	gushort ymin;
	gushort xmax;
	gushort ymax;
	gushort vres;
	gushort hres;
	guchar palette[48];
	guchar reserved;
	guchar color_layers;
	gushort bytes_per_line;
	gushort palette_type;
	guchar unused[58];

} pcx_header_t;


typedef struct _PcxData PcxData;
struct _PcxData
{
	ModulePreparedNotifyFunc prepare_func;
	ModuleUpdatedNotifyFunc update_func;
	gpointer user_data;

	gchar *tempname;
	FILE *file;
	gboolean all_okay;
};


GdkPixbuf   *gdk_pixbuf__pcx_image_load          (FILE *f);
gpointer    gdk_pixbuf__pcx_image_begin_load     (ModulePreparedNotifyFunc func, 
						  ModuleUpdatedNotifyFunc func2,
						  ModuleFrameDoneNotifyFunc frame_done_func,
						  ModuleAnimationDoneNotifyFunc anim_done_func,
						  gpointer user_data);
void        gdk_pixbuf__pcx_image_stop_load      (gpointer context);
gboolean    gdk_pixbuf__pcx_image_load_increment (gpointer context, guchar *buf, guint size);

/* Destroy notification function for the pixbuf */
static void
free_buffer (guchar *pixels, gpointer data)
{
	g_free (pixels);
}

/* Shared library entry point */
GdkPixbuf *
gdk_pixbuf__pcx_image_load (FILE *f)
{
   guint size, i, index, width, height;
   guchar *indexed_image = NULL;
   guchar *palette = NULL;
   guchar *image = NULL;
   pcx_header_t header;
   guchar buf;
   guint counter;


	if (!f)
		return NULL;

   fseek(f, 0, SEEK_SET);
   
	if (fread(&header, sizeof(pcx_header_t), 1, f) < 1)
	{
		perror("gdk_pixbuf__pcx_image_load> Failed to read file.\n");
		return NULL;
	}

	if ((header.signature != 0x0a) || (header.version != 5))
	{
		fprintf(stderr, "gdk_pixbuf__pcx_image_load> Unknown PCX format.\n");
		return NULL;
	}

	/* Get height and length */
	width = header.xmax + 1 - header.xmin;
	height = header.ymax + 1 - header.ymin;
    
	size = width * height;

	if (!size)
	{
		fprintf(stderr, "gdk_pixbuf__pcx_image_load> Will not allocate 0bytes.\n");
		return NULL;
	}

	printf("PCX [%ix%i 8bpp]\n", width, height);

	/* Allocate indexed palette, indexed image, and rgb image */
	palette = g_malloc(768);
	indexed_image = g_malloc(size);
	image = g_malloc(size * 3);

	if (!indexed_image || !palette || !image)
   {
		if (image)
			g_free(image);

		if (indexed_image)
			g_free(indexed_image);

		if (palette)
			g_free(palette);

		fprintf(stderr, "gdk_pixbuf__pcx_image_load> Malloc failed.\n");
		return NULL;
	}

	/* Read the indexed image from file */
	for (i = 0; i <= size;)
   {
		/* Get one byte */
		fread(&buf, 1, 1, f);

		/* Check the 2 most significant bits */
		if ((buf & 192) == 192)
      {
			/* We have 11xxxxxx */
			counter = (buf & 63); /* Number of times to repeat next byte */

			fread(&buf, 1, 1, f);     /* Get next byte */

			for(; counter > 0; counter--) /* and copy it counter times */
         {
				indexed_image[i++] = buf;
			}
		}
		else
      {
			/* Just copy the byte */
			indexed_image[i++] = buf;
		}
	}

	/* Read the palette index */
	fseek(f, -768, SEEK_END);
	fread(palette, 1, 768, f);

	/* Convert to RGB image  */
	for (i = 0; i < size; i++)
	{
		index = indexed_image[i];

		if (index * 3 + 2 > 768)
			printf("gdk_pixbuf::pcx_load> Corupt image index.\n");
		else
		{
			image[i*3] = palette[index*3];
			image[i*3+1] = palette[index*3+1];
			image[i*3+2] = palette[index*3+2];
		}
	}

	if (indexed_image)
		g_free(indexed_image);
	
	if (palette)
		g_free(palette);


	return gdk_pixbuf_new_from_data(image, GDK_COLORSPACE_RGB, FALSE, 8,
											  width, height, 
											  width * 3, free_buffer, NULL);
}



/* Progressive loader, barrowed file cache to disk hack from tiff for now */

gpointer
gdk_pixbuf__pcx_image_begin_load (ModulePreparedNotifyFunc prepare_func,
				   ModuleUpdatedNotifyFunc update_func,
				   ModuleFrameDoneNotifyFunc frame_done_func,
				   ModuleAnimationDoneNotifyFunc anim_done_func,
				   gpointer user_data)
{
	PcxData *context;
	gint fd;

	context = g_new (PcxData, 1);
	context->prepare_func = prepare_func;
	context->update_func = update_func;
	context->user_data = user_data;
	context->all_okay = TRUE;
	context->tempname = g_strdup ("/tmp/gdkpixbuf-pcx-tmp.XXXXXX");
	fd = mkstemp (context->tempname);
	if (fd < 0) {
	        g_free (context->tempname);
		g_free (context);
		return NULL;
	}

	context->file = fdopen (fd, "w");
	if (context->file == NULL) {
		g_free (context->tempname);
		g_free (context);
		return NULL;
	}

	return context;
}

void
gdk_pixbuf__pcx_image_stop_load (gpointer data)
{
	PcxData *context = (PcxData*) data;
	GdkPixbuf *pixbuf;


	g_return_if_fail (data != NULL);

	fflush (context->file);
	rewind (context->file);

	// KAOS!!!!  SHONOVEATA!!!
	if (context->all_okay)
	{
		pixbuf = gdk_pixbuf__pcx_image_load(fopen(context->tempname, "rb"));
		//context->file);

		(* context->prepare_func) (pixbuf, context->user_data);

		(* context->update_func)(pixbuf, 0, 0, 
										 gdk_pixbuf_get_width(pixbuf), 
										 gdk_pixbuf_get_height(pixbuf), 
										 context->user_data);
		gdk_pixbuf_unref(pixbuf);
	}

	fclose (context->file);
	unlink (context->tempname);
	g_free (context->tempname);
	g_free ((PcxData *) context);
}

gboolean
gdk_pixbuf__pcx_image_load_increment (gpointer data, guchar *buf, guint size)
{
	PcxData *context = (PcxData *) data;

	g_return_val_if_fail (data != NULL, FALSE);

	if (fwrite (buf, sizeof (guchar), size, context->file) != size) {
		context->all_okay = FALSE;
		return FALSE;
	}

	return TRUE;
}
#endif


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]