1 /* -*- mode: C; c-file-style: "linux" -*- */
3 * GdkPixbuf library - TGA image loader
4 * Copyright (C) 1999 Nicola Girardi <nikke@swlibero.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
24 * Some NOTES about the TGA loader (2001/06/07, nikke@swlibero.org)
26 * - The TGAFooter isn't present in all TGA files. In fact, there's an older
27 * format specification, still in use, which doesn't cover the TGAFooter.
28 * Actually, most TGA files I have are of the older type. Anyway I put the
29 * struct declaration here for completeness.
31 * - Error handling was designed to be very paranoid.
38 #include "gdk-pixbuf-private.h"
39 #include "gdk-pixbuf-io.h"
43 #define TGA_INTERLEAVE_MASK 0xc0
44 #define TGA_INTERLEAVE_NONE 0x00
45 #define TGA_INTERLEAVE_2WAY 0x40
46 #define TGA_INTERLEAVE_4WAY 0x80
48 #define TGA_ORIGIN_MASK 0x30
49 #define TGA_ORIGIN_RIGHT 0x10
50 #define TGA_ORIGIN_UPPER 0x20
54 TGA_TYPE_PSEUDOCOLOR = 1,
55 TGA_TYPE_TRUECOLOR = 2,
56 TGA_TYPE_GRAYSCALE = 3,
57 TGA_TYPE_RLE_PSEUDOCOLOR = 9,
58 TGA_TYPE_RLE_TRUECOLOR = 10,
59 TGA_TYPE_RLE_GRAYSCALE = 11
62 #define LE16(p) ((p)[0] + ((p)[1] << 8))
64 typedef struct _IOBuffer IOBuffer;
66 typedef struct _TGAHeader TGAHeader;
67 typedef struct _TGAFooter TGAFooter;
69 typedef struct _TGAColormap TGAColormap;
70 typedef struct _TGAColor TGAColor;
72 typedef struct _TGAContext TGAContext;
80 guint8 cmap_n_colors[2];
94 guint32 extension_area_offset;
95 guint32 developer_directory_offset;
97 /* Standard TGA signature, "TRUEVISION-XFILE.\0". */
107 struct _TGAColormap {
119 guint completed_lines;
120 gboolean run_length_encoded;
127 guint pbuf_bytes_done;
132 gboolean skipped_info;
136 GdkPixbufModuleSizeFunc sfunc;
137 GdkPixbufModulePreparedFunc pfunc;
138 GdkPixbufModuleUpdatedFunc ufunc;
147 static IOBuffer *io_buffer_new(GError **err)
150 buffer = g_try_malloc(sizeof(IOBuffer));
152 g_set_error(err, GDK_PIXBUF_ERROR,
153 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
154 _("Cannot allocate memory for IOBuffer struct"));
162 static IOBuffer *io_buffer_append(IOBuffer *buffer,
163 const guchar *data, guint len,
169 buffer->data = g_try_malloc(len);
171 g_set_error(err, GDK_PIXBUF_ERROR,
172 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
173 _("Cannot allocate memory for IOBuffer data"));
177 g_memmove(buffer->data, data, len);
180 guchar *tmp = g_try_realloc (buffer->data, buffer->size + len);
182 g_set_error(err, GDK_PIXBUF_ERROR,
183 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
184 _("Cannot realloc IOBuffer data"));
189 g_memmove(&buffer->data[buffer->size], data, len);
195 static IOBuffer *io_buffer_free_segment(IOBuffer *buffer,
199 g_return_val_if_fail(buffer != NULL, NULL);
200 g_return_val_if_fail(buffer->data != NULL, NULL);
201 if (count == buffer->size) {
202 g_free(buffer->data);
209 new_size = buffer->size - count;
210 new_buf = g_try_malloc(new_size);
212 g_set_error(err, GDK_PIXBUF_ERROR,
213 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
214 _("Cannot allocate temporary IOBuffer data"));
215 g_free(buffer->data);
220 g_memmove(new_buf, &buffer->data[count], new_size);
221 g_free(buffer->data);
222 buffer->data = new_buf;
223 buffer->size = new_size;
228 static void io_buffer_free(IOBuffer *buffer)
230 g_return_if_fail(buffer != NULL);
232 g_free(buffer->data);
236 static void free_buffer(guchar *pixels, gpointer data)
241 static GdkPixbuf *get_contiguous_pixbuf (guint width,
246 guint channels, rowstride, bytes;
253 rowstride = width * channels;
255 if (rowstride / channels != width)
258 bytes = height * rowstride;
260 if (bytes / rowstride != height)
263 pixels = g_try_malloc (bytes);
268 return gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, has_alpha, 8,
269 width, height, rowstride, free_buffer, NULL);
272 static void pixbuf_flip_row (GdkPixbuf *pixbuf, guchar *ph)
279 s = p + pixbuf->n_channels * (pixbuf->width - 1);
281 for (count = pixbuf->n_channels; count > 0; count--, p++, s++) {
286 s -= 2 * pixbuf->n_channels;
290 static void pixbuf_flip_vertically (GdkPixbuf *pixbuf)
292 guchar *ph, *sh, *p, *s;
297 sh = pixbuf->pixels + pixbuf->height*pixbuf->rowstride;
298 while (ph < sh - pixbuf->rowstride) {
300 s = sh - pixbuf->rowstride;
301 for (count = pixbuf->n_channels * pixbuf->width; count > 0; count--, p++, s++) {
306 sh -= pixbuf->rowstride;
307 ph += pixbuf->rowstride;
311 static gboolean fill_in_context(TGAContext *ctx, GError **err)
316 g_return_val_if_fail(ctx != NULL, FALSE);
318 ctx->run_length_encoded =
319 ((ctx->hdr->type == TGA_TYPE_RLE_PSEUDOCOLOR)
320 || (ctx->hdr->type == TGA_TYPE_RLE_TRUECOLOR)
321 || (ctx->hdr->type == TGA_TYPE_RLE_GRAYSCALE));
323 if (ctx->hdr->has_cmap)
324 ctx->cmap_size = ((ctx->hdr->cmap_bpp + 7) >> 3) *
325 LE16(ctx->hdr->cmap_n_colors);
327 alpha = ((ctx->hdr->bpp == 16) ||
328 (ctx->hdr->bpp == 32) ||
329 (ctx->hdr->has_cmap && (ctx->hdr->cmap_bpp == 32)));
331 w = LE16(ctx->hdr->width);
332 h = LE16(ctx->hdr->height);
338 (*ctx->sfunc) (&wi, &hi, ctx->udata);
340 if (wi == 0 || hi == 0)
344 ctx->pbuf = get_contiguous_pixbuf (w, h, alpha);
347 g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
348 _("Cannot allocate new pixbuf"));
352 ctx->pbuf_bytes = ctx->pbuf->rowstride * ctx->pbuf->height;
353 if (ctx->hdr->flags & TGA_ORIGIN_UPPER || ctx->run_length_encoded)
354 ctx->pptr = ctx->pbuf->pixels;
356 ctx->pptr = ctx->pbuf->pixels + (ctx->pbuf->height - 1)*ctx->pbuf->rowstride;
358 if (ctx->hdr->type == TGA_TYPE_PSEUDOCOLOR)
359 ctx->rowstride = ctx->pbuf->width;
360 else if (ctx->hdr->type == TGA_TYPE_GRAYSCALE)
361 ctx->rowstride = (alpha ? ctx->pbuf->width * 2 : ctx->pbuf->width);
362 else if (ctx->hdr->type == TGA_TYPE_TRUECOLOR)
363 ctx->rowstride = ctx->pbuf->rowstride;
365 ctx->completed_lines = 0;
369 static void parse_data_for_row_pseudocolor(TGAContext *ctx)
371 guchar *s = ctx->in->data;
372 guint upper_bound = ctx->pbuf->width;
373 guchar *p = ctx->pptr;
375 for (; upper_bound; upper_bound--, s++) {
376 *p++ = ctx->cmap->cols[*s].r;
377 *p++ = ctx->cmap->cols[*s].g;
378 *p++ = ctx->cmap->cols[*s].b;
379 if (ctx->hdr->cmap_bpp == 32)
380 *p++ = ctx->cmap->cols[*s].a;
384 static void swap_channels(TGAContext *ctx)
388 guchar *p = ctx->pptr;
389 for (count = ctx->pbuf->width; count; count--) {
393 p += ctx->pbuf->n_channels;
397 static void parse_data_for_row_truecolor(TGAContext *ctx)
399 g_memmove(ctx->pptr, ctx->in->data, ctx->pbuf->rowstride);
403 static void parse_data_for_row_grayscale(TGAContext *ctx)
405 guchar *s = ctx->in->data;
406 guint upper_bound = ctx->pbuf->width;
408 guchar *p = ctx->pptr;
409 for (; upper_bound; upper_bound--) {
410 p[0] = p[1] = p[2] = *s++;
411 if (ctx->pbuf->n_channels == 4)
413 p += ctx->pbuf->n_channels;
417 static gboolean parse_data_for_row(TGAContext *ctx, GError **err)
421 if (ctx->hdr->type == TGA_TYPE_PSEUDOCOLOR)
422 parse_data_for_row_pseudocolor(ctx);
423 else if (ctx->hdr->type == TGA_TYPE_TRUECOLOR)
424 parse_data_for_row_truecolor(ctx);
425 else if (ctx->hdr->type == TGA_TYPE_GRAYSCALE)
426 parse_data_for_row_grayscale(ctx);
428 if (ctx->hdr->flags & TGA_ORIGIN_RIGHT)
429 pixbuf_flip_row (ctx->pbuf, ctx->pptr);
430 if (ctx->hdr->flags & TGA_ORIGIN_UPPER)
431 ctx->pptr += ctx->pbuf->rowstride;
433 ctx->pptr -= ctx->pbuf->rowstride;
434 ctx->pbuf_bytes_done += ctx->pbuf->rowstride;
435 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
438 ctx->in = io_buffer_free_segment(ctx->in, ctx->rowstride, err);
441 row = (ctx->pptr - ctx->pbuf->pixels) / ctx->pbuf->rowstride - 1;
443 (*ctx->ufunc) (ctx->pbuf, 0, row, ctx->pbuf->width, 1, ctx->udata);
447 static void write_rle_data(TGAContext *ctx, TGAColor *color, guint *rle_count)
449 for (; *rle_count; (*rle_count)--) {
450 g_memmove(ctx->pptr, (guchar *) color, ctx->pbuf->n_channels);
451 ctx->pptr += ctx->pbuf->n_channels;
452 ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
453 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
458 static guint parse_rle_data_pseudocolor(TGAContext *ctx)
460 guint rle_num, raw_num;
464 g_return_val_if_fail(ctx->in->size > 0, 0);
467 for (n = 0; n < ctx->in->size; ) {
471 if (n == ctx->in->size) {
474 rle_num = (tag & 0x7f) + 1;
475 write_rle_data(ctx, &ctx->cmap->cols[*s], &rle_num);
477 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
484 if (n + raw_num >= ctx->in->size) {
487 for (; raw_num; raw_num--) {
489 ctx->cmap->cols[*s].r;
491 ctx->cmap->cols[*s].g;
493 ctx->cmap->cols[*s].b;
494 if (ctx->pbuf->n_channels == 4)
495 *ctx->pptr++ = ctx->cmap->cols[*s].a;
497 ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
498 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
507 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
513 static guint parse_rle_data_truecolor(TGAContext *ctx)
516 guint rle_num, raw_num;
520 g_return_val_if_fail(ctx->in->size > 0, 0);
523 for (n = 0; n < ctx->in->size; ) {
527 if (n + ctx->pbuf->n_channels >= ctx->in->size) {
530 rle_num = (tag & 0x7f) + 1;
534 if (ctx->hdr->bpp == 32)
536 n += ctx->pbuf->n_channels;
537 write_rle_data(ctx, &col, &rle_num);
538 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
545 if (n + (raw_num * ctx->pbuf->n_channels) >= ctx->in->size) {
548 for (; raw_num; raw_num--) {
552 if (ctx->hdr->bpp == 32)
554 n += ctx->pbuf->n_channels;
555 ctx->pptr += ctx->pbuf->n_channels;
556 ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
557 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
563 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
570 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
575 static guint parse_rle_data_grayscale(TGAContext *ctx)
578 guint rle_num, raw_num;
582 g_return_val_if_fail(ctx->in->size > 0, 0);
585 for (n = 0; n < ctx->in->size; ) {
589 if (n + (ctx->pbuf->n_channels == 4 ? 2 : 1) >= ctx->in->size) {
592 rle_num = (tag & 0x7f) + 1;
593 tone.r = tone.g = tone.b = *s;
595 if (ctx->pbuf->n_channels == 4) {
599 write_rle_data(ctx, &tone, &rle_num);
600 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
607 if (n + raw_num * (ctx->pbuf->n_channels == 4 ? 2 : 1) >= ctx->in->size) {
610 for (; raw_num; raw_num--) {
611 ctx->pptr[0] = ctx->pptr[1] = ctx->pptr[2] = *s;
613 if (ctx->pbuf->n_channels == 4) {
617 ctx->pptr += ctx->pbuf->n_channels;
618 ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
619 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
627 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
632 static gboolean parse_rle_data(TGAContext *ctx, GError **err)
636 guint bytes_done_before = ctx->pbuf_bytes_done;
638 if (ctx->hdr->type == TGA_TYPE_RLE_PSEUDOCOLOR)
639 count = parse_rle_data_pseudocolor(ctx);
640 else if (ctx->hdr->type == TGA_TYPE_RLE_TRUECOLOR)
641 count = parse_rle_data_truecolor(ctx);
642 else if (ctx->hdr->type == TGA_TYPE_RLE_GRAYSCALE)
643 count = parse_rle_data_grayscale(ctx);
645 if (ctx->hdr->flags & TGA_ORIGIN_RIGHT) {
646 guchar *row = ctx->pbuf->pixels + (bytes_done_before / ctx->pbuf->rowstride) * ctx->pbuf->rowstride;
647 guchar *row_after = ctx->pbuf->pixels + (ctx->pbuf_bytes_done / ctx->pbuf->rowstride) * ctx->pbuf->rowstride;
648 for (; row < row_after; row += ctx->pbuf->rowstride)
649 pixbuf_flip_row (ctx->pbuf, row);
652 ctx->in = io_buffer_free_segment(ctx->in, count, err);
657 /* FIXME doing the vertical flipping afterwards is not
658 * perfect, but doing it during the rle decoding in place
659 * is considerably more work.
661 if (!(ctx->hdr->flags & TGA_ORIGIN_UPPER)) {
662 pixbuf_flip_vertically (ctx->pbuf);
663 ctx->hdr->flags |= TGA_ORIGIN_UPPER;
668 rows = ctx->pbuf_bytes_done / ctx->pbuf->rowstride - bytes_done_before / ctx->pbuf->rowstride;
670 (*ctx->ufunc) (ctx->pbuf, 0, bytes_done_before / ctx->pbuf->rowstride,
671 ctx->pbuf->width, rows,
677 static gboolean try_colormap(TGAContext *ctx, GError **err)
682 g_return_val_if_fail(ctx != NULL, FALSE);
683 g_return_val_if_fail(ctx->cmap_size > 0, TRUE);
685 ctx->cmap = g_try_malloc(sizeof(TGAColormap));
687 g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
688 _("Cannot allocate colormap structure"));
691 ctx->cmap->size = LE16(ctx->hdr->cmap_n_colors);
692 ctx->cmap->cols = g_try_malloc(sizeof(TGAColor) * ctx->cmap->size);
693 if (!ctx->cmap->cols) {
694 g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
695 _("Cannot allocate colormap entries"));
700 for (n = 0; n < ctx->cmap->size; n++) {
701 if ((ctx->hdr->cmap_bpp == 15) || (ctx->hdr->cmap_bpp == 16)) {
702 guint16 col = p[0] + (p[1] << 8);
703 ctx->cmap->cols[n].b = (col >> 7) & 0xf8;
704 ctx->cmap->cols[n].g = (col >> 2) & 0xf8;
705 ctx->cmap->cols[n].r = col << 3;
708 else if ((ctx->hdr->cmap_bpp == 24) || (ctx->hdr->cmap_bpp == 32)) {
709 ctx->cmap->cols[n].b = *p++;
710 ctx->cmap->cols[n].g = *p++;
711 ctx->cmap->cols[n].r = *p++;
712 if (ctx->hdr->cmap_bpp == 32)
713 ctx->cmap->cols[n].a = *p++;
715 g_set_error(err, GDK_PIXBUF_ERROR,
716 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
717 _("Unexpected bitdepth for colormap entries"));
721 ctx->in = io_buffer_free_segment(ctx->in, ctx->cmap_size, err);
727 static gboolean try_preload(TGAContext *ctx, GError **err)
730 if (ctx->in->size >= sizeof(TGAHeader)) {
731 ctx->hdr = g_try_malloc(sizeof(TGAHeader));
733 g_set_error(err, GDK_PIXBUF_ERROR,
734 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
735 _("Cannot allocate TGA header memory"));
738 g_memmove(ctx->hdr, ctx->in->data, sizeof(TGAHeader));
739 ctx->in = io_buffer_free_segment(ctx->in, sizeof(TGAHeader), err);
741 g_print ("infolen %d "
747 "x %d y %d width %d height %d bpp %d "
752 LE16(ctx->hdr->cmap_start),
753 LE16(ctx->hdr->cmap_n_colors),
755 LE16(ctx->hdr->x_origin),
756 LE16(ctx->hdr->y_origin),
757 LE16(ctx->hdr->width),
758 LE16(ctx->hdr->height),
764 if (LE16(ctx->hdr->width) == 0 ||
765 LE16(ctx->hdr->height) == 0) {
766 g_set_error(err, GDK_PIXBUF_ERROR,
767 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
768 _("TGA image has invalid dimensions"));
771 if ((ctx->hdr->flags & TGA_INTERLEAVE_MASK) != TGA_INTERLEAVE_NONE) {
772 g_set_error(err, GDK_PIXBUF_ERROR,
773 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
774 _("TGA image type not supported"));
777 switch (ctx->hdr->type) {
778 case TGA_TYPE_PSEUDOCOLOR:
779 case TGA_TYPE_RLE_PSEUDOCOLOR:
780 if (ctx->hdr->bpp != 8) {
781 g_set_error(err, GDK_PIXBUF_ERROR,
782 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
783 _("TGA image type not supported"));
787 case TGA_TYPE_TRUECOLOR:
788 case TGA_TYPE_RLE_TRUECOLOR:
789 if (ctx->hdr->bpp != 24 &&
790 ctx->hdr->bpp != 32) {
791 g_set_error(err, GDK_PIXBUF_ERROR,
792 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
793 _("TGA image type not supported"));
797 case TGA_TYPE_GRAYSCALE:
798 case TGA_TYPE_RLE_GRAYSCALE:
799 if (ctx->hdr->bpp != 8 &&
800 ctx->hdr->bpp != 16) {
801 g_set_error(err, GDK_PIXBUF_ERROR,
802 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
803 _("TGA image type not supported"));
808 g_set_error(err, GDK_PIXBUF_ERROR,
809 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
810 _("TGA image type not supported"));
813 if (!fill_in_context(ctx, err))
819 if (!ctx->skipped_info) {
820 if (ctx->in->size >= ctx->hdr->infolen) {
821 ctx->in = io_buffer_free_segment(ctx->in, ctx->hdr->infolen, err);
824 ctx->skipped_info = TRUE;
829 if (ctx->hdr->has_cmap && !ctx->cmap) {
830 if (ctx->in->size >= ctx->cmap_size) {
831 if (!try_colormap(ctx, err))
837 if (!ctx->prepared) {
839 (*ctx->pfunc) (ctx->pbuf, NULL, ctx->udata);
840 ctx->prepared = TRUE;
842 /* We shouldn't get here anyway. */
846 static gpointer gdk_pixbuf__tga_begin_load(GdkPixbufModuleSizeFunc f0,
847 GdkPixbufModulePreparedFunc f1,
848 GdkPixbufModuleUpdatedFunc f2,
849 gpointer udata, GError **err)
853 ctx = g_try_malloc(sizeof(TGAContext));
855 g_set_error(err, GDK_PIXBUF_ERROR,
856 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
857 _("Cannot allocate memory for TGA context struct"));
863 ctx->run_length_encoded = FALSE;
870 ctx->pbuf_bytes_done = 0;
873 ctx->in = io_buffer_new(err);
879 ctx->skipped_info = FALSE;
880 ctx->prepared = FALSE;
891 static gboolean gdk_pixbuf__tga_load_increment(gpointer data,
892 const guchar *buffer,
896 TGAContext *ctx = (TGAContext*) data;
897 g_return_val_if_fail(ctx != NULL, FALSE);
902 g_return_val_if_fail(buffer != NULL, TRUE);
903 ctx->in = io_buffer_append(ctx->in, buffer, size, err);
906 if (!ctx->prepared) {
907 if (!try_preload(ctx, err))
911 if (ctx->in->size == 0)
915 if (ctx->run_length_encoded) {
916 if (!parse_rle_data(ctx, err))
919 while (ctx->in->size >= ctx->rowstride) {
920 if (ctx->completed_lines >= ctx->pbuf->height) {
921 g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED,
922 _("Excess data in file"));
925 if (!parse_data_for_row(ctx, err))
927 ctx->completed_lines++;
934 static gboolean gdk_pixbuf__tga_stop_load(gpointer data, GError **err)
936 TGAContext *ctx = (TGAContext *) data;
937 g_return_val_if_fail(ctx != NULL, FALSE);
939 if (!(ctx->hdr->flags & TGA_ORIGIN_UPPER) && ctx->run_length_encoded) {
940 pixbuf_flip_vertically (ctx->pbuf);
942 (*ctx->ufunc) (ctx->pbuf, 0, 0,
943 ctx->pbuf->width, ctx->pbuf->height,
950 g_free (ctx->cmap->cols);
954 g_object_unref (ctx->pbuf);
955 if (ctx->in && ctx->in->size)
956 ctx->in = io_buffer_free_segment (ctx->in, ctx->in->size, err);
961 io_buffer_free (ctx->in);
967 #define MODULE_ENTRY(type,function) function
969 #define MODULE_ENTRY(type,function) _gdk_pixbuf__ ## type ## _ ## function
973 MODULE_ENTRY (tga, fill_vtable) (GdkPixbufModule *module)
975 module->begin_load = gdk_pixbuf__tga_begin_load;
976 module->stop_load = gdk_pixbuf__tga_stop_load;
977 module->load_increment = gdk_pixbuf__tga_load_increment;
981 MODULE_ENTRY (tga, fill_info) (GdkPixbufFormat *info)
983 static GdkPixbufModulePattern signature[] = {
984 { " \x1\x1", "x ", 100 },
985 { " \x1\x9", "x ", 100 },
986 { " \x2", "xz ", 99 }, /* only 99 since .CUR also matches this */
987 { " \x3", "xz ", 100 },
988 { " \xa", "xz ", 100 },
989 { " \xb", "xz ", 100 },
992 static gchar * mime_types[] = {
996 static gchar * extensions[] = {
1003 info->signature = signature;
1004 info->description = N_("The Targa image format");
1005 info->mime_types = mime_types;
1006 info->extensions = extensions;
1007 info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
1008 info->license = "LGPL";