***********************************************************/
#include "image.h"
+#include "pcx.h"
#include "misc.h"
+/* exclude all except newImage() and freeImage() */
+#ifndef MSDOS
-#ifdef DEBUG
-
-#define DEBUG_TIMING
-
-#endif
-
-#ifdef DEBUG_TIMING
- long count1, count2;
-#endif
-
-
-/* extra colors to try allocating in private color maps to minimise flashing */
+/* extra colors to try allocating in private color maps to minimize flashing */
#define NOFLASH_COLORS 256
-static void Image_to_Mask(Image *image)
+/* architecture independent value-to-memory conversion
+ 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 ) ))
+
+static Pixmap Image_to_Mask(Image *image, Display *display, Window window)
{
- unsigned char *src_ptr, *dst_ptr, *dst_ptr2;
+ byte *src_ptr, *dst_ptr, *dst_ptr2;
unsigned int bytes_per_row;
unsigned int x, y;
- unsigned char bitmask;
+ byte bitmask;
+ byte *mask_data;
+ Pixmap mask_pixmap;
bytes_per_row = (image->width + 7) / 8;
+ mask_data = checked_calloc(bytes_per_row * image->height);
+
src_ptr = image->data;
- dst_ptr = image->data_mask;
+ dst_ptr = mask_data;
+
+ /* create bitmap data which can be used by 'XCreateBitmapFromData()'
+ * directly to create a pixmap of depth 1 for use as a clip mask for
+ * the corresponding image pixmap
+ */
for (y=0; y<image->height; y++)
{
- bitmask = 0x80; /* start with leftmost bit in the byte */
+ bitmask = 0x01; /* start with leftmost bit in the byte */
dst_ptr2 = dst_ptr; /* start with leftmost byte in the row */
for (x=0; x<image->width; x++)
if (*src_ptr++) /* source pixel solid? (pixel index != 0) */
*dst_ptr2 |= bitmask; /* then write a bit into the image mask */
- if ((bitmask >>= 1) == 0) /* bit at rightmost byte position reached? */
+ if ((bitmask <<= 1) == 0) /* bit at rightmost byte position reached? */
{
- bitmask = 0x80; /* start again with leftmost bit position */
+ bitmask = 0x01; /* start again with leftmost bit position */
dst_ptr2++; /* continue with next byte in image mask */
}
}
dst_ptr += bytes_per_row; /* continue with leftmost byte of next row */
}
-}
-
-static boolean XImage_to_Pixmap(Display *display, Window parent,
- XImageInfo *ximageinfo)
-{
- XGCValues gcv;
-
- ximageinfo->pixmap =
- XCreatePixmap(display, parent,
- ximageinfo->ximage->width,
- ximageinfo->ximage->height,
- ximageinfo->depth);
-
- ximageinfo->pixmap_mask =
- XCreatePixmap(display, parent,
- ximageinfo->ximage->width,
- ximageinfo->ximage->height,
- 1);
-
- /* build and cache the GC */
-
- if (!ximageinfo->gc)
- {
- gcv.function = GXcopy;
- ximageinfo->gc =
- XCreateGC(ximageinfo->display, ximageinfo->pixmap,
- GCFunction, &gcv);
- }
-
- if (!ximageinfo->gc_mask)
- {
- gcv.function = GXcopy;
- gcv.foreground = ximageinfo->foreground;
- gcv.background = ximageinfo->background;
- ximageinfo->gc_mask =
- XCreateGC(ximageinfo->display, ximageinfo->pixmap_mask,
- GCFunction | GCForeground | GCBackground, &gcv);
- }
- XPutImage(ximageinfo->display, ximageinfo->pixmap, ximageinfo->gc,
- ximageinfo->ximage, 0, 0, 0, 0,
- ximageinfo->ximage->width, ximageinfo->ximage->height);
- XPutImage(ximageinfo->display, ximageinfo->pixmap_mask, ximageinfo->gc_mask,
- ximageinfo->ximage_mask, 0, 0, 0, 0,
- ximageinfo->ximage->width, ximageinfo->ximage->height);
+ mask_pixmap = XCreateBitmapFromData(display, window, (char *)mask_data,
+ image->width, image->height);
+ free(mask_data);
- return (ximageinfo->pixmap != None && ximageinfo->pixmap_mask != None);
+ return mask_pixmap;
}
-/* find the best pixmap depth supported by the server for a particular
- * visual and return that depth.
- */
-
-static unsigned int bitsPerPixelAtDepth(Display *display, int screen,
- unsigned int depth)
+static int bitsPerPixelAtDepth(Display *display, int screen, int depth)
{
- XPixmapFormatValues *xf;
- int nxf, a;
+ XPixmapFormatValues *pixmap_format;
+ int i, num_pixmap_formats, bits_per_pixel = -1;
- xf = XListPixmapFormats(display, &nxf);
- for (a = 0; a < nxf; a++)
- {
- if (xf[a].depth == depth)
- {
- int bpp;
- bpp = xf[a].bits_per_pixel;
- XFree(xf);
- return (unsigned int) bpp;
- }
- }
- XFree(xf);
+ /* get Pixmap formats supported by the X server */
+ pixmap_format = XListPixmapFormats(display, &num_pixmap_formats);
+
+ /* find format that matches the given depth */
+ for (i=0; i<num_pixmap_formats; i++)
+ if (pixmap_format[i].depth == depth)
+ bits_per_pixel = pixmap_format[i].bits_per_pixel;
- /* this should never happen; if it does, we're in trouble */
+ XFree(pixmap_format);
- fprintf(stderr, "bitsPerPixelAtDepth: Can't find pixmap depth info!\n");
- exit(1);
+ if (bits_per_pixel == -1)
+ Error(ERR_EXIT, "cannot find pixmap format for depth %d", depth);
+
+ return bits_per_pixel;
}
-XImageInfo *Image_to_XImage(Display *display, int screen, Visual *visual,
- unsigned int ddepth, Image *image)
+XImageInfo *Image_to_Pixmap(Display *display, int screen, Visual *visual,
+ Window window, GC gc, int depth, Image *image)
{
static XColor xcolor_private[NOFLASH_COLORS];
static int colorcell_used[NOFLASH_COLORS];
static Colormap global_cmap = 0;
static Pixel *global_cmap_index;
static int num_cmap_entries, free_cmap_entries;
- static private_cmap = FALSE;
+ static boolean private_cmap = FALSE;
Pixel *redvalue, *greenvalue, *bluevalue;
- unsigned int a, c=0, x, y, linelen, dpixlen, dbits;
+ unsigned int a, c = 0, x, y, bytes_per_pixel, bits_per_pixel;
XColor xcolor;
- XGCValues gcv;
+ XImage *ximage;
XImageInfo *ximageinfo;
-
- /* for building image */
- byte *data, *destptr, *srcptr;
-
- /* for building image mask */
- byte *data_mask;
+ byte *src_ptr, *dst_ptr;
if (!global_cmap)
{
else
{
global_cmap = XCreateColormap(display, RootWindow(display, screen),
- visual, AllocNone);
+ visual, AllocNone);
private_cmap = TRUE;
}
}
xcolor.flags = DoRed | DoGreen | DoBlue;
redvalue = greenvalue = bluevalue = NULL;
- ximageinfo = (XImageInfo *)checked_malloc(sizeof(XImageInfo));
+ ximageinfo = checked_malloc(sizeof(XImageInfo));
ximageinfo->display = display;
- ximageinfo->screen = screen;
- ximageinfo->depth = 0;
- ximageinfo->drawable = None;
- ximageinfo->index = NULL;
- ximageinfo->rootimage = FALSE;
- ximageinfo->foreground = ximageinfo->background= 0;
- ximageinfo->gc = NULL;
- ximageinfo->gc_mask = NULL;
- ximageinfo->ximage = NULL;
- ximageinfo->ximage_mask = NULL;
+ ximageinfo->depth = depth;
switch (visual->class)
{
retry_direct: /* tag we hit if a DirectColor allocation fails on
* default colormap */
- /* calculate number of distinct colors in each band
- */
+ /* calculate number of distinct colors in each band */
redcolors = greencolors = bluecolors = 1;
for (pixval=1; pixval; pixval <<= 1)
bluecolors <<= 1;
}
- /* sanity check
- */
-
- if ((redcolors > visual->map_entries) ||
- (greencolors > visual->map_entries) ||
- (bluecolors > visual->map_entries))
- {
- fprintf(stderr, "Warning: inconsistency in color information (this may be ugly)\n");
- }
+ /* consistency check */
+ if (redcolors > visual->map_entries ||
+ greencolors > visual->map_entries ||
+ bluecolors > visual->map_entries)
+ Error(ERR_WARN, "inconsistency in color information");
redstep = 256 / redcolors;
greenstep = 256 / greencolors;
if (!XAllocColor(display, ximageinfo->cmap, &xcolor))
{
/* if an allocation fails for a DirectColor default visual then
- * we should create a private colormap and try again.
- */
+ we should create a private colormap and try again. */
if ((visual->class == DirectColor) &&
(visual == DefaultVisual(display, screen)))
goto retry_direct;
}
- /* something completely unexpected happened
- */
+ /* something completely unexpected happened */
fprintf(stderr, "imageToXImage: XAllocColor failed on a TrueColor/Directcolor visual\n");
- free((byte *)redvalue);
- free((byte *)greenvalue);
- free((byte *)bluevalue);
- free((byte *)ximageinfo);
- return(NULL);
+ free(redvalue);
+ free(greenvalue);
+ free(bluevalue);
+ free(ximageinfo);
+ return NULL;
}
- /* fill in pixel values for each band at this intensity
- */
+ /* fill in pixel values for each band at this intensity */
while ((redbottom < 256) && (redbottom < redtop))
redvalue[redbottom++] = xcolor.pixel & visual->red_mask;
case PseudoColor:
ximageinfo->cmap = global_cmap;
- ximageinfo->index =
- (Pixel *)checked_malloc(sizeof(Pixel) * image->rgb.used);
-
-#if 0
- for (a=0; a<image->rgb.used; a++)
-#endif
for (a=0; a<MAX_COLORS; a++)
{
}
if (!color_found) /* no more free color cells */
- {
- printf("Sorry, cannot allocate enough colors!\n");
- exit(0);
- }
+ Error(ERR_EXIT, "cannot allocate enough color cells");
xcolor.pixel = xcolor2.pixel;
xcolor_private[xcolor.pixel] = xcolor;
break;
default:
- printf("Sorry, only DirectColor, TrueColor and PseudoColor supported\n");
- exit(0);
+ Error(ERR_RETURN, "display class not supported");
+ Error(ERR_EXIT, "DirectColor, TrueColor or PseudoColor display needed");
break;
}
-#ifdef DEBUG_TIMING
- count2 = Counter();
- printf(" CONVERTING IMAGE TO XIMAGE (COLORMAP) IN %.2f SECONDS\n",
- (float)(count2-count1)/1000.0);
- count1 = Counter();
+#if DEBUG_TIMING
+ debug_print_timestamp(2, " ALLOCATING IMAGE COLORS: ");
#endif
- /* CREATE IMAGE ITSELF */
- /* modify image data to match visual and colormap */
+ /* create XImage from internal image structure and convert it to Pixmap */
- dbits = bitsPerPixelAtDepth(display, screen, ddepth);/* bits per pixel */
- dpixlen = (dbits + 7) / 8; /* bytes per pixel */
+ bits_per_pixel = bitsPerPixelAtDepth(display, screen, depth);
+ bytes_per_pixel = (bits_per_pixel + 7) / 8;
- ximageinfo->ximage = XCreateImage(display, visual, ddepth, ZPixmap, 0,
- NULL, image->width, image->height,
- 8, image->width * dpixlen);
+ ximage = XCreateImage(display, visual, depth, ZPixmap, 0,
+ NULL, image->width, image->height,
+ 8, image->width * bytes_per_pixel);
+ ximage->data =
+ checked_malloc(image->width * image->height * bytes_per_pixel);
+ ximage->byte_order = MSBFirst;
- data = (byte *)checked_malloc(image->width * image->height * dpixlen);
- ximageinfo->depth = ddepth;
- ximageinfo->ximage->data = (char *)data;
- ximageinfo->ximage->byte_order = MSBFirst;
- srcptr = image->data;
- destptr = data;
+ src_ptr = image->data;
+ dst_ptr = (byte *)ximage->data;
switch (visual->class)
{
{
Pixel pixval;
- for (y=0; y<image->height; y++)
+ for (y=0; y<image->height; y++) /* general case */
{
for (x=0; x<image->width; x++)
{
- pixval = memToVal(srcptr, 1);
+ pixval = *src_ptr++;
pixval =
redvalue[image->rgb.red[pixval] >> 8] |
greenvalue[image->rgb.green[pixval] >> 8] |
bluevalue[image->rgb.blue[pixval] >> 8];
- valToMem(pixval, destptr, dpixlen);
- srcptr += 1;
- destptr += dpixlen;
+ value_to_memory(pixval, dst_ptr, bytes_per_pixel);
+ dst_ptr += bytes_per_pixel;
}
}
break;
}
- default:
+ case PseudoColor:
{
- if (dpixlen == 1) /* most common */
+ if (bytes_per_pixel == 1) /* (common) special case */
{
for (y=0; y<image->height; y++)
- {
for (x=0; x<image->width; x++)
- {
- *destptr = ximageinfo->index[c + *srcptr];
- srcptr++;
- destptr++;
- }
- }
+ *dst_ptr++ = ximageinfo->index[c + *src_ptr++];
}
- else /* less common */
+ else /* general case */
{
for (y=0; y<image->height; y++)
{
for (x=0; x<image->width; x++)
{
- register unsigned long temp;
- temp = memToVal(srcptr, 1);
- valToMem(ximageinfo->index[c + temp], destptr, dpixlen);
- srcptr += 1;
- destptr += dpixlen;
+ value_to_memory(ximageinfo->index[c + *src_ptr++],
+ dst_ptr, bytes_per_pixel);
+ dst_ptr += bytes_per_pixel;
}
}
}
+ break;
}
- }
-
- /* NOW CREATE IMAGE MASK */
- /* we copy the data to be more consistent */
-
- linelen = ((image->width + 7) / 8);
- data_mask = checked_malloc(linelen * image->height);
- memcpy((char *)data_mask, (char *)image->data_mask,
- linelen * image->height);
-
- gcv.function = GXcopy;
- ximageinfo->ximage_mask =
- XCreateImage(display, visual, 1, XYBitmap, 0, (char *)data_mask,
- image->width, image->height, 8, linelen);
-
-#if 0
- if (visual->class == DirectColor || visual->class == TrueColor)
- {
- Pixel pixval;
- dbits = bitsPerPixelAtDepth(display, screen, ddepth);
- dpixlen = (dbits + 7) / 8;
- pixval =
- redvalue[65535 >> 8] |
- greenvalue[65535 >> 8] |
- bluevalue[65535 >> 8];
- ximageinfo->background = pixval;
- pixval =
- redvalue[0 >> 8] |
- greenvalue[0 >> 8] |
- bluevalue[0 >> 8];
- ximageinfo->foreground = pixval;
- }
- else /* Not Direct or True Color */
- {
- ximageinfo->foreground = BlackPixel(display, screen);
- ximageinfo->background = WhitePixel(display, screen);
+ default:
+ Error(ERR_RETURN, "display class not supported");
+ Error(ERR_EXIT, "DirectColor, TrueColor or PseudoColor display needed");
+ break;
}
-#else
- ximageinfo->foreground = WhitePixel(display, screen);
- ximageinfo->background = BlackPixel(display, screen);
-#endif
-
- ximageinfo->ximage_mask->bitmap_bit_order = MSBFirst;
- ximageinfo->ximage_mask->byte_order = MSBFirst;
if (redvalue)
{
free((byte *)bluevalue);
}
+#if DEBUG_TIMING
+ debug_print_timestamp(2, " CONVERTING IMAGE TO XIMAGE:");
+#endif
+
+ ximageinfo->pixmap = XCreatePixmap(display, window,
+ ximage->width, ximage->height,
+ ximageinfo->depth);
+
+ XPutImage(ximageinfo->display, ximageinfo->pixmap, gc,
+ ximage, 0, 0, 0, 0, ximage->width, ximage->height);
+
+ free(ximage->data);
+ ximage->data = NULL;
+ XDestroyImage(ximage);
+
return(ximageinfo);
}
-/* free up anything cached in the local Ximage structure.
- */
-
void freeXImage(Image *image, XImageInfo *ximageinfo)
{
- if (ximageinfo->index != NULL) /* if we allocated colors */
- {
- if (ximageinfo->no > 0 && !ximageinfo->rootimage) /* don't free root colors */
- XFreeColors(ximageinfo->display, ximageinfo->cmap, ximageinfo->index,
- ximageinfo->no, 0);
- free(ximageinfo->index);
- }
- if (ximageinfo->gc)
- XFreeGC(ximageinfo->display, ximageinfo->gc);
- free((byte *)ximageinfo->ximage->data);
- ximageinfo->ximage->data= NULL;
- XDestroyImage(ximageinfo->ximage);
- free((byte *)ximageinfo);
- /* should we free private color map to ??? */
+ if (ximageinfo->index != NULL && ximageinfo->no > 0)
+ XFreeColors(ximageinfo->display, ximageinfo->cmap, ximageinfo->index,
+ ximageinfo->no, 0);
+ /* this ^^^^^^^^^^^^^^ is wrong, because the used color cells
+ * are somewhere between 0 and MAX_COLORS; there are indeed 'ximageinfo->no'
+ * used color cells, but they are not at array position 0 - 'ximageinfo->no'
+ */
+
+ free(ximageinfo);
}
+#endif /* !MSDOS */
+
Image *newImage(unsigned int width, unsigned int height, unsigned int depth)
{
Image *image;
- unsigned int bytes_per_row;
const unsigned int bytes_per_pixel = 1;
int i;
for (i=0; i<MAX_COLORS; i++)
image->rgb.color_used[i] = FALSE;
- bytes_per_row = (width + 7) / 8;
- image->data_mask = checked_calloc(bytes_per_row * height);
-
return image;
}
void freeImage(Image *image)
{
free(image->data);
- free(image->data_mask);
free(image);
}
-/* ------------------------------------------------------------------------- */
-
+#ifndef MSDOS
-
-int Read_PCX_to_Pixmaps(Display *display, Window window, char *filename,
- Pixmap *pixmap, Pixmap *pixmap_mask)
+int Read_PCX_to_Pixmap(Display *display, Window window, GC gc, char *filename,
+ Pixmap *pixmap, Pixmap *pixmap_mask)
{
Image *image;
XImageInfo *ximageinfo;
-
- /*
- Image *image, *image_mask;
- XImageInfo *ximageinfo, *ximageinfo_mask;
- */
-
int screen;
Visual *visual;
- unsigned int depth;
+ int depth;
-#ifdef DEBUG_TIMING
- count1 = Counter();
+#if DEBUG_TIMING
+ debug_print_timestamp(2, NULL); /* initialize timestamp function */
#endif
+ /* read the graphic file in PCX format to image structure */
if ((image = Read_PCX_to_Image(filename)) == NULL)
- return PCX_FileInvalid;
+ return errno_pcx;
-#ifdef DEBUG_TIMING
- count2 = Counter();
- printf(" LOADING '%s' IN %.2f SECONDS\n",
- filename, (float)(count2-count1)/1000.0);
- count1 = Counter();
-#endif
-
- /* create image mask */
- Image_to_Mask(image);
-
-#ifdef DEBUG_TIMING
- count2 = Counter();
- printf(" CONVERTING IMAGE TO MASK IN %.2f SECONDS\n",
- (float)(count2-count1)/1000.0);
- count1 = Counter();
+#if DEBUG_TIMING
+ printf("%s:\n", filename);
+ debug_print_timestamp(2, " READING PCX FILE TO IMAGE: ");
#endif
screen = DefaultScreen(display);
visual = DefaultVisual(display, screen);
depth = DefaultDepth(display, screen);
- /* convert internal image structure to X11 XImage */
- if (!(ximageinfo = Image_to_XImage(display, screen, visual, depth, image)))
- {
- fprintf(stderr, "Cannot convert Image to XImage.\n");
- exit(1);
- }
-
-#ifdef DEBUG_TIMING
- count2 = Counter();
- printf(" CONVERTING IMAGE TO XIMAGE (BITMAP) IN %.2f SECONDS\n",
- (float)(count2-count1)/1000.0);
- count1 = Counter();
-#endif
+ /* convert image structure to X11 Pixmap */
+ if (!(ximageinfo = Image_to_Pixmap(display, screen, visual,
+ window, gc, depth, image)))
+ Error(ERR_EXIT, "cannot convert Image to Pixmap");
+ /* if a private colormap has been created, install it */
if (ximageinfo->cmap != DefaultColormap(display, screen))
XSetWindowColormap(display, window, ximageinfo->cmap);
- /* convert XImage to Pixmap */
- if (!(XImage_to_Pixmap(display, window, ximageinfo)))
- {
- fprintf(stderr, "Cannot convert XImage to Pixmap.\n");
- exit(1);
- }
+#if DEBUG_TIMING
+ debug_print_timestamp(2, " CONVERTING IMAGE TO PIXMAP:");
+#endif
-#ifdef DEBUG_TIMING
- count2 = Counter();
- printf(" CONVERTING IMAGE TO PIXMAP IN %.2f SECONDS\n",
- (float)(count2-count1)/1000.0);
- count1 = Counter();
+ /* create clip mask for the image */
+ ximageinfo->pixmap_mask = Image_to_Mask(image, display, window);
+
+#if DEBUG_TIMING
+ debug_print_timestamp(2, " CONVERTING IMAGE TO MASK: ");
#endif
*pixmap = ximageinfo->pixmap;
*pixmap_mask = ximageinfo->pixmap_mask;
- return(PCX_Success);
+ return PCX_Success;
}
+
+#endif /* !MSDOS */