diff options
author | Matthias Clasen <matthiasc@src.gnome.org> | 2001-08-21 08:51:06 +0000 |
---|---|---|
committer | Matthias Clasen <matthiasc@src.gnome.org> | 2001-08-21 08:51:06 +0000 |
commit | a2e555e814e0fe60b912e0e0397d932842a0645c (patch) | |
tree | 9aff120ed4b13ae9e83a381f5444c888669c97cc | |
parent | ce46c83ab88c932aa2e42089f0afaeb8bb60b3f1 (diff) | |
download | gtk+-a2e555e814e0fe60b912e0e0397d932842a0645c.tar.gz |
Add tga loader, patch by Nicola Girardi. (#56067)
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | ChangeLog.pre-2-0 | 5 | ||||
-rw-r--r-- | ChangeLog.pre-2-10 | 5 | ||||
-rw-r--r-- | ChangeLog.pre-2-2 | 5 | ||||
-rw-r--r-- | ChangeLog.pre-2-4 | 5 | ||||
-rw-r--r-- | ChangeLog.pre-2-6 | 5 | ||||
-rw-r--r-- | ChangeLog.pre-2-8 | 5 | ||||
-rw-r--r-- | configure.in | 2 | ||||
-rw-r--r-- | gdk-pixbuf/ChangeLog | 5 | ||||
-rw-r--r-- | gdk-pixbuf/Makefile.am | 13 | ||||
-rw-r--r-- | gdk-pixbuf/gdk-pixbuf-io.c | 29 | ||||
-rw-r--r-- | gdk-pixbuf/io-tga.c | 1162 | ||||
-rw-r--r-- | gdk-pixbuf/pixbufloader_tga.def | 2 |
13 files changed, 1245 insertions, 3 deletions
@@ -1,3 +1,8 @@ +2001-08-21 Matthias Clasen <matthiasc@waldgeist.poet.de> + + * configure.in (all_loaders): Add tga loader, + patch by Nicola Girardi. (#56067) + Tue Aug 21 02:57:13 2001 Jonathan Blandford <jrb@redhat.com>> * gtk/gtktreeview.c (gtk_tree_view_button_press): Fix up selection diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index 4302f8a0f9..8ab11263ac 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,8 @@ +2001-08-21 Matthias Clasen <matthiasc@waldgeist.poet.de> + + * configure.in (all_loaders): Add tga loader, + patch by Nicola Girardi. (#56067) + Tue Aug 21 02:57:13 2001 Jonathan Blandford <jrb@redhat.com>> * gtk/gtktreeview.c (gtk_tree_view_button_press): Fix up selection diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 4302f8a0f9..8ab11263ac 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,8 @@ +2001-08-21 Matthias Clasen <matthiasc@waldgeist.poet.de> + + * configure.in (all_loaders): Add tga loader, + patch by Nicola Girardi. (#56067) + Tue Aug 21 02:57:13 2001 Jonathan Blandford <jrb@redhat.com>> * gtk/gtktreeview.c (gtk_tree_view_button_press): Fix up selection diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index 4302f8a0f9..8ab11263ac 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,8 @@ +2001-08-21 Matthias Clasen <matthiasc@waldgeist.poet.de> + + * configure.in (all_loaders): Add tga loader, + patch by Nicola Girardi. (#56067) + Tue Aug 21 02:57:13 2001 Jonathan Blandford <jrb@redhat.com>> * gtk/gtktreeview.c (gtk_tree_view_button_press): Fix up selection diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 4302f8a0f9..8ab11263ac 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,8 @@ +2001-08-21 Matthias Clasen <matthiasc@waldgeist.poet.de> + + * configure.in (all_loaders): Add tga loader, + patch by Nicola Girardi. (#56067) + Tue Aug 21 02:57:13 2001 Jonathan Blandford <jrb@redhat.com>> * gtk/gtktreeview.c (gtk_tree_view_button_press): Fix up selection diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 4302f8a0f9..8ab11263ac 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,8 @@ +2001-08-21 Matthias Clasen <matthiasc@waldgeist.poet.de> + + * configure.in (all_loaders): Add tga loader, + patch by Nicola Girardi. (#56067) + Tue Aug 21 02:57:13 2001 Jonathan Blandford <jrb@redhat.com>> * gtk/gtktreeview.c (gtk_tree_view_button_press): Fix up selection diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 4302f8a0f9..8ab11263ac 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,8 @@ +2001-08-21 Matthias Clasen <matthiasc@waldgeist.poet.de> + + * configure.in (all_loaders): Add tga loader, + patch by Nicola Girardi. (#56067) + Tue Aug 21 02:57:13 2001 Jonathan Blandford <jrb@redhat.com>> * gtk/gtktreeview.c (gtk_tree_view_button_press): Fix up selection diff --git a/configure.in b/configure.in index 98b30409fe..76dc6fda6d 100644 --- a/configure.in +++ b/configure.in @@ -524,7 +524,7 @@ else fi fi -all_loaders="png,bmp,wbmp,gif,ico,jpeg,pnm,ras,tiff,xpm" +all_loaders="png,bmp,wbmp,gif,ico,jpeg,pnm,ras,tiff,xpm,tga" included_loaders="" # If no loaders specified, include all if test "x$with_included_loaders" = xyes ; then diff --git a/gdk-pixbuf/ChangeLog b/gdk-pixbuf/ChangeLog index 8785db5f13..e36719def0 100644 --- a/gdk-pixbuf/ChangeLog +++ b/gdk-pixbuf/ChangeLog @@ -1,3 +1,8 @@ +2001-08-21 Matthias Clasen <matthiasc@waldgeist.poet.de> + + * Makefile.am, gdk-pixbuf-io.c, pixbufloader_tga.def, + io-tga.c: Add tga loader, patch by Nicola Girardi. (#56067) + 2001-08-20 Matthias Clasen <matthiasc@waldgeist.poet.de> * test-images.h, test-loaders.c: Add ico and wbmp tests. diff --git a/gdk-pixbuf/Makefile.am b/gdk-pixbuf/Makefile.am index 374ea905a3..f1100f89eb 100644 --- a/gdk-pixbuf/Makefile.am +++ b/gdk-pixbuf/Makefile.am @@ -95,6 +95,14 @@ libpixbufloader_xbm_la_LDFLAGS = -version-info 1:0:0 -module libpixbufloader_xbm_la_LDFLAGS = -avoid-version -module libpixbufloader_xbm_la_LIBADD = $(module_libs) +# +# The TGA loader +# +libpixbufloader_tga_la_SOURCES = io-tga.c +libpixbufloader_tga_la_LDFLAGS = -version-info 1:0:0 -module +libpixbufloader_tga_la_LDFLAGS = -avoid-version -module +libpixbufloader_tga_la_LIBADD = $(module_libs) + if HAVE_PNG PNG_LIB = libpixbufloader-png.la endif @@ -123,6 +131,8 @@ WBMP_LIB = libpixbufloader-wbmp.la XBM_LIB = libpixbufloader-xbm.la +TGA_LIB = libpixbufloader-tga.la + if BUILD_DYNAMIC_MODULES loader_LTLIBRARIES = \ @@ -136,7 +146,8 @@ loader_LTLIBRARIES = \ $(PNM_LIB) \ $(BMP_LIB) \ $(WBMP_LIB) \ - $(XBM_LIB) + $(XBM_LIB) \ + $(TGA_LIB) extra_sources = diff --git a/gdk-pixbuf/gdk-pixbuf-io.c b/gdk-pixbuf/gdk-pixbuf-io.c index 2ffed40659..aef06defc8 100644 --- a/gdk-pixbuf/gdk-pixbuf-io.c +++ b/gdk-pixbuf/gdk-pixbuf-io.c @@ -200,6 +200,24 @@ pixbuf_check_xbm (guchar *buffer, int size) return TRUE; } +static gboolean +pixbuf_check_tga (guchar *buffer, int size) +{ + if (size < 18) + return FALSE; + /* buffer[1] is a boolean telling if in the file a colormap is + present, while buffer[2] is the byte which specifies the image + type. (GrayScale/PseudoColor/TrueColor/RLE) */ + if ((buffer[2] == 1) || (buffer[2] == 9)) { + if (buffer[1] != 1) + return FALSE; + } else { + if (buffer[1] != 0) + return FALSE; + } + return TRUE; +} + static GdkPixbufModule file_formats [] = { { "png", pixbuf_check_png, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }, { "jpeg", pixbuf_check_jpeg, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, @@ -209,10 +227,13 @@ static GdkPixbufModule file_formats [] = { { "xpm", pixbuf_check_xpm, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, { "pnm", pixbuf_check_pnm, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, { "ras", pixbuf_check_sunras, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, - { "ico", pixbuf_check_ico, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, { "bmp", pixbuf_check_bmp, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, { "wbmp", pixbuf_check_wbmp, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, { "xbm", pixbuf_check_xbm, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, + { "tga", pixbuf_check_tga, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, + /* Moved at the bottom, because it causes false positives against many + of my TGA files. */ + { "ico", pixbuf_check_ico, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } }; @@ -336,6 +357,7 @@ m_fill_vtable (ras); m_fill_vtable (tiff); m_fill_vtable (xpm); m_fill_vtable (xbm); +m_fill_vtable (tga); gboolean _gdk_pixbuf_load_module (GdkPixbufModule *image_module, @@ -414,6 +436,11 @@ _gdk_pixbuf_load_module (GdkPixbufModule *image_module, } #endif +#ifdef INCLUDE_tga + else if (strcmp (image_module->module_name, "tga") == 0){ + fill_vtable = mname (tga, fill_vtable); + } +#endif if (fill_vtable) { (* fill_vtable) (image_module); diff --git a/gdk-pixbuf/io-tga.c b/gdk-pixbuf/io-tga.c new file mode 100644 index 0000000000..1f84d5ad2d --- /dev/null +++ b/gdk-pixbuf/io-tga.c @@ -0,0 +1,1162 @@ +/* + * GdkPixbuf library - TGA image loader + * Copyright (C) 1999 Nicola Girardi <nikke@swlibero.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, + * Boston, MA 02111-1307, USA. + * + * Some NOTES about the TGA loader (2001/06/07, nikke@swlibero.org) + * + * - The module doesn't currently provide support for TGA images where the + * order of the pixels isn't left-to-right and top-to-bottom. I plan to + * add support for those files as soon as I get one of them. I haven't + * run into one yet. (And I don't seem to be able to create it with GIMP.) + * + * - The TGAFooter isn't present in all TGA files. In fact, there's an older + * format specification, still in use, which doesn't cover the TGAFooter. + * Actually, most TGA files I have are of the older type. Anyway I put the + * struct declaration here for completeness. + * + * - Error handling was designed to be very paranoid. + */ + +#include <stdio.h> +#include <string.h> + +#include "gdk-pixbuf.h" +#include "gdk-pixbuf-io.h" +#include "gdk-pixbuf-private.h" + +#define TGA_INTERLEAVE_MASK 0xc0 +#define TGA_INTERLEAVE_NONE 0x00 +#define TGA_INTERLEAVE_2WAY 0x40 +#define TGA_INTERLEAVE_4WAY 0x80 + +#define TGA_ORIGIN_MASK 0x30 +#define TGA_ORIGIN_LEFT 0x00 +#define TGA_ORIGIN_RIGHT 0x10 +#define TGA_ORIGIN_LOWER 0x00 +#define TGA_ORIGIN_UPPER 0x20 + +enum { + TGA_TYPE_NODATA = 0, + TGA_TYPE_PSEUDOCOLOR = 1, + TGA_TYPE_TRUECOLOR = 2, + TGA_TYPE_GRAYSCALE = 3, + TGA_TYPE_RLE_PSEUDOCOLOR = 9, + TGA_TYPE_RLE_TRUECOLOR = 10, + TGA_TYPE_RLE_GRAYSCALE = 11 +}; + +#define LE16(p) ((p)[0] + ((p)[1] << 8)) + +typedef struct _IOBuffer IOBuffer; + +typedef struct _TGAHeader TGAHeader; +typedef struct _TGAFooter TGAFooter; + +typedef struct _TGAColormap TGAColormap; +typedef struct _TGAColor TGAColor; + +typedef struct _TGAContext TGAContext; + +struct _TGAHeader { + guint8 infolen; + guint8 has_cmap; + guint8 type; + + guint8 cmap_start[2]; + guint8 cmap_n_colors[2]; + guint8 cmap_bpp; + + guint8 x_origin[2]; + guint8 y_origin[2]; + + guint8 width[2]; + guint8 height[2]; + guint8 bpp; + + guint8 flags; +}; + +struct _TGAFooter { + guint32 extension_area_offset; + guint32 developer_directory_offset; + + /* Standard TGA signature, "TRUEVISION-XFILE.\0". */ + union { + gchar sig_full[18]; + struct { + gchar sig_chunk[16]; + gchar dot, null; + } sig_struct; + } sig; +}; + +struct _TGAColormap { + gint size; + TGAColor *cols; +}; + +struct _TGAColor { + guchar r, g, b, a; +}; + +struct _TGAContext { + TGAHeader *hdr; + guint rowstride; + gboolean run_length_encoded; + + TGAColormap *cmap; + guint cmap_size; + + GdkPixbuf *pbuf; + guint pbuf_bytes; + guint pbuf_bytes_done; + guchar *pptr; + + IOBuffer *in; + + gboolean skipped_info; + gboolean prepared; + gboolean done; + + ModulePreparedNotifyFunc pfunc; + ModuleUpdatedNotifyFunc ufunc; + gpointer udata; +}; + +struct _IOBuffer { + guchar *data; + guint size; +}; + +static IOBuffer *io_buffer_new(GError **err) +{ + IOBuffer *buffer; + buffer = g_try_malloc(sizeof(IOBuffer)); + if (!buffer) { + g_set_error(err, GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, + _("Can't allocate memory for IOBuffer struct")); + return NULL; + } + buffer->data = NULL; + buffer->size = 0; + return buffer; +} + +static IOBuffer *io_buffer_append(IOBuffer *buffer, + const guchar *data, guint len, + GError **err) +{ + if (!buffer) + return NULL; + if (!buffer->data) { + buffer->data = g_try_malloc(len); + if (!buffer->data) { + g_set_error(err, GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, + _("Can't allocate memory for IOBuffer data")); + g_free(buffer); + return NULL; + } + g_memmove(buffer->data, data, len); + buffer->size = len; + } else { + buffer->data = g_try_realloc(buffer->data, buffer->size + len); + if (!buffer->data) { + g_set_error(err, GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, + _("Can't realloc IOBuffer data")); + g_free(buffer); + return NULL; + } + g_memmove(&buffer->data[buffer->size], data, len); + buffer->size += len; + } + return buffer; +} + +static IOBuffer *io_buffer_free_segment(IOBuffer *buffer, + guint count, + GError **err) +{ + g_return_val_if_fail(buffer != NULL, NULL); + g_return_val_if_fail(buffer->data != NULL, NULL); + if (count == buffer->size) { + g_free(buffer->data); + buffer->data = NULL; + buffer->size = 0; + } else { + guchar *new_buf; + guint new_size; + + new_size = buffer->size - count; + new_buf = g_try_malloc(new_size); + if (!new_buf) { + g_set_error(err, GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, + _("Can't allocate temporary IOBuffer data")); + g_free(buffer->data); + g_free(buffer); + return NULL; + } + + g_memmove(new_buf, &buffer->data[count], new_size); + g_free(buffer->data); + buffer->data = new_buf; + buffer->size = new_size; + } + return buffer; +} + +static void io_buffer_free(IOBuffer *buffer) +{ + g_return_if_fail(buffer != NULL); + if (buffer->data) + g_free(buffer->data); + g_free(buffer); +} + +static void free_buffer(guchar *pixels, gpointer data) +{ + g_free(pixels); +} + +static gboolean fread_check(gpointer dest, + size_t size, size_t count, + FILE *f, GError **err) +{ + if (fread(dest, size, count, f) != count) { + g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, + _("fread() failed -- premature end-of-file probably encountered")); + return FALSE; + } + return TRUE; +} + +static gboolean fseek_check(FILE *f, glong offset, gint whence, GError **err) +{ + if (fseek(f, offset, whence) != 0) { + g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, + _("fseek() failed -- premature end-of-file probably encountered")); + return FALSE; + } + return TRUE; +} + +static gboolean fill_in_context(TGAContext *ctx, GError **err) +{ + gboolean alpha; + + g_return_val_if_fail(ctx != NULL, FALSE); + + ctx->run_length_encoded = + ((ctx->hdr->type == TGA_TYPE_RLE_PSEUDOCOLOR) + || (ctx->hdr->type == TGA_TYPE_RLE_TRUECOLOR) + || (ctx->hdr->type == TGA_TYPE_RLE_GRAYSCALE)); + + if (ctx->hdr->has_cmap) + ctx->cmap_size = ((ctx->hdr->cmap_bpp + 7) >> 3) * + LE16(ctx->hdr->cmap_n_colors); + + alpha = ((ctx->hdr->bpp == 32) || + (ctx->hdr->has_cmap && (ctx->hdr->cmap_bpp == 32))); + + ctx->pbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, alpha, 8, + LE16(ctx->hdr->width), + LE16(ctx->hdr->height)); + if (!ctx->pbuf) { + g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, + _("Can't allocate new pixbuf")); + return FALSE; + } + ctx->pbuf_bytes = ctx->pbuf->rowstride * ctx->pbuf->height; + ctx->pptr = ctx->pbuf->pixels; + + if ((ctx->hdr->type == TGA_TYPE_PSEUDOCOLOR) || + (ctx->hdr->type == TGA_TYPE_GRAYSCALE)) + ctx->rowstride = ctx->pbuf->width; + else if (ctx->hdr->type == TGA_TYPE_TRUECOLOR) + ctx->rowstride = ctx->pbuf->rowstride; + + return TRUE; +} + +static void parse_data_for_row_pseudocolor(TGAContext *ctx) +{ + guchar *s = ctx->in->data; + guint upper_bound = ctx->pbuf->width; + + for (; upper_bound; upper_bound--, s++) { + *ctx->pptr++ = ctx->cmap->cols[*s].r; + *ctx->pptr++ = ctx->cmap->cols[*s].g; + *ctx->pptr++ = ctx->cmap->cols[*s].b; + if (ctx->hdr->cmap_bpp == 32) + *ctx->pptr++ = ctx->cmap->cols[*s].a; + } + ctx->pbuf_bytes_done += ctx->pbuf->n_channels * ctx->pbuf->width; + if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) + ctx->done = TRUE; +} + +static void swap_channels(TGAContext *ctx) +{ + register guchar swap; + register guint count; + for (count = ctx->pbuf->width; count; count--) { + swap = ctx->pptr[0]; + ctx->pptr[0] = ctx->pptr[2]; + ctx->pptr[2] = swap; + ctx->pptr += ctx->pbuf->n_channels; + } +} + +static void parse_data_for_row_truecolor(TGAContext *ctx) +{ + g_memmove(ctx->pptr, ctx->in->data, ctx->pbuf->rowstride); + swap_channels(ctx); + ctx->pbuf_bytes_done += ctx->pbuf->rowstride; + if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) + ctx->done = TRUE; +} + +static void parse_data_for_row_grayscale(TGAContext *ctx) +{ + guchar *s = ctx->in->data; + guint upper_bound = ctx->pbuf->width; + + for (; upper_bound; upper_bound--) { + ctx->pptr[0] = ctx->pptr[1] = ctx->pptr[2] = *s++; + ctx->pptr += 3; + } + ctx->pbuf_bytes_done = ctx->pbuf->width * 3; + if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) + ctx->done = TRUE; +} + +static gboolean parse_data_for_row(TGAContext *ctx, GError **err) +{ + if (ctx->hdr->type == TGA_TYPE_PSEUDOCOLOR) + parse_data_for_row_pseudocolor(ctx); + else if (ctx->hdr->type == TGA_TYPE_TRUECOLOR) + parse_data_for_row_truecolor(ctx); + else if (ctx->hdr->type == TGA_TYPE_GRAYSCALE) + parse_data_for_row_grayscale(ctx); + ctx->in = io_buffer_free_segment(ctx->in, ctx->rowstride, err); + if (!ctx->in) + return FALSE; + (*ctx->ufunc) (ctx->pbuf, 0, + (ctx->pbuf_bytes_done / ctx->pbuf->rowstride) - 1, + ctx->pbuf->width, 1, ctx->udata); + return TRUE; +} + +static void write_rle_data(TGAContext *ctx, TGAColor *color, guint *rle_count) +{ + ctx->pbuf_bytes_done += ctx->pbuf->n_channels * (*rle_count); + for (; *rle_count; (*rle_count)--) { + g_memmove(ctx->pptr, (guchar *) color, ctx->pbuf->n_channels); + ctx->pptr += ctx->pbuf->n_channels; + } +} + +static guint parse_rle_data_pseudocolor(TGAContext *ctx) +{ + guint rle_num, raw_num; + guchar *s, tag; + guint n; + + g_return_val_if_fail(ctx->in->size > 0, 0); + s = ctx->in->data; + + for (n = 0; n < ctx->in->size; ) { + tag = *s; + s++, n++; + if (tag & 0x80) { + if (n == ctx->in->size) { + return --n; + } else { + rle_num = (tag & 0x7f) + 1; + write_rle_data(ctx, &ctx->cmap->cols[*s], &rle_num); + s++, n++; + } + } else { + raw_num = tag + 1; + if (n + raw_num >= ctx->in->size) { + return --n; + } else { + for (; raw_num; raw_num--) { + *ctx->pptr++ = + ctx->cmap->cols[*s].r; + *ctx->pptr++ = + ctx->cmap->cols[*s].g; + *ctx->pptr++ = + ctx->cmap->cols[*s].b; + if (ctx->pbuf->n_channels == 4) + *ctx->pptr++ = ctx->cmap->cols[*s].a; + s++, n++; + ctx->pbuf_bytes_done += ctx->pbuf->n_channels; + } + } + } + } + if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) + ctx->done = TRUE; + return n; +} + +static void swap_channels_rle(TGAContext *ctx, guint count) +{ + register guchar swap; + for (; count; count--) { + swap = ctx->pptr[0]; + ctx->pptr[0] = ctx->pptr[2]; + ctx->pptr[2] = swap; + ctx->pptr += ctx->pbuf->n_channels; + } +} + +static guint parse_rle_data_truecolor(TGAContext *ctx) +{ + TGAColor col; + guint rle_num, raw_num; + guchar *s, tag; + guint n = 0; + + g_return_val_if_fail(ctx->in->size > 0, 0); + s = ctx->in->data; + + for (n = 0; n < ctx->in->size; ) { + tag = *s; + s++, n++; + if (tag & 0x80) { + if (n + ctx->pbuf->n_channels >= ctx->in->size) { + return --n; + } else { + rle_num = (tag & 0x7f) + 1; + col.b = *s++; + col.g = *s++; + col.r = *s++; + if (ctx->hdr->bpp == 32) + col.a = *s++; + write_rle_data(ctx, &col, &rle_num); + n += ctx->pbuf->n_channels; + } + } else { + raw_num = tag + 1; + if (n + (raw_num * ctx->pbuf->n_channels) >= ctx->in->size) { + return --n; + } else { + g_memmove(ctx->pptr, s, raw_num * ctx->pbuf->n_channels); + swap_channels_rle(ctx, raw_num); + s += raw_num * ctx->pbuf->n_channels; + n += raw_num * ctx->pbuf->n_channels; + ctx->pbuf_bytes_done += raw_num * ctx->pbuf->n_channels; + } + } + } + if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) + ctx->done = TRUE; + return n; +} + +static guint parse_rle_data_grayscale(TGAContext *ctx) +{ + TGAColor tone; + guint rle_num, raw_num; + guchar *s, tag; + guint n; + + g_return_val_if_fail(ctx->in->size > 0, 0); + s = ctx->in->data; + + for (n = 0; n < ctx->in->size; ) { + tag = *s; + s++, n++; + if (tag & 0x80) { + if (n == ctx->in->size) { + return --n; + } else { + rle_num = (tag & 0x7f) + 1; + tone.r = tone.g = tone.b = *s; + s++, n++; + write_rle_data(ctx, &tone, &rle_num); + } + } else { + raw_num = tag + 1; + if (n + raw_num >= ctx->in->size) { + return --n; + } else { + for (; raw_num; raw_num--) { + ctx->pptr[0] = ctx->pptr[1] = ctx->pptr[2] = *s; + s++, n++; + ctx->pptr += 3; + ctx->pbuf_bytes_done += 3; + } + } + } + } + if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) + ctx->done = TRUE; + return n; +} + +static gboolean parse_rle_data(TGAContext *ctx, GError **err) +{ + guint count = 0; + guint pbuf_count = 0; + if (ctx->hdr->type == TGA_TYPE_RLE_PSEUDOCOLOR) { + count = parse_rle_data_pseudocolor(ctx); + pbuf_count = count *ctx->pbuf->n_channels; + } else if (ctx->hdr->type == TGA_TYPE_RLE_TRUECOLOR) { + count = parse_rle_data_truecolor(ctx); + pbuf_count = count; + } else if (ctx->hdr->type == TGA_TYPE_RLE_GRAYSCALE) { + count = parse_rle_data_grayscale(ctx); + pbuf_count = count * 3; + } + ctx->in = io_buffer_free_segment(ctx->in, count, err); + if (!ctx->in) + return FALSE; + (*ctx->ufunc) (ctx->pbuf, 0, ctx->pbuf_bytes_done / ctx->pbuf->rowstride, + ctx->pbuf->width, pbuf_count / ctx->pbuf->rowstride, + ctx->udata); + return TRUE; +} + +static gboolean try_colormap(TGAContext *ctx, GError **err) +{ + static guchar *p; + static guint n; + + g_return_val_if_fail(ctx != NULL, FALSE); + g_return_val_if_fail(ctx->cmap_size > 0, TRUE); + + ctx->cmap = g_try_malloc(sizeof(TGAColormap)); + if (!ctx->cmap) { + g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, + _("Can't allocate colormap structure")); + return FALSE; + } + ctx->cmap->size = LE16(ctx->hdr->cmap_n_colors); + ctx->cmap->cols = g_try_malloc(sizeof(TGAColor) * ctx->cmap->size); + if (!ctx->cmap->cols) { + g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, + _("Can't allocate colormap entries")); + g_free(ctx->cmap); + return FALSE; + } + + p = ctx->in->data; + for (n = 0; n < ctx->cmap->size; n++) { + if ((ctx->hdr->cmap_bpp == 15) || (ctx->hdr->cmap_bpp == 16)) { + guint16 col = p[0] + (p[1] << 8); + ctx->cmap->cols[n].b = (col >> 7) & 0xf8; + ctx->cmap->cols[n].g = (col >> 2) & 0xf8; + ctx->cmap->cols[n].r = col << 3; + p += 2; + } + else if ((ctx->hdr->cmap_bpp == 24) || (ctx->hdr->cmap_bpp == 32)) { + ctx->cmap->cols[n].b = *p++; + ctx->cmap->cols[n].g = *p++; + ctx->cmap->cols[n].r = *p++; + if (ctx->hdr->cmap_bpp == 32) + ctx->cmap->cols[n].a = *p++; + } else { + g_set_error(err, GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Unexpected bitdepth for colormap entries")); + g_free(ctx->cmap->cols); + g_free(ctx->cmap); + return FALSE; + } + } + ctx->in = io_buffer_free_segment(ctx->in, ctx->cmap_size, err); + if (!ctx->in) + return FALSE; + return TRUE; +} + +static gboolean try_preload(TGAContext *ctx, GError **err) +{ + if (!ctx->hdr) { + if (ctx->in->size >= sizeof(TGAHeader)) { + ctx->hdr = g_try_malloc(sizeof(TGAHeader)); + if (!ctx->hdr) { + g_set_error(err, GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, + _("Can't allocate TGA header memory")); + return FALSE; + } + g_memmove(ctx->hdr, ctx->in->data, sizeof(TGAHeader)); + ctx->in = io_buffer_free_segment(ctx->in, sizeof(TGAHeader), err); + if (!ctx->in) + return FALSE; + if (!fill_in_context(ctx, err)) + return FALSE; + if (ctx->hdr->infolen > 255) { + g_set_error(err, GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("TGA image comment length is too long")); + return FALSE; + } + if ((ctx->hdr->flags & TGA_INTERLEAVE_MASK) != + TGA_INTERLEAVE_NONE || + ctx->hdr->flags & TGA_ORIGIN_RIGHT || + ctx->hdr->flags & TGA_ORIGIN_LOWER) { + g_set_error(err, GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_UNKNOWN_TYPE, + _("TGA image type not supported")); + return FALSE; + } + } else { + return TRUE; + } + } + if (!ctx->skipped_info) { + if (ctx->in->size >= ctx->hdr->infolen) { + ctx->in = io_buffer_free_segment(ctx->in, ctx->hdr->infolen, err); + if (!ctx->in) + return FALSE; + ctx->skipped_info = TRUE; + } else { + return TRUE; + } + } + if (ctx->hdr->has_cmap && !ctx->cmap) { + if (ctx->in->size >= ctx->cmap_size) { + if (!try_colormap(ctx, err)) + return FALSE; + } else { + return TRUE; + } + } + if (!ctx->prepared) { + (*ctx->pfunc) (ctx->pbuf, NULL, ctx->udata); + ctx->prepared = TRUE; + } + /* We shouldn't get here anyway. */ + return TRUE; +} + +static gpointer gdk_pixbuf__tga_begin_load(ModulePreparedNotifyFunc f1, + ModuleUpdatedNotifyFunc f2, + gpointer udata, GError **err) +{ + TGAContext *ctx; + + ctx = g_try_malloc(sizeof(TGAContext)); + if (!ctx) { + g_set_error(err, GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, + _("Can't allocate memory for TGA context struct")); + return NULL; + } + + ctx->hdr = NULL; + ctx->rowstride = 0; + ctx->run_length_encoded = FALSE; + + ctx->cmap = NULL; + ctx->cmap_size = 0; + + ctx->pbuf = NULL; + ctx->pbuf_bytes = 0; + ctx->pbuf_bytes_done = 0; + ctx->pptr = NULL; + + ctx->in = io_buffer_new(err); + if (!ctx->in) { + g_free(ctx); + return NULL; + } + + ctx->skipped_info = FALSE; + ctx->prepared = FALSE; + ctx->done = FALSE; + + ctx->pfunc = f1; + ctx->ufunc = f2; + ctx->udata = udata; + + return ctx; +} + +static gboolean gdk_pixbuf__tga_load_increment(gpointer data, + const guchar *buffer, + guint size, + GError **err) +{ + TGAContext *ctx = (TGAContext*) data; + g_return_val_if_fail(ctx != NULL, FALSE); + + if (ctx->done) + return TRUE; + + g_return_val_if_fail(buffer != NULL, TRUE); + ctx->in = io_buffer_append(ctx->in, buffer, size, err); + if (!ctx->in) + return FALSE; + if (!ctx->prepared) { + if (!try_preload(ctx, err)) + return FALSE; + if (!ctx->prepared) + return TRUE; + if (ctx->in->size == 0) + return TRUE; + } + + if (ctx->run_length_encoded) { + if (!parse_rle_data(ctx, err)) + return FALSE; + } else { + while (ctx->in->size >= ctx->rowstride) + if (!parse_data_for_row(ctx, err)) + return FALSE; + } + + return TRUE; +} + +static gboolean gdk_pixbuf__tga_stop_load(gpointer data, GError **err) +{ + TGAContext *ctx = (TGAContext *) data; + g_return_val_if_fail(ctx != NULL, FALSE); + + g_free(ctx->hdr); + if (ctx->cmap) + g_free(ctx->cmap); + gdk_pixbuf_unref(ctx->pbuf); + if (ctx->in->size) + ctx->in = io_buffer_free_segment(ctx->in, ctx->in->size, err); + if (!ctx->in) { + g_free(ctx); + return FALSE; + } + io_buffer_free(ctx->in); + g_free(ctx); + return TRUE; +} + +static TGAHeader *get_header_from_file(FILE *f, GError **err) +{ + TGAHeader *hdr; + + if (!fseek_check(f, 0, SEEK_SET, err)) + return NULL; + if (!(hdr = g_try_malloc(sizeof(TGAHeader)))) { + g_set_error(err, GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, + _("Can't allocate memory for TGA header")); + return NULL; + } + if (!fread_check(hdr, sizeof(TGAHeader), 1, f, err)) { + g_free(hdr); + return NULL; + } + if (hdr->infolen > 255) { + g_set_error(err, GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Too big value in the infolen field of TGA header.")); + g_free(hdr); + return NULL; + } + + return hdr; +} + +static TGAColormap *get_colormap_from_file(FILE *f, + TGAHeader *hdr, + GError **err) +{ + TGAColormap *cmap; + guchar *pal_buf, *p; + guint n, pal_size; + + if (!fseek_check(f, sizeof(TGAHeader) + hdr->infolen, SEEK_SET, err)) + return NULL; + + pal_size = LE16(hdr->cmap_n_colors) * ((hdr->cmap_bpp + 7) >> 3); + pal_buf = g_try_malloc(pal_size); + if (!pal_buf) { + g_set_error(err, GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, + _("Can't allocate memory for TGA cmap temporary buffer")); + return NULL; + } + if (!fread_check(pal_buf, pal_size, 1, f, err)) { + g_free(pal_buf); + return NULL; + } + p = pal_buf; + + if (!(cmap = g_try_malloc(sizeof(TGAColormap)))) { + g_set_error(err, GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, + _("Can't allocate memory for TGA colormap struct")); + g_free(pal_buf); + return NULL; + } + cmap->size = LE16(hdr->cmap_n_colors); + cmap->cols = g_try_malloc(sizeof(TGAColor) * cmap->size); + if (!cmap->cols) { + g_set_error(err, GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, + _("Can't allocate memory for TGA colormap entries")); + g_free(pal_buf); + g_free(cmap); + return NULL; + } + + if (hdr->cmap_bpp != 15 && hdr->cmap_bpp != 16 && + hdr->cmap_bpp != 24 && hdr->cmap_bpp != 32) { + g_set_error(err, GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_UNKNOWN_TYPE, + _("Unexpected bitdepth for TGA colormap")); + g_free(pal_buf); + g_free(cmap->cols); + g_free(cmap); + return NULL; + } + + for (n = 0; n < cmap->size; n++) { + if ((hdr->cmap_bpp == 15) || (hdr->cmap_bpp == 16)) { + guint16 col = p[0] + (p[1] << 8); + p += 2; + cmap->cols[n].b = (col >> 7) & 0xf8; + cmap->cols[n].g = (col >> 2) & 0xf8; + cmap->cols[n].r = col << 3; + } else if ((hdr->cmap_bpp == 24) || (hdr->cmap_bpp == 32)) { + cmap->cols[n].b = *p++; + cmap->cols[n].g = *p++; + cmap->cols[n].r = *p++; + if (hdr->cmap_bpp == 32) + cmap->cols[n].a = *p++; + } + } + + g_free(pal_buf); + return cmap; +} + +static GdkPixbuf *get_image_pseudocolor(FILE *f, TGAHeader *hdr, + TGAColormap *cmap, gboolean rle, + GError **err) +{ + GdkPixbuf *pbuf; + guchar *p, color, tag; + glong n, image_offset; + guint count; + + image_offset = sizeof(TGAHeader) + hdr->infolen; + if (!hdr->has_cmap) { + g_set_error(err, GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + _("Pseudo-Color image without colormap")); + return NULL; + } else { + image_offset += cmap->size * ((hdr->cmap_bpp + 7) >> 3); + } + if (!fseek_check(f, image_offset, SEEK_SET, err)) { + g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, + _("Can't seek to image offset -- end-of-file probably encountered")); + return NULL; + } + + pbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, (hdr->cmap_bpp == 32), 8, + LE16(hdr->width), LE16(hdr->height)); + if (!pbuf) { + g_set_error(err, GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, + _("Can't allocate pixbuf")); + return NULL; + } + pbuf->destroy_fn = free_buffer; + pbuf->destroy_fn_data = NULL; + p = pbuf->pixels; + + if (rle) { + n = count = 0; + for (; n < pbuf->width * pbuf->height;) { + if (!fread_check(&tag, 1, 1, f, err)) { + gdk_pixbuf_unref(pbuf); + return NULL; + } + if (tag & 0x80) { + count = (tag & 0x7f) + 1; + n += count; + if (!fread_check(&color, 1, 1, f, err)) { + gdk_pixbuf_unref(pbuf); + return NULL; + } + for (; count; count--) { + *p++ = cmap->cols[color].r; + *p++ = cmap->cols[color].g; + *p++ = cmap->cols[color].b; + if (hdr->cmap_bpp == 32) + *p++ = cmap->cols[color].a; + } + } else { + count = tag + 1; + n += count; + for (; count; count--) { + if (!fread_check(&color, 1, 1, f, err)) { + gdk_pixbuf_unref(pbuf); + return NULL; + } + *p++ = cmap->cols[color].r; + *p++ = cmap->cols[color].g; + *p++ = cmap->cols[color].b; + if (hdr->cmap_bpp == 32) + *p++ = cmap->cols[color].a; + } + } + } + } else { + for (n = 0; n < pbuf->width * pbuf->height; n++) { + if (!fread_check(&color, 1, 1, f, err)) { + gdk_pixbuf_unref(pbuf); + return NULL; + } + *p++ = cmap->cols[color].r; + *p++ = cmap->cols[color].g; + *p++ = cmap->cols[color].b; + if (hdr->cmap_bpp == 32) + *p++ = cmap->cols[color].a; + } + } + + return pbuf; +} + +static void swap_channels_pixbuf(GdkPixbuf *pbuf) +{ + guchar *p, swap; + glong n; + + p = pbuf->pixels; + for (n = 0; n < pbuf->width * pbuf->height; n++) { + swap = p[0]; + p[0] = p[2]; + p[2] = swap; + p += pbuf->n_channels; + } +} + +static GdkPixbuf *get_image_truecolor(FILE *f, TGAHeader *hdr, + gboolean rle, GError **err) +{ + GdkPixbuf *pbuf; + guchar *p, tag; + glong n, image_offset; + guint32 pixel; + guint count; + + image_offset = sizeof(TGAHeader) + hdr->infolen; + /* A truecolor image shouldn't actually have a colormap. */ + if (hdr->has_cmap) + image_offset += LE16(hdr->cmap_n_colors) * ((hdr->cmap_bpp + 7) >> 3); + if (!fseek_check(f, image_offset, SEEK_SET, err)) + return NULL; + + pbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, (hdr->bpp == 32), 8, + LE16(hdr->width), LE16(hdr->height)); + if (!pbuf) { + g_set_error(err, GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, + _("Can't allocate pixbuf")); + return NULL; + } + pbuf->destroy_fn = free_buffer; + pbuf->destroy_fn_data = NULL; + p = pbuf->pixels; + + if (rle) { + n = count = 0; + for (; n < pbuf->width * pbuf->height;) { + if (!fread_check(&tag, 1, 1, f, err)) { + gdk_pixbuf_unref(pbuf); + return NULL; + } + if (tag & 0x80) { + count = (tag & 0x7f) + 1; + n += count; + if (!fread_check(&pixel, pbuf->n_channels, 1, f, err)) { + gdk_pixbuf_unref(pbuf); + return NULL; + } + for (; count; count--) { + g_memmove(p, &pixel, pbuf->n_channels); + p += pbuf->n_channels; + } + } else { + count = tag + 1; + n += count; + if (!fread_check(p, pbuf->n_channels * count, 1, f, err)) { + gdk_pixbuf_unref(pbuf); + return NULL; + } + p += pbuf->n_channels * count; + } + } + } else { + if (!fread_check(p, pbuf->rowstride * pbuf->height, 1, f, err)) { + gdk_pixbuf_unref(pbuf); + return NULL; + } + } + + swap_channels_pixbuf(pbuf); + return pbuf; +} + +static GdkPixbuf *get_image_grayscale(FILE *f, TGAHeader *hdr, + gboolean rle, GError **err) +{ + GdkPixbuf *pbuf; + glong n, image_offset; + guchar *p, color, tag; + guint count; + + image_offset = sizeof(TGAHeader) + hdr->infolen; + /* A grayscale image shouldn't actually have a colormap. */ + if (hdr->has_cmap) + image_offset += LE16(hdr->cmap_n_colors) * ((hdr->cmap_bpp + 7) >> 3); + if (!fseek_check(f, image_offset, SEEK_SET, err)) + return NULL; + + pbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, + LE16(hdr->width), LE16(hdr->height)); + if (!pbuf) { + g_set_error(err, GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, + _("Can't allocate pixbuf")); + return NULL; + } + pbuf->destroy_fn = free_buffer; + pbuf->destroy_fn_data = NULL; + p = pbuf->pixels; + + if (rle) { + n = count = 0; + for (; n < pbuf->width * pbuf->height;) { + if (!fread_check(&tag, 1, 1, f, err)) { + gdk_pixbuf_unref(pbuf); + return NULL; + } + if (tag & 0x80) { + count = (tag & 0x7f) + 1; + n += count; + if (!fread_check(&color, 1, 1, f, err)) { + gdk_pixbuf_unref(pbuf); + return NULL; + } + for (; count; count--) { + p[0] = p[1] = p[2] = color; + p += 3; + } + } else { + count = tag + 1; + n += count; + for (; count; count--) { + if (!fread_check(&color, 1, 1, f, err)) { + gdk_pixbuf_unref(pbuf); + return NULL; + } + p[0] = p[1] = p[2] = color; + p += 3; + } + } + } + } else { + for (n = 0; n < pbuf->width * pbuf->height; n++) { + if (!fread_check(&color, 1, 1, f, err)) { + gdk_pixbuf_unref(pbuf); + return NULL; + } + p[0] = p[1] = p[2] = color; + p += 3; + } + } + + return pbuf; +} + +static GdkPixbuf *gdk_pixbuf__tga_load(FILE *f, GError **err) +{ + TGAHeader *hdr; + TGAColormap *cmap; + GdkPixbuf *pbuf; + + cmap = NULL; + hdr = get_header_from_file(f, err); + if (!hdr) + return NULL; + if ((hdr->flags & TGA_INTERLEAVE_MASK) != TGA_INTERLEAVE_NONE || + hdr->flags & TGA_ORIGIN_RIGHT || hdr->flags & TGA_ORIGIN_LOWER) { + g_set_error(err, GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_UNKNOWN_TYPE, + _("Unsupported TGA image type")); + g_free(hdr); + return NULL; + } + + if (hdr->has_cmap && ((hdr->type == TGA_TYPE_PSEUDOCOLOR) || + (hdr->type == TGA_TYPE_RLE_PSEUDOCOLOR))) { + cmap = get_colormap_from_file(f, hdr, err); + if (!cmap) { + g_free(hdr); + return NULL; + } + } + + if (hdr->type == TGA_TYPE_PSEUDOCOLOR) + pbuf = get_image_pseudocolor(f, hdr, cmap, FALSE, err); + else if (hdr->type == TGA_TYPE_RLE_PSEUDOCOLOR) + pbuf = get_image_pseudocolor(f, hdr, cmap, TRUE, err); + else if (hdr->type == TGA_TYPE_TRUECOLOR) + pbuf = get_image_truecolor(f, hdr, FALSE, err); + else if (hdr->type == TGA_TYPE_RLE_TRUECOLOR) + pbuf = get_image_truecolor(f, hdr, TRUE, err); + else if (hdr->type == TGA_TYPE_GRAYSCALE) + pbuf = get_image_grayscale(f, hdr, FALSE, err); + else if (hdr->type == TGA_TYPE_RLE_GRAYSCALE) + pbuf = get_image_grayscale(f, hdr, TRUE, err); + else { + g_set_error(err, GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_UNKNOWN_TYPE, + _("Unsupported TGA image type")); + pbuf = NULL; + } + + if (cmap) { + g_free(cmap->cols); + g_free(cmap); + } + g_free(hdr); + + return pbuf; +} + +void +gdk_pixbuf__tga_fill_vtable (GdkPixbufModule *module) +{ + module->load = gdk_pixbuf__tga_load; + module->begin_load = gdk_pixbuf__tga_begin_load; + module->stop_load = gdk_pixbuf__tga_stop_load; + module->load_increment = gdk_pixbuf__tga_load_increment; +} diff --git a/gdk-pixbuf/pixbufloader_tga.def b/gdk-pixbuf/pixbufloader_tga.def new file mode 100644 index 0000000000..1505585669 --- /dev/null +++ b/gdk-pixbuf/pixbufloader_tga.def @@ -0,0 +1,2 @@ +EXPORTS + gdk_pixbuf__tga_fill_vtable |