rnd-19981112-1
authorHolger Schemel <info@artsoft.org>
Thu, 12 Nov 1998 19:49:26 +0000 (20:49 +0100)
committerHolger Schemel <info@artsoft.org>
Sat, 30 Aug 2014 08:31:41 +0000 (10:31 +0200)
src/Makefile
src/image.c
src/image.h
src/init.c
src/pcx.c

index a3a5b396b7630fb745abcf774112515fd8ed8de2..6dc3a1a2480e7645034ce1ae99dbfa051f5ff3dd 100644 (file)
@@ -92,7 +92,6 @@ SRCS =        main.c          \
        joystick.c      \
        cartoons.c      \
        random.c        \
-       gif.c           \
        pcx.c           \
        image.c         \
        network.c       \
@@ -113,7 +112,6 @@ OBJS =      main.o          \
        joystick.o      \
        cartoons.o      \
        random.o        \
-       gif.o           \
        pcx.o           \
        image.o         \
        network.o       \
index d73c9a5a4afdd112d5f7d8fee937c80e306dbdf8..f82a981b301b6688060981a5deb342e08bc62b22 100644 (file)
 /* extra colors to try allocating in private color maps to minimise flashing */
 #define NOFLASH_COLORS 256
 
-Image *monochrome(Image *cimage)
+static void Image_to_Mask(Image *image)
 {
-  Image         *image;
-  unsigned char *sp, *dp, *dp2; /* data pointers */
-  unsigned int   spl;           /* source pixel length in bytes */
-  unsigned int   dll;           /* destination line length in bytes */
-  Pixel          color;         /* pixel color */
-  unsigned int   x, y;          /* random counters */
-  int bitmap_pixel;
-
-  if (BITMAPP(cimage))
-  {
-    printf("-->ERROR(monochrome)\n");
-
-    return(NULL);
-  }
-
-  image = newBitImage(cimage->width, cimage->height);
-
-  spl = cimage->pixlen;
-  dll = (image->width / 8) + (image->width % 8 ? 1 : 0);
-
-  sp = cimage->data;
-  dp = image->data;
-
-  for (y=0; y<cimage->height; y++)
-  {
-    for (x=0; x<cimage->width; x++)
-    {
-      dp2 = dp + (x / 8);      /* dp + x/8 */
-      color = memToVal(sp, spl);
-
-      if (cimage->rgb.red[color] > 0x0000 ||
-         cimage->rgb.green[color] > 0x0000 ||
-         cimage->rgb.blue[color] > 0x0000)
-       bitmap_pixel = 0x00;
-      else
-       bitmap_pixel = 0x80;
-
-      *dp2 |= bitmap_pixel >> (x % 8);
-      sp += spl;
-    }
-
-    dp += dll; /* next row */
-  }
+  unsigned char *src_ptr, *dst_ptr, *dst_ptr2;
+  unsigned int bytes_per_row;
+  unsigned int x, y;
+  unsigned char bitmask;
 
-  return(image);
-}
-
-static unsigned int *buildIndex(unsigned int width,
-                               unsigned int zoom,
-                               unsigned int *rwidth)
-{
-  float         fzoom;
-  unsigned int *index;
-  unsigned int  a;
+  bytes_per_row = (image->width + 7) / 8;
+  src_ptr = image->data;
+  dst_ptr = image->data_mask;
 
-  if (!zoom)
+  for (y=0; y<image->height; y++)
   {
-    fzoom = 100.0;
-    *rwidth = width;
-  }
-  else
-  {
-    fzoom = (float)zoom / 100.0;
-    *rwidth = (unsigned int)(fzoom * width + 0.5);
-  }
-  index = (unsigned int *)checked_malloc(sizeof(unsigned int) * *rwidth);
-  for (a=0; a<*rwidth; a++)
-  {
-    if (zoom)
-      *(index + a) = (unsigned int)((float)a / fzoom + 0.5);
-    else
-      *(index + a) = a;
-  }
-  return(index);
-}
-
-Image *zoom(Image *oimage, unsigned int xzoom, unsigned int yzoom)
-{
-  Image        *image;
-  unsigned int *xindex, *yindex;
-  unsigned int  xwidth, ywidth;
-  unsigned int  x, y, xsrc, ysrc;
-  unsigned int  pixlen;
-  unsigned int  srclinelen;
-  unsigned int  destlinelen;
-  byte         *srcline, *srcptr;
-  byte         *destline, *destptr;
-  byte          srcmask, destmask, bit;
-  Pixel         value;
-
-  if ((!xzoom || xzoom == 100) && (!yzoom || yzoom == 100)) 
-    return(oimage);
-
-  if (!xzoom)
-    printf("  Zooming image Y axis by %d%%...", yzoom);
-  else if (!yzoom)
-    printf("  Zooming image X axis by %d%%...", xzoom);
-  else if (xzoom == yzoom)
-    printf("  Zooming image by %d%%...", xzoom);
-  else
-    printf("  Zooming image X axis by %d%% and Y axis by %d%%...",
-            xzoom, yzoom);
-  fflush(stdout);
-
-  xindex = buildIndex(oimage->width, xzoom, &xwidth);
-  yindex = buildIndex(oimage->height, yzoom, &ywidth);
-
-  switch (oimage->type)
-  {
-    case IBITMAP:
-      image = newBitImage(xwidth, ywidth);
-      for (x=0; x<oimage->rgb.used; x++)
-      {
-       *(image->rgb.red + x) = *(oimage->rgb.red + x);
-       *(image->rgb.green + x) = *(oimage->rgb.green + x);
-       *(image->rgb.blue + x) = *(oimage->rgb.blue + x);
-      }
-      image->rgb.used = oimage->rgb.used;
-      destline = image->data;
-      destlinelen = (xwidth / 8) + (xwidth % 8 ? 1 : 0);
-      srcline = oimage->data;
-      srclinelen = (oimage->width / 8) + (oimage->width % 8 ? 1 : 0);
-      for (y=0, ysrc=*(yindex + y); y<ywidth; y++)
-      {
-       while (ysrc != *(yindex + y))
-       {
-         ysrc++;
-         srcline += srclinelen;
-       }
-       srcptr = srcline;
-       destptr = destline;
-       srcmask = 0x80;
-       destmask = 0x80;
-       bit = srcmask & *srcptr;
-       for (x=0, xsrc=*(xindex + x); x<xwidth; x++)
-       {
-         if (xsrc != *(xindex + x))
-         {
-           do
-           {
-             xsrc++;
-             if (!(srcmask >>= 1))
-             {
-               srcmask = 0x80;
-               srcptr++;
-             }
-           }
-           while (xsrc != *(xindex + x));
+    bitmask = 0x80;            /* start with leftmost bit in the byte     */
+    dst_ptr2 = dst_ptr;                /* start with leftmost byte in the row     */
 
-           bit = srcmask & *srcptr;
-         }
-         if (bit)
-           *destptr |= destmask;
-         if (!(destmask >>= 1))
-         {
-           destmask = 0x80;
-           destptr++;
-         }
-       }
-       destline += destlinelen;
-      }
-      break;
+    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    */
 
-    case IRGB:
-      image = newRGBImage(xwidth, ywidth, oimage->depth);
-      for (x=0; x<oimage->rgb.used; x++)
+      if ((bitmask >>= 1) == 0)        /* bit at rightmost byte position reached? */
       {
-       *(image->rgb.red + x) = *(oimage->rgb.red + x);
-       *(image->rgb.green + x) = *(oimage->rgb.green + x);
-       *(image->rgb.blue + x) = *(oimage->rgb.blue + x);
+       bitmask = 0x80;         /* start again with leftmost bit position  */
+       dst_ptr2++;             /* continue with next byte in image mask   */
       }
-      image->rgb.used = oimage->rgb.used;
-
-      pixlen = oimage->pixlen;
-      destptr = image->data;
-      srcline = oimage->data;
-      srclinelen = oimage->width * pixlen;
-      for (y=0, ysrc=*(yindex + y); y<ywidth; y++)
-      {
-       while (ysrc != *(yindex + y))
-       {
-         ysrc++;
-         srcline += srclinelen;
-       }
-
-       srcptr = srcline;
-       value = memToVal(srcptr, image->pixlen);
-
-       for (x=0, xsrc=*(xindex + x); x<xwidth; x++)
-       {
-         if (xsrc != *(xindex + x))
-         {
-           do
-           {
-             xsrc++;
-             srcptr++;
-           }
-           while (xsrc != *(xindex + x));
-           value = memToVal(srcptr, 1);
-         }
-         valToMem(value, destptr, 1);
-         destptr++;
-       }
-      }
-      break;
+    }
 
-    default:
-      /* no zooming */
-      return(oimage);
-      break;
+    dst_ptr += bytes_per_row;  /* continue with leftmost byte of next row */
   }
