Error(ERR_EXIT, "images with more than 256 colors are not supported");
depth = 8;
+
image = checked_malloc(sizeof(Image));
image->data = checked_malloc(width * height * bytes_per_pixel);
image->width = width;
image->height = height;
image->depth = depth;
image->rgb.used = 0;
+
for (i=0; i<MAX_COLORS; i++)
image->rgb.color_used[i] = FALSE;
+ image->type = (depth < 8 ? IMAGETYPE_BITMAP :
+ depth > 8 ? IMAGETYPE_TRUECOLOR : IMAGETYPE_RGB);
+
+ image->bytes_per_row = (depth + 7) / 8;
+ image->bytes_per_row *= width;
+
return image;
}
/* extra colors to try allocating in private color maps to minimize flashing */
#define NOFLASH_COLORS 256
-/* architecture independent value-to-memory conversion
+/* architecture independent value <-> memory conversions;
note: the internal format is big endian */
-#define value_to_memory(value, ptr, length) ( \
-(length) == 1 ? (*( (byte *)(ptr) ) = ( value ) ) : \
-(length) == 2 ? (*( (byte *)(ptr) ) = (((unsigned long)(value))>> 8), \
- *(((byte *)(ptr))+1) = ( value ) ) : \
-(length) == 3 ? (*( (byte *)(ptr) ) = (((unsigned long)(value))>>16), \
- *(((byte *)(ptr))+1) = (((unsigned long)(value))>> 8), \
- *(((byte *)(ptr))+2) = ( value ) ) : \
- (*( (byte *)(ptr) ) = (((unsigned long)(value))>>24), \
- *(((byte *)(ptr))+1) = (((unsigned long)(value))>>16), \
- *(((byte *)(ptr))+2) = (((unsigned long)(value))>> 8), \
- *(((byte *)(ptr))+3) = ( value ) ))
+#define memory_to_value(ptr, len) ( \
+(len) == 1 ? (unsigned long)( *( (byte *)(ptr)) ) : \
+(len) == 2 ? (unsigned long)(((unsigned long)(*( (byte *)(ptr)) ))<< 8) \
+ + ( *(((byte *)(ptr))+1) ) : \
+(len) == 3 ? (unsigned long)(((unsigned long)(*( (byte *)(ptr)) ))<<16) \
+ + (((unsigned long)(*(((byte *)(ptr))+1)))<< 8) \
+ + ( *(((byte *)(ptr))+2) ) : \
+ (unsigned long)(((unsigned long)(*( (byte *)(ptr)) ))<<24) \
+ + (((unsigned long)(*(((byte *)(ptr))+1)))<<16) \
+ + (((unsigned long)(*(((byte *)(ptr))+2)))<< 8) \
+ + ( *(((byte *)(ptr))+3) ) )
+
+
+#define value_to_memory(value, ptr, len) ( \
+(len) == 1 ? (*( (byte *)(ptr) ) = ( value ) ) : \
+(len) == 2 ? (*( (byte *)(ptr) ) = (((unsigned long)(value))>> 8), \
+ *(((byte *)(ptr))+1) = ( value ) ) : \
+(len) == 3 ? (*( (byte *)(ptr) ) = (((unsigned long)(value))>>16), \
+ *(((byte *)(ptr))+1) = (((unsigned long)(value))>> 8), \
+ *(((byte *)(ptr))+2) = ( value ) ) : \
+ (*( (byte *)(ptr) ) = (((unsigned long)(value))>>24), \
+ *(((byte *)(ptr))+1) = (((unsigned long)(value))>>16), \
+ *(((byte *)(ptr))+2) = (((unsigned long)(value))>> 8), \
+ *(((byte *)(ptr))+3) = ( value ) ))
static Pixmap Image_to_Mask(Image *image, Display *display, Window window)
{
/* something completely unexpected happened */
- fprintf(stderr, "imageToXImage: XAllocColor failed on a TrueColor/Directcolor visual\n");
+ fprintf(stderr, "Image_to_Pixmap: XAllocColor failed on a TrueColor/Directcolor visual\n");
free(redvalue);
free(greenvalue);
free(bluevalue);
{
Pixel pixval;
- for (y=0; y<image->height; y++) /* general case */
+ switch (image->type)
{
- for (x=0; x<image->width; x++)
+ case IMAGETYPE_RGB:
+ {
+ for (y=0; y<image->height; y++) /* general case */
+ {
+ for (x=0; x<image->width; x++)
+ {
+ pixval = *src_ptr++;
+ pixval =
+ redvalue[image->rgb.red[pixval] >> 8] |
+ greenvalue[image->rgb.green[pixval] >> 8] |
+ bluevalue[image->rgb.blue[pixval] >> 8];
+ value_to_memory(pixval, dst_ptr, bytes_per_pixel);
+ dst_ptr += bytes_per_pixel;
+ }
+ }
+ break;
+ }
+
+ case IMAGETYPE_TRUECOLOR:
{
- pixval = *src_ptr++;
- pixval =
- redvalue[image->rgb.red[pixval] >> 8] |
- greenvalue[image->rgb.green[pixval] >> 8] |
- bluevalue[image->rgb.blue[pixval] >> 8];
- value_to_memory(pixval, dst_ptr, bytes_per_pixel);
- dst_ptr += bytes_per_pixel;
+ for (y=0; y<image->height; y++) /* general case */
+ {
+ for (x=0; x<image->width; x++)
+ {
+ pixval = memory_to_value(src_ptr, image->depth);
+ pixval =
+ redvalue[TRUECOLOR_RED(pixval)] |
+ greenvalue[TRUECOLOR_GREEN(pixval)] |
+ bluevalue[TRUECOLOR_BLUE(pixval)];
+ value_to_memory(pixval, dst_ptr, bytes_per_pixel);
+ src_ptr += image->depth;
+ dst_ptr += bytes_per_pixel;
+ }
+ }
+ break;
}
+
+ default:
+ Error(ERR_RETURN, "image type not supported");
+ Error(ERR_EXIT, "RGB or TrueColor image needed");
+ break;
}
break;
}
#include "misc.h"
-#define PCX_DEBUG FALSE
+#define PCX_DEBUG TRUE
#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
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 */
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 */
/* 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,
/* 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;
/* 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;
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;
#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",
/* 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; i<PCX_MAXCOLORS; i++)
- if (image->rgb.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; i<PCX_MAXCOLORS; i++)
+ if (image->rgb.color_used[i])
+ image->rgb.used++;
+ }
#if PCX_DEBUG
if (options.verbose)