2 * GdkPixbuf library - TGA image loader
3 * Copyright (C) 1999 Nicola Girardi <nikke@swlibero.org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
23 * Some NOTES about the TGA loader (2001/06/07, nikke@swlibero.org)
25 * - The module doesn't currently provide support for TGA images where the
26 * order of the pixels isn't left-to-right and top-to-bottom. I plan to
27 * add support for those files as soon as I get one of them. I haven't
28 * run into one yet. (And I don't seem to be able to create it with GIMP.)
30 * - The TGAFooter isn't present in all TGA files. In fact, there's an older
31 * format specification, still in use, which doesn't cover the TGAFooter.
32 * Actually, most TGA files I have are of the older type. Anyway I put the
33 * struct declaration here for completeness.
35 * - Error handling was designed to be very paranoid.
41 #include "gdk-pixbuf.h"
42 #include "gdk-pixbuf-io.h"
43 #include "gdk-pixbuf-private.h"
45 #define TGA_INTERLEAVE_MASK 0xc0
46 #define TGA_INTERLEAVE_NONE 0x00
47 #define TGA_INTERLEAVE_2WAY 0x40
48 #define TGA_INTERLEAVE_4WAY 0x80
50 #define TGA_ORIGIN_MASK 0x30
51 #define TGA_ORIGIN_LEFT 0x00
52 #define TGA_ORIGIN_RIGHT 0x10
53 #define TGA_ORIGIN_LOWER 0x00
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 ModulePreparedNotifyFunc pfunc;
141 ModuleUpdatedNotifyFunc ufunc;
150 static IOBuffer *io_buffer_new(GError **err)
153 buffer = g_try_malloc(sizeof(IOBuffer));
155 g_set_error(err, GDK_PIXBUF_ERROR,
156 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
157 _("Can't allocate memory for IOBuffer struct"));
165 static IOBuffer *io_buffer_append(IOBuffer *buffer,
166 const guchar *data, guint len,
172 buffer->data = g_try_malloc(len);
174 g_set_error(err, GDK_PIXBUF_ERROR,
175 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
176 _("Can't allocate memory for IOBuffer data"));
180 g_memmove(buffer->data, data, len);
183 buffer->data = g_try_realloc(buffer->data, buffer->size + len);
185 g_set_error(err, GDK_PIXBUF_ERROR,
186 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
187 _("Can't realloc IOBuffer data"));
191 g_memmove(&buffer->data[buffer->size], data, len);
197 static IOBuffer *io_buffer_free_segment(IOBuffer *buffer,
201 g_return_val_if_fail(buffer != NULL, NULL);
202 g_return_val_if_fail(buffer->data != NULL, NULL);
203 if (count == buffer->size) {
204 g_free(buffer->data);
211 new_size = buffer->size - count;
212 new_buf = g_try_malloc(new_size);
214 g_set_error(err, GDK_PIXBUF_ERROR,
215 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
216 _("Can't allocate temporary IOBuffer data"));
217 g_free(buffer->data);
222 g_memmove(new_buf, &buffer->data[count], new_size);
223 g_free(buffer->data);
224 buffer->data = new_buf;
225 buffer->size = new_size;
230 static void io_buffer_free(IOBuffer *buffer)
232 g_return_if_fail(buffer != NULL);
234 g_free(buffer->data);
238 static void free_buffer(guchar *pixels, gpointer data)
243 static gboolean fread_check(gpointer dest,
244 size_t size, size_t count,
245 FILE *f, GError **err)
247 if (fread(dest, size, count, f) != count) {
248 g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED,
249 _("fread() failed -- premature end-of-file probably encountered"));
255 static gboolean fseek_check(FILE *f, glong offset, gint whence, GError **err)
257 if (fseek(f, offset, whence) != 0) {
258 g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED,
259 _("fseek() failed -- premature end-of-file probably encountered"));
265 static gboolean fill_in_context(TGAContext *ctx, GError **err)
269 g_return_val_if_fail(ctx != NULL, FALSE);
271 ctx->run_length_encoded =
272 ((ctx->hdr->type == TGA_TYPE_RLE_PSEUDOCOLOR)
273 || (ctx->hdr->type == TGA_TYPE_RLE_TRUECOLOR)
274 || (ctx->hdr->type == TGA_TYPE_RLE_GRAYSCALE));
276 if (ctx->hdr->has_cmap)
277 ctx->cmap_size = ((ctx->hdr->cmap_bpp + 7) >> 3) *
278 LE16(ctx->hdr->cmap_n_colors);
280 alpha = ((ctx->hdr->bpp == 32) ||
281 (ctx->hdr->has_cmap && (ctx->hdr->cmap_bpp == 32)));
283 ctx->pbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, alpha, 8,
284 LE16(ctx->hdr->width),
285 LE16(ctx->hdr->height));
287 g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
288 _("Can't allocate new pixbuf"));
291 ctx->pbuf_bytes = ctx->pbuf->rowstride * ctx->pbuf->height;
292 ctx->pptr = ctx->pbuf->pixels;
294 if ((ctx->hdr->type == TGA_TYPE_PSEUDOCOLOR) ||
295 (ctx->hdr->type == TGA_TYPE_GRAYSCALE))
296 ctx->rowstride = ctx->pbuf->width;
297 else if (ctx->hdr->type == TGA_TYPE_TRUECOLOR)
298 ctx->rowstride = ctx->pbuf->rowstride;
300 ctx->completed_lines = 0;
304 static void parse_data_for_row_pseudocolor(TGAContext *ctx)
306 guchar *s = ctx->in->data;
307 guint upper_bound = ctx->pbuf->width;
309 for (; upper_bound; upper_bound--, s++) {
310 *ctx->pptr++ = ctx->cmap->cols[*s].r;
311 *ctx->pptr++ = ctx->cmap->cols[*s].g;
312 *ctx->pptr++ = ctx->cmap->cols[*s].b;
313 if (ctx->hdr->cmap_bpp == 32)
314 *ctx->pptr++ = ctx->cmap->cols[*s].a;
316 ctx->pbuf_bytes_done += ctx->pbuf->n_channels * ctx->pbuf->width;
317 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
321 static void swap_channels(TGAContext *ctx)
323 register guchar swap;
324 register guint count;
325 for (count = ctx->pbuf->width; count; count--) {
327 ctx->pptr[0] = ctx->pptr[2];
329 ctx->pptr += ctx->pbuf->n_channels;
333 static void parse_data_for_row_truecolor(TGAContext *ctx)
335 g_memmove(ctx->pptr, ctx->in->data, ctx->pbuf->rowstride);
337 ctx->pbuf_bytes_done += ctx->pbuf->rowstride;
338 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
342 static void parse_data_for_row_grayscale(TGAContext *ctx)
344 guchar *s = ctx->in->data;
345 guint upper_bound = ctx->pbuf->width;
347 for (; upper_bound; upper_bound--) {
348 ctx->pptr[0] = ctx->pptr[1] = ctx->pptr[2] = *s++;
351 ctx->pbuf_bytes_done = ctx->pbuf->width * 3;
352 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
356 static gboolean parse_data_for_row(TGAContext *ctx, GError **err)
358 if (ctx->hdr->type == TGA_TYPE_PSEUDOCOLOR)
359 parse_data_for_row_pseudocolor(ctx);
360 else if (ctx->hdr->type == TGA_TYPE_TRUECOLOR)
361 parse_data_for_row_truecolor(ctx);
362 else if (ctx->hdr->type == TGA_TYPE_GRAYSCALE)
363 parse_data_for_row_grayscale(ctx);
364 ctx->in = io_buffer_free_segment(ctx->in, ctx->rowstride, err);
367 (*ctx->ufunc) (ctx->pbuf, 0,
368 (ctx->pbuf_bytes_done / ctx->pbuf->rowstride) - 1,
369 ctx->pbuf->width, 1, ctx->udata);
373 static void write_rle_data(TGAContext *ctx, TGAColor *color, guint *rle_count)
375 ctx->pbuf_bytes_done += ctx->pbuf->n_channels * (*rle_count);
376 for (; *rle_count; (*rle_count)--) {
377 g_memmove(ctx->pptr, (guchar *) color, ctx->pbuf->n_channels);
378 ctx->pptr += ctx->pbuf->n_channels;
382 static guint parse_rle_data_pseudocolor(TGAContext *ctx)
384 guint rle_num, raw_num;
388 g_return_val_if_fail(ctx->in->size > 0, 0);
391 for (n = 0; n < ctx->in->size; ) {
395 if (n == ctx->in->size) {
398 rle_num = (tag & 0x7f) + 1;
399 write_rle_data(ctx, &ctx->cmap->cols[*s], &rle_num);
404 if (n + raw_num >= ctx->in->size) {
407 for (; raw_num; raw_num--) {
409 ctx->cmap->cols[*s].r;
411 ctx->cmap->cols[*s].g;
413 ctx->cmap->cols[*s].b;
414 if (ctx->pbuf->n_channels == 4)
415 *ctx->pptr++ = ctx->cmap->cols[*s].a;
417 ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
422 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
427 static void swap_channels_rle(TGAContext *ctx, guint count)
429 register guchar swap;
430 for (; count; count--) {
432 ctx->pptr[0] = ctx->pptr[2];
434 ctx->pptr += ctx->pbuf->n_channels;
438 static guint parse_rle_data_truecolor(TGAContext *ctx)
441 guint rle_num, raw_num;
445 g_return_val_if_fail(ctx->in->size > 0, 0);
448 for (n = 0; n < ctx->in->size; ) {
452 if (n + ctx->pbuf->n_channels >= ctx->in->size) {
455 rle_num = (tag & 0x7f) + 1;
459 if (ctx->hdr->bpp == 32)
461 write_rle_data(ctx, &col, &rle_num);
462 n += ctx->pbuf->n_channels;
466 if (n + (raw_num * ctx->pbuf->n_channels) >= ctx->in->size) {
469 g_memmove(ctx->pptr, s, raw_num * ctx->pbuf->n_channels);
470 swap_channels_rle(ctx, raw_num);
471 s += raw_num * ctx->pbuf->n_channels;
472 n += raw_num * ctx->pbuf->n_channels;
473 ctx->pbuf_bytes_done += raw_num * ctx->pbuf->n_channels;
477 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
482 static guint parse_rle_data_grayscale(TGAContext *ctx)
485 guint rle_num, raw_num;
489 g_return_val_if_fail(ctx->in->size > 0, 0);
492 for (n = 0; n < ctx->in->size; ) {
496 if (n == ctx->in->size) {
499 rle_num = (tag & 0x7f) + 1;
500 tone.r = tone.g = tone.b = *s;
502 write_rle_data(ctx, &tone, &rle_num);
506 if (n + raw_num >= ctx->in->size) {
509 for (; raw_num; raw_num--) {
510 ctx->pptr[0] = ctx->pptr[1] = ctx->pptr[2] = *s;
513 ctx->pbuf_bytes_done += 3;
518 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
523 static gboolean parse_rle_data(TGAContext *ctx, GError **err)
526 guint pbuf_count = 0;
527 if (ctx->hdr->type == TGA_TYPE_RLE_PSEUDOCOLOR) {
528 count = parse_rle_data_pseudocolor(ctx);
529 pbuf_count = count *ctx->pbuf->n_channels;
530 } else if (ctx->hdr->type == TGA_TYPE_RLE_TRUECOLOR) {
531 count = parse_rle_data_truecolor(ctx);
533 } else if (ctx->hdr->type == TGA_TYPE_RLE_GRAYSCALE) {
534 count = parse_rle_data_grayscale(ctx);
535 pbuf_count = count * 3;
537 ctx->in = io_buffer_free_segment(ctx->in, count, err);
540 (*ctx->ufunc) (ctx->pbuf, 0, ctx->pbuf_bytes_done / ctx->pbuf->rowstride,
541 ctx->pbuf->width, pbuf_count / ctx->pbuf->rowstride,
546 static gboolean try_colormap(TGAContext *ctx, GError **err)
551 g_return_val_if_fail(ctx != NULL, FALSE);
552 g_return_val_if_fail(ctx->cmap_size > 0, TRUE);
554 ctx->cmap = g_try_malloc(sizeof(TGAColormap));
556 g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
557 _("Can't allocate colormap structure"));
560 ctx->cmap->size = LE16(ctx->hdr->cmap_n_colors);
561 ctx->cmap->cols = g_try_malloc(sizeof(TGAColor) * ctx->cmap->size);
562 if (!ctx->cmap->cols) {
563 g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
564 _("Can't allocate colormap entries"));
570 for (n = 0; n < ctx->cmap->size; n++) {
571 if ((ctx->hdr->cmap_bpp == 15) || (ctx->hdr->cmap_bpp == 16)) {
572 guint16 col = p[0] + (p[1] << 8);
573 ctx->cmap->cols[n].b = (col >> 7) & 0xf8;
574 ctx->cmap->cols[n].g = (col >> 2) & 0xf8;
575 ctx->cmap->cols[n].r = col << 3;
578 else if ((ctx->hdr->cmap_bpp == 24) || (ctx->hdr->cmap_bpp == 32)) {
579 ctx->cmap->cols[n].b = *p++;
580 ctx->cmap->cols[n].g = *p++;
581 ctx->cmap->cols[n].r = *p++;
582 if (ctx->hdr->cmap_bpp == 32)
583 ctx->cmap->cols[n].a = *p++;
585 g_set_error(err, GDK_PIXBUF_ERROR,
586 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
587 _("Unexpected bitdepth for colormap entries"));
588 g_free(ctx->cmap->cols);
593 ctx->in = io_buffer_free_segment(ctx->in, ctx->cmap_size, err);
599 static gboolean try_preload(TGAContext *ctx, GError **err)
602 if (ctx->in->size >= sizeof(TGAHeader)) {
603 ctx->hdr = g_try_malloc(sizeof(TGAHeader));
605 g_set_error(err, GDK_PIXBUF_ERROR,
606 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
607 _("Can't allocate TGA header memory"));
610 g_memmove(ctx->hdr, ctx->in->data, sizeof(TGAHeader));
611 ctx->in = io_buffer_free_segment(ctx->in, sizeof(TGAHeader), err);
614 if (!fill_in_context(ctx, err))
616 if (ctx->hdr->infolen > 255) {
617 g_set_error(err, GDK_PIXBUF_ERROR,
618 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
619 _("TGA image comment length is too long"));
622 if ((ctx->hdr->flags & TGA_INTERLEAVE_MASK) !=
623 TGA_INTERLEAVE_NONE ||
624 ctx->hdr->flags & TGA_ORIGIN_RIGHT ||
625 ctx->hdr->flags & TGA_ORIGIN_LOWER) {
626 g_set_error(err, GDK_PIXBUF_ERROR,
627 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
628 _("TGA image type not supported"));
635 if (!ctx->skipped_info) {
636 if (ctx->in->size >= ctx->hdr->infolen) {
637 ctx->in = io_buffer_free_segment(ctx->in, ctx->hdr->infolen, err);
640 ctx->skipped_info = TRUE;
645 if (ctx->hdr->has_cmap && !ctx->cmap) {
646 if (ctx->in->size >= ctx->cmap_size) {
647 if (!try_colormap(ctx, err))
653 if (!ctx->prepared) {
654 (*ctx->pfunc) (ctx->pbuf, NULL, ctx->udata);
655 ctx->prepared = TRUE;
657 /* We shouldn't get here anyway. */
661 static gpointer gdk_pixbuf__tga_begin_load(ModulePreparedNotifyFunc f1,
662 ModuleUpdatedNotifyFunc f2,
663 gpointer udata, GError **err)
667 ctx = g_try_malloc(sizeof(TGAContext));
669 g_set_error(err, GDK_PIXBUF_ERROR,
670 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
671 _("Can't allocate memory for TGA context struct"));
677 ctx->run_length_encoded = FALSE;
684 ctx->pbuf_bytes_done = 0;
687 ctx->in = io_buffer_new(err);
693 ctx->skipped_info = FALSE;
694 ctx->prepared = FALSE;
704 static gboolean gdk_pixbuf__tga_load_increment(gpointer data,
705 const guchar *buffer,
709 TGAContext *ctx = (TGAContext*) data;
710 g_return_val_if_fail(ctx != NULL, FALSE);
715 g_return_val_if_fail(buffer != NULL, TRUE);
716 ctx->in = io_buffer_append(ctx->in, buffer, size, err);
719 if (!ctx->prepared) {
720 if (!try_preload(ctx, err))
724 if (ctx->in->size == 0)
728 if (ctx->run_length_encoded) {
729 if (!parse_rle_data(ctx, err))
732 while (ctx->in->size >= ctx->rowstride) {
733 if (ctx->completed_lines >= ctx->pbuf->height) {
734 g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED,
735 _("Excess data in file"));
738 if (!parse_data_for_row(ctx, err))
740 ctx->completed_lines++;
747 static gboolean gdk_pixbuf__tga_stop_load(gpointer data, GError **err)
749 TGAContext *ctx = (TGAContext *) data;
750 g_return_val_if_fail(ctx != NULL, FALSE);
755 gdk_pixbuf_unref(ctx->pbuf);
757 ctx->in = io_buffer_free_segment(ctx->in, ctx->in->size, err);
762 io_buffer_free(ctx->in);
767 static TGAHeader *get_header_from_file(FILE *f, GError **err)
771 if (!fseek_check(f, 0, SEEK_SET, err))
773 if (!(hdr = g_try_malloc(sizeof(TGAHeader)))) {
774 g_set_error(err, GDK_PIXBUF_ERROR,
775 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
776 _("Can't allocate memory for TGA header"));
779 if (!fread_check(hdr, sizeof(TGAHeader), 1, f, err)) {
783 if (hdr->infolen > 255) {
784 g_set_error(err, GDK_PIXBUF_ERROR,
785 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
786 _("Too big value in the infolen field of TGA header."));
794 static TGAColormap *get_colormap_from_file(FILE *f,
802 if (!fseek_check(f, sizeof(TGAHeader) + hdr->infolen, SEEK_SET, err))
805 pal_size = LE16(hdr->cmap_n_colors) * ((hdr->cmap_bpp + 7) >> 3);
806 pal_buf = g_try_malloc(pal_size);
808 g_set_error(err, GDK_PIXBUF_ERROR,
809 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
810 _("Can't allocate memory for TGA cmap temporary buffer"));
813 if (!fread_check(pal_buf, pal_size, 1, f, err)) {
819 if (!(cmap = g_try_malloc(sizeof(TGAColormap)))) {
820 g_set_error(err, GDK_PIXBUF_ERROR,
821 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
822 _("Can't allocate memory for TGA colormap struct"));
826 cmap->size = LE16(hdr->cmap_n_colors);
827 cmap->cols = g_try_malloc(sizeof(TGAColor) * cmap->size);
829 g_set_error(err, GDK_PIXBUF_ERROR,
830 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
831 _("Can't allocate memory for TGA colormap entries"));
837 if (hdr->cmap_bpp != 15 && hdr->cmap_bpp != 16 &&
838 hdr->cmap_bpp != 24 && hdr->cmap_bpp != 32) {
839 g_set_error(err, GDK_PIXBUF_ERROR,
840 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
841 _("Unexpected bitdepth for TGA colormap"));
848 for (n = 0; n < cmap->size; n++) {
849 if ((hdr->cmap_bpp == 15) || (hdr->cmap_bpp == 16)) {
850 guint16 col = p[0] + (p[1] << 8);
852 cmap->cols[n].b = (col >> 7) & 0xf8;
853 cmap->cols[n].g = (col >> 2) & 0xf8;
854 cmap->cols[n].r = col << 3;
855 } else if ((hdr->cmap_bpp == 24) || (hdr->cmap_bpp == 32)) {
856 cmap->cols[n].b = *p++;
857 cmap->cols[n].g = *p++;
858 cmap->cols[n].r = *p++;
859 if (hdr->cmap_bpp == 32)
860 cmap->cols[n].a = *p++;
868 static GdkPixbuf *get_image_pseudocolor(FILE *f, TGAHeader *hdr,
869 TGAColormap *cmap, gboolean rle,
873 guchar *p, color, tag;
874 glong n, image_offset;
877 image_offset = sizeof(TGAHeader) + hdr->infolen;
878 if (!hdr->has_cmap) {
879 g_set_error(err, GDK_PIXBUF_ERROR,
880 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
881 _("Pseudo-Color image without colormap"));
884 image_offset += cmap->size * ((hdr->cmap_bpp + 7) >> 3);
886 if (!fseek_check(f, image_offset, SEEK_SET, err)) {
887 g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED,
888 _("Can't seek to image offset -- end-of-file probably encountered"));
892 pbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, (hdr->cmap_bpp == 32), 8,
893 LE16(hdr->width), LE16(hdr->height));
895 g_set_error(err, GDK_PIXBUF_ERROR,
896 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
897 _("Can't allocate pixbuf"));
900 pbuf->destroy_fn = free_buffer;
901 pbuf->destroy_fn_data = NULL;
906 for (; n < pbuf->width * pbuf->height;) {
907 if (!fread_check(&tag, 1, 1, f, err)) {
908 gdk_pixbuf_unref(pbuf);
912 count = (tag & 0x7f) + 1;
914 if (!fread_check(&color, 1, 1, f, err)) {
915 gdk_pixbuf_unref(pbuf);
918 for (; count; count--) {
919 *p++ = cmap->cols[color].r;
920 *p++ = cmap->cols[color].g;
921 *p++ = cmap->cols[color].b;
922 if (hdr->cmap_bpp == 32)
923 *p++ = cmap->cols[color].a;
928 for (; count; count--) {
929 if (!fread_check(&color, 1, 1, f, err)) {
930 gdk_pixbuf_unref(pbuf);
933 *p++ = cmap->cols[color].r;
934 *p++ = cmap->cols[color].g;
935 *p++ = cmap->cols[color].b;
936 if (hdr->cmap_bpp == 32)
937 *p++ = cmap->cols[color].a;
942 for (n = 0; n < pbuf->width * pbuf->height; n++) {
943 if (!fread_check(&color, 1, 1, f, err)) {
944 gdk_pixbuf_unref(pbuf);
947 *p++ = cmap->cols[color].r;
948 *p++ = cmap->cols[color].g;
949 *p++ = cmap->cols[color].b;
950 if (hdr->cmap_bpp == 32)
951 *p++ = cmap->cols[color].a;
958 static void swap_channels_pixbuf(GdkPixbuf *pbuf)
964 for (n = 0; n < pbuf->width * pbuf->height; n++) {
968 p += pbuf->n_channels;
972 static GdkPixbuf *get_image_truecolor(FILE *f, TGAHeader *hdr,
973 gboolean rle, GError **err)
977 glong n, image_offset;
981 image_offset = sizeof(TGAHeader) + hdr->infolen;
982 /* A truecolor image shouldn't actually have a colormap. */
984 image_offset += LE16(hdr->cmap_n_colors) * ((hdr->cmap_bpp + 7) >> 3);
985 if (!fseek_check(f, image_offset, SEEK_SET, err))
988 pbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, (hdr->bpp == 32), 8,
989 LE16(hdr->width), LE16(hdr->height));
991 g_set_error(err, GDK_PIXBUF_ERROR,
992 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
993 _("Can't allocate pixbuf"));
996 pbuf->destroy_fn = free_buffer;
997 pbuf->destroy_fn_data = NULL;
1002 for (; n < pbuf->width * pbuf->height;) {
1003 if (!fread_check(&tag, 1, 1, f, err)) {
1004 gdk_pixbuf_unref(pbuf);
1008 count = (tag & 0x7f) + 1;
1010 if (!fread_check(&pixel, pbuf->n_channels, 1, f, err)) {
1011 gdk_pixbuf_unref(pbuf);
1014 for (; count; count--) {
1015 g_memmove(p, &pixel, pbuf->n_channels);
1016 p += pbuf->n_channels;
1021 if (!fread_check(p, pbuf->n_channels * count, 1, f, err)) {
1022 gdk_pixbuf_unref(pbuf);
1025 p += pbuf->n_channels * count;
1029 if (!fread_check(p, pbuf->rowstride * pbuf->height, 1, f, err)) {
1030 gdk_pixbuf_unref(pbuf);
1035 swap_channels_pixbuf(pbuf);
1039 static GdkPixbuf *get_image_grayscale(FILE *f, TGAHeader *hdr,
1040 gboolean rle, GError **err)
1043 glong n, image_offset;
1044 guchar *p, color, tag;
1047 image_offset = sizeof(TGAHeader) + hdr->infolen;
1048 /* A grayscale image shouldn't actually have a colormap. */
1050 image_offset += LE16(hdr->cmap_n_colors) * ((hdr->cmap_bpp + 7) >> 3);
1051 if (!fseek_check(f, image_offset, SEEK_SET, err))
1054 pbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
1055 LE16(hdr->width), LE16(hdr->height));
1057 g_set_error(err, GDK_PIXBUF_ERROR,
1058 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
1059 _("Can't allocate pixbuf"));
1062 pbuf->destroy_fn = free_buffer;
1063 pbuf->destroy_fn_data = NULL;
1068 for (; n < pbuf->width * pbuf->height;) {
1069 if (!fread_check(&tag, 1, 1, f, err)) {
1070 gdk_pixbuf_unref(pbuf);
1074 count = (tag & 0x7f) + 1;
1076 if (!fread_check(&color, 1, 1, f, err)) {
1077 gdk_pixbuf_unref(pbuf);
1080 for (; count; count--) {
1081 p[0] = p[1] = p[2] = color;
1087 for (; count; count--) {
1088 if (!fread_check(&color, 1, 1, f, err)) {
1089 gdk_pixbuf_unref(pbuf);
1092 p[0] = p[1] = p[2] = color;
1098 for (n = 0; n < pbuf->width * pbuf->height; n++) {
1099 if (!fread_check(&color, 1, 1, f, err)) {
1100 gdk_pixbuf_unref(pbuf);
1103 p[0] = p[1] = p[2] = color;
1111 static GdkPixbuf *gdk_pixbuf__tga_load(FILE *f, GError **err)
1118 hdr = get_header_from_file(f, err);
1121 if ((hdr->flags & TGA_INTERLEAVE_MASK) != TGA_INTERLEAVE_NONE ||
1122 hdr->flags & TGA_ORIGIN_RIGHT || hdr->flags & TGA_ORIGIN_LOWER) {
1123 g_set_error(err, GDK_PIXBUF_ERROR,
1124 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
1125 _("Unsupported TGA image type"));
1130 if (hdr->has_cmap && ((hdr->type == TGA_TYPE_PSEUDOCOLOR) ||
1131 (hdr->type == TGA_TYPE_RLE_PSEUDOCOLOR))) {
1132 cmap = get_colormap_from_file(f, hdr, err);
1139 if (hdr->type == TGA_TYPE_PSEUDOCOLOR)
1140 pbuf = get_image_pseudocolor(f, hdr, cmap, FALSE, err);
1141 else if (hdr->type == TGA_TYPE_RLE_PSEUDOCOLOR)
1142 pbuf = get_image_pseudocolor(f, hdr, cmap, TRUE, err);
1143 else if (hdr->type == TGA_TYPE_TRUECOLOR)
1144 pbuf = get_image_truecolor(f, hdr, FALSE, err);
1145 else if (hdr->type == TGA_TYPE_RLE_TRUECOLOR)
1146 pbuf = get_image_truecolor(f, hdr, TRUE, err);
1147 else if (hdr->type == TGA_TYPE_GRAYSCALE)
1148 pbuf = get_image_grayscale(f, hdr, FALSE, err);
1149 else if (hdr->type == TGA_TYPE_RLE_GRAYSCALE)
1150 pbuf = get_image_grayscale(f, hdr, TRUE, err);
1152 g_set_error(err, GDK_PIXBUF_ERROR,
1153 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
1154 _("Unsupported TGA image type"));
1168 gdk_pixbuf__tga_fill_vtable (GdkPixbufModule *module)
1170 module->load = gdk_pixbuf__tga_load;
1171 module->begin_load = gdk_pixbuf__tga_begin_load;
1172 module->stop_load = gdk_pixbuf__tga_stop_load;
1173 module->load_increment = gdk_pixbuf__tga_load_increment;