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 module doesn't currently provide support for TGA images where the
27 * order of the pixels isn't left-to-right and top-to-bottom. I plan to
28 * add support for those files as soon as I get one of them. I haven't
29 * run into one yet. (And I don't seem to be able to create it with GIMP.)
31 * - The TGAFooter isn't present in all TGA files. In fact, there's an older
32 * format specification, still in use, which doesn't cover the TGAFooter.
33 * Actually, most TGA files I have are of the older type. Anyway I put the
34 * struct declaration here for completeness.
36 * - Error handling was designed to be very paranoid.
42 #include "gdk-pixbuf-private.h"
43 #include "gdk-pixbuf-io.h"
47 #define TGA_INTERLEAVE_MASK 0xc0
48 #define TGA_INTERLEAVE_NONE 0x00
49 #define TGA_INTERLEAVE_2WAY 0x40
50 #define TGA_INTERLEAVE_4WAY 0x80
52 #define TGA_ORIGIN_MASK 0x30
53 #define TGA_ORIGIN_RIGHT 0x10
54 #define TGA_ORIGIN_UPPER 0x20
58 TGA_TYPE_PSEUDOCOLOR = 1,
59 TGA_TYPE_TRUECOLOR = 2,
60 TGA_TYPE_GRAYSCALE = 3,
61 TGA_TYPE_RLE_PSEUDOCOLOR = 9,
62 TGA_TYPE_RLE_TRUECOLOR = 10,
63 TGA_TYPE_RLE_GRAYSCALE = 11
66 #define LE16(p) ((p)[0] + ((p)[1] << 8))
68 typedef struct _IOBuffer IOBuffer;
70 typedef struct _TGAHeader TGAHeader;
71 typedef struct _TGAFooter TGAFooter;
73 typedef struct _TGAColormap TGAColormap;
74 typedef struct _TGAColor TGAColor;
76 typedef struct _TGAContext TGAContext;
84 guint8 cmap_n_colors[2];
98 guint32 extension_area_offset;
99 guint32 developer_directory_offset;
101 /* Standard TGA signature, "TRUEVISION-XFILE.\0". */
111 struct _TGAColormap {
123 guint completed_lines;
124 gboolean run_length_encoded;
131 guint pbuf_bytes_done;
136 gboolean skipped_info;
140 GdkPixbufModuleSizeFunc sfunc;
141 GdkPixbufModulePreparedFunc pfunc;
142 GdkPixbufModuleUpdatedFunc ufunc;
151 static IOBuffer *io_buffer_new(GError **err)
154 buffer = g_try_malloc(sizeof(IOBuffer));
156 g_set_error(err, GDK_PIXBUF_ERROR,
157 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
158 _("Can't allocate memory for IOBuffer struct"));
166 static IOBuffer *io_buffer_append(IOBuffer *buffer,
167 const guchar *data, guint len,
173 buffer->data = g_try_malloc(len);
175 g_set_error(err, GDK_PIXBUF_ERROR,
176 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
177 _("Can't allocate memory for IOBuffer data"));
181 g_memmove(buffer->data, data, len);
184 guchar *tmp = g_try_realloc (buffer->data, buffer->size + len);
186 g_set_error(err, GDK_PIXBUF_ERROR,
187 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
188 _("Can't realloc IOBuffer data"));
193 g_memmove(&buffer->data[buffer->size], data, len);
199 static IOBuffer *io_buffer_free_segment(IOBuffer *buffer,
203 g_return_val_if_fail(buffer != NULL, NULL);
204 g_return_val_if_fail(buffer->data != NULL, NULL);
205 if (count == buffer->size) {
206 g_free(buffer->data);
213 new_size = buffer->size - count;
214 new_buf = g_try_malloc(new_size);
216 g_set_error(err, GDK_PIXBUF_ERROR,
217 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
218 _("Can't allocate temporary IOBuffer data"));
219 g_free(buffer->data);
224 g_memmove(new_buf, &buffer->data[count], new_size);
225 g_free(buffer->data);
226 buffer->data = new_buf;
227 buffer->size = new_size;
232 static void io_buffer_free(IOBuffer *buffer)
234 g_return_if_fail(buffer != NULL);
236 g_free(buffer->data);
240 static void free_buffer(guchar *pixels, gpointer data)
245 static GdkPixbuf *get_contiguous_pixbuf (guint width,
250 guint channels, rowstride, bytes;
257 rowstride = width * channels;
259 if (rowstride / channels != width)
262 bytes = height * rowstride;
264 if (bytes / rowstride != height)
267 pixels = g_try_malloc (bytes);
272 return gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, has_alpha, 8,
273 width, height, rowstride, free_buffer, NULL);
276 static void pixbuf_flip_row (GdkPixbuf *pixbuf, guchar *ph)
283 s = p + pixbuf->n_channels * (pixbuf->width - 1);
285 for (count = pixbuf->n_channels; count > 0; count--, p++, s++) {
290 s -= 2 * pixbuf->n_channels;
294 static void pixbuf_flip_vertically (GdkPixbuf *pixbuf)
296 guchar *ph, *sh, *p, *s;
301 sh = pixbuf->pixels + pixbuf->height*pixbuf->rowstride;
302 while (ph < sh - pixbuf->rowstride) {
304 s = sh - pixbuf->rowstride;
305 for (count = pixbuf->n_channels * pixbuf->width; count > 0; count--, p++, s++) {
310 sh -= pixbuf->rowstride;
311 ph += pixbuf->rowstride;
315 static gboolean fill_in_context(TGAContext *ctx, GError **err)
320 g_return_val_if_fail(ctx != NULL, FALSE);
322 ctx->run_length_encoded =
323 ((ctx->hdr->type == TGA_TYPE_RLE_PSEUDOCOLOR)
324 || (ctx->hdr->type == TGA_TYPE_RLE_TRUECOLOR)
325 || (ctx->hdr->type == TGA_TYPE_RLE_GRAYSCALE));
327 if (ctx->hdr->has_cmap)
328 ctx->cmap_size = ((ctx->hdr->cmap_bpp + 7) >> 3) *
329 LE16(ctx->hdr->cmap_n_colors);
331 alpha = ((ctx->hdr->bpp == 16) ||
332 (ctx->hdr->bpp == 32) ||
333 (ctx->hdr->has_cmap && (ctx->hdr->cmap_bpp == 32)));
335 w = LE16(ctx->hdr->width);
336 h = LE16(ctx->hdr->height);
342 (*ctx->sfunc) (&wi, &hi, ctx->udata);
344 if (wi == 0 || hi == 0)
348 ctx->pbuf = get_contiguous_pixbuf (w, h, alpha);
351 g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
352 _("Can't allocate new pixbuf"));
356 ctx->pbuf_bytes = ctx->pbuf->rowstride * ctx->pbuf->height;
357 if (ctx->hdr->flags & TGA_ORIGIN_UPPER || ctx->run_length_encoded)
358 ctx->pptr = ctx->pbuf->pixels;
360 ctx->pptr = ctx->pbuf->pixels + (ctx->pbuf->height - 1)*ctx->pbuf->rowstride;
362 if (ctx->hdr->type == TGA_TYPE_PSEUDOCOLOR)
363 ctx->rowstride = ctx->pbuf->width;
364 else if (ctx->hdr->type == TGA_TYPE_GRAYSCALE)
365 ctx->rowstride = (alpha ? ctx->pbuf->width * 2 : ctx->pbuf->width);
366 else if (ctx->hdr->type == TGA_TYPE_TRUECOLOR)
367 ctx->rowstride = ctx->pbuf->rowstride;
369 ctx->completed_lines = 0;
373 static void parse_data_for_row_pseudocolor(TGAContext *ctx)
375 guchar *s = ctx->in->data;
376 guint upper_bound = ctx->pbuf->width;
377 guchar *p = ctx->pptr;
379 for (; upper_bound; upper_bound--, s++) {
380 *p++ = ctx->cmap->cols[*s].r;
381 *p++ = ctx->cmap->cols[*s].g;
382 *p++ = ctx->cmap->cols[*s].b;
383 if (ctx->hdr->cmap_bpp == 32)
384 *p++ = ctx->cmap->cols[*s].a;
388 static void swap_channels(TGAContext *ctx)
392 guchar *p = ctx->pptr;
393 for (count = ctx->pbuf->width; count; count--) {
397 p += ctx->pbuf->n_channels;
401 static void parse_data_for_row_truecolor(TGAContext *ctx)
403 g_memmove(ctx->pptr, ctx->in->data, ctx->pbuf->rowstride);
407 static void parse_data_for_row_grayscale(TGAContext *ctx)
409 guchar *s = ctx->in->data;
410 guint upper_bound = ctx->pbuf->width;
412 guchar *p = ctx->pptr;
413 for (; upper_bound; upper_bound--) {
414 p[0] = p[1] = p[2] = *s++;
415 if (ctx->pbuf->n_channels == 4)
417 p += ctx->pbuf->n_channels;
421 static gboolean parse_data_for_row(TGAContext *ctx, GError **err)
425 if (ctx->hdr->type == TGA_TYPE_PSEUDOCOLOR)
426 parse_data_for_row_pseudocolor(ctx);
427 else if (ctx->hdr->type == TGA_TYPE_TRUECOLOR)
428 parse_data_for_row_truecolor(ctx);
429 else if (ctx->hdr->type == TGA_TYPE_GRAYSCALE)
430 parse_data_for_row_grayscale(ctx);
432 if (ctx->hdr->flags & TGA_ORIGIN_RIGHT)
433 pixbuf_flip_row (ctx->pbuf, ctx->pptr);
434 if (ctx->hdr->flags & TGA_ORIGIN_UPPER)
435 ctx->pptr += ctx->pbuf->rowstride;
437 ctx->pptr -= ctx->pbuf->rowstride;
438 ctx->pbuf_bytes_done += ctx->pbuf->rowstride;
439 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
442 ctx->in = io_buffer_free_segment(ctx->in, ctx->rowstride, err);
445 row = (ctx->pptr - ctx->pbuf->pixels) / ctx->pbuf->rowstride - 1;
447 (*ctx->ufunc) (ctx->pbuf, 0, row, ctx->pbuf->width, 1, ctx->udata);
451 static void write_rle_data(TGAContext *ctx, TGAColor *color, guint *rle_count)
453 for (; *rle_count; (*rle_count)--) {
454 g_memmove(ctx->pptr, (guchar *) color, ctx->pbuf->n_channels);
455 ctx->pptr += ctx->pbuf->n_channels;
456 ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
457 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
462 static guint parse_rle_data_pseudocolor(TGAContext *ctx)
464 guint rle_num, raw_num;
468 g_return_val_if_fail(ctx->in->size > 0, 0);
471 for (n = 0; n < ctx->in->size; ) {
475 if (n == ctx->in->size) {
478 rle_num = (tag & 0x7f) + 1;
479 write_rle_data(ctx, &ctx->cmap->cols[*s], &rle_num);
481 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
488 if (n + raw_num >= ctx->in->size) {
491 for (; raw_num; raw_num--) {
493 ctx->cmap->cols[*s].r;
495 ctx->cmap->cols[*s].g;
497 ctx->cmap->cols[*s].b;
498 if (ctx->pbuf->n_channels == 4)
499 *ctx->pptr++ = ctx->cmap->cols[*s].a;
501 ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
502 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
511 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
516 static guint parse_rle_data_truecolor(TGAContext *ctx)
519 guint rle_num, raw_num;
523 g_return_val_if_fail(ctx->in->size > 0, 0);
526 for (n = 0; n < ctx->in->size; ) {
530 if (n + ctx->pbuf->n_channels >= ctx->in->size) {
533 rle_num = (tag & 0x7f) + 1;
537 if (ctx->hdr->bpp == 32)
539 n += ctx->pbuf->n_channels;
540 write_rle_data(ctx, &col, &rle_num);
541 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
548 if (n + (raw_num * ctx->pbuf->n_channels) >= ctx->in->size) {
551 for (; raw_num; raw_num--) {
555 if (ctx->hdr->bpp == 32)
557 n += ctx->pbuf->n_channels;
558 ctx->pptr += ctx->pbuf->n_channels;
559 ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
560 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
566 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
573 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
578 static guint parse_rle_data_grayscale(TGAContext *ctx)
581 guint rle_num, raw_num;
585 g_return_val_if_fail(ctx->in->size > 0, 0);
588 for (n = 0; n < ctx->in->size; ) {
592 if (n + (ctx->pbuf->n_channels == 4 ? 2 : 1) >= ctx->in->size) {
595 rle_num = (tag & 0x7f) + 1;
596 tone.r = tone.g = tone.b = *s;
598 if (ctx->pbuf->n_channels == 4) {
602 write_rle_data(ctx, &tone, &rle_num);
603 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
610 if (n + raw_num * (ctx->pbuf->n_channels == 4 ? 2 : 1) >= ctx->in->size) {
613 for (; raw_num; raw_num--) {
614 ctx->pptr[0] = ctx->pptr[1] = ctx->pptr[2] = *s;
616 if (ctx->pbuf->n_channels == 4) {
620 ctx->pptr += ctx->pbuf->n_channels;
621 ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
622 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
630 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
635 static gboolean parse_rle_data(TGAContext *ctx, GError **err)
638 guint pbuf_count = 0;
639 guint bytes_done_before = ctx->pbuf_bytes_done;
640 if (ctx->hdr->type == TGA_TYPE_RLE_PSEUDOCOLOR) {
641 count = parse_rle_data_pseudocolor(ctx);
642 pbuf_count = count * ctx->pbuf->n_channels;
643 } else if (ctx->hdr->type == TGA_TYPE_RLE_TRUECOLOR) {
644 count = parse_rle_data_truecolor(ctx);
646 } else if (ctx->hdr->type == TGA_TYPE_RLE_GRAYSCALE) {
647 count = parse_rle_data_grayscale(ctx);
648 pbuf_count = count * (ctx->pbuf->n_channels == 4 ? 2 : 3);
651 if (ctx->hdr->flags & TGA_ORIGIN_RIGHT) {
652 guchar *row = ctx->pbuf->pixels + (bytes_done_before / ctx->pbuf->rowstride) * ctx->pbuf->rowstride;
653 guchar *row_after = ctx->pbuf->pixels + (ctx->pbuf_bytes_done / ctx->pbuf->rowstride) * ctx->pbuf->rowstride;
654 for (; row < row_after; row += ctx->pbuf->rowstride)
655 pixbuf_flip_row (ctx->pbuf, row);
658 ctx->in = io_buffer_free_segment(ctx->in, count, err);
663 /* FIXME doing the vertical flipping afterwards is not
664 * perfect, but doing it during the rle decoding in place
665 * is considerably more work.
667 if (!(ctx->hdr->flags & TGA_ORIGIN_UPPER))
668 pixbuf_flip_vertically (ctx->pbuf);
672 (*ctx->ufunc) (ctx->pbuf, 0, ctx->pbuf_bytes_done / ctx->pbuf->rowstride,
673 ctx->pbuf->width, pbuf_count / ctx->pbuf->rowstride,
680 static gboolean try_colormap(TGAContext *ctx, GError **err)
685 g_return_val_if_fail(ctx != NULL, FALSE);
686 g_return_val_if_fail(ctx->cmap_size > 0, TRUE);
688 ctx->cmap = g_try_malloc(sizeof(TGAColormap));
690 g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
691 _("Can't allocate colormap structure"));
694 ctx->cmap->size = LE16(ctx->hdr->cmap_n_colors);
695 ctx->cmap->cols = g_try_malloc(sizeof(TGAColor) * ctx->cmap->size);
696 if (!ctx->cmap->cols) {
697 g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
698 _("Can't allocate colormap entries"));
703 for (n = 0; n < ctx->cmap->size; n++) {
704 if ((ctx->hdr->cmap_bpp == 15) || (ctx->hdr->cmap_bpp == 16)) {
705 guint16 col = p[0] + (p[1] << 8);
706 ctx->cmap->cols[n].b = (col >> 7) & 0xf8;
707 ctx->cmap->cols[n].g = (col >> 2) & 0xf8;
708 ctx->cmap->cols[n].r = col << 3;
711 else if ((ctx->hdr->cmap_bpp == 24) || (ctx->hdr->cmap_bpp == 32)) {
712 ctx->cmap->cols[n].b = *p++;
713 ctx->cmap->cols[n].g = *p++;
714 ctx->cmap->cols[n].r = *p++;
715 if (ctx->hdr->cmap_bpp == 32)
716 ctx->cmap->cols[n].a = *p++;
718 g_set_error(err, GDK_PIXBUF_ERROR,
719 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
720 _("Unexpected bitdepth for colormap entries"));
724 ctx->in = io_buffer_free_segment(ctx->in, ctx->cmap_size, err);
730 static gboolean try_preload(TGAContext *ctx, GError **err)
733 if (ctx->in->size >= sizeof(TGAHeader)) {
734 ctx->hdr = g_try_malloc(sizeof(TGAHeader));
736 g_set_error(err, GDK_PIXBUF_ERROR,
737 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
738 _("Can't allocate TGA header memory"));
741 g_memmove(ctx->hdr, ctx->in->data, sizeof(TGAHeader));
742 ctx->in = io_buffer_free_segment(ctx->in, sizeof(TGAHeader), err);
744 g_print ("infolen %d "
750 "x %d y %d width %d height %d bpp %d "
755 LE16(ctx->hdr->cmap_start),
756 LE16(ctx->hdr->cmap_n_colors),
758 LE16(ctx->hdr->x_origin),
759 LE16(ctx->hdr->y_origin),
760 LE16(ctx->hdr->width),
761 LE16(ctx->hdr->height),
767 if (LE16(ctx->hdr->width) == 0 ||
768 LE16(ctx->hdr->height) == 0) {
769 g_set_error(err, GDK_PIXBUF_ERROR,
770 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
771 _("TGA image has invalid dimensions"));
774 if ((ctx->hdr->flags & TGA_INTERLEAVE_MASK) != TGA_INTERLEAVE_NONE) {
775 g_set_error(err, GDK_PIXBUF_ERROR,
776 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
777 _("TGA image type not supported"));
780 switch (ctx->hdr->type) {
781 case TGA_TYPE_PSEUDOCOLOR:
782 case TGA_TYPE_RLE_PSEUDOCOLOR:
783 if (ctx->hdr->bpp != 8) {
784 g_set_error(err, GDK_PIXBUF_ERROR,
785 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
786 _("TGA image type not supported"));
790 case TGA_TYPE_TRUECOLOR:
791 case TGA_TYPE_RLE_TRUECOLOR:
792 if (ctx->hdr->bpp != 24 &&
793 ctx->hdr->bpp != 32) {
794 g_set_error(err, GDK_PIXBUF_ERROR,
795 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
796 _("TGA image type not supported"));
800 case TGA_TYPE_GRAYSCALE:
801 case TGA_TYPE_RLE_GRAYSCALE:
802 if (ctx->hdr->bpp != 8 &&
803 ctx->hdr->bpp != 16) {
804 g_set_error(err, GDK_PIXBUF_ERROR,
805 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
806 _("TGA image type not supported"));
811 g_set_error(err, GDK_PIXBUF_ERROR,
812 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
813 _("TGA image type not supported"));
816 if (!fill_in_context(ctx, err))
822 if (!ctx->skipped_info) {
823 if (ctx->in->size >= ctx->hdr->infolen) {
824 ctx->in = io_buffer_free_segment(ctx->in, ctx->hdr->infolen, err);
827 ctx->skipped_info = TRUE;
832 if (ctx->hdr->has_cmap && !ctx->cmap) {
833 if (ctx->in->size >= ctx->cmap_size) {
834 if (!try_colormap(ctx, err))
840 if (!ctx->prepared) {
842 (*ctx->pfunc) (ctx->pbuf, NULL, ctx->udata);
843 ctx->prepared = TRUE;
845 /* We shouldn't get here anyway. */
849 static gpointer gdk_pixbuf__tga_begin_load(GdkPixbufModuleSizeFunc f0,
850 GdkPixbufModulePreparedFunc f1,
851 GdkPixbufModuleUpdatedFunc f2,
852 gpointer udata, GError **err)
856 ctx = g_try_malloc(sizeof(TGAContext));
858 g_set_error(err, GDK_PIXBUF_ERROR,
859 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
860 _("Can't allocate memory for TGA context struct"));
866 ctx->run_length_encoded = FALSE;
873 ctx->pbuf_bytes_done = 0;
876 ctx->in = io_buffer_new(err);
882 ctx->skipped_info = FALSE;
883 ctx->prepared = FALSE;
894 static gboolean gdk_pixbuf__tga_load_increment(gpointer data,
895 const guchar *buffer,
899 TGAContext *ctx = (TGAContext*) data;
900 g_return_val_if_fail(ctx != NULL, FALSE);
905 g_return_val_if_fail(buffer != NULL, TRUE);
906 ctx->in = io_buffer_append(ctx->in, buffer, size, err);
909 if (!ctx->prepared) {
910 if (!try_preload(ctx, err))
914 if (ctx->in->size == 0)
918 if (ctx->run_length_encoded) {
919 if (!parse_rle_data(ctx, err))
922 while (ctx->in->size >= ctx->rowstride) {
923 if (ctx->completed_lines >= ctx->pbuf->height) {
924 g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED,
925 _("Excess data in file"));
928 if (!parse_data_for_row(ctx, err))
930 ctx->completed_lines++;
937 static gboolean gdk_pixbuf__tga_stop_load(gpointer data, GError **err)
939 TGAContext *ctx = (TGAContext *) data;
940 g_return_val_if_fail(ctx != NULL, FALSE);
946 g_free (ctx->cmap->cols);
950 g_object_unref (ctx->pbuf);
951 if (ctx->in && ctx->in->size)
952 ctx->in = io_buffer_free_segment (ctx->in, ctx->in->size, err);
957 io_buffer_free (ctx->in);
963 MODULE_ENTRY (tga, fill_vtable) (GdkPixbufModule *module)
965 module->begin_load = gdk_pixbuf__tga_begin_load;
966 module->stop_load = gdk_pixbuf__tga_stop_load;
967 module->load_increment = gdk_pixbuf__tga_load_increment;
971 MODULE_ENTRY (tga, fill_info) (GdkPixbufFormat *info)
973 static GdkPixbufModulePattern signature[] = {
974 { " \x1\x1", "x ", 100 },
975 { " \x1\x9", "x ", 100 },
976 { " \x2", "xz ", 99 }, /* only 99 since .CUR also matches this */
977 { " \x3", "xz ", 100 },
978 { " \xa", "xz ", 100 },
979 { " \xb", "xz ", 100 },
982 static gchar * mime_types[] = {
986 static gchar * extensions[] = {
993 info->signature = signature;
994 info->description = N_("The Targa image format");
995 info->mime_types = mime_types;
996 info->extensions = extensions;