-
-  free((byte *)xindex);
-  free((byte *)yindex);
-
-  printf("done\n");
-
-  return(image);
 }
 
-void compress(Image *image)
+static boolean XImage_to_Pixmap(Display *display, Window parent,
+                               XImageInfo *ximageinfo)
 {
-  unsigned char          *used, fast[32][32][32];
-  unsigned int     dmask;       /* Depth mask protection */
-  Pixel           *map;
-  unsigned int     next_index;
-  Intensity *red = image->rgb.red,
-            *green = image->rgb.green,
-            *blue = image->rgb.blue;
-  Intensity r,g,b;
-  unsigned int x, y, badcount = 0, dupcount = 0, unusedcount = 0;
-  unsigned char *pixptr, *pixend;
-
-  if (!RGBP(image) || image->rgb.compressed)
-    return;
-
-  used = (unsigned char *)checked_calloc(sizeof(unsigned char) * depthToColors(image->depth));
-  dmask = (1 << image->depth) -1;      /* Mask any illegal bits for that depth */
-  map = (Pixel *)checked_calloc(sizeof(Pixel) * depthToColors(image->depth));
-
-  /* init fast duplicate check table */
-  for(r=0;r<32;r++)
-    for(g=0;g<32;g++)
-      for(b=0;b<32;b++)
-        fast[r][g][b] = 0;
-
-  /* do pass 1 through the image to check index usage */
-
-  pixptr = image->data;
-  pixend = pixptr + (image->height * image->width);
-  for(;pixptr < pixend; pixptr++)
-    used[(*pixptr) & dmask] = 1;
-
-  /* count the bad pixels */
-  for (x = image->rgb.used; x < depthToColors(image->depth); x++)
-    if (used[x])
-      badcount++;
-
-  /* figure out duplicates and unuseds, and create the new mapping */
-  next_index = 0;
-  for (x = 0; x < image->rgb.used; x++)
-  {
-    if (!used[x])
-    {
-      unusedcount++;
-      continue;                /* delete this index */
-    }
+  XGCValues gcv;
 
-    /* check for duplicate */
-    r = red[x];
-    g = green[x];
-    b = blue[x];
-    if (fast[r>>11][g>>11][b>>11])     /* if matches fast check */
-    {
-      /* then do a linear search */
-      for (y = x+1; y < image->rgb.used; y++)
-      {
-        if (r == red[y] && g == green[y] && b == blue[y])
-          break;
-      }
-      if (y < image->rgb.used) /* found match */
-      {
-       map[x] = y;
-        dupcount++;
-       continue;               /* delete this index */
-      }
-      fast[r>>11][g>>11][b>>11] = 1;
-    }
-    /* will map to this index */
-    map[x] = next_index;
-    next_index++;
-  }
+  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);
 
-  /* change the image pixels */
-  pixptr = image->data;
-  pixend = pixptr + (image->height * image->width);
-  for(;pixptr < pixend; pixptr++)
-    *pixptr = map[(*pixptr) & dmask];
+  /* build and cache the GC */
 
-  /* change the colormap */
-  for (x = 0; x < image->rgb.used; x++)
+  if (!ximageinfo->gc)
   {
-    if (!used[x])
-      continue;
-    red[map[x]] = red[x];
-    green[map[x]] = green[x];
-    blue[map[x]] = blue[x];
+    gcv.function = GXcopy;
+    ximageinfo->gc =
+      XCreateGC(ximageinfo->display, ximageinfo->pixmap,
+               GCFunction, &gcv);
   }
-  image->rgb.used = next_index;
 
