summaryrefslogtreecommitdiff
path: root/gdk-pixbuf
diff options
context:
space:
mode:
authorMatthias Clasen <maclas@gmx.de>2003-05-21 20:20:07 +0000
committerMatthias Clasen <matthiasc@src.gnome.org>2003-05-21 20:20:07 +0000
commitb5adee991a31f5119aad62dc0733373a16afb529 (patch)
tree51c6c747841a5d8ce30d8fc92efbe4c6ac9a88fe /gdk-pixbuf
parentec288c70173ef83df937ed13f5b78e4b8163df12 (diff)
downloadgdk-pixbuf-b5adee991a31f5119aad62dc0733373a16afb529.tar.gz
A loader for PCX files. (#113035, Josh Beam)
2003-05-21 Matthias Clasen <maclas@gmx.de> * pixbufloader_pcx.def: * io-pcx.c: A loader for PCX files. (#113035, Josh Beam) * gdk-pixbuf-io.c: * Makefile.am: Add PCX loader.
Diffstat (limited to 'gdk-pixbuf')
-rw-r--r--gdk-pixbuf/ChangeLog8
-rw-r--r--gdk-pixbuf/Makefile.am17
-rw-r--r--gdk-pixbuf/gdk-pixbuf-io.c10
-rw-r--r--gdk-pixbuf/io-pcx.c757
-rw-r--r--gdk-pixbuf/pixbufloader_pcx.def3
5 files changed, 792 insertions, 3 deletions
diff --git a/gdk-pixbuf/ChangeLog b/gdk-pixbuf/ChangeLog
index 905eb2378..7286682db 100644
--- a/gdk-pixbuf/ChangeLog
+++ b/gdk-pixbuf/ChangeLog
@@ -1,3 +1,11 @@
+2003-05-21 Matthias Clasen <maclas@gmx.de>
+
+ * pixbufloader_pcx.def:
+ * io-pcx.c: A loader for PCX files. (#113035, Josh Beam)
+
+ * gdk-pixbuf-io.c:
+ * Makefile.am: Add PCX loader.
+
2003-05-19 Matthias Clasen <maclas@gmx.de>
Improve progressive loading from slow sources: (#107368)
diff --git a/gdk-pixbuf/Makefile.am b/gdk-pixbuf/Makefile.am
index 1031ce8e5..b1c214df4 100644
--- a/gdk-pixbuf/Makefile.am
+++ b/gdk-pixbuf/Makefile.am
@@ -150,6 +150,14 @@ libpixbufloader_tga_la_SOURCES = io-tga.c
libpixbufloader_tga_la_LDFLAGS = -avoid-version -module $(no_undefined)
libpixbufloader_tga_la_LIBADD = $(module_libs)
+#
+# The PCX loader
+#
+libpixbufloader_static_pcx_la_SOURCES = io-pcx.c
+libpixbufloader_pcx_la_SOURCES = io-pcx.c
+libpixbufloader_pcx_la_LDFLAGS = -avoid-version -module $(no_undefined)
+libpixbufloader_pcx_la_LIBADD = $(module_libs)
+
if HAVE_PNG
PNG_LIB = libpixbufloader-png.la
STATIC_PNG_LIB = libpixbufloader-static-png.la
@@ -195,6 +203,9 @@ STATIC_XBM_LIB = libpixbufloader-static-xbm.la
TGA_LIB = libpixbufloader-tga.la
STATIC_TGA_LIB = libpixbufloader-static-tga.la
+PCX_LIB = libpixbufloader-pcx.la
+STATIC_PCX_LIB = libpixbufloader-static-pcx.la
+
if BUILD_DYNAMIC_MODULES
loader_LTLIBRARIES = \
@@ -210,7 +221,8 @@ loader_LTLIBRARIES = \
$(BMP_LIB) \
$(WBMP_LIB) \
$(XBM_LIB) \
- $(TGA_LIB)
+ $(TGA_LIB) \
+ $(PCX_LIB)
extra_sources =
@@ -231,7 +243,8 @@ noinst_LTLIBRARIES = \
$(STATIC_BMP_LIB) \
$(STATIC_WBMP_LIB) \
$(STATIC_XBM_LIB) \
- $(STATIC_TGA_LIB)
+ $(STATIC_TGA_LIB) \
+ $(STATIC_PCX_LIB)
builtin_objs = @INCLUDED_LOADER_OBJ@
diff --git a/gdk-pixbuf/gdk-pixbuf-io.c b/gdk-pixbuf/gdk-pixbuf-io.c
index 218c44c29..f3f6f4b32 100644
--- a/gdk-pixbuf/gdk-pixbuf-io.c
+++ b/gdk-pixbuf/gdk-pixbuf-io.c
@@ -413,6 +413,7 @@ module (tiff);
module (xpm);
module (xbm);
module (tga);
+module (pcx);
gboolean
_gdk_pixbuf_load_module (GdkPixbufModule *image_module,
@@ -518,6 +519,13 @@ _gdk_pixbuf_load_module (GdkPixbufModule *image_module,
}
#endif
+#ifdef INCLUDE_pcx
+ else if (strcmp (image_module->module_name, "pcx") == 0) {
+ fill_info = MODULE_ENTRY (pcx, fill_info);
+ fill_vtable = MODULE_ENTRY (pcx, fill_vtable);
+ }
+#endif
+
if (fill_vtable) {
(* fill_vtable) (image_module);
image_module->info = g_new0 (GdkPixbufFormat, 1);
@@ -541,7 +549,7 @@ gdk_pixbuf_io_init ()
gchar *included_formats[] = {
"ani", "png", "bmp", "wbmp", "gif",
"ico", "jpeg", "pnm", "ras", "tiff",
- "xpm", "xbm", "tga",
+ "xpm", "xbm", "tga", "pcx",
NULL
};
gchar **name;
diff --git a/gdk-pixbuf/io-pcx.c b/gdk-pixbuf/io-pcx.c
new file mode 100644
index 000000000..10c26f3c2
--- /dev/null
+++ b/gdk-pixbuf/io-pcx.c
@@ -0,0 +1,757 @@
+/*
+ * GdkPixbuf library - PCX image loader
+ *
+ * Copyright (C) 2003 Josh A. Beam
+ *
+ * Authors: Josh A. Beam <josh@joshbeam.com>
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include "gdk-pixbuf-private.h"
+#include "gdk-pixbuf-io.h"
+
+#define PCX_DEBUG
+
+#define PCX_TASK_DONE 0
+#define PCX_TASK_LOAD_HEADER 1
+#define PCX_TASK_LOAD_DATA 2
+#define PCX_TASK_LOAD_PALETTE 3
+
+struct pcx_header {
+ guint8 manufacturer;
+ guint8 version;
+ guint8 encoding;
+ guint8 bitsperpixel;
+ gint16 xmin;
+ gint16 ymin;
+ gint16 xmax;
+ gint16 ymax;
+ guint16 horizdpi;
+ guint16 vertdpi;
+ guint8 palette[48];
+ guint8 reserved;
+ guint8 colorplanes;
+ guint16 bytesperline;
+ guint16 palettetype;
+ guint16 hscrsize;
+ guint16 vscrsize;
+ guint8 filler[54];
+};
+
+struct pcx_context {
+ GdkPixbuf *pixbuf;
+ gint rowstride;
+
+ GdkPixbufModuleSizeFunc size_func;
+ GdkPixbufModuleUpdatedFunc updated_func;
+ GdkPixbufModulePreparedFunc prepared_func;
+ gpointer user_data;
+
+ guchar current_task;
+
+ gboolean header_loaded;
+ struct pcx_header *header;
+ guint bpp;
+ gint width, height;
+ guint num_planes;
+ guint bytesperline;
+
+ guchar *buf;
+ guint buf_size;
+ guint buf_pos;
+ guchar *data;
+ guchar *line;
+ guint current_line;
+ guchar *p_data;
+};
+
+/*
+ * set context's image information based on the header
+ */
+static void
+fill_pcx_context(struct pcx_context *context)
+{
+ struct pcx_header *header = context->header;
+
+ context->bpp = header->bitsperpixel;
+ context->width = header->xmax - header->xmin + 1;
+ context->height = header->ymax - header->ymin + 1;
+ context->num_planes = header->colorplanes;
+ context->bytesperline = header->bytesperline;
+
+ if(header->version == 5 && context->bpp == 8 && context->num_planes == 3)
+ context->bpp = 24;
+}
+
+static void
+free_pcx_context(struct pcx_context *context, gboolean unref_pixbuf)
+{
+ if(context->header)
+ g_free(context->header);
+ if(context->buf)
+ g_free(context->buf);
+ if(unref_pixbuf && context->pixbuf)
+ g_object_unref(context->pixbuf);
+ if(context->line)
+ g_free(context->line);
+ if(context->p_data)
+ g_free(context->p_data);
+
+ g_free(context);
+}
+
+/*
+ * read each plane of a single scanline. store_planes is
+ * the number of planes that can be stored in the planes array.
+ * data is the pointer to the block of memory to read
+ * from, size is the length of that data, and line_bytes
+ * is where the number of bytes read will be stored.
+ */
+static gboolean
+read_scanline_data(guchar *data, guint size, guchar *planes[],
+ guint store_planes, guint num_planes, guint bytesperline,
+ guint *line_bytes)
+{
+ guint i, j;
+ guint p, count;
+ guint d = 0;
+ guint8 byte;
+
+ for(p = 0; p < num_planes; p++) {
+ for(i = 0; i < bytesperline;) { /* i incremented when line byte set */
+ if(d >= size)
+ return FALSE;
+ byte = data[d++];
+
+ if(byte >> 6 == 0x3) {
+ count = byte & ~(0x3 << 6);
+ if(count == 0)
+ return FALSE;
+ if(d >= size)
+ return FALSE;
+ byte = data[d++];
+ } else {
+ count = 1;
+ }
+
+ for(j = 0; j < count; j++) {
+ if(p < store_planes)
+ planes[p][i++] = byte;
+ else
+ i++;
+
+ if(i >= bytesperline) {
+ p++;
+ if(p >= num_planes) {
+ *line_bytes = d;
+ return TRUE;
+ }
+ i = 0;
+ }
+ }
+ }
+ }
+
+ *line_bytes = d; /* number of bytes read for scanline */
+ return TRUE;
+}
+
+static gpointer
+gdk_pixbuf__pcx_begin_load(GdkPixbufModuleSizeFunc size_func,
+ GdkPixbufModulePreparedFunc prepared_func,
+ GdkPixbufModuleUpdatedFunc updated_func,
+ gpointer user_data, GError **error)
+{
+ struct pcx_context *context;
+
+ context = g_new0(struct pcx_context, 1);
+ if(!context)
+ return NULL;
+
+ context->header = g_try_malloc(sizeof(struct pcx_header));
+ if(!context->header) {
+ g_free(context);
+ g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't allocate memory for header"));
+ return NULL;
+ }
+
+ context->size_func = size_func;
+ context->updated_func = updated_func;
+ context->prepared_func = prepared_func;
+ context->user_data = user_data;
+
+ context->current_task = PCX_TASK_LOAD_HEADER;
+
+ context->buf = g_try_malloc(sizeof(guchar) * 512);
+ if(!context->buf) {
+ g_free(context->header);
+ g_free(context);
+ g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't allocate memory for context buffer"));
+ return NULL;
+ }
+ context->buf_size = 512;
+
+ context->header_loaded = FALSE;
+
+ return context;
+}
+
+static gboolean
+pcx_resize_context_buf(struct pcx_context *context, guint size)
+{
+ guchar *new_buf;
+
+ new_buf = g_try_realloc(context->buf, size);
+ if(!new_buf)
+ return FALSE;
+
+ context->buf = new_buf;
+ context->buf_size = size;
+ return TRUE;
+}
+
+/*
+ * remove a number of bytes (specified by size) from the
+ * beginning of a context's buf
+ */
+static gboolean
+pcx_chop_context_buf(struct pcx_context *context, guint size)
+{
+ guint i, j;
+
+ if(size > context->buf_pos)
+ return FALSE;
+ else if(size < 0)
+ return FALSE;
+ else if(size == 0)
+ return TRUE;
+
+ for(i = 0, j = size; j < context->buf_pos; i++, j++)
+ context->buf[i] = context->buf[j];
+
+ context->buf_pos -= size;
+
+ return TRUE;
+}
+
+static guchar
+read_pixel_1(guchar *data, guint offset)
+{
+ guchar retval;
+ guint bit_offset;
+
+ if(!(offset % 8)) {
+ offset /= 8;
+ retval = data[offset] >> 7;
+ } else {
+ bit_offset = offset % 8;
+ offset -= bit_offset;
+ offset /= 8;
+ retval = (data[offset] >> (7 - bit_offset)) & 0x1;
+ }
+
+ return retval;
+}
+
+static guchar
+read_pixel_4(guchar *data, guint offset)
+{
+ guchar retval;
+
+ if(!(offset % 2)) {
+ offset /= 2;
+ retval = data[offset] >> 4;
+ } else {
+ offset--;
+ offset /= 2;
+ retval = data[offset] & 0xf;
+ }
+
+ return retval;
+}
+
+static gboolean
+pcx_increment_load_data_1(struct pcx_context *context)
+{
+ guint i;
+ guchar *planes[4];
+ guint line_bytes;
+ guint store_planes;
+
+ if(context->num_planes == 4) {
+ planes[0] = context->line;
+ planes[1] = planes[0] + context->bytesperline;
+ planes[2] = planes[1] + context->bytesperline;
+ planes[3] = planes[2] + context->bytesperline;
+ store_planes = 4;
+ } else if(context->num_planes == 3) {
+ planes[0] = context->line;
+ planes[1] = planes[0] + context->bytesperline;
+ planes[2] = planes[1] + context->bytesperline;
+ store_planes = 3;
+ } else if(context->num_planes == 2) {
+ planes[0] = context->line;
+ planes[1] = planes[0] + context->bytesperline;
+ store_planes = 2;
+ } else if(context->num_planes == 1) {
+ planes[0] = context->line;
+ store_planes = 1;
+ } else {
+ return FALSE;
+ }
+
+ while(read_scanline_data(context->buf, context->buf_pos, planes, store_planes, context->num_planes, context->bytesperline, &line_bytes)) {
+ pcx_chop_context_buf(context, line_bytes);
+
+ for(i = 0; i < context->width; i++) {
+ guchar p;
+
+ if(context->num_planes == 4) {
+ p = read_pixel_1(planes[3], i);
+ p <<= 1;
+ p |= read_pixel_1(planes[2], i);
+ p <<= 1;
+ p |= read_pixel_1(planes[1], i);
+ p <<= 1;
+ p |= read_pixel_1(planes[0], i);
+ } else if(context->num_planes == 3) {
+ p = read_pixel_1(planes[2], i);
+ p <<= 1;
+ p |= read_pixel_1(planes[1], i);
+ p <<= 1;
+ p |= read_pixel_1(planes[0], i);
+ } else if(context->num_planes == 2) {
+ p = read_pixel_1(planes[1], i);
+ p <<= 1;
+ p |= read_pixel_1(planes[0], i);
+ } else if(context->num_planes == 1) {
+ p = read_pixel_1(planes[0], i);
+ } else {
+ return FALSE;
+ }
+ p &= 0xf;
+ context->data[context->current_line * context->rowstride + i * 3 + 0] = context->header->palette[p * 3 + 0];
+ context->data[context->current_line * context->rowstride + i * 3 + 1] = context->header->palette[p * 3 + 1];
+ context->data[context->current_line * context->rowstride + i * 3 + 2] = context->header->palette[p * 3 + 2];
+ }
+
+ if(context->updated_func)
+ context->updated_func(context->pixbuf, 0, context->current_line, context->width, 1, context->user_data);
+
+ context->current_line++;
+
+ if(context->current_line == context->height) {
+ context->current_task = PCX_TASK_DONE;
+ return TRUE;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+pcx_increment_load_data_2(struct pcx_context *context)
+{
+ guint i;
+ guchar *planes[1];
+ guint line_bytes;
+ guint shift, h;
+
+ planes[0] = context->line;
+
+ while(read_scanline_data(context->buf, context->buf_pos, planes, 1, context->num_planes, context->bytesperline, &line_bytes)) {
+ pcx_chop_context_buf(context, line_bytes);
+
+ for(i = 0; i < context->width; i++) {
+ shift = 6 - 2 * (i % 4);
+ h = (planes[0][i / 4] >> shift) & 0x3;
+ context->data[context->current_line * context->rowstride + i * 3 + 0] = context->header->palette[h * 3 + 0];
+ context->data[context->current_line * context->rowstride + i * 3 + 1] = context->header->palette[h * 3 + 1];
+ context->data[context->current_line * context->rowstride + i * 3 + 2] = context->header->palette[h * 3 + 2];
+ }
+
+ if(context->updated_func)
+ context->updated_func(context->pixbuf, 0, context->current_line, context->width, 1, context->user_data);
+
+ context->current_line++;
+
+ if(context->current_line == context->height) {
+ context->current_task = PCX_TASK_DONE;
+ return TRUE;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+pcx_increment_load_data_4(struct pcx_context *context)
+{
+ guint i;
+ guchar *planes[1];
+ guint line_bytes;
+
+ planes[0] = context->line;
+
+ while(read_scanline_data(context->buf, context->buf_pos, planes, 1, context->num_planes, context->bytesperline, &line_bytes)) {
+ pcx_chop_context_buf(context, line_bytes);
+
+ for(i = 0; i < context->width; i++) {
+ guchar p;
+
+ p = read_pixel_4(planes[0], i) & 0xf;
+ context->data[context->current_line * context->rowstride + i * 3 + 0] = context->header->palette[p * 3 + 0];
+ context->data[context->current_line * context->rowstride + i * 3 + 1] = context->header->palette[p * 3 + 1];
+ context->data[context->current_line * context->rowstride + i * 3 + 2] = context->header->palette[p * 3 + 2];
+ }
+
+ if(context->updated_func)
+ context->updated_func(context->pixbuf, 0, context->current_line, context->width, 1, context->user_data);
+
+ context->current_line++;
+
+ if(context->current_line == context->height) {
+ context->current_task = PCX_TASK_DONE;
+ return TRUE;
+ }
+ }
+
+ return TRUE;
+}
+
+/*
+ * for loading 8-bit pcx images, we keep a buffer containing
+ * each pixel's palette number; once we've loaded each scanline,
+ * we wait for loading to stop and call pcx_load_palette_8,
+ * which finds the palette at the end of the pcx data and sets the
+ * RGB data.
+ */
+static gboolean
+pcx_increment_load_data_8(struct pcx_context *context)
+{
+ guint i;
+ guchar *planes[1];
+ guint line_bytes;
+
+ planes[0] = context->line;
+
+ while(read_scanline_data(context->buf, context->buf_pos, planes, 1, context->num_planes, context->bytesperline, &line_bytes)) {
+ pcx_chop_context_buf(context, line_bytes);
+
+ for(i = 0; i < context->width; i++)
+ context->p_data[context->current_line * context->width + i + 0] = planes[0][i];
+
+ context->current_line++;
+
+ if(context->current_line == context->height) {
+ context->current_task = PCX_TASK_LOAD_PALETTE;
+ return TRUE;
+ }
+ }
+
+ return TRUE;
+}
+
+/*
+ * read the palette and set the RGB data
+ */
+static gboolean
+pcx_load_palette_8(struct pcx_context *context)
+{
+ guint i, j;
+
+ if(context->current_line < context->height)
+ return FALSE;
+
+ if(context->buf_pos >= 769) {
+ guchar *palette = context->buf + (context->buf_pos - 769);
+
+ if(palette[0] == 12) {
+ palette++;
+ for(i = 0; i < context->height; i++) {
+ for(j = 0; j < context->width; j++) {
+ context->data[i * context->rowstride + j * 3 + 0] = palette[(context->p_data[i * context->width + j]) * 3 + 0];
+ context->data[i * context->rowstride + j * 3 + 1] = palette[(context->p_data[i * context->width + j]) * 3 + 1];
+ context->data[i * context->rowstride + j * 3 + 2] = palette[(context->p_data[i * context->width + j]) * 3 + 2];
+ }
+
+ if(context->updated_func)
+ context->updated_func(context->pixbuf, 0, context->current_line, context->width, 1, context->user_data);
+ }
+
+#ifdef PCX_DEBUG
+ g_print("read palette\n");
+#endif
+
+ context->current_task = PCX_TASK_DONE;
+ return TRUE;
+ } else {
+#ifdef PCX_DEBUG
+ g_print("this ain't a palette\n");
+#endif
+ return FALSE;
+ }
+ }
+
+ return FALSE;
+}
+
+/*
+ * in 24-bit images, each scanline has three color planes
+ * for red, green, and blue, respectively.
+ */
+static gboolean
+pcx_increment_load_data_24(struct pcx_context *context)
+{
+ guint i;
+ guchar *planes[3];
+ guint line_bytes;
+
+ planes[0] = context->line;
+ planes[1] = planes[0] + context->bytesperline;
+ planes[2] = planes[1] + context->bytesperline;
+
+ while(read_scanline_data(context->buf, context->buf_pos, planes, 3, context->num_planes, context->bytesperline, &line_bytes)) {
+ pcx_chop_context_buf(context, line_bytes);
+
+ for(i = 0; i < context->width; i++) {
+ context->data[context->current_line * context->rowstride + i * 3 + 0] = planes[0][i];
+ context->data[context->current_line * context->rowstride + i * 3 + 1] = planes[1][i];
+ context->data[context->current_line * context->rowstride + i * 3 + 2] = planes[2][i];
+ }
+
+ if(context->updated_func)
+ context->updated_func(context->pixbuf, 0, context->current_line, context->width, 1, context->user_data);
+
+ context->current_line++;
+
+ if(context->current_line == context->height) {
+ context->current_task = PCX_TASK_DONE;
+ return TRUE;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+gdk_pixbuf__pcx_load_increment(gpointer data, const guchar *buf, guint size,
+ GError **error)
+{
+ struct pcx_context *context = (struct pcx_context *)data;
+ struct pcx_header *header;
+ guint i;
+ gboolean retval = TRUE;
+
+ /* if context's buf isn't large enough to hold its current data plus the passed buf, increase its size */
+ if(context->buf_pos + size > context->buf_size) {
+ if(!pcx_resize_context_buf(context, sizeof(guchar) * (context->buf_pos + size))) {
+ g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't allocate memory for context buffer"));
+ return FALSE;
+ }
+ }
+
+ for(i = 0; i < size; i++)
+ context->buf[context->buf_pos++] = buf[i];
+
+ if(context->current_task == PCX_TASK_LOAD_HEADER) {
+ if(!context->header_loaded && context->buf_pos > sizeof(struct pcx_header)) { /* set header */
+ gint width, height;
+
+ memcpy(context->header, context->buf, sizeof(struct pcx_header));
+ pcx_chop_context_buf(context, sizeof(struct pcx_header));
+ header = context->header;
+
+ /* convert the multi-byte header variables that will be used */
+ header->xmin = GINT16_FROM_LE(header->xmin);
+ header->ymin = GINT16_FROM_LE(header->ymin);
+ header->xmax = GINT16_FROM_LE(header->xmax);
+ header->ymax = GINT16_FROM_LE(header->ymax);
+ header->bytesperline = GUINT16_FROM_LE(header->bytesperline);
+
+#ifdef PCX_DEBUG
+ g_print ("Manufacturer %d\n"
+ "Version %d\n"
+ "Encoding %d\n"
+ "Bits/Pixel %d\n"
+ "Planes %d\n"
+ "Palette %d\n",
+ header->manufacturer, header->version,
+ header->encoding, header->bitsperpixel,
+ header->colorplanes, header->palettetype);
+#endif
+
+ context->header_loaded = TRUE;
+ fill_pcx_context(context);
+
+ width = context->width;
+ height = context->height;
+ if(width <= 0 || height <= 0) {
+ g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Image has invalid width and/or height"));
+ return FALSE;
+ }
+ if(context->size_func)
+ context->size_func(&width, &height, context->user_data);
+
+ switch(context->bpp) {
+ default:
+ g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_UNKNOWN_TYPE, _("Image has unsupported bpp"));
+ return FALSE;
+ break;
+ case 1:
+ if(context->num_planes < 1 || context->num_planes > 4) {
+ g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_UNKNOWN_TYPE, _("Image has unsupported number of 1-bit planes"));
+ return FALSE;
+ }
+ break;
+ case 2:
+ case 4:
+ case 8:
+ if(context->num_planes != 1) {
+ g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_UNKNOWN_TYPE, _("Image has unsupported number of %d-bit planes"), context->bpp);
+ return FALSE;
+ }
+ break;
+ case 24:
+ break; /* context's bpp is set to 24 if there are three 8-bit planes */
+ }
+
+#ifdef PCX_DEBUG
+ g_print("io-pcx: header loaded\n");
+ g_print("bpp: %u\n", context->bpp);
+ g_print("dimensions: %ux%u\n", context->width, context->height);
+#endif
+
+ context->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, context->width, context->height);
+ if(!context->pixbuf) {
+ g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't create new pixbuf"));
+ return FALSE;
+ }
+ context->data = gdk_pixbuf_get_pixels(context->pixbuf);
+ context->rowstride = gdk_pixbuf_get_rowstride(context->pixbuf);
+
+ context->line = g_try_malloc(sizeof(guchar) * context->bytesperline * context->num_planes);
+ if(!context->line) {
+ g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't allocate memory for line data"));
+ return FALSE;
+ }
+
+ if(context->bpp == 8) {
+ context->p_data = g_try_malloc(sizeof(guchar) * context->width * context->height);
+ if(!context->p_data) {
+ g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't allocate memory for paletted data"));
+ return FALSE;
+ }
+ }
+
+ if(context->prepared_func)
+ context->prepared_func(context->pixbuf, NULL, context->user_data);
+
+ context->current_task = PCX_TASK_LOAD_DATA;
+ }
+
+ retval = TRUE;
+ }
+
+ if(context->current_task == PCX_TASK_LOAD_DATA) {
+ switch(context->bpp) {
+ default:
+ g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_UNKNOWN_TYPE, _("Image has unsupported bpp"));
+ retval = FALSE;
+ break;
+ case 1:
+ retval = pcx_increment_load_data_1(context);
+ break;
+ case 2:
+ retval = pcx_increment_load_data_2(context);
+ break;
+ case 4:
+ retval = pcx_increment_load_data_4(context);
+ break;
+ case 8:
+ retval = pcx_increment_load_data_8(context);
+ break;
+ case 24:
+ retval = pcx_increment_load_data_24(context);
+ break;
+ }
+ }
+
+ return retval;
+}
+
+static gboolean
+gdk_pixbuf__pcx_stop_load(gpointer data, GError **error)
+{
+ struct pcx_context *context = (struct pcx_context *)data;
+
+ if(context->current_line != context->height) {
+ g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, _("Didn't get all lines of PCX image"));
+ free_pcx_context(context, FALSE);
+ return FALSE;
+ }
+
+ if(context->current_task == PCX_TASK_LOAD_PALETTE) {
+ if(!pcx_load_palette_8(context)) {
+ g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, _("No palette found at end of PCX data"));
+ free_pcx_context(context, FALSE);
+ return FALSE;
+ }
+ }
+
+ free_pcx_context(context, FALSE);
+
+ return TRUE;
+}
+
+void
+MODULE_ENTRY (pcx, fill_vtable) (GdkPixbufModule *module)
+{
+ module->begin_load = gdk_pixbuf__pcx_begin_load;
+ module->stop_load = gdk_pixbuf__pcx_stop_load;
+ module->load_increment = gdk_pixbuf__pcx_load_increment;
+}
+
+void
+MODULE_ENTRY (pcx, fill_info) (GdkPixbufFormat *info)
+{
+ static GdkPixbufModulePattern signature[] = {
+ { "\x0a \x01", NULL, 100 },
+ { "\x0a\x02\x01", NULL, 100 },
+ { "\x0a\x03\x01", NULL, 100 },
+ { "\x0a\x04\x01", NULL, 100 },
+ { "\x0a\x05\x01", NULL, 100 },
+ { NULL, NULL, 0 }
+ };
+ static gchar *mime_types[] = {
+ "image/x-pcx",
+ NULL,
+ };
+ static gchar *extensions[] = {
+ "pcx",
+ NULL,
+ };
+
+ info->name = "pcx";
+ info->signature = signature;
+ info->description = N_("The PCX image format");
+ info->mime_types = mime_types;
+ info->extensions = extensions;
+ info->flags = 0;
+}
diff --git a/gdk-pixbuf/pixbufloader_pcx.def b/gdk-pixbuf/pixbufloader_pcx.def
new file mode 100644
index 000000000..9044f0897
--- /dev/null
+++ b/gdk-pixbuf/pixbufloader_pcx.def
@@ -0,0 +1,3 @@
+EXPORTS
+ fill_vtable
+ fill_info