forked from AuroraMiddleware/gtk
Fix assumptions on rowstride by manually allocating a contiguous pixel
* io-tga.c: Fix assumptions on rowstride by manually allocating a contiguous pixel buffer. Catch buffer overruns in RLE-modi. Support grayscale + alpha (which can be written, but not read (!) by the Gimp).
This commit is contained in:
parent
aa3d5719b7
commit
ac7e3c9584
@ -1,3 +1,10 @@
|
|||||||
|
2002-03-18 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
|
* io-tga.c: Fix assumptions on rowstride by manually allocating a
|
||||||
|
contiguous pixel buffer. Catch buffer overruns in RLE-modi.
|
||||||
|
Support grayscale + alpha (which can be written, but not read (!)
|
||||||
|
by the Gimp).
|
||||||
|
|
||||||
2002-03-15 Matthias Clasen <maclas@gmx.de>
|
2002-03-15 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
* io-gif.c (gif_get_frame_info): Catch invalid frame dimensions.
|
* io-gif.c (gif_get_frame_info): Catch invalid frame dimensions.
|
||||||
|
@ -42,6 +42,8 @@
|
|||||||
#include "gdk-pixbuf-io.h"
|
#include "gdk-pixbuf-io.h"
|
||||||
#include "gdk-pixbuf-private.h"
|
#include "gdk-pixbuf-private.h"
|
||||||
|
|
||||||
|
#undef DEBUG_TGA
|
||||||
|
|
||||||
#define TGA_INTERLEAVE_MASK 0xc0
|
#define TGA_INTERLEAVE_MASK 0xc0
|
||||||
#define TGA_INTERLEAVE_NONE 0x00
|
#define TGA_INTERLEAVE_NONE 0x00
|
||||||
#define TGA_INTERLEAVE_2WAY 0x40
|
#define TGA_INTERLEAVE_2WAY 0x40
|
||||||
@ -265,6 +267,8 @@ static gboolean fseek_check(FILE *f, glong offset, gint whence, GError **err)
|
|||||||
static gboolean fill_in_context(TGAContext *ctx, GError **err)
|
static gboolean fill_in_context(TGAContext *ctx, GError **err)
|
||||||
{
|
{
|
||||||
gboolean alpha;
|
gboolean alpha;
|
||||||
|
guint w, h;
|
||||||
|
guchar *pixels;
|
||||||
|
|
||||||
g_return_val_if_fail(ctx != NULL, FALSE);
|
g_return_val_if_fail(ctx != NULL, FALSE);
|
||||||
|
|
||||||
@ -277,12 +281,25 @@ static gboolean fill_in_context(TGAContext *ctx, GError **err)
|
|||||||
ctx->cmap_size = ((ctx->hdr->cmap_bpp + 7) >> 3) *
|
ctx->cmap_size = ((ctx->hdr->cmap_bpp + 7) >> 3) *
|
||||||
LE16(ctx->hdr->cmap_n_colors);
|
LE16(ctx->hdr->cmap_n_colors);
|
||||||
|
|
||||||
alpha = ((ctx->hdr->bpp == 32) ||
|
alpha = ((ctx->hdr->bpp == 16) ||
|
||||||
|
(ctx->hdr->bpp == 32) ||
|
||||||
(ctx->hdr->has_cmap && (ctx->hdr->cmap_bpp == 32)));
|
(ctx->hdr->has_cmap && (ctx->hdr->cmap_bpp == 32)));
|
||||||
|
|
||||||
ctx->pbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, alpha, 8,
|
w = LE16(ctx->hdr->width);
|
||||||
LE16(ctx->hdr->width),
|
h = LE16(ctx->hdr->height);
|
||||||
LE16(ctx->hdr->height));
|
|
||||||
|
pixels = g_try_malloc (w * h * (alpha ? 4 : 3));
|
||||||
|
|
||||||
|
if (!pixels) {
|
||||||
|
g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
|
||||||
|
_("Insufficient memory to load TGA image"));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->pbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, alpha, 8,
|
||||||
|
w, h, w * (alpha ? 4 : 3),
|
||||||
|
free_buffer, NULL);
|
||||||
|
|
||||||
if (!ctx->pbuf) {
|
if (!ctx->pbuf) {
|
||||||
g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
|
g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
|
||||||
_("Can't allocate new pixbuf"));
|
_("Can't allocate new pixbuf"));
|
||||||
@ -291,9 +308,10 @@ static gboolean fill_in_context(TGAContext *ctx, GError **err)
|
|||||||
ctx->pbuf_bytes = ctx->pbuf->rowstride * ctx->pbuf->height;
|
ctx->pbuf_bytes = ctx->pbuf->rowstride * ctx->pbuf->height;
|
||||||
ctx->pptr = ctx->pbuf->pixels;
|
ctx->pptr = ctx->pbuf->pixels;
|
||||||
|
|
||||||
if ((ctx->hdr->type == TGA_TYPE_PSEUDOCOLOR) ||
|
if (ctx->hdr->type == TGA_TYPE_PSEUDOCOLOR)
|
||||||
(ctx->hdr->type == TGA_TYPE_GRAYSCALE))
|
ctx->rowstride = ctx->pbuf->width;
|
||||||
ctx->rowstride = ctx->pbuf->width;
|
else if (ctx->hdr->type == TGA_TYPE_GRAYSCALE)
|
||||||
|
ctx->rowstride = (alpha ? ctx->pbuf->width * 2 : ctx->pbuf->width);
|
||||||
else if (ctx->hdr->type == TGA_TYPE_TRUECOLOR)
|
else if (ctx->hdr->type == TGA_TYPE_TRUECOLOR)
|
||||||
ctx->rowstride = ctx->pbuf->rowstride;
|
ctx->rowstride = ctx->pbuf->rowstride;
|
||||||
|
|
||||||
@ -305,28 +323,31 @@ static void parse_data_for_row_pseudocolor(TGAContext *ctx)
|
|||||||
{
|
{
|
||||||
guchar *s = ctx->in->data;
|
guchar *s = ctx->in->data;
|
||||||
guint upper_bound = ctx->pbuf->width;
|
guint upper_bound = ctx->pbuf->width;
|
||||||
|
guchar *p = ctx->pptr;
|
||||||
|
|
||||||
for (; upper_bound; upper_bound--, s++) {
|
for (; upper_bound; upper_bound--, s++) {
|
||||||
*ctx->pptr++ = ctx->cmap->cols[*s].r;
|
*p++ = ctx->cmap->cols[*s].r;
|
||||||
*ctx->pptr++ = ctx->cmap->cols[*s].g;
|
*p++ = ctx->cmap->cols[*s].g;
|
||||||
*ctx->pptr++ = ctx->cmap->cols[*s].b;
|
*p++ = ctx->cmap->cols[*s].b;
|
||||||
if (ctx->hdr->cmap_bpp == 32)
|
if (ctx->hdr->cmap_bpp == 32)
|
||||||
*ctx->pptr++ = ctx->cmap->cols[*s].a;
|
*p++ = ctx->cmap->cols[*s].a;
|
||||||
}
|
}
|
||||||
ctx->pbuf_bytes_done += ctx->pbuf->n_channels * ctx->pbuf->width;
|
ctx->pptr += ctx->pbuf->rowstride;
|
||||||
|
ctx->pbuf_bytes_done += ctx->pbuf->rowstride;
|
||||||
if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
|
if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
|
||||||
ctx->done = TRUE;
|
ctx->done = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void swap_channels(TGAContext *ctx)
|
static void swap_channels(TGAContext *ctx)
|
||||||
{
|
{
|
||||||
register guchar swap;
|
guchar swap;
|
||||||
register guint count;
|
guint count;
|
||||||
|
guchar *p = ctx->pptr;
|
||||||
for (count = ctx->pbuf->width; count; count--) {
|
for (count = ctx->pbuf->width; count; count--) {
|
||||||
swap = ctx->pptr[0];
|
swap = p[0];
|
||||||
ctx->pptr[0] = ctx->pptr[2];
|
p[0] = p[2];
|
||||||
ctx->pptr[2] = swap;
|
p[2] = swap;
|
||||||
ctx->pptr += ctx->pbuf->n_channels;
|
p += ctx->pbuf->n_channels;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,6 +355,7 @@ static void parse_data_for_row_truecolor(TGAContext *ctx)
|
|||||||
{
|
{
|
||||||
g_memmove(ctx->pptr, ctx->in->data, ctx->pbuf->rowstride);
|
g_memmove(ctx->pptr, ctx->in->data, ctx->pbuf->rowstride);
|
||||||
swap_channels(ctx);
|
swap_channels(ctx);
|
||||||
|
ctx->pptr += ctx->pbuf->rowstride;
|
||||||
ctx->pbuf_bytes_done += ctx->pbuf->rowstride;
|
ctx->pbuf_bytes_done += ctx->pbuf->rowstride;
|
||||||
if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
|
if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
|
||||||
ctx->done = TRUE;
|
ctx->done = TRUE;
|
||||||
@ -344,11 +366,15 @@ static void parse_data_for_row_grayscale(TGAContext *ctx)
|
|||||||
guchar *s = ctx->in->data;
|
guchar *s = ctx->in->data;
|
||||||
guint upper_bound = ctx->pbuf->width;
|
guint upper_bound = ctx->pbuf->width;
|
||||||
|
|
||||||
|
guchar *p = ctx->pptr;
|
||||||
for (; upper_bound; upper_bound--) {
|
for (; upper_bound; upper_bound--) {
|
||||||
ctx->pptr[0] = ctx->pptr[1] = ctx->pptr[2] = *s++;
|
p[0] = p[1] = p[2] = *s++;
|
||||||
ctx->pptr += 3;
|
if (ctx->pbuf->n_channels == 4)
|
||||||
|
p[3] = *s++;
|
||||||
|
p += ctx->pbuf->n_channels;
|
||||||
}
|
}
|
||||||
ctx->pbuf_bytes_done = ctx->pbuf->width * 3;
|
ctx->pptr += ctx->pbuf->rowstride;
|
||||||
|
ctx->pbuf_bytes_done += ctx->pbuf->rowstride;
|
||||||
if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
|
if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
|
||||||
ctx->done = TRUE;
|
ctx->done = TRUE;
|
||||||
}
|
}
|
||||||
@ -372,10 +398,12 @@ static gboolean parse_data_for_row(TGAContext *ctx, GError **err)
|
|||||||
|
|
||||||
static void write_rle_data(TGAContext *ctx, TGAColor *color, guint *rle_count)
|
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)--) {
|
for (; *rle_count; (*rle_count)--) {
|
||||||
g_memmove(ctx->pptr, (guchar *) color, ctx->pbuf->n_channels);
|
g_memmove(ctx->pptr, (guchar *) color, ctx->pbuf->n_channels);
|
||||||
ctx->pptr += ctx->pbuf->n_channels;
|
ctx->pptr += ctx->pbuf->n_channels;
|
||||||
|
ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
|
||||||
|
if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,6 +426,10 @@ static guint parse_rle_data_pseudocolor(TGAContext *ctx)
|
|||||||
rle_num = (tag & 0x7f) + 1;
|
rle_num = (tag & 0x7f) + 1;
|
||||||
write_rle_data(ctx, &ctx->cmap->cols[*s], &rle_num);
|
write_rle_data(ctx, &ctx->cmap->cols[*s], &rle_num);
|
||||||
s++, n++;
|
s++, n++;
|
||||||
|
if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
|
||||||
|
ctx->done = TRUE;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
raw_num = tag + 1;
|
raw_num = tag + 1;
|
||||||
@ -415,26 +447,20 @@ static guint parse_rle_data_pseudocolor(TGAContext *ctx)
|
|||||||
*ctx->pptr++ = ctx->cmap->cols[*s].a;
|
*ctx->pptr++ = ctx->cmap->cols[*s].a;
|
||||||
s++, n++;
|
s++, n++;
|
||||||
ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
|
ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
|
||||||
|
if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
|
||||||
|
ctx->done = TRUE;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
|
if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
|
||||||
ctx->done = TRUE;
|
ctx->done = TRUE;
|
||||||
return n;
|
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)
|
static guint parse_rle_data_truecolor(TGAContext *ctx)
|
||||||
{
|
{
|
||||||
TGAColor col;
|
TGAColor col;
|
||||||
@ -458,19 +484,37 @@ static guint parse_rle_data_truecolor(TGAContext *ctx)
|
|||||||
col.r = *s++;
|
col.r = *s++;
|
||||||
if (ctx->hdr->bpp == 32)
|
if (ctx->hdr->bpp == 32)
|
||||||
col.a = *s++;
|
col.a = *s++;
|
||||||
write_rle_data(ctx, &col, &rle_num);
|
|
||||||
n += ctx->pbuf->n_channels;
|
n += ctx->pbuf->n_channels;
|
||||||
|
write_rle_data(ctx, &col, &rle_num);
|
||||||
|
if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
|
||||||
|
ctx->done = TRUE;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
raw_num = tag + 1;
|
raw_num = tag + 1;
|
||||||
if (n + (raw_num * ctx->pbuf->n_channels) >= ctx->in->size) {
|
if (n + (raw_num * ctx->pbuf->n_channels) >= ctx->in->size) {
|
||||||
return --n;
|
return --n;
|
||||||
} else {
|
} else {
|
||||||
g_memmove(ctx->pptr, s, raw_num * ctx->pbuf->n_channels);
|
for (; raw_num; raw_num--) {
|
||||||
swap_channels_rle(ctx, raw_num);
|
ctx->pptr[2] = *s++;
|
||||||
s += raw_num * ctx->pbuf->n_channels;
|
ctx->pptr[1] = *s++;
|
||||||
n += raw_num * ctx->pbuf->n_channels;
|
ctx->pptr[0] = *s++;
|
||||||
ctx->pbuf_bytes_done += raw_num * ctx->pbuf->n_channels;
|
if (ctx->hdr->bpp == 32)
|
||||||
|
ctx->pptr[3] = *s++;
|
||||||
|
n += ctx->pbuf->n_channels;
|
||||||
|
ctx->pptr += ctx->pbuf->n_channels;
|
||||||
|
ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
|
||||||
|
if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
|
||||||
|
ctx->done = TRUE;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
|
||||||
|
ctx->done = TRUE;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -493,24 +537,40 @@ static guint parse_rle_data_grayscale(TGAContext *ctx)
|
|||||||
tag = *s;
|
tag = *s;
|
||||||
s++, n++;
|
s++, n++;
|
||||||
if (tag & 0x80) {
|
if (tag & 0x80) {
|
||||||
if (n == ctx->in->size) {
|
if (n + (ctx->pbuf->n_channels == 4 ? 2 : 1) >= ctx->in->size) {
|
||||||
return --n;
|
return --n;
|
||||||
} else {
|
} else {
|
||||||
rle_num = (tag & 0x7f) + 1;
|
rle_num = (tag & 0x7f) + 1;
|
||||||
tone.r = tone.g = tone.b = *s;
|
tone.r = tone.g = tone.b = *s;
|
||||||
s++, n++;
|
s++, n++;
|
||||||
|
if (ctx->pbuf->n_channels == 4) {
|
||||||
|
tone.a = *s++;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
write_rle_data(ctx, &tone, &rle_num);
|
write_rle_data(ctx, &tone, &rle_num);
|
||||||
|
if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
|
||||||
|
ctx->done = TRUE;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
raw_num = tag + 1;
|
raw_num = tag + 1;
|
||||||
if (n + raw_num >= ctx->in->size) {
|
if (n + raw_num * (ctx->pbuf->n_channels == 4 ? 2 : 1) >= ctx->in->size) {
|
||||||
return --n;
|
return --n;
|
||||||
} else {
|
} else {
|
||||||
for (; raw_num; raw_num--) {
|
for (; raw_num; raw_num--) {
|
||||||
ctx->pptr[0] = ctx->pptr[1] = ctx->pptr[2] = *s;
|
ctx->pptr[0] = ctx->pptr[1] = ctx->pptr[2] = *s;
|
||||||
s++, n++;
|
s++, n++;
|
||||||
ctx->pptr += 3;
|
if (ctx->pbuf->n_channels == 4) {
|
||||||
ctx->pbuf_bytes_done += 3;
|
ctx->pptr[3] = *s++;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
ctx->pptr += ctx->pbuf->n_channels;
|
||||||
|
ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
|
||||||
|
if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
|
||||||
|
ctx->done = TRUE;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -526,13 +586,13 @@ static gboolean parse_rle_data(TGAContext *ctx, GError **err)
|
|||||||
guint pbuf_count = 0;
|
guint pbuf_count = 0;
|
||||||
if (ctx->hdr->type == TGA_TYPE_RLE_PSEUDOCOLOR) {
|
if (ctx->hdr->type == TGA_TYPE_RLE_PSEUDOCOLOR) {
|
||||||
count = parse_rle_data_pseudocolor(ctx);
|
count = parse_rle_data_pseudocolor(ctx);
|
||||||
pbuf_count = count *ctx->pbuf->n_channels;
|
pbuf_count = count * ctx->pbuf->n_channels;
|
||||||
} else if (ctx->hdr->type == TGA_TYPE_RLE_TRUECOLOR) {
|
} else if (ctx->hdr->type == TGA_TYPE_RLE_TRUECOLOR) {
|
||||||
count = parse_rle_data_truecolor(ctx);
|
count = parse_rle_data_truecolor(ctx);
|
||||||
pbuf_count = count;
|
pbuf_count = count;
|
||||||
} else if (ctx->hdr->type == TGA_TYPE_RLE_GRAYSCALE) {
|
} else if (ctx->hdr->type == TGA_TYPE_RLE_GRAYSCALE) {
|
||||||
count = parse_rle_data_grayscale(ctx);
|
count = parse_rle_data_grayscale(ctx);
|
||||||
pbuf_count = count * 3;
|
pbuf_count = count * (ctx->pbuf->n_channels == 4 ? 2 : 3);
|
||||||
}
|
}
|
||||||
ctx->in = io_buffer_free_segment(ctx->in, count, err);
|
ctx->in = io_buffer_free_segment(ctx->in, count, err);
|
||||||
if (!ctx->in)
|
if (!ctx->in)
|
||||||
@ -609,6 +669,28 @@ static gboolean try_preload(TGAContext *ctx, GError **err)
|
|||||||
}
|
}
|
||||||
g_memmove(ctx->hdr, ctx->in->data, sizeof(TGAHeader));
|
g_memmove(ctx->hdr, ctx->in->data, sizeof(TGAHeader));
|
||||||
ctx->in = io_buffer_free_segment(ctx->in, sizeof(TGAHeader), err);
|
ctx->in = io_buffer_free_segment(ctx->in, sizeof(TGAHeader), err);
|
||||||
|
#ifdef DEBUG_TGA
|
||||||
|
g_print ("infolen %d "
|
||||||
|
"has_cmap %d "
|
||||||
|
"type %d "
|
||||||
|
"cmap_start %d "
|
||||||
|
"cmap_n_colors %d "
|
||||||
|
"cmap_bpp %d "
|
||||||
|
"x %d y %d width %d height %d bpp %d "
|
||||||
|
"flags %#x",
|
||||||
|
ctx->hdr->infolen,
|
||||||
|
ctx->hdr->has_cmap,
|
||||||
|
ctx->hdr->type,
|
||||||
|
LE16(ctx->hdr->cmap_start),
|
||||||
|
LE16(ctx->hdr->cmap_n_colors),
|
||||||
|
ctx->hdr->cmap_bpp,
|
||||||
|
LE16(ctx->hdr->x_origin),
|
||||||
|
LE16(ctx->hdr->y_origin),
|
||||||
|
LE16(ctx->hdr->width),
|
||||||
|
LE16(ctx->hdr->height),
|
||||||
|
ctx->hdr->bpp,
|
||||||
|
ctx->hdr->flags);
|
||||||
|
#endif
|
||||||
if (!ctx->in)
|
if (!ctx->in)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
if (LE16(ctx->hdr->width) == 0 ||
|
if (LE16(ctx->hdr->width) == 0 ||
|
||||||
@ -635,17 +717,39 @@ static gboolean try_preload(TGAContext *ctx, GError **err)
|
|||||||
}
|
}
|
||||||
switch (ctx->hdr->type) {
|
switch (ctx->hdr->type) {
|
||||||
case TGA_TYPE_PSEUDOCOLOR:
|
case TGA_TYPE_PSEUDOCOLOR:
|
||||||
case TGA_TYPE_TRUECOLOR:
|
|
||||||
case TGA_TYPE_GRAYSCALE:
|
|
||||||
case TGA_TYPE_RLE_PSEUDOCOLOR:
|
case TGA_TYPE_RLE_PSEUDOCOLOR:
|
||||||
|
if (ctx->hdr->bpp != 8) {
|
||||||
|
g_set_error(err, GDK_PIXBUF_ERROR,
|
||||||
|
GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
|
||||||
|
_("TGA image type not supported"));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TGA_TYPE_TRUECOLOR:
|
||||||
case TGA_TYPE_RLE_TRUECOLOR:
|
case TGA_TYPE_RLE_TRUECOLOR:
|
||||||
|
if (ctx->hdr->bpp != 24 &&
|
||||||
|
ctx->hdr->bpp != 32) {
|
||||||
|
g_set_error(err, GDK_PIXBUF_ERROR,
|
||||||
|
GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
|
||||||
|
_("TGA image type not supported"));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TGA_TYPE_GRAYSCALE:
|
||||||
case TGA_TYPE_RLE_GRAYSCALE:
|
case TGA_TYPE_RLE_GRAYSCALE:
|
||||||
break;
|
if (ctx->hdr->bpp != 8 &&
|
||||||
|
ctx->hdr->bpp != 16) {
|
||||||
|
g_set_error(err, GDK_PIXBUF_ERROR,
|
||||||
|
GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
|
||||||
|
_("TGA image type not supported"));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
g_set_error(err, GDK_PIXBUF_ERROR,
|
g_set_error(err, GDK_PIXBUF_ERROR,
|
||||||
GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
|
GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
|
||||||
_("TGA image type not supported"));
|
_("TGA image type not supported"));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (!fill_in_context(ctx, err))
|
if (!fill_in_context(ctx, err))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -894,7 +998,9 @@ static GdkPixbuf *get_image_pseudocolor(FILE *f, TGAHeader *hdr,
|
|||||||
GdkPixbuf *pbuf;
|
GdkPixbuf *pbuf;
|
||||||
guchar *p, color, tag;
|
guchar *p, color, tag;
|
||||||
glong n, image_offset;
|
glong n, image_offset;
|
||||||
guint count;
|
guint count, w, h;
|
||||||
|
guchar *pixels;
|
||||||
|
gboolean alpha;
|
||||||
|
|
||||||
image_offset = sizeof(TGAHeader) + hdr->infolen;
|
image_offset = sizeof(TGAHeader) + hdr->infolen;
|
||||||
if (!hdr->has_cmap) {
|
if (!hdr->has_cmap) {
|
||||||
@ -911,8 +1017,22 @@ static GdkPixbuf *get_image_pseudocolor(FILE *f, TGAHeader *hdr,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, (hdr->cmap_bpp == 32), 8,
|
w = LE16(hdr->width);
|
||||||
LE16(hdr->width), LE16(hdr->height));
|
h = LE16(hdr->height);
|
||||||
|
|
||||||
|
alpha = (hdr->cmap_bpp == 32);
|
||||||
|
|
||||||
|
pixels = g_try_malloc (w * h * (alpha ? 4 : 3));
|
||||||
|
|
||||||
|
if (!pixels) {
|
||||||
|
g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
|
||||||
|
_("Insufficient memory to load TGA image"));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
pbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, alpha, 8,
|
||||||
|
w, h, w * (alpha ? 4 : 3),
|
||||||
|
free_buffer, NULL);
|
||||||
if (!pbuf) {
|
if (!pbuf) {
|
||||||
g_set_error(err, GDK_PIXBUF_ERROR,
|
g_set_error(err, GDK_PIXBUF_ERROR,
|
||||||
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
|
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
|
||||||
@ -998,7 +1118,9 @@ static GdkPixbuf *get_image_truecolor(FILE *f, TGAHeader *hdr,
|
|||||||
guchar *p, tag;
|
guchar *p, tag;
|
||||||
glong n, image_offset;
|
glong n, image_offset;
|
||||||
guint32 pixel;
|
guint32 pixel;
|
||||||
guint count;
|
guint count, w, h;
|
||||||
|
guchar *pixels;
|
||||||
|
gboolean alpha;
|
||||||
|
|
||||||
image_offset = sizeof(TGAHeader) + hdr->infolen;
|
image_offset = sizeof(TGAHeader) + hdr->infolen;
|
||||||
/* A truecolor image shouldn't actually have a colormap. */
|
/* A truecolor image shouldn't actually have a colormap. */
|
||||||
@ -1007,8 +1129,23 @@ static GdkPixbuf *get_image_truecolor(FILE *f, TGAHeader *hdr,
|
|||||||
if (!fseek_check(f, image_offset, SEEK_SET, err))
|
if (!fseek_check(f, image_offset, SEEK_SET, err))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
pbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, (hdr->bpp == 32), 8,
|
w = LE16(hdr->width);
|
||||||
LE16(hdr->width), LE16(hdr->height));
|
h = LE16(hdr->height);
|
||||||
|
|
||||||
|
alpha = (hdr->bpp == 32);
|
||||||
|
|
||||||
|
pixels = g_try_malloc (w * h * (alpha ? 4 : 3));
|
||||||
|
|
||||||
|
if (!pixels) {
|
||||||
|
g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
|
||||||
|
_("Insufficient memory to load TGA image"));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
pbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, alpha, 8,
|
||||||
|
w, h, w * (alpha ? 4 : 3),
|
||||||
|
free_buffer, NULL);
|
||||||
|
|
||||||
if (!pbuf) {
|
if (!pbuf) {
|
||||||
g_set_error(err, GDK_PIXBUF_ERROR,
|
g_set_error(err, GDK_PIXBUF_ERROR,
|
||||||
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
|
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
|
||||||
@ -1063,8 +1200,10 @@ static GdkPixbuf *get_image_grayscale(FILE *f, TGAHeader *hdr,
|
|||||||
{
|
{
|
||||||
GdkPixbuf *pbuf;
|
GdkPixbuf *pbuf;
|
||||||
glong n, image_offset;
|
glong n, image_offset;
|
||||||
guchar *p, color, tag;
|
guchar *p, color[2], tag;
|
||||||
guint count;
|
guint count, w, h;
|
||||||
|
guchar *pixels;
|
||||||
|
gboolean alpha;
|
||||||
|
|
||||||
image_offset = sizeof(TGAHeader) + hdr->infolen;
|
image_offset = sizeof(TGAHeader) + hdr->infolen;
|
||||||
/* A grayscale image shouldn't actually have a colormap. */
|
/* A grayscale image shouldn't actually have a colormap. */
|
||||||
@ -1073,8 +1212,23 @@ static GdkPixbuf *get_image_grayscale(FILE *f, TGAHeader *hdr,
|
|||||||
if (!fseek_check(f, image_offset, SEEK_SET, err))
|
if (!fseek_check(f, image_offset, SEEK_SET, err))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
pbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
|
w = LE16(hdr->width);
|
||||||
LE16(hdr->width), LE16(hdr->height));
|
h = LE16(hdr->height);
|
||||||
|
|
||||||
|
alpha = (hdr->bpp == 16);
|
||||||
|
|
||||||
|
pixels = g_try_malloc (w * h * (alpha ? 4 : 3));
|
||||||
|
|
||||||
|
if (!pixels) {
|
||||||
|
g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
|
||||||
|
_("Insufficient memory to load TGA image"));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
pbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, alpha, 8,
|
||||||
|
w, h, w * (alpha ? 4 : 3),
|
||||||
|
free_buffer, NULL);
|
||||||
|
|
||||||
if (!pbuf) {
|
if (!pbuf) {
|
||||||
g_set_error(err, GDK_PIXBUF_ERROR,
|
g_set_error(err, GDK_PIXBUF_ERROR,
|
||||||
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
|
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
|
||||||
@ -1095,35 +1249,41 @@ static GdkPixbuf *get_image_grayscale(FILE *f, TGAHeader *hdr,
|
|||||||
if (tag & 0x80) {
|
if (tag & 0x80) {
|
||||||
count = (tag & 0x7f) + 1;
|
count = (tag & 0x7f) + 1;
|
||||||
n += count;
|
n += count;
|
||||||
if (!fread_check(&color, 1, 1, f, err)) {
|
if (!fread_check(color, (alpha ? 2 : 1), 1, f, err)) {
|
||||||
g_object_unref(pbuf);
|
g_object_unref(pbuf);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
for (; count; count--) {
|
for (; count; count--) {
|
||||||
p[0] = p[1] = p[2] = color;
|
p[0] = p[1] = p[2] = color[0];
|
||||||
p += 3;
|
if (alpha)
|
||||||
|
p[3] = color[1];
|
||||||
|
p += pbuf->n_channels;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
count = tag + 1;
|
count = tag + 1;
|
||||||
n += count;
|
n += count;
|
||||||
for (; count; count--) {
|
for (; count; count--) {
|
||||||
if (!fread_check(&color, 1, 1, f, err)) {
|
if (!fread_check(color, (alpha ? 2 : 1), 1, f, err)) {
|
||||||
g_object_unref(pbuf);
|
g_object_unref(pbuf);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
p[0] = p[1] = p[2] = color;
|
p[0] = p[1] = p[2] = color[0];
|
||||||
p += 3;
|
if (alpha)
|
||||||
|
p[3] = color[1];
|
||||||
|
p += pbuf->n_channels;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (n = 0; n < pbuf->width * pbuf->height; n++) {
|
for (n = 0; n < pbuf->width * pbuf->height; n++) {
|
||||||
if (!fread_check(&color, 1, 1, f, err)) {
|
if (!fread_check(color, (alpha ? 2 : 1), 1, f, err)) {
|
||||||
g_object_unref(pbuf);
|
g_object_unref(pbuf);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
p[0] = p[1] = p[2] = color;
|
p[0] = p[1] = p[2] = color[0];
|
||||||
p += 3;
|
if (alpha)
|
||||||
|
p[3] = color[1];
|
||||||
|
p += pbuf->n_channels;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user