X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Flibgame%2Fpcx.c;h=908def5c1aa4f438e0d23e47fd5d3bbc1183b26f;hb=a8816d6e5319f9ec26a45346b08250f61e95c011;hp=a43e67d5ff4ea2d5ccbbe17857c80fc7c2d3249c;hpb=681721dddc91bcdaef50002d1e861cc8d484e938;p=rocksndiamonds.git diff --git a/src/libgame/pcx.c b/src/libgame/pcx.c index a43e67d5..908def5c 100644 --- a/src/libgame/pcx.c +++ b/src/libgame/pcx.c @@ -1,7 +1,7 @@ /*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* -* (c) 1994-2001 Artsoft Entertainment * +* (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * @@ -11,21 +11,18 @@ * pcx.c * ***********************************************************/ -#ifndef TARGET_SDL - -#include - #include "pcx.h" #include "misc.h" -#define PCX_DEBUG FALSE +#if !defined(TARGET_SDL) + +#define PCX_DEBUG 0 #define PCX_MAGIC 0x0a /* first byte in a PCX image file */ -#define PCX_LAST_VERSION 5 /* last acceptable version number */ +#define PCX_SUPPORTED_VERSION 5 /* last acceptable version number */ #define PCX_ENCODING 1 /* PCX encoding method */ #define PCX_256COLORS_MAGIC 0x0c /* first byte of a PCX 256 color map */ -#define PCX_MAXDEPTH 8 /* supports up to 8 bits per pixel */ #define PCX_MAXCOLORS 256 /* maximum number of colors */ #define PCX_HEADER_SIZE 128 @@ -36,7 +33,7 @@ struct PCX_Header unsigned char signature; /* PCX file identifier */ unsigned char version; /* version compatibility level */ unsigned char encoding; /* encoding method */ - unsigned char bits_per_pixel; /* bits per pixel, or depth */ + unsigned char bits_per_pixel; /* bits per pixel (not depth!) */ unsigned short xmin; /* X position of left edge */ unsigned short ymin; /* Y position of top edge */ unsigned short xmax; /* X position of right edge */ @@ -45,7 +42,7 @@ struct PCX_Header unsigned short vres; /* Y screen resolution of source image */ unsigned char palette[16][3]; /* PCX color map */ unsigned char reserved; /* should be 0, 1 if std res fax */ - unsigned char color_planes; /* bit planes in image */ + unsigned char color_planes; /* "color planes" in image */ unsigned short bytes_per_line;/* byte delta between scanlines */ unsigned short palette_type; /* 0 = undef, 1 = color, 2 = grayscale */ unsigned char filler[58]; /* fill to struct size of 128 */ @@ -54,86 +51,161 @@ struct PCX_Header /* global PCX error value */ int errno_pcx = PCX_Success; -static byte *PCX_ReadBitmap(Image *image, byte *buffer_ptr, byte *buffer_last) +static boolean PCX_ReadBitmap(FILE *file, struct PCX_Header *pcx, Image *image) { - /* Run Length Encoding: If the two high bits are set, - * then the low 6 bits contain a repeat count, and the byte to - * repeat is the next byte in the file. If the two high bits are - * not set, then this is the byte to write. - */ + int width = image->width; + int height = image->height; + int pcx_depth = pcx->bits_per_pixel * pcx->color_planes; + int bytes_per_row = pcx->color_planes * pcx->bytes_per_line; + byte *row_buffer = checked_malloc(bytes_per_row); + byte *bitmap_ptr = image->data; + int y; + + for (y = 0; y < height; y++) + { + /* decode a scan line into a temporary buffer first */ + byte *dst_ptr = (pcx_depth == 8 ? bitmap_ptr : row_buffer); + byte value = 0, count = 0; + int value_int; + int i; + + for (i = 0; i < bytes_per_row; i++) + { + if (count == 0) + { + if ((value_int = fgetc(file)) == EOF) + { + free(row_buffer); + return FALSE; + } + + value = (byte)value_int; + + if ((value & 0xc0) == 0xc0) /* this is a repeat count byte */ + { + count = value & 0x3f; /* extract repeat count from byte */ + + if ((value_int = fgetc(file)) == EOF) + { + free(row_buffer); + return FALSE; + } + + value = (byte)value_int; + } + else + count = 1; + } + + dst_ptr[i] = value; + count--; + + if (pcx_depth == 8) + image->rgb.color_used[value] = TRUE; + } - unsigned int bytes_per_pixel = (image->depth + 7) / 8; - register byte *bitmap_ptr, *bitmap_last; - register byte value, count; + if (pcx_depth <= 4) /* expand planes to 1 byte/pixel */ + { + byte *src_ptr = row_buffer; + int plane; - bitmap_ptr = image->data; - bitmap_last = bitmap_ptr + (image->width * image->height * bytes_per_pixel); + for (plane = 0; plane < pcx->color_planes; plane++) + { + int i, j, x = 0; - while (bitmap_ptr < bitmap_last && buffer_ptr < buffer_last) - { - value = *buffer_ptr++; + for (i = 0; i < pcx->bytes_per_line; i++) + { + byte value = *src_ptr++; - if ((value & 0xc0) == 0xc0) /* this is a repeat count byte */ - { - count = value & 0x3f; /* extract repeat count from byte */ - value = *buffer_ptr++; /* next byte is value to repeat */ + for (j = 7; j >= 0; j--) + { + byte bit = (value >> j) & 1; - for (; count && bitmap_ptr < bitmap_last; count--) - *bitmap_ptr++ = value; + if (i * 8 + j >= width) /* skip padding bits */ + continue; - if (count) /* repeat count spans end of bitmap */ - return NULL; + bitmap_ptr[x++] |= bit << plane; + } + } + } + } + else if (pcx_depth == 24) /* de-interlace planes */ + { + byte *src_ptr = row_buffer; + int plane; + + for (plane = 0; plane < pcx->color_planes; plane++) + { + int x; + + dst_ptr = bitmap_ptr + plane; + for (x = 0; x < width; x++) + { + *dst_ptr = *src_ptr++; + dst_ptr += pcx->color_planes; + } + } } - else - *bitmap_ptr++ = value; - image->rgb.color_used[value] = TRUE; + bitmap_ptr += image->bytes_per_row; } - /* check if end of buffer was reached before end of bitmap */ - if (bitmap_ptr < bitmap_last) - return NULL; + free(row_buffer); - /* return current buffer position for next decoding function */ - return buffer_ptr; + return TRUE; } -static byte *PCX_ReadColormap(Image *image,byte *buffer_ptr, byte *buffer_last) +static boolean PCX_ReadColormap(FILE *file,struct PCX_Header *pcx,Image *image) { - int i, magic; + int pcx_depth = pcx->bits_per_pixel * pcx->color_planes; + int num_colors = (1 << pcx_depth); + int i; - /* read colormap magic byte */ - magic = *buffer_ptr++; + if (image->depth != 8) + return TRUE; - /* check magic colormap header byte */ - if (magic != PCX_256COLORS_MAGIC) - return NULL; + if (pcx_depth == 8) + { + byte value; + int value_int; - /* check if enough bytes left for a complete colormap */ - if (buffer_ptr + PCX_COLORMAP_SIZE > buffer_last) - return NULL; + /* look for a 256-colour palette */ + do + { + if ((value_int = fgetc(file)) == EOF) + return FALSE; + value = (byte)value_int; + } + while (value != PCX_256COLORS_MAGIC); - /* read 256 colors from PCX colormap */ - for (i=0; irgb.red[i] = (byte)fgetc(file) << 8; + image->rgb.green[i] = (byte)fgetc(file) << 8; + image->rgb.blue[i] = (byte)fgetc(file) << 8; + } + } + else { - image->rgb.red[i] = *buffer_ptr++ << 8; - image->rgb.green[i] = *buffer_ptr++ << 8; - image->rgb.blue[i] = *buffer_ptr++ << 8; + for (i = 0; i < num_colors; i++) + { + image->rgb.red[i] = pcx->palette[i][0] << 8; + image->rgb.green[i] = pcx->palette[i][1] << 8; + image->rgb.blue[i] = pcx->palette[i][2] << 8; + } } - /* return current buffer position for next decoding function */ - return buffer_ptr; + return TRUE; } Image *Read_PCX_to_Image(char *filename) { FILE *file; - byte *file_buffer; - byte *buffer_ptr, *buffer_last; - unsigned int file_length; + byte header_buffer[PCX_HEADER_SIZE]; struct PCX_Header pcx; Image *image; - int width, height, depth; + int width, height, depth, pcx_depth; int i; errno_pcx = PCX_Success; @@ -144,57 +216,40 @@ Image *Read_PCX_to_Image(char *filename) return NULL; } - if (fseek(file, 0, SEEK_END) == -1) - { - fclose(file); - errno_pcx = PCX_ReadFailed; - return NULL; - } - - file_length = ftell(file); - rewind(file); - - if (file_length < PCX_HEADER_SIZE) + if (fread(header_buffer, 1, PCX_HEADER_SIZE, file) != PCX_HEADER_SIZE) { - /* PCX file is too short to contain a valid PCX header */ fclose(file); - errno_pcx = PCX_FileInvalid; - return NULL; - } - - file_buffer = checked_malloc(file_length); - - if (fread(file_buffer, 1, file_length, file) != file_length) - { - fclose(file); errno_pcx = PCX_ReadFailed; return NULL; } - fclose(file); - - pcx.signature = file_buffer[0]; - pcx.version = file_buffer[1]; - pcx.encoding = file_buffer[2]; - pcx.bits_per_pixel = file_buffer[3]; - pcx.xmin = file_buffer[4] + 256 * file_buffer[5]; - pcx.ymin = file_buffer[6] + 256 * file_buffer[7]; - pcx.xmax = file_buffer[8] + 256 * file_buffer[9]; - pcx.ymax = file_buffer[10] + 256 * file_buffer[11]; - pcx.color_planes = file_buffer[65]; - pcx.bytes_per_line = file_buffer[66] + 256 * file_buffer[67]; - pcx.palette_type = file_buffer[68] + 256 * file_buffer[69]; + pcx.signature = header_buffer[0]; + pcx.version = header_buffer[1]; + pcx.encoding = header_buffer[2]; + pcx.bits_per_pixel = header_buffer[3]; + pcx.xmin = (header_buffer[5] << 8) | header_buffer[4]; + pcx.ymin = (header_buffer[7] << 8) | header_buffer[6]; + pcx.xmax = (header_buffer[9] << 8) | header_buffer[8]; + pcx.ymax = (header_buffer[11] << 8) | header_buffer[10]; + pcx.color_planes = header_buffer[65]; + pcx.bytes_per_line = (header_buffer[67] << 8) | header_buffer[66]; + pcx.palette_type = (header_buffer[69] << 8) | header_buffer[68]; + + for (i = 0; i < 48; i++) + pcx.palette[i / 3][i % 3] = header_buffer[16 + i]; width = pcx.xmax - pcx.xmin + 1; height = pcx.ymax - pcx.ymin + 1; - depth = pcx.bits_per_pixel; + pcx_depth = pcx.bits_per_pixel * pcx.color_planes; + depth = ((pcx_depth + 7) / 8) * 8; - if (pcx.signature != PCX_MAGIC || pcx.version > PCX_LAST_VERSION || - pcx.encoding != PCX_ENCODING || pcx.color_planes > PCX_MAXDEPTH || + if (pcx.signature != PCX_MAGIC || + pcx.version != PCX_SUPPORTED_VERSION || + pcx.encoding != PCX_ENCODING || width < 0 || height < 0) { - free(file_buffer); + fclose(file); errno_pcx = PCX_FileInvalid; return NULL; @@ -203,10 +258,10 @@ Image *Read_PCX_to_Image(char *filename) #if PCX_DEBUG if (options.verbose) { - printf("%s is a %dx%d PC Paintbrush image with %d bitplanes\n", - filename, width, height, - pcx.color_planes); - printf("depth: %d\n", pcx.bits_per_pixel); + printf("\n"); + printf("%s is a %dx%d PC Paintbrush image\n", filename, width, height); + printf("depth: %d\n", depth); + printf("bits_per_pixel: %d\n", pcx.bits_per_pixel); printf("color_planes: %d\n", pcx.color_planes); printf("bytes_per_line: %d\n", pcx.bytes_per_line); printf("palette type: %s\n", @@ -218,47 +273,39 @@ Image *Read_PCX_to_Image(char *filename) /* allocate new image structure */ image = newImage(width, height, depth); - buffer_ptr = file_buffer + PCX_HEADER_SIZE; - buffer_last = file_buffer + file_length; - /* read compressed bitmap data */ - if ((buffer_ptr = PCX_ReadBitmap(image, buffer_ptr, buffer_last)) == NULL) + if (!PCX_ReadBitmap(file, &pcx, image)) { - free(file_buffer); + fclose(file); freeImage(image); errno_pcx = PCX_FileInvalid; return NULL; } - if (file_length < PCX_HEADER_SIZE + PCX_COLORMAP_SIZE) - { - /* PCX file is too short to contain a valid 256 colors colormap */ - fclose(file); - errno_pcx = PCX_ColorFailed; - return NULL; - } - /* read colormap data */ - if (!PCX_ReadColormap(image, buffer_ptr, buffer_last)) + if (!PCX_ReadColormap(file, &pcx, image)) { - free(file_buffer); + fclose(file); freeImage(image); + errno_pcx = PCX_ColorFailed; return NULL; } - free(file_buffer); + fclose(file); - /* determine number of used colormap entries */ - image->rgb.used = 0; - for (i=0; irgb.color_used[i]) - image->rgb.used++; + if (pcx_depth == 8) + { + /* determine number of used colormap entries for 8-bit PCX images */ + for (i = 0; i < PCX_MAXCOLORS; i++) + if (image->rgb.color_used[i]) + image->rgb.used++; + } #if PCX_DEBUG if (options.verbose) - printf("Read_PCX_to_Image: %d colors found\n", image->rgb.used); + printf("Read_PCX_to_Image: %d colors in colormap\n", image->rgb.used); #endif return image;