-  /* clean up */
-  free(map);
-  free(used);
-
-
-
-#if 0
-  if (badcount)
-    printf("%d out-of-range pixels, ", badcount);
-
-  if (!unusedcount && !dupcount)
-    printf("no improvment\n");
-  else
+  if (!ximageinfo->gc_mask)
   {
-    if (dupcount)
-      printf("%d duplicate%s and %d unused color%s removed...",
-            dupcount, (dupcount == 1 ? "" : "s"),
-            unusedcount, (unusedcount == 1 ? "" : "s"));
-    printf("%d unique color%s\n",
-          next_index, (next_index == 1 ? "" : "s"));
+    gcv.function = GXcopy;
+    gcv.foreground = ximageinfo->foreground;
+    gcv.background = ximageinfo->background;
+    ximageinfo->gc_mask =
+      XCreateGC(ximageinfo->display, ximageinfo->pixmap_mask,
+               GCFunction | GCForeground | GCBackground, &gcv);
   }
-#endif
-
 
+  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);
 
-  image->rgb.compressed = TRUE;        /* don't do it again */
-}
-
-
-
-
-Pixmap XImage_to_Pixmap(Display *display, Window parent,
-                       XImageInfo *ximageinfo)
-{
-  Pixmap pixmap;
-
-  pixmap = XCreatePixmap(display, parent,
-                        ximageinfo->ximage->width, ximageinfo->ximage->height,
-                        ximageinfo->depth);
-
-  ximageinfo->drawable = pixmap;
-
-  XImage_to_Drawable(ximageinfo, 0, 0, 0, 0,
-                    ximageinfo->ximage->width, ximageinfo->ximage->height);
-  return(pixmap);
+  return (ximageinfo->pixmap != None && ximageinfo->pixmap_mask != None);
 }
 
 /* find the best pixmap depth supported by the server for a particular
  * visual and return that depth.
- *
- * this is complicated by R3's lack of XListPixmapFormats so we fake it
- * by looking at the structure ourselves.
  */
 
 static unsigned int bitsPerPixelAtDepth(Display *display, int screen,
@@ -402,8 +119,7 @@ static unsigned int bitsPerPixelAtDepth(Display *display, int screen,
   }
   XFree(xf);
 
-  /* this should never happen; if it does, we're in trouble
-   */
+  /* this should never happen; if it does, we're in trouble */
 
   fprintf(stderr, "bitsPerPixelAtDepth: Can't find pixmap depth info!\n");
   exit(1);
@@ -424,6 +140,12 @@ XImageInfo *Image_to_XImage(Display *display, int screen, Visual *visual,
   XGCValues gcv;
   XImageInfo *ximageinfo;
 
+  /* for building image */
+  byte *data, *destptr, *srcptr;
+
+  /* for building image mask */
+  byte *data_mask;
+
   if (!global_cmap)
   {
     if (visual == DefaultVisual(display, screen))
@@ -447,7 +169,9 @@ XImageInfo *Image_to_XImage(Display *display, int screen, Visual *visual,
   ximageinfo->rootimage = FALSE;
   ximageinfo->foreground = ximageinfo->background= 0;
   ximageinfo->gc = NULL;
+  ximageinfo->gc_mask = NULL;
   ximageinfo->ximage = NULL;
+  ximageinfo->ximage_mask = NULL;
 
   switch (visual->class)
   {
@@ -556,13 +280,20 @@ XImageInfo *Image_to_XImage(Display *display, int screen, Visual *visual,
       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++)
       {
        XColor xcolor2;
        unsigned short mask;
        int color_found;
        int i;
-  
+
+       if (!image->rgb.color_used[a])
+         continue;
+
        xcolor.red = *(image->rgb.red + a);
        xcolor.green = *(image->rgb.green + a);
        xcolor.blue = *(image->rgb.blue + a);
@@ -572,9 +303,8 @@ XImageInfo *Image_to_XImage(Display *display, int screen, Visual *visual,
        {
          if (!private_cmap)
          {
-           /*
-           printf("switching to private colormap...\n");
-           */
+           if (options.verbose)
+             Error(ERR_RETURN, "switching to private colormap");
 
            /* we just filled up the default colormap -- get a private one
               which contains all already allocated colors */
@@ -680,186 +410,150 @@ XImageInfo *Image_to_XImage(Display *display, int screen, Visual *visual,
       break;
   }
 
-  /* create an XImage and related colormap based on the image type
-   * we have.
-   */
-
-  /*
-  printf("  Building XImage...");
-  fflush(stdout);
-  */
-
-  switch (image->type)
-  {
-    case IBITMAP:
-    {
-      byte *data;
-
-      /* we copy the data to be more consistent
-       */
+  /* CREATE IMAGE ITSELF */
+  /* modify image data to match visual and colormap */
 
-      linelen = ((image->width + 7) / 8);
-      data= checked_malloc(linelen * image->height);
+  dbits = bitsPerPixelAtDepth(display, screen, ddepth);/* bits per pixel */
+  dpixlen = (dbits + 7) / 8;                   /* bytes per pixel */
 
-      memcpy((char *)data, (char *)image->data, linelen * image->height);
+  ximageinfo->ximage = XCreateImage(display, visual, ddepth, ZPixmap, 0,
+                                   NULL, image->width, image->height,
+                                   8, image->width * dpixlen);
 
-      gcv.function= GXcopy;
-      ximageinfo->ximage= XCreateImage(display, visual, 1, XYBitmap,
-                                      0, (char *)data, image->width,
-                                      image->height,
-                                      8, linelen);
+  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;
 
-      /* use this if you want to use the bitmap as a mask */
-      ximageinfo->depth = image->depth;
+  switch (visual->class)
+  {
+    case DirectColor:
+    case TrueColor:
+    {
+      Pixel pixval;
 
-      if(visual->class == DirectColor || visual->class == TrueColor)
+      for (y=0; y<image->height; y++)
       {
-        Pixel pixval;
-        dbits= bitsPerPixelAtDepth(display, screen, ddepth);
-        dpixlen= (dbits + 7) / 8;
-        pixval= redvalue[image->rgb.red[0] >> 8] |
-                greenvalue[image->rgb.green[0] >> 8] |
-                bluevalue[image->rgb.blue[0] >> 8];
-        ximageinfo->background = pixval;
-        pixval= redvalue[image->rgb.red[1] >> 8] |
-                greenvalue[image->rgb.green[1] >> 8] |
-                bluevalue[image->rgb.blue[1] >> 8];
-        ximageinfo->foreground = pixval;
-      }
-      else     /* Not Direct or True Color */
-      {
-        ximageinfo->foreground = BlackPixel(display, screen);
-        ximageinfo->background = WhitePixel(display, screen);
+       for (x=0; x<image->width; x++)
+       {
+         pixval = memToVal(srcptr, 1);
+         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;
+       }
       }
-      ximageinfo->ximage->bitmap_bit_order= MSBFirst;
-      ximageinfo->ximage->byte_order= MSBFirst;
-
       break;
     }
 
-    case IRGB:
+    default:
     {
-      /* modify image data to match visual and colormap
-       */
-
-      byte *data, *destptr, *srcptr;
-
-      dbits = bitsPerPixelAtDepth(display, screen, ddepth);/* bits per pixel */
-      dpixlen = (dbits + 7) / 8;                       /* bytes per pixel */
-
-      ximageinfo->ximage = XCreateImage(display, visual, ddepth, ZPixmap, 0,
-                                       NULL, image->width, image->height,
-                                       8, image->width * dpixlen);
-
-      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;
-
-      switch (visual->class)
+      if (dpixlen == 1)                        /* most common */
       {
-       case DirectColor:
-       case TrueColor:
-       {
-         Pixel pixval;
-
-         for (y=0; y<image->height; y++)
-         {
-           for (x=0; x<image->width; x++)
-           {
-             pixval = memToVal(srcptr, 1);
-             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;
-           }
-         }
-         break;
-       }
-  
-        default:
-       {  
-         if (dpixlen == 1)                     /* most common */
+       for (y=0; y<image->height; y++)
+       {
+         for (x=0; x<image->width; x++)
          {
-           for (y=0; y<image->height; y++)
-           {
-             for (x=0; x<image->width; x++)
-             {
-               *destptr = ximageinfo->index[c + *srcptr];
-               srcptr++;
-               destptr++;
-             }
-           }
+           *destptr = ximageinfo->index[c + *srcptr];
+           srcptr++;
+           destptr++;
          }
-         else                                  /* less common */
+       }
+      }
+      else                                     /* less common */
+      {
+       for (y=0; y<image->height; y++)
+       {
+         for (x=0; x<image->width; x++)
          {
-           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;
-             }
-           }
+           register unsigned long temp;
+           temp = memToVal(srcptr, 1);
+           valToMem(ximageinfo->index[c + temp], destptr, dpixlen);
+           srcptr += 1;
+           destptr += dpixlen;
          }
        }
-       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);
+
+
+  /* use this if you want to use the bitmap as a mask */
   /*
-  printf("done\n");
-  */
+    ximageinfo->depth = image->depth;
+    */
 
-  if (redvalue)
+  if (visual->class == DirectColor || visual->class == TrueColor)
   {
-    free((byte *)redvalue);
-    free((byte *)greenvalue);
-    free((byte *)bluevalue);
+    Pixel pixval;
+    dbits = bitsPerPixelAtDepth(display, screen, ddepth);
+    dpixlen = (dbits + 7) / 8;
+    pixval =
+      redvalue[65535 >> 8] |
+      greenvalue[65535 >> 8] |
+      bluevalue[65535 >> 8];
+    /*
+      redvalue[image->rgb.red[0] >> 8] |
+      greenvalue[image->rgb.green[0] >> 8] |
+      bluevalue[image->rgb.blue[0] >> 8];
+      */
+    ximageinfo->background = pixval;
+    pixval =
+      redvalue[0 >> 8] |
+      greenvalue[0 >> 8] |
+      bluevalue[0 >> 8];
+    /*
+      redvalue[image->rgb.red[1] >> 8] |
+      greenvalue[image->rgb.green[1] >> 8] |
+      bluevalue[image->rgb.blue[1] >> 8];
+      */
+    ximageinfo->foreground = pixval;
+  }
+  else /* Not Direct or True Color */
+  {
+    ximageinfo->foreground = BlackPixel(display, screen);
+    ximageinfo->background = WhitePixel(display, screen);
   }
 
-  return(ximageinfo);
-}
+  /*
+    ximageinfo->foreground = BlackPixel(display, screen);
+    ximageinfo->background = WhitePixel(display, screen);
+    */
 
-/* Given an XImage and a drawable, move a rectangle from the Ximage
- * to the drawable.
- */
+  ximageinfo->foreground = WhitePixel(display, screen);
+  ximageinfo->background = BlackPixel(display, screen);
 
-void XImage_to_Drawable(XImageInfo *ximageinfo,
-                       int src_x, int src_y, int dst_x, int dst_y,
-                       unsigned int w, unsigned int h)
-{
-  XGCValues gcv;
 
-  /* build and cache the GC
-   */
+  ximageinfo->ximage_mask->bitmap_bit_order = MSBFirst;
+  ximageinfo->ximage_mask->byte_order = MSBFirst;
 
-  if (!ximageinfo->gc)
+  if (redvalue)
   {
-    gcv.function = GXcopy;
-    if (ximageinfo->ximage->depth == 1)
-    {
-      gcv.foreground = ximageinfo->foreground;
-      gcv.background = ximageinfo->background;
-      ximageinfo->gc = XCreateGC(ximageinfo->display, ximageinfo->drawable,
-                                GCFunction | GCForeground | GCBackground,
-                                &gcv);
-    }
-    else
-      ximageinfo->gc = XCreateGC(ximageinfo->display, ximageinfo->drawable,
-                                GCFunction, &gcv);
+    free((byte *)redvalue);
+    free((byte *)greenvalue);
+    free((byte *)bluevalue);
   }
 
-  XPutImage(ximageinfo->display, ximageinfo->drawable, ximageinfo->gc,
-           ximageinfo->ximage, src_x, src_y, dst_x, dst_y, w, h);
+  return(ximageinfo);
 }
 
 /* free up anything cached in the local Ximage structure.
@@ -883,123 +577,60 @@ void freeXImage(Image *image, XImageInfo *ximageinfo)
   /* should we free private color map to ??? */
 }
 
-
-
-/* this table is useful for quick conversions between depth and ncolors
- */
-
-unsigned long DepthToColorsTable[] =
+Image *newImage(unsigned int width, unsigned int height, unsigned int depth)
 {
-  /*  0 */ 1,
-  /*  1 */ 2,
-  /*  2 */ 4,
-  /*  3 */ 8,
-  /*  4 */ 16,
-  /*  5 */ 32,
-  /*  6 */ 64,
-  /*  7 */ 128,
-  /*  8 */ 256,
-  /*  9 */ 512,
-  /* 10 */ 1024,
-  /* 11 */ 2048,
-  /* 12 */ 4096,
-  /* 13 */ 8192,
-  /* 14 */ 16384,
-  /* 15 */ 32768,
-  /* 16 */ 65536,
-  /* 17 */ 131072,
-  /* 18 */ 262144,
-  /* 19 */ 524288,
-  /* 20 */ 1048576,
-  /* 21 */ 2097152,
-  /* 22 */ 4194304,
-  /* 23 */ 8388608,
-  /* 24 */ 16777216
-};
-
-void newRGBMapData(RGBMap *rgb, unsigned int size)
-{
-  rgb->used = 0;
-  rgb->size = size;
-  rgb->compressed = FALSE;
-  rgb->red = (Intensity *)checked_malloc(sizeof(Intensity) * size);
-  rgb->green = (Intensity *)checked_malloc(sizeof(Intensity) * size);
-  rgb->blue = (Intensity *)checked_malloc(sizeof(Intensity) * size);
-}
-
-void freeRGBMapData(RGBMap *rgb)
-{
-  free((byte *)rgb->red);
-  free((byte *)rgb->green);
-  free((byte *)rgb->blue);
-}
+  Image *image;
+  unsigned int bytes_per_row;
+  const unsigned int bytes_per_pixel = 1;
+  int i;
 
-Image *newBitImage(unsigned int width, unsigned int height)
-{
-  Image        *image;
-  unsigned int  linelen;
-
-  image = (Image *)checked_malloc(sizeof(Image));
-  image->type = IBITMAP;
-  newRGBMapData(&(image->rgb), (unsigned int)2);
-  *(image->rgb.red)= *(image->rgb.green) = *(image->rgb.blue)= 65535;
-  *(image->rgb.red + 1)= *(image->rgb.green + 1) = *(image->rgb.blue + 1)= 0;
-  image->rgb.used = 2;
-  image->width = width;
-  image->height = height;
-  image->depth = 1;
-  linelen = ((width + 7) / 8);
-  image->data = (unsigned char *)checked_calloc(linelen * height);
-  return(image);
-}
+  if (depth > 8)
+    Error(ERR_EXIT, "images with more than 256 colors are not supported");
 
-Image *newRGBImage(unsigned int width, unsigned int height, unsigned int depth)
-{
-  Image        *image;
-  unsigned int  pixlen, numcolors;
-
-  if (depth == 0)      /* special case for `zero' depth image, which is */
-    depth = 1;         /* sometimes interpreted as `one color' */
-  pixlen = ((depth+7) / 8);
-  numcolors = depthToColors(depth);
-  image = (Image *)checked_malloc(sizeof(Image));
-  image->type = IRGB;
-  newRGBMapData(&(image->rgb), numcolors);
+  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->pixlen = pixlen;
-  image->data = (unsigned char *)checked_malloc(width * height * pixlen);
-  return(image);
-}
+  image->rgb.used = 0;
+  for (i=0; i<MAX_COLORS; i++)
+    image->rgb.color_used[i] = FALSE;
 
-void freeImageData(Image *image)
-{
-  freeRGBMapData(&(image->rgb));
-  free(image->data);
+  bytes_per_row = (width + 7) / 8;
+  image->data_mask = checked_calloc(bytes_per_row * height);
+
+  return image;
 }
 
 void freeImage(Image *image)
 {
-  freeImageData(image);
-  free((byte *)image);
+  free(image->data);
+  free(image->data_mask);
+  free(image);
 }
 
 /* ------------------------------------------------------------------------- */
 
 
 #ifdef DEBUG
-/*
+
 #define DEBUG_TIMING
-*/
+
 #endif
 
 
 int Read_PCX_to_Pixmaps(Display *display, Window window, 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;
@@ -1009,12 +640,8 @@ int Read_PCX_to_Pixmaps(Display *display, Window window, char *filename,
   count1 = Counter();
 #endif
 
-  /* load GIF file */
-  if (!(image = Read_PCX_to_Image(filename)))
-  {
-    printf("Loading GIF image failed -- maybe no GIF...\n");
-    exit(1);
-  }
+  if ((image = Read_PCX_to_Image(filename)) == NULL)
+    return PCX_FileInvalid;
 
 #ifdef DEBUG_TIMING
   count2 = Counter();
@@ -1023,18 +650,12 @@ int Read_PCX_to_Pixmaps(Display *display, Window window, char *filename,
   count1 = Counter();
 #endif
 
-  if (image->depth > 8)
-  {
-    printf("Sorry, GIFs with more than 256 colors are not supported.\n");
-    exit(1);
-  }
-
-  /* minimize colormap */
-  compress(image);
+  /* create image mask */
+  Image_to_Mask(image);
 
 #ifdef DEBUG_TIMING
   count2 = Counter();
-  printf("   COMPRESSING IMAGE COLORMAP IN %.2f SECONDS\n",
+  printf("   CONVERTING IMAGE TO MASK IN %.2f SECONDS\n",
         (float)(count2-count1)/1000.0);
   count1 = Counter();
 #endif
@@ -1061,7 +682,7 @@ int Read_PCX_to_Pixmaps(Display *display, Window window, char *filename,
     XSetWindowColormap(display, window, ximageinfo->cmap);
 
   /* convert XImage to Pixmap */
-  if ((*pixmap = XImage_to_Pixmap(display, window, ximageinfo)) == None)
+  if (!(XImage_to_Pixmap(display, window, ximageinfo)))
   {
     fprintf(stderr, "Cannot convert XImage to Pixmap.\n");
     exit(1);
@@ -1074,44 +695,8 @@ int Read_PCX_to_Pixmaps(Display *display, Window window, char *filename,
   count1 = Counter();
 #endif
 
-  /* create mono image for masking */
-  image_mask = monochrome(image);
-
-#ifdef DEBUG_TIMING
-  count2 = Counter();
-  printf("   CONVERTING IMAGE TO MASK IN %.2f SECONDS\n",
-        (float)(count2-count1)/1000.0);
-  count1 = Counter();
-#endif
-
-  /* convert internal image structure to X11 XImage */
-  if (!(ximageinfo_mask = Image_to_XImage(display, screen, visual, depth,
-                                       image_mask)))
-  {
-    fprintf(stderr, "Cannot convert Image to XImage.\n");
-    exit(1);
-  }
-
-#ifdef DEBUG_TIMING
-  count2 = Counter();
-  printf("   CONVERTING MASK TO XIMAGE IN %.2f SECONDS\n",
-        (float)(count2-count1)/1000.0);
-  count1 = Counter();
-#endif
-
-  /* convert XImage to Pixmap */
-  if ((*pixmap_mask = XImage_to_Pixmap(display, window, ximageinfo_mask)) == None)
-  {
-    fprintf(stderr, "Cannot convert XImage to Pixmap.\n");
-    exit(1);
-  }
-
-#ifdef DEBUG_TIMING
-  count2 = Counter();
-  printf("   CONVERTING MASK TO PIXMAP IN %.2f SECONDS\n",
-        (float)(count2-count1)/1000.0);
-  count1 = Counter();
-#endif
+  *pixmap = ximageinfo->pixmap;
+  *pixmap_mask = ximageinfo->pixmap_mask;
 
-  return(GIF_Success);
+  return(PCX_Success);
 }
index 087ad921f9adb2e8afb5f8211c6abdfa977a2338..0561257f17832d5bdae66fca952d7949c43d5d38 100644 (file)
 
 #include "main.h"
 
+#define MAX_COLORS     256     /* maximal number of colors for each image */
+
 typedef unsigned short Intensity; /* what X thinks an RGB intensity is */
 
-/* This struct holds the X-client side bits for a rendered image. */
 typedef struct
 {
-  Display  *display;   /* destination display */
-  int       screen;    /* destination screen */
-  int       depth;     /* depth of drawable we want/have */
-  Drawable  drawable;  /* drawable to send image to */
-  Pixel    *index;     /* array of pixel values allocated */
-  int       no;                /* number of pixels in the array */
-  int       rootimage; /* True if is a root image - eg, retain colors */
+  Display  *display;   /* destination display                              */
+  int       screen;    /* destination screen                               */
+  int       depth;     /* depth of drawable we want/have                   */
+  Drawable  drawable;  /* drawable to send image to                        */
+  Pixel    *index;     /* array of pixel values allocated                  */
+  int       no;                /* number of pixels in the array                    */
+  int       rootimage; /* True if is a root image - eg, retain colors      */
   Pixel     foreground; /* foreground and background pixels for mono images */
   Pixel     background;
-  Colormap  cmap;      /* colormap used for image */
-  GC        gc;                /* cached gc for sending image */
-  XImage   *ximage;    /* ximage structure */
+  Colormap  cmap;      /* colormap used for image                          */
+  GC        gc;                /* cached gc for sending image                      */
+  GC        gc_mask;   /* cached gc for sending image mask                 */
+  XImage   *ximage;    /* ximage structure                                 */
+  XImage   *ximage_mask;/* ximage structure of mask                         */
+  Pixmap   pixmap;     /* final pixmap                                     */
+  Pixmap   pixmap_mask;        /* final pixmap of mask                             */
 } XImageInfo;
 
-/* Function declarations */
-void        sendXImage(); /* send.c */
-XImageInfo *imageToXImage();
-Pixmap      ximageToPixmap();
-void        freeXImage();
-
-
-typedef struct rgbmap
+struct RGBMap
 {
-  unsigned int  size;       /* size of RGB map */
-  unsigned int  used;       /* number of colors used in RGB map */
-  int           compressed; /* image uses colormap fully */
-  Intensity    *red;        /* color values in X style */
-  Intensity    *green;
-  Intensity    *blue;
-} RGBMap;
-
-/* image structure
- */
+  unsigned int used;                   /* number of colors used in RGB map */
+  Intensity    red[MAX_COLORS];                /* color values in X style          */
+  Intensity    green[MAX_COLORS];
+  Intensity    blue[MAX_COLORS];
+  boolean      color_used[MAX_COLORS]; /* flag if color cell is used       */
+};
 
-typedef struct {
-  unsigned int  type;   /* type of image */
-  RGBMap        rgb;    /* RGB map of image if IRGB type */
-  unsigned int  width;  /* width of image in pixels */
-  unsigned int  height; /* height of image in pixels */
-  unsigned int  depth;  /* depth of image in bits if IRGB type */
-  unsigned int  pixlen; /* length of pixel if IRGB type */
-  byte         *data;   /* data rounded to full byte for each row */
-  float                gamma;  /* gamma of display the image is adjusted for */
+typedef struct
+{
+  struct RGBMap rgb;           /* RGB map of image if IRGB type       */
+  unsigned int  width;         /* width of image in pixels            */
+  unsigned int  height;                /* height of image in pixels           */
+  unsigned int  depth;         /* depth of image in bits if IRGB type */
+  byte         *data;          /* image data                          */
+  byte         *data_mask;     /* clip mask data                      */
 } Image;
 
-#define IBITMAP 0 /* image is a bitmap */
-#define IRGB    1 /* image is RGB */
-
-#define BITMAPP(IMAGE) ((IMAGE)->type == IBITMAP)
-#define RGBP(IMAGE)    ((IMAGE)->type == IRGB)
-
-#define depthToColors(n) DepthToColorsTable[((n) < 24 ? (n) : 24)]
-
 /*
- * Architecture independent memory to value conversions.
- * Note the "Normal" internal format is big endian.
+ * architecture independent memory-to-value conversions
+ * note: the internal format is big endian
  */
 
 #define memToVal(PTR,LEN) (                                   \
@@ -103,16 +88,6 @@ typedef struct {
               *(((byte *)(PTR))+2) = (((unsigned long)(VAL))>> 8),        \
               *(((byte *)(PTR))+3) = ( VAL     ) ))
 
-
-/* return values */
-
-#define GIF_Success             0
-#define GIF_OpenFailed         -1
-#define GIF_ReadFailed         -2
-#define        GIF_FileInvalid         -3
-#define GIF_NoMemory           -4
-#define GIF_ColorFailed                -5
-
 #define PCX_Success             0
 #define PCX_OpenFailed         -1
 #define PCX_ReadFailed         -2
@@ -120,32 +95,11 @@ typedef struct {
 #define PCX_NoMemory           -4
 #define PCX_ColorFailed                -5
 
-/* functions */
-
-extern unsigned long DepthToColorsTable[];
-Image *newBitImage();
-Image *newRGBImage();
-void   freeImage();
-void   freeImageData();
-void   newRGBMapData();
-void   freeRGBMapData();
-byte  *lcalloc();
-byte  *lmalloc();
-
-Image *Read_GIF_to_Image();
-Image *Read_PCX_to_Image();
-
-int Read_GIF_to_Pixmaps(Display *, Window, char *, Pixmap *, Pixmap *);
 int Read_PCX_to_Pixmaps(Display *, Window, char *, Pixmap *, Pixmap *);
 
-Image *monochrome();
-Image *zoom();
-
-void compress();
-
-Pixmap XImage_to_Pixmap(Display *, Window, XImageInfo *);
-XImageInfo *Image_to_XImage(Display *, int, Visual *, unsigned int, Image *);
-void XImage_to_Drawable(XImageInfo *, int, int, int, int,
-                       unsigned int, unsigned int);
+Image *Read_PCX_to_Image();
+Image *newImage();
+void freeImage();
+void freeXImage();
 
 #endif /* IMAGE_H */
index e19daafde4e658c38b981b711dd60ef64f368108..184ea73f333c5beef4801ae7a5ff229041c3039e 100644 (file)
@@ -25,9 +25,9 @@
 #include "netserv.h"
 
 #ifdef DEBUG
-/*
+
 #define DEBUG_TIMING
-*/
+
 #endif
 
 struct PictureFileInfo
@@ -640,7 +640,7 @@ void LoadGfx(int pos, struct PictureFileInfo *pic)
   char *picture_ext = ".xpm";
   char *picturemask_ext = "Mask.xbm";
 #else
-  int gif_err;
+  int pcx_err;
   char *picture_ext = ".pcx";
 #endif
 
@@ -693,30 +693,30 @@ void LoadGfx(int pos, struct PictureFileInfo *pic)
 
 #else 
 
-    gif_err = Read_PCX_to_Pixmaps(display, window, filename,
+    pcx_err = Read_PCX_to_Pixmaps(display, window, filename,
                                  &pix[pos], &clipmask[pos]);
 
-    switch(gif_err)
+    switch(pcx_err)
     {
-      case GIF_Success:
+      case PCX_Success:
         break;
-      case GIF_OpenFailed:
-        Error(ERR_EXIT, "cannot open GIF file '%s'", filename);
-      case GIF_ReadFailed:
-        Error(ERR_EXIT, "cannot read GIF file '%s'", filename);
-      case GIF_FileInvalid:
-       Error(ERR_EXIT, "invalid GIF file '%s'", filename);
-      case GIF_NoMemory:
-       Error(ERR_EXIT, "not enough memory for GIF file '%s'", filename);
-      case GIF_ColorFailed:
-       Error(ERR_EXIT, "cannot get colors for GIF file '%s'", filename);
+      case PCX_OpenFailed:
+        Error(ERR_EXIT, "cannot open PCX file '%s'", filename);
+      case PCX_ReadFailed:
+        Error(ERR_EXIT, "cannot read PCX file '%s'", filename);
+      case PCX_FileInvalid:
+       Error(ERR_EXIT, "invalid PCX file '%s'", filename);
+      case PCX_NoMemory:
+       Error(ERR_EXIT, "not enough memory for PCX file '%s'", filename);
+      case PCX_ColorFailed:
+       Error(ERR_EXIT, "cannot get colors for PCX file '%s'", filename);
       default:
        break;
     }
 
 #ifdef DEBUG_TIMING
     count2 = Counter();
-    printf("GIF LOADING %s IN %.2f SECONDS\n",
+    printf("PCX LOADING %s IN %.2f SECONDS\n",
           filename,(float)(count2-count1)/1000.0);
 #endif
 
index 582f4ce52530ac50ac4a7c5292f054d2de403a2d..f2dac1d9cfdb266bc669d54bab7a6a3770b4988b 100644 (file)
--- a/src/pcx.c
+++ b/src/pcx.c
 ***********************************************************/
 
 #include "image.h"
+#include "misc.h"
 
-#define PCX_MAGIC              0x0a    /* first byte in a PCX image file */
-#define PCX_LAST_VERSION       5       /* last acceptable version number */
-#define PCX_ENCODING           1       /* PCX encoding method */
+#define PCX_MAGIC              0x0a    /* first byte in a PCX image file    */
+#define PCX_LAST_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_MAXDEPTH           8       /* supports up to 8 bits per pixel   */
+#define PCX_MAXCOLORS          256     /* maximum number of colors          */
+
 #define PCX_HEADER_SIZE                128
-#define PCX_PALETTE_SIZE       (3 * PCX_MAXCOLORS)
+#define PCX_COLORMAP_SIZE      (3 * PCX_MAXCOLORS)
 
 struct PCX_Header
 {
@@ -42,48 +44,69 @@ struct PCX_Header
   unsigned char filler[58];    /* fill to struct size of 128          */
 };
 
-static boolean PCX_LoadImage();                /* Routine to load PCX bitmap */
-static boolean PCX_LoadColormap();     /* Routine to load PCX colormap */
+static byte *PCX_ReadBitmap(Image *, byte *, byte *);
+static byte *PCX_ReadColormap(Image *, byte *, byte *);
 
 Image *Read_PCX_to_Image(char *filename)
 {
   FILE *file;
-  unsigned char buffer[PCX_HEADER_SIZE];
+  byte *file_buffer;
+  byte *buffer_ptr, *buffer_last;
+  unsigned int file_length;
   struct PCX_Header pcx;
   Image *image;
   int width, height, depth;
+  int i;
 
   if (!(file = fopen(filename, "r")))
     return NULL;
 
-  /* read PCX header */
-  if (fread(buffer, 1, PCX_HEADER_SIZE, file) != PCX_HEADER_SIZE)
+  if (fseek(file, 0, SEEK_END) == -1)
   {
     fclose(file);
     return NULL;
   }
 
-  pcx.signature = buffer[0];
-  pcx.version = buffer[1];
-  pcx.encoding = buffer[2];
-  pcx.bits_per_pixel = buffer[3];
-  pcx.xmin = buffer[4]  + 256 * buffer[5];
-  pcx.ymin = buffer[6]  + 256 * buffer[7];
-  pcx.xmax = buffer[8]  + 256 * buffer[9];
-  pcx.ymax = buffer[10] + 256 * buffer[11];
-  pcx.color_planes = buffer[65];
-  pcx.bytes_per_line = buffer[66] + 256 * buffer[67];
-  pcx.palette_type = buffer[68] + 256 * buffer[69];
-
-  width = pcx.xmax - pcx.xmin + 1;
+  file_length = ftell(file);
+  rewind(file);
+
+  if (file_length < PCX_HEADER_SIZE + PCX_COLORMAP_SIZE)
+  {
+    fclose(file);
+    return NULL;
+  }
+
+  file_buffer = checked_malloc(file_length);
+
+  if (fread(file_buffer, 1, file_length, file) != file_length)
+  {
+    fclose(file);
+    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];
+
+  width  = pcx.xmax - pcx.xmin + 1;
   height = pcx.ymax - pcx.ymin + 1;
-  depth = pcx.bits_per_pixel;
+  depth  = pcx.bits_per_pixel;
 
   if (pcx.signature != PCX_MAGIC || pcx.version > PCX_LAST_VERSION ||
       pcx.encoding != PCX_ENCODING || pcx.color_planes > PCX_MAXDEPTH ||
       width < 0 || height < 0)
   {
-    fclose(file);
+    free(file_buffer);
     return NULL;
   }
 
@@ -100,27 +123,42 @@ Image *Read_PCX_to_Image(char *filename)
   }
 
   /* allocate new image structure */
-  image = newRGBImage(width, height, depth);
+  image = newImage(width, height, depth);
+
+  buffer_ptr  = file_buffer + PCX_HEADER_SIZE;
+  buffer_last = file_buffer + file_length;
 
   /* read compressed bitmap data */
-  if (!PCX_LoadImage(file, image))
+  if ((buffer_ptr = PCX_ReadBitmap(image, buffer_ptr, buffer_last)) == NULL)
   {
-    fclose(file);
-    return image;
+    free(file_buffer);
+    freeImage(image);
+    return NULL;
   }
 
   /* read colormap data */
-  if (!PCX_LoadColormap(file, image))
+  if (!PCX_ReadColormap(image, buffer_ptr, buffer_last))
   {
-    fclose(file);
-    return image;
+    free(file_buffer);
+    freeImage(image);
+    return NULL;
   }
 
-  fclose(file);
-  return(image);
+  free(file_buffer);
+
+  /* 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 (options.verbose)
+    printf("Read_PCX_to_Image: %d colors found\n", image->rgb.used);
+
+  return image;
 }
 
-static boolean PCX_LoadImage(FILE *file, Image *image)
+static byte *PCX_ReadBitmap(Image *image, byte *buffer_ptr, byte *buffer_last)
 {
   /* Run Length Encoding: If the two high bits are set,
    * then the low 6 bits contain a repeat count, and the byte to
@@ -128,60 +166,65 @@ static boolean PCX_LoadImage(FILE *file, Image *image)
    * not set, then this is the byte to write.
    */
 
-  register unsigned char *ptr, *ptr_last;
-  int value, count;
+  unsigned int bytes_per_pixel = (image->depth + 7) / 8;
+  register byte *bitmap_ptr, *bitmap_last;
+  register byte value, count;
 
-  ptr = image->data;
-  ptr_last = ptr + (image->width * image->height * image->pixlen);
+  bitmap_ptr = image->data;
+  bitmap_last = bitmap_ptr + (image->width * image->height * bytes_per_pixel);
 
-  while (ptr < ptr_last)
+  while (bitmap_ptr < bitmap_last && buffer_ptr < buffer_last)
   {
-    if ((value = fgetc(file)) == EOF)
-      return FALSE;
+    value = *buffer_ptr++;
 
-    if ((value & 0xc0) == 0xc0)
+    if ((value & 0xc0) == 0xc0)                /* this is a repeat count byte */
     {
-      count = value & 0x3f;
+      count = value & 0x3f;            /* extract repeat count from byte */
+      value = *buffer_ptr++;           /* next byte is value to repeat */
 
-      if ((value = fgetc(file)) == EOF)
-       return FALSE;
+      for (; count && bitmap_ptr < bitmap_last; count--)
+       *bitmap_ptr++ = value;
 
-      for ( ; count && (ptr < ptr_last); count--)
-       *ptr++ = (unsigned char)value;
-
-      if (count)
-       printf("Repeat count spans end of image!\n");
+      if (count)                       /* repeat count spans end of bitmap */
+       return NULL;
     }
     else
-      *ptr++ = (unsigned char)value;
+      *bitmap_ptr++ = value;
+
+    image->rgb.color_used[value] = TRUE;
   }
 
-  return TRUE;
+  /* check if end of buffer was reached before end of bitmap */
+  if (bitmap_ptr < bitmap_last)
+    return NULL;
+
+  /* return current buffer position for next decoding function */
+  return buffer_ptr;
 }
 
-static boolean PCX_LoadColormap(FILE *file, Image *image)
+static byte *PCX_ReadColormap(Image *image,byte *buffer_ptr, byte *buffer_last)
 {
-  unsigned char buffer[PCX_PALETTE_SIZE];
-  int i, result, magic;
+  int i, magic;
 
   /* read colormap magic byte */
-  if ((magic = fgetc(file)) == EOF)
-    return FALSE;
+  magic = *buffer_ptr++;
 
+  /* check magic colormap header byte */
   if (magic != PCX_256COLORS_MAGIC)
-    return FALSE;
+    return NULL;
 
-  /* read PCX 256 colors colormap */
-  if ((result = fread(buffer, 1, PCX_PALETTE_SIZE, file)) != PCX_PALETTE_SIZE)
-    return FALSE;
+  /* check if enough bytes left for a complete colormap */
+  if (buffer_ptr + PCX_COLORMAP_SIZE > buffer_last)
+    return NULL;
 
+  /* read 256 colors from PCX colormap */
   for (i=0; i<PCX_MAXCOLORS; i++)
   {
-    image->rgb.red[i]   = buffer[i*3 + 0] << 8;
-    image->rgb.green[i] = buffer[i*3 + 1] << 8;
-    image->rgb.blue[i]  = buffer[i*3 + 2] << 8;
+    image->rgb.red[i]   = *buffer_ptr++ << 8;
+    image->rgb.green[i] = *buffer_ptr++ << 8;
+    image->rgb.blue[i]  = *buffer_ptr++ << 8;
   }
-  image->rgb.used = PCX_MAXCOLORS;
 
-  return TRUE;
+  /* return current buffer position for next decoding function */
+  return buffer_ptr;
 }