X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Flibgame%2Fpcx.c;h=9792331422cbb919763f6d13a45eee7dc90201ed;hb=a750ba6776fdfb711f5da2e6094c8010cd19645a;hp=f50e2c9a40a32c4de7e1139cbeb3044c01b0c386;hpb=e0560b41a1796a02b15937b0ae5453bca745e5ff;p=rocksndiamonds.git diff --git a/src/libgame/pcx.c b/src/libgame/pcx.c index f50e2c9a..97923314 100644 --- a/src/libgame/pcx.c +++ b/src/libgame/pcx.c @@ -1,7 +1,7 @@ /*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* -* (c) 1994-2000 Artsoft Entertainment * +* (c) 1994-2002 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * @@ -22,10 +22,9 @@ #define PCX_DEBUG FALSE #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 +35,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 +44,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,6 +53,7 @@ struct PCX_Header /* global PCX error value */ int errno_pcx = PCX_Success; +#if 0 static byte *PCX_ReadBitmap(Image *image, byte *buffer_ptr, byte *buffer_last) { /* Run Length Encoding: If the two high bits are set, @@ -97,7 +97,99 @@ static byte *PCX_ReadBitmap(Image *image, byte *buffer_ptr, byte *buffer_last) /* return current buffer position for next decoding function */ return buffer_ptr; } +#endif + +static boolean PCX_ReadBitmap(FILE *file, struct PCX_Header *pcx, Image *image) +{ + 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) + 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) + return FALSE; + value = (byte)value_int; + } + else + count = 1; + } + + dst_ptr[i] = value; + count--; + + if (pcx_depth == 8) + image->rgb.color_used[value] = TRUE; + } + + if (pcx_depth <= 4) /* expand planes to 1 byte/pixel */ + { + byte *src_ptr = row_buffer; + int plane; + + for (plane = 0; plane < pcx->color_planes; plane++) + { + int i, j, x = 0; + + for (i = 0; i < pcx->bytes_per_line; i++) + { + byte value = *src_ptr++; + + for (j = 7; j >= 0; j--) + { + byte bit = (value >> j) & 1; + + 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; + } + } + } + + bitmap_ptr += image->bytes_per_row; + } + return TRUE; +} + +#if 0 static byte *PCX_ReadColormap(Image *image,byte *buffer_ptr, byte *buffer_last) { int i, magic; @@ -124,16 +216,59 @@ static byte *PCX_ReadColormap(Image *image,byte *buffer_ptr, byte *buffer_last) /* return current buffer position for next decoding function */ return buffer_ptr; } +#endif + +static boolean PCX_ReadColormap(FILE *file,struct PCX_Header *pcx,Image *image) +{ + int pcx_depth = pcx->bits_per_pixel * pcx->color_planes; + int num_colors = (1 << pcx_depth); + int i; + + if (image->depth != 8) + return TRUE; + + if (pcx_depth == 8) + { + byte value; + int value_int; + + /* 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; i < PCX_MAXCOLORS; i++) + { + image->rgb.red[i] = (byte)fgetc(file) << 8; + image->rgb.green[i] = (byte)fgetc(file) << 8; + image->rgb.blue[i] = (byte)fgetc(file) << 8; + } + } + else + { + 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 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 +279,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 +321,9 @@ 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("%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,43 +335,36 @@ 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 */ + image->rgb.used = 0; + for (i=0; irgb.color_used[i]) + image->rgb.used++; + } #if PCX_DEBUG if (options.verbose)