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_literal(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_literal(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_literal(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_literal(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);
231 g_free(buffer->data);
235 static void free_buffer(guchar *pixels, gpointer data)
240 static GdkPixbuf *get_contiguous_pixbuf (guint width,
245 guint channels, rowstride, bytes;
252 rowstride = width * channels;
254 if (rowstride / channels != width)
257 bytes = height * rowstride;
259 if (bytes / rowstride != height)
262 pixels = g_try_malloc (bytes);
267 return gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, has_alpha, 8,
268 width, height, rowstride, free_buffer, NULL);
271 static void pixbuf_flip_row (GdkPixbuf *pixbuf, guchar *ph)
278 s = p + pixbuf->n_channels * (pixbuf->width - 1);
280 for (count = pixbuf->n_channels; count > 0; count--, p++, s++) {
285 s -= 2 * pixbuf->n_channels;
289 static void pixbuf_flip_vertically (GdkPixbuf *pixbuf)
291 guchar *ph, *sh, *p, *s;
296 sh = pixbuf->pixels + pixbuf->height*pixbuf->rowstride;
297 while (ph < sh - pixbuf->rowstride) {
299 s = sh - pixbuf->rowstride;
300 for (count = pixbuf->n_channels * pixbuf->width; count > 0; count--, p++, s++) {
305 sh -= pixbuf->rowstride;
306 ph += pixbuf->rowstride;
310 static gboolean fill_in_context(TGAContext *ctx, GError **err)
315 g_return_val_if_fail(ctx != NULL, FALSE);
317 ctx->run_length_encoded =
318 ((ctx->hdr->type == TGA_TYPE_RLE_PSEUDOCOLOR)
319 || (ctx->hdr->type == TGA_TYPE_RLE_TRUECOLOR)
320 || (ctx->hdr->type == TGA_TYPE_RLE_GRAYSCALE));
322 if (ctx->hdr->has_cmap)
323 ctx->cmap_size = ((ctx->hdr->cmap_bpp + 7) >> 3) *
324 LE16(ctx->hdr->cmap_n_colors);
326 alpha = ((ctx->hdr->bpp == 16) ||
327 (ctx->hdr->bpp == 32) ||
328 (ctx->hdr->has_cmap && (ctx->hdr->cmap_bpp == 32)));
330 w = LE16(ctx->hdr->width);
331 h = LE16(ctx->hdr->height);
337 (*ctx->sfunc) (&wi, &hi, ctx->udata);
339 if (wi == 0 || hi == 0)
343 ctx->pbuf = get_contiguous_pixbuf (w, h, alpha);
346 g_set_error_literal(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
347 _("Cannot allocate new pixbuf"));
351 ctx->pbuf_bytes = ctx->pbuf->rowstride * ctx->pbuf->height;
352 if ((ctx->hdr->flags & TGA_ORIGIN_UPPER) || ctx->run_length_encoded)
353 ctx->pptr = ctx->pbuf->pixels;
355 ctx->pptr = ctx->pbuf->pixels + (ctx->pbuf->height - 1)*ctx->pbuf->rowstride;
357 if (ctx->hdr->type == TGA_TYPE_PSEUDOCOLOR)
358 ctx->rowstride = ctx->pbuf->width;
359 else if (ctx->hdr->type == TGA_TYPE_GRAYSCALE)
360 ctx->rowstride = (alpha ? ctx->pbuf->width * 2 : ctx->pbuf->width);
361 else if (ctx->hdr->type == TGA_TYPE_TRUECOLOR)
362 ctx->rowstride = ctx->pbuf->rowstride;
364 ctx->completed_lines = 0;
368 static void parse_data_for_row_pseudocolor(TGAContext *ctx)
370 guchar *s = ctx->in->data;
371 guint upper_bound = ctx->pbuf->width;
372 guchar *p = ctx->pptr;
374 for (; upper_bound; upper_bound--, s++) {
375 *p++ = ctx->cmap->cols[*s].r;
376 *p++ = ctx->cmap->cols[*s].g;
377 *p++ = ctx->cmap->cols[*s].b;
378 if (ctx->hdr->cmap_bpp == 32)
379 *p++ = ctx->cmap->cols[*s].a;
383 static void swap_channels(TGAContext *ctx)
387 guchar *p = ctx->pptr;
388 for (count = ctx->pbuf->width; count; count--) {
392 p += ctx->pbuf->n_channels;
396 static void parse_data_for_row_truecolor(TGAContext *ctx)
398 g_memmove(ctx->pptr, ctx->in->data, ctx->pbuf->rowstride);
402 static void parse_data_for_row_grayscale(TGAContext *ctx)
404 guchar *s = ctx->in->data;
405 guint upper_bound = ctx->pbuf->width;
407 guchar *p = ctx->pptr;
408 for (; upper_bound; upper_bound--) {
409 p[0] = p[1] = p[2] = *s++;
410 if (ctx->pbuf->n_channels == 4)
412 p += ctx->pbuf->n_channels;
416 static gboolean parse_data_for_row(TGAContext *ctx, GError **err)
420 if (ctx->hdr->type == TGA_TYPE_PSEUDOCOLOR)
421 parse_data_for_row_pseudocolor(ctx);
422 else if (ctx->hdr->type == TGA_TYPE_TRUECOLOR)
423 parse_data_for_row_truecolor(ctx);
424 else if (ctx->hdr->type == TGA_TYPE_GRAYSCALE)
425 parse_data_for_row_grayscale(ctx);
427 if (ctx->hdr->flags & TGA_ORIGIN_RIGHT)
428 pixbuf_flip_row (ctx->pbuf, ctx->pptr);
429 if (ctx->hdr->flags & TGA_ORIGIN_UPPER)
430 ctx->pptr += ctx->pbuf->rowstride;
432 ctx->pptr -= ctx->pbuf->rowstride;
433 ctx->pbuf_bytes_done += ctx->pbuf->rowstride;
434 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
437 ctx->in = io_buffer_free_segment(ctx->in, ctx->rowstride, err);
440 row = (ctx->pptr - ctx->pbuf->pixels) / ctx->pbuf->rowstride - 1;
442 (*ctx->ufunc) (ctx->pbuf, 0, row, ctx->pbuf->width, 1, ctx->udata);
446 static void write_rle_data(TGAContext *ctx, TGAColor *color, guint *rle_count)
448 for (; *rle_count; (*rle_count)--) {
449 g_memmove(ctx->pptr, (guchar *) color, ctx->pbuf->n_channels);
450 ctx->pptr += ctx->pbuf->n_channels;
451 ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
452 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
457 static guint parse_rle_data_pseudocolor(TGAContext *ctx)
459 guint rle_num, raw_num;
463 g_return_val_if_fail(ctx->in->size > 0, 0);
466 for (n = 0; n < ctx->in->size; ) {
470 if (n == ctx->in->size) {
473 rle_num = (tag & 0x7f) + 1;
474 write_rle_data(ctx, &ctx->cmap->cols[*s], &rle_num);
476 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
483 if (n + raw_num >= ctx->in->size) {
486 for (; raw_num; raw_num--) {
488 ctx->cmap->cols[*s].r;
490 ctx->cmap->cols[*s].g;
492 ctx->cmap->cols[*s].b;
493 if (ctx->pbuf->n_channels == 4)
494 *ctx->pptr++ = ctx->cmap->cols[*s].a;
496 ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
497 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
506 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
512 static guint parse_rle_data_truecolor(TGAContext *ctx)
515 guint rle_num, raw_num;
519 g_return_val_if_fail(ctx->in->size > 0, 0);
522 for (n = 0; n < ctx->in->size; ) {
526 if (n + ctx->pbuf->n_channels >= ctx->in->size) {
529 rle_num = (tag & 0x7f) + 1;
533 if (ctx->hdr->bpp == 32)
535 n += ctx->pbuf->n_channels;
536 write_rle_data(ctx, &col, &rle_num);
537 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
544 if (n + (raw_num * ctx->pbuf->n_channels) >= ctx->in->size) {
547 for (; raw_num; raw_num--) {
551 if (ctx->hdr->bpp == 32)
553 n += ctx->pbuf->n_channels;
554 ctx->pptr += ctx->pbuf->n_channels;
555 ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
556 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
562 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
569 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
574 static guint parse_rle_data_grayscale(TGAContext *ctx)
577 guint rle_num, raw_num;
581 g_return_val_if_fail(ctx->in->size > 0, 0);
584 for (n = 0; n < ctx->in->size; ) {
588 if (n + (ctx->pbuf->n_channels == 4 ? 2 : 1) >= ctx->in->size) {
591 rle_num = (tag & 0x7f) + 1;
592 tone.r = tone.g = tone.b = *s;
594 if (ctx->pbuf->n_channels == 4) {
598 write_rle_data(ctx, &tone, &rle_num);
599 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
606 if (n + raw_num * (ctx->pbuf->n_channels == 4 ? 2 : 1) >= ctx->in->size) {
609 for (; raw_num; raw_num--) {
610 ctx->pptr[0] = ctx->pptr[1] = ctx->pptr[2] = *s;
612 if (ctx->pbuf->n_channels == 4) {
616 ctx->pptr += ctx->pbuf->n_channels;
617 ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
618 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
626 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
631 static gboolean parse_rle_data(TGAContext *ctx, GError **err)
635 guint bytes_done_before = ctx->pbuf_bytes_done;
637 if (ctx->hdr->type == TGA_TYPE_RLE_PSEUDOCOLOR)
638 count = parse_rle_data_pseudocolor(ctx);
639 else if (ctx->hdr->type == TGA_TYPE_RLE_TRUECOLOR)
640 count = parse_rle_data_truecolor(ctx);
641 else if (ctx->hdr->type == TGA_TYPE_RLE_GRAYSCALE)
642 count = parse_rle_data_grayscale(ctx);
644 if (ctx->hdr->flags & TGA_ORIGIN_RIGHT) {
645 guchar *row = ctx->pbuf->pixels + (bytes_done_before / ctx->pbuf->rowstride) * ctx->pbuf->rowstride;
646 guchar *row_after = ctx->pbuf->pixels + (ctx->pbuf_bytes_done / ctx->pbuf->rowstride) * ctx->pbuf->rowstride;
647 for (; row < row_after; row += ctx->pbuf->rowstride)
648 pixbuf_flip_row (ctx->pbuf, row);
651 ctx->in = io_buffer_free_segment(ctx->in, count, err);
656 /* FIXME doing the vertical flipping afterwards is not
657 * perfect, but doing it during the rle decoding in place
658 * is considerably more work.
660 if (!(ctx->hdr->flags & TGA_ORIGIN_UPPER)) {
661 pixbuf_flip_vertically (ctx->pbuf);
662 ctx->hdr->flags |= TGA_ORIGIN_UPPER;
667 rows = ctx->pbuf_bytes_done / ctx->pbuf->rowstride - bytes_done_before / ctx->pbuf->rowstride;
669 (*ctx->ufunc) (ctx->pbuf, 0, bytes_done_before / ctx->pbuf->rowstride,
670 ctx->pbuf->width, rows,
676 static gboolean try_colormap(TGAContext *ctx, GError **err)
681 g_return_val_if_fail(ctx != NULL, FALSE);
683 if (ctx->cmap_size == 0) {
684 g_set_error_literal(err, GDK_PIXBUF_ERROR,
685 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
686 _("Image is corrupted or truncated"));
690 ctx->cmap = g_try_malloc(sizeof(TGAColormap));
692 g_set_error_literal(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
693 _("Cannot allocate colormap structure"));
696 ctx->cmap->size = LE16(ctx->hdr->cmap_n_colors);
697 ctx->cmap->cols = g_try_malloc(sizeof(TGAColor) * ctx->cmap->size);
698 if (!ctx->cmap->cols) {
699 g_set_error_literal(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
700 _("Cannot allocate colormap entries"));
705 for (n = 0; n < ctx->cmap->size; n++) {
706 if ((ctx->hdr->cmap_bpp == 15) || (ctx->hdr->cmap_bpp == 16)) {
707 guint16 col = p[0] + (p[1] << 8);
708 ctx->cmap->cols[n].b = (col >> 7) & 0xf8;
709 ctx->cmap->cols[n].g = (col >> 2) & 0xf8;
710 ctx->cmap->cols[n].r = col << 3;
713 else if ((ctx->hdr->cmap_bpp == 24) || (ctx->hdr->cmap_bpp == 32)) {
714 ctx->cmap->cols[n].b = *p++;
715 ctx->cmap->cols[n].g = *p++;
716 ctx->cmap->cols[n].r = *p++;
717 if (ctx->hdr->cmap_bpp == 32)
718 ctx->cmap->cols[n].a = *p++;
720 g_set_error_literal(err, GDK_PIXBUF_ERROR,
721 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
722 _("Unexpected bitdepth for colormap entries"));
726 ctx->in = io_buffer_free_segment(ctx->in, ctx->cmap_size, err);
732 static gboolean try_preload(TGAContext *ctx, GError **err)
735 if (ctx->in->size >= sizeof(TGAHeader)) {
736 ctx->hdr = g_try_malloc(sizeof(TGAHeader));
738 g_set_error_literal(err, GDK_PIXBUF_ERROR,
739 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
740 _("Cannot allocate TGA header memory"));
743 g_memmove(ctx->hdr, ctx->in->data, sizeof(TGAHeader));
744 ctx->in = io_buffer_free_segment(ctx->in, sizeof(TGAHeader), err);
746 g_print ("infolen %d "
752 "x %d y %d width %d height %d bpp %d "
757 LE16(ctx->hdr->cmap_start),
758 LE16(ctx->hdr->cmap_n_colors),
760 LE16(ctx->hdr->x_origin),
761 LE16(ctx->hdr->y_origin),
762 LE16(ctx->hdr->width),
763 LE16(ctx->hdr->height),
769 if (LE16(ctx->hdr->width) == 0 ||
770 LE16(ctx->hdr->height) == 0) {
771 g_set_error_literal(err, GDK_PIXBUF_ERROR,
772 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
773 _("TGA image has invalid dimensions"));
776 if ((ctx->hdr->flags & TGA_INTERLEAVE_MASK) != TGA_INTERLEAVE_NONE) {
777 g_set_error_literal(err, GDK_PIXBUF_ERROR,
778 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
779 _("TGA image type not supported"));
782 switch (ctx->hdr->type) {
783 case TGA_TYPE_PSEUDOCOLOR:
784 case TGA_TYPE_RLE_PSEUDOCOLOR:
785 if (ctx->hdr->bpp != 8) {
786 g_set_error_literal(err, GDK_PIXBUF_ERROR,
787 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
788 _("TGA image type not supported"));
792 case TGA_TYPE_TRUECOLOR:
793 case TGA_TYPE_RLE_TRUECOLOR:
794 if (ctx->hdr->bpp != 24 &&
795 ctx->hdr->bpp != 32) {
796 g_set_error_literal(err, GDK_PIXBUF_ERROR,
797 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
798 _("TGA image type not supported"));
802 case TGA_TYPE_GRAYSCALE:
803 case TGA_TYPE_RLE_GRAYSCALE:
804 if (ctx->hdr->bpp != 8 &&
805 ctx->hdr->bpp != 16) {
806 g_set_error_literal(err, GDK_PIXBUF_ERROR,
807 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
808 _("TGA image type not supported"));
813 g_set_error_literal(err, GDK_PIXBUF_ERROR,
814 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
815 _("TGA image type not supported"));
818 if (!fill_in_context(ctx, err))
824 if (!ctx->skipped_info) {
825 if (ctx->in->size >= ctx->hdr->infolen) {
826 ctx->in = io_buffer_free_segment(ctx->in, ctx->hdr->infolen, err);
829 ctx->skipped_info = TRUE;
834 if (ctx->hdr->has_cmap && !ctx->cmap) {
835 if (ctx->in->size >= ctx->cmap_size) {
836 if (!try_colormap(ctx, err))
842 if (!ctx->prepared) {
844 (*ctx->pfunc) (ctx->pbuf, NULL, ctx->udata);
845 ctx->prepared = TRUE;
847 /* We shouldn't get here anyway. */
851 static gpointer gdk_pixbuf__tga_begin_load(GdkPixbufModuleSizeFunc f0,
852 GdkPixbufModulePreparedFunc f1,
853 GdkPixbufModuleUpdatedFunc f2,
854 gpointer udata, GError **err)
858 ctx = g_try_malloc(sizeof(TGAContext));
860 g_set_error_literal(err, GDK_PIXBUF_ERROR,
861 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
862 _("Cannot allocate memory for TGA context struct"));
868 ctx->run_length_encoded = FALSE;
875 ctx->pbuf_bytes_done = 0;
878 ctx->in = io_buffer_new(err);
884 ctx->skipped_info = FALSE;
885 ctx->prepared = FALSE;
896 static gboolean gdk_pixbuf__tga_load_increment(gpointer data,
897 const guchar *buffer,
901 TGAContext *ctx = (TGAContext*) data;
902 g_return_val_if_fail(ctx != NULL, FALSE);
907 g_return_val_if_fail(buffer != NULL, TRUE);
908 ctx->in = io_buffer_append(ctx->in, buffer, size, err);
911 if (!ctx->prepared) {
912 if (!try_preload(ctx, err))
916 if (ctx->in->size == 0)
920 if (ctx->run_length_encoded) {
921 if (!parse_rle_data(ctx, err))
924 while (ctx->in->size >= ctx->rowstride) {
925 if (ctx->completed_lines >= ctx->pbuf->height) {
926 g_set_error_literal(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED,
927 _("Excess data in file"));
930 if (!parse_data_for_row(ctx, err))
932 ctx->completed_lines++;
939 static gboolean gdk_pixbuf__tga_stop_load(gpointer data, GError **err)
941 TGAContext *ctx = (TGAContext *) data;
942 g_return_val_if_fail(ctx != NULL, FALSE);
945 (ctx->hdr->flags & TGA_ORIGIN_UPPER) == 0 &&
946 ctx->run_length_encoded &&
948 pixbuf_flip_vertically (ctx->pbuf);
950 (*ctx->ufunc) (ctx->pbuf, 0, 0,
951 ctx->pbuf->width, ctx->pbuf->height,
956 g_free (ctx->cmap->cols);
960 g_object_unref (ctx->pbuf);
961 if (ctx->in && ctx->in->size)
962 ctx->in = io_buffer_free_segment (ctx->in, ctx->in->size, err);
967 io_buffer_free (ctx->in);
973 #define MODULE_ENTRY(function) G_MODULE_EXPORT void function
975 #define MODULE_ENTRY(function) void _gdk_pixbuf__tga_ ## function
978 MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
980 module->begin_load = gdk_pixbuf__tga_begin_load;
981 module->stop_load = gdk_pixbuf__tga_stop_load;
982 module->load_increment = gdk_pixbuf__tga_load_increment;
985 MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
987 static GdkPixbufModulePattern signature[] = {
988 { " \x1\x1", "x ", 100 },
989 { " \x1\x9", "x ", 100 },
990 { " \x2", "xz ", 99 }, /* only 99 since .CUR also matches this */
991 { " \x3", "xz ", 100 },
992 { " \xa", "xz ", 100 },
993 { " \xb", "xz ", 100 },
996 static gchar * mime_types[] = {
1000 static gchar * extensions[] = {
1007 info->signature = signature;
1008 info->description = N_("The Targa image format");
1009 info->mime_types = mime_types;
1010 info->extensions = extensions;
1011 info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
1012 info->license = "LGPL";