Logo Search packages:      
Sourcecode: ecos version File versions  Download package

devimage.c

#define FASTJPEG  1     /* =1 for temp quick jpeg 8bpp display */
#ifdef __ECOS
// Why isn't this handled in the global config file?
#undef HAVE_MMAP
#else
#define HAVE_MMAP       1       /* =1 to use mmap if available         */
#endif

#if defined(HAVE_FILEIO)      /* temp for entire file*/

/*
 * Copyright (c) 2000, 2001 Greg Haerr <greg@censoft.com>
 * Portions Copyright (c) 2000 Martin Jolicoeur <martinj@visuaide.com>
 * Portions Copyright (c) 2000 Alex Holden <alex@linuxhacker.org>
 * Portions Copyright (c) Independant JPEG group (ijg)
 *
 * Image load/cache/resize/display routines
 *
 * GIF, BMP, JPEG, PPM, PGM, PBM, PNG, and XPM formats are supported.
 * JHC:  Instead of working with a file, we work with a buffer
 *       (either provided by the user or through mmap).  This
 *     improves speed, and provides a mechanism by which the
 *     client can send image data directly to the engine 
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
 
#ifdef HAVE_MMAP
#include <sys/mman.h>
#endif
 
#include "device.h"
#include "swap.h"

/* cached image list*/
typedef struct {
      MWLIST            link;       /* link list*/
      int         id;         /* image id*/
      PMWIMAGEHDR pimage;           /* image data*/
      PSD         psd;        /* FIXME shouldn't need this*/
} IMAGEITEM, *PIMAGEITEM;

static MWLISTHEAD imagehead;        /* global image list*/
static int nextimageid = 1;

typedef struct {  /* structure for reading images from buffer   */
  void *start;    /* The pointer to the beginning of the buffer */
  int offset;     /* The current offset within the buffer       */
  int size;       /* The total size of the buffer               */
} buffer_t;
 

static void ComputePitch(int bpp, int width, int *pitch, int *bytesperpixel);
#if defined(HAVE_BMP_SUPPORT)
static int  LoadBMP(buffer_t *src, PMWIMAGEHDR pimage);
#endif
#if defined(HAVE_JPEG_SUPPORT)
static int  LoadJPEG(buffer_t *src, PMWIMAGEHDR pimage, PSD psd,
            MWBOOL fast_grayscale);
#endif
#if defined(HAVE_PNG_SUPPORT)
static int  LoadPNG(buffer_t *src, PMWIMAGEHDR pimage);
#endif
#if defined(HAVE_GIF_SUPPORT)
static int  LoadGIF(buffer_t *src, PMWIMAGEHDR pimage);
#endif
#if defined(HAVE_PNM_SUPPORT)
static int LoadPNM(buffer_t *src, PMWIMAGEHDR pimage);
#endif
#if defined(HAVE_XPM_SUPPORT)
static int LoadXPM(buffer_t *src, PMWIMAGEHDR pimage, PSD psd) ;
#endif

/*
 * Buffered input functions to replace stdio functions
 */
static void
binit(void *in, int size, buffer_t *dest)
{
      dest->start = in;
      dest->offset = 0;
      dest->size = size;
}
 
static int
bseek(buffer_t *buffer, int offset, int whence)
{
      int new;

      switch(whence) {
      case SEEK_SET:
            if (offset >= buffer->size || offset < 0)
                  return(-1);
            buffer->offset = offset;
            return(0);

      case SEEK_CUR:
            new = buffer->offset + offset;
            if (new >= buffer->size || new < 0)
                  return(-1);
            buffer->offset = new;
            return(0);

      case SEEK_END:
            if (offset >= buffer->size || offset > 0)
                  return(-1);
            buffer->offset = (buffer->size - 1) - offset;
            return(0);

      default:
            return(-1);
      }
}
   
static int
bread(buffer_t *buffer, void *dest, int size)
{
      int copysize = size;

      if (buffer->offset == buffer->size)
            return(0);

      if (buffer->offset + size > buffer->size) 
            copysize = (buffer->size - buffer->offset);

      memcpy((void *)dest, (void *)(buffer->start + buffer->offset),copysize);

      buffer->offset += copysize;
      return(copysize);
}
 
static int
bgetc(buffer_t *buffer)
{
      int ch;

      if (buffer->offset == buffer->size) 
            return(EOF);

      ch = *((unsigned char *) (buffer->start + buffer->offset));
      buffer->offset++;
      return(ch);
}
 
static char *
bgets(buffer_t *buffer, char *dest, int size)
{
      int i,o;
      int copysize = size - 1;

      if (buffer->offset == buffer->size) 
            return(0);

      if (buffer->offset + copysize > buffer->size) 
            copysize = buffer->size - buffer->offset;

      for(o=0, i=buffer->offset; i < buffer->offset + copysize; i++, o++) {
            dest[o] = *((char *) (buffer->start + i));
            if (dest[o] == '\n')
                  break;
      }

      buffer->offset = i + 1;
      dest[o + 1] = 0;

      return(dest);
}
 
static int
beof(buffer_t *buffer)
{
      return (buffer->offset == buffer->size);
}
 
/*
 * Image decoding and display
 * NOTE: This routine and APIs will change in subsequent releases.
 *
 * Decodes and loads a graphics file, then resizes to width/height,
 * then displays image at x, y
 * If width/height == -1, don't resize, use image size.
 * Clipping is not currently supported, just stretch/shrink to fit.
 *
 */

static int GdDecodeImage(PSD psd, buffer_t *src, int flags);

int
GdLoadImageFromBuffer(PSD psd, void *buffer, int size, int flags)
{
      buffer_t src;
      binit(buffer, size, &src);

      return(GdDecodeImage(psd, &src, flags));
}

void
GdDrawImageFromBuffer(PSD psd, MWCOORD x, MWCOORD y, MWCOORD width,
      MWCOORD height, void *buffer, int size, int flags)
{
      int id;
      buffer_t src;

      binit(buffer, size, &src);
      id = GdDecodeImage(psd, &src, flags);

      if (id) {
            GdDrawImageToFit(psd, x, y, width, height, id);
            GdFreeImage(id);
      }
}

void
GdDrawImageFromFile(PSD psd, MWCOORD x, MWCOORD y, MWCOORD width,
      MWCOORD height, char *path, int flags)
{
      int   id;

      id = GdLoadImageFromFile(psd, path, flags);
      if (id) {
            GdDrawImageToFit(psd, x, y, width, height, id);
            GdFreeImage(id);
      }
}

int
GdLoadImageFromFile(PSD psd, char *path, int flags)
{
  int fd, id;
  struct stat s;
  void *buffer = 0;
  buffer_t src;
  
  fd = open(path, O_RDONLY);
  if (fd <= 0) {
    EPRINTF("GdLoadImageFromFile: can't open image: %s\n", path);
    return(0);
  }
  
  fstat(fd, &s);

#ifdef HAVE_MMAP
  buffer = mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0);

  if (!buffer) {
    EPRINTF("GdLoadImageFromFile:  Couldn't map image %s\n", path);
    close(fd);
    return(0);
  }
#else
  buffer = malloc(s.st_size);
  if (!buffer) {
     EPRINTF("GdLoadImageFromFile:  Couldn't load image %s\n", path);
     close(fd);
     return(0);
  }
  
  if (read(fd, buffer, s.st_size) != s.st_size) {
    EPRINTF("GdLoadImageFromFile:  Couldn't load image %s\n", path);
    close(fd);
    return(0);
  }
#endif

  binit(buffer, s.st_size, &src);
  id = GdDecodeImage(psd, &src, flags);
  
#ifdef HAVE_MMAP
  munmap(buffer, s.st_size);
#else
  free(buffer);
#endif

  close(fd);
  return(id);
}

static int
GdDecodeImage(PSD psd, buffer_t * src, int flags)
{
        int         loadOK = 0;
        PMWIMAGEHDR pimage;
        PIMAGEITEM  pItem;

      /* allocate image struct*/
      pimage = (PMWIMAGEHDR)malloc(sizeof(MWIMAGEHDR));
      if(!pimage) {
            return 0;
      }
      pimage->imagebits = NULL;
      pimage->palette = NULL;
      pimage->transcolor = -1L;

#if defined(HAVE_BMP_SUPPORT)
      if (loadOK == 0) 
            loadOK = LoadBMP(src, pimage);
#endif
#if defined(HAVE_GIF_SUPPORT)
      if (loadOK == 0) 
            loadOK = LoadGIF(src, pimage);
#endif
#if defined(HAVE_JPEG_SUPPORT)
      if (loadOK == 0) 
            loadOK = LoadJPEG(src, pimage, psd, flags);
#endif
#if defined(HAVE_PNG_SUPPORT)
      if (loadOK == 0) 
            loadOK = LoadPNG(src, pimage);
#endif
#if defined(HAVE_PNM_SUPPORT)
      if(loadOK == 0)
            loadOK = LoadPNM(src, pimage);
#endif
#if defined(HAVE_XPM_SUPPORT)
      if (loadOK == 0) 
            loadOK = LoadXPM(src, pimage, psd);
#endif

      if (loadOK == 0) {
            EPRINTF("GdLoadImageFromFile: unknown image type:\n");
        //        EPRINTF("GdLoadImageFromFile: unknown image type: \n", path);
            goto err;         /* image loading error*/
      }
      if (loadOK != 1)
            goto err;         /* image loading error*/

      /* allocate id*/
      pItem = GdItemNew(IMAGEITEM);
      if (!pItem)
            goto err;
      pItem->id = nextimageid++;
      pItem->pimage = pimage;
      pItem->psd = psd;
      GdListAdd(&imagehead, &pItem->link);

      return pItem->id;

err:
      free(pimage);
      return 0;               /* image loading error*/
}

static PIMAGEITEM
findimage(int id)
{
      PMWLIST           p;
      PIMAGEITEM  pimagelist;

      for (p=imagehead.head; p; p=p->next) {
            pimagelist = GdItemAddr(p, IMAGEITEM, link);
            if (pimagelist->id == id)
                  return pimagelist;
      }
      return NULL;
}

void
GdDrawImageToFit(PSD psd, MWCOORD x, MWCOORD y, MWCOORD width, MWCOORD height,
      int id)
{
      PIMAGEITEM  pItem;
      PMWIMAGEHDR pimage;

      pItem = findimage(id);
      if (!pItem)
            return;
      pimage = pItem->pimage;

      /*
       * Display image, possibly stretch/shrink to resize
       */
      if (height < 0)
            height = pimage->height;
      if (width < 0)
            width = pimage->width;

      if (height != pimage->height || width != pimage->width) {
            MWCLIPRECT  rcDst;
            MWIMAGEHDR  image2;

            /* create similar image, different width/height*/

            image2.width = width;
            image2.height = height;
            image2.planes = pimage->planes;
            image2.bpp = pimage->bpp;
            ComputePitch(pimage->bpp, width, &image2.pitch,
                  &image2.bytesperpixel);
            image2.compression = pimage->compression;
            image2.palsize = pimage->palsize;
            image2.palette = pimage->palette;   /* already allocated*/
            image2.transcolor = pimage->transcolor;
            if( (image2.imagebits = malloc(image2.pitch*height)) == NULL) {
                  EPRINTF("GdDrawImageToFit: no memory\n");
                  return;
            }

            rcDst.x = 0;
            rcDst.y = 0;
            rcDst.width = width;
            rcDst.height = height;

            /* Stretch full soruce to destination rectangle*/
            GdStretchImage(pimage, NULL, &image2, &rcDst);
            GdDrawImage(psd, x, y, &image2);
            free(image2.imagebits);
      } else
            GdDrawImage(psd, x, y, pimage);
}

void
GdFreeImage(int id)
{
      PIMAGEITEM  pItem;
      PMWIMAGEHDR pimage;

      pItem = findimage(id);
      if (pItem) {
            GdListRemove(&imagehead, &pItem->link);
            pimage = pItem->pimage;

            /* delete image bits*/
            if(pimage->imagebits)
                  free(pimage->imagebits);
            if(pimage->palette)
                  free(pimage->palette);

            free(pimage);
            GdItemFree(pItem);
      }
}

MWBOOL
GdGetImageInfo(int id, PMWIMAGEINFO pii)
{
      PMWIMAGEHDR pimage;
      PIMAGEITEM  pItem;
      int         i;

      pItem = findimage(id);
      if (!pItem) {
            memset(pii, 0, sizeof(*pii));
            return FALSE;
      }
      pimage = pItem->pimage;
      pii->id = id;
      pii->width = pimage->width;
      pii->height = pimage->height;
      pii->planes = pimage->planes;
      pii->bpp = pimage->bpp;
      pii->pitch = pimage->pitch;
      pii->bytesperpixel = pimage->bytesperpixel;
      pii->compression = pimage->compression;
      pii->palsize = pimage->palsize;
      if (pimage->palsize) {
            if (pimage->palette) {
                  for (i=0; i<pimage->palsize; ++i)
                        pii->palette[i] = pimage->palette[i];
            } else {
                  /* FIXME handle jpeg's without palette*/
                  GdGetPalette(pItem->psd, 0, pimage->palsize,
                        pii->palette);
            }
      }
      return TRUE;
}

#define PIX2BYTES(n)    (((n)+7)/8)
/*
 * compute image line size and bytes per pixel
 * from bits per pixel and width
 */
static void
ComputePitch(int bpp, int width, int *pitch, int *bytesperpixel)
{
      int   linesize;
      int   bytespp = 1;

      if(bpp == 1)
            linesize = PIX2BYTES(width);
      else if(bpp <= 4)
            linesize = PIX2BYTES(width<<2);
      else if(bpp <= 8)
            linesize = width;
      else if(bpp <= 16) {
            linesize = width * 2;
            bytespp = 2;
      } else if(bpp <= 24) {
            linesize = width * 3;
            bytespp = 3;
      } else {
            linesize = width * 4;
            bytespp = 4;
      }

      /* rows are DWORD right aligned*/
      *pitch = (linesize + 3) & ~3;
      *bytesperpixel = bytespp;
}

/*
 * StretchImage - Resize an image
 *
 * Major portions from SDL Simple DirectMedia Layer by Sam Lantinga
 * Copyright (C) 1997, 1998, 1999, 2000  Sam Lantinga <slouken@devolution.com>
 * This a stretch blit implementation based on ideas given to me by
 *  Tomasz Cejner - thanks! :)
 */
/*
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#define DEFINE_COPY_ROW(name, type)                         \
static void name(type *src, int src_w, type *dst, int dst_w)            \
{                                                     \
      int i;                                                \
      int pos, inc;                                         \
      type pixel = 0;                                       \
                                                      \
      pos = 0x10000;                                        \
      inc = (src_w << 16) / dst_w;                          \
      for ( i=dst_w; i>0; --i ) {                           \
            while ( pos >= 0x10000L ) {                     \
                  pixel = *src++;                           \
                  pos -= 0x10000L;                    \
            }                                         \
            *dst++ = pixel;                                 \
            pos += inc;                               \
      }                                               \
}

DEFINE_COPY_ROW(copy_row1, unsigned char)
DEFINE_COPY_ROW(copy_row2, unsigned short)
DEFINE_COPY_ROW(copy_row4, unsigned long)

static void copy_row3(unsigned char *src, int src_w, unsigned char *dst,
      int dst_w)
{
      int i;
      int pos, inc;
      unsigned char r = 0;
      unsigned char g = 0;
      unsigned char b = 0;

      pos = 0x10000;
      inc = (src_w << 16) / dst_w;
      for ( i=dst_w; i>0; --i ) {
            while ( pos >= 0x10000L ) {
                  b = *src++;
                  g = *src++;
                  r = *src++;
                  pos -= 0x10000L;
            }
            *dst++ = b;
            *dst++ = g;
            *dst++ = r;
            pos += inc;
      }
}

/* Perform a stretch blit between two image structs of the same format.*/
void
GdStretchImage(PMWIMAGEHDR src, MWCLIPRECT *srcrect, PMWIMAGEHDR dst,
      MWCLIPRECT *dstrect)
{
      int pos, inc;
      int bytesperpixel;
      int dst_maxrow;
      int src_row, dst_row;
      MWUCHAR *srcp = 0;
      MWUCHAR *dstp;
      MWCLIPRECT full_src;
      MWCLIPRECT full_dst;

      if ( src->bytesperpixel != dst->bytesperpixel ) {
            EPRINTF("GdStretchImage: bytesperpixel mismatch\n");
            return;
      }

      /* Verify the blit rectangles */
      if ( srcrect ) {
            if ( (srcrect->x < 0) || (srcrect->y < 0) ||
                 ((srcrect->x+srcrect->width) > src->width) ||
                 ((srcrect->y+srcrect->height) > src->height) ) {
                  EPRINTF("GdStretchImage: invalid source rect\n");
                  return;
            }
      } else {
            full_src.x = 0;
            full_src.y = 0;
            full_src.width = src->width;
            full_src.height = src->height;
            srcrect = &full_src;
      }
      if ( dstrect ) {
            /* if stretching to nothing, return*/
            if (!dstrect->width || !dstrect->height)
                  return;
            if ( (dstrect->x < 0) || (dstrect->y < 0) ||
                 ((dstrect->x+dstrect->width) > dst->width) ||
                 ((dstrect->y+dstrect->height) > dst->height) ) {
                  EPRINTF("GdStretchImage: invalid dest rect\n");
                  return;
            }
      } else {
            full_dst.x = 0;
            full_dst.y = 0;
            full_dst.width = dst->width;
            full_dst.height = dst->height;
            dstrect = &full_dst;
      }

      /* Set up the data... */
      pos = 0x10000;
      inc = (srcrect->height << 16) / dstrect->height;
      src_row = srcrect->y;
      dst_row = dstrect->y;
      bytesperpixel = dst->bytesperpixel;

      /* Perform the stretch blit */
      for ( dst_maxrow = dst_row+dstrect->height; dst_row<dst_maxrow;
                                                ++dst_row ) {
            dstp = (MWUCHAR *)dst->imagebits + (dst_row*dst->pitch)
                            + (dstrect->x*bytesperpixel);
            while ( pos >= 0x10000L ) {
                  srcp = (MWUCHAR *)src->imagebits + (src_row*src->pitch)
                            + (srcrect->x*bytesperpixel);
                  ++src_row;
                  pos -= 0x10000L;
            }

            switch (bytesperpixel) {
            case 1:
                  copy_row1(srcp, srcrect->width, dstp, dstrect->width);
                  break;
            case 2:
                  copy_row2((unsigned short *)srcp, srcrect->width,
                        (unsigned short *)dstp, dstrect->width);
                  break;
            case 3:
                  copy_row3(srcp, srcrect->width, dstp, dstrect->width);
                  break;
            case 4:
                  copy_row4((unsigned long *)srcp, srcrect->width,
                        (unsigned long *)dstp, dstrect->width);
                  break;
            }

            pos += inc;
      }
}

#if defined(HAVE_FILEIO) && defined(HAVE_JPEG_SUPPORT)
#include "jpeglib.h"
/*
 * JPEG decompression routine
 *
 * JPEG support must be enabled (see README.txt in contrib/jpeg)
 *
 * SOME FINE POINTS: (from libjpeg)
 * In the below code, we ignored the return value of jpeg_read_scanlines,
 * which is the number of scanlines actually read.  We could get away with
 * this because we asked for only one line at a time and we weren't using
 * a suspending data source.  See libjpeg.doc for more info.
 *
 * We cheated a bit by calling alloc_sarray() after jpeg_start_decompress();
 * we should have done it beforehand to ensure that the space would be
 * counted against the JPEG max_memory setting.  In some systems the above
 * code would risk an out-of-memory error.  However, in general we don't
 * know the output image dimensions before jpeg_start_decompress(), unless we
 * call jpeg_calc_output_dimensions().  See libjpeg.doc for more about this.
 *
 * Scanlines are returned in the same order as they appear in the JPEG file,
 * which is standardly top-to-bottom.  If you must emit data bottom-to-top,
 * you can use one of the virtual arrays provided by the JPEG memory manager
 * to invert the data.  See wrbmp.c for an example.
 *
 * As with compression, some operating modes may require temporary files.
 * On some systems you may need to set up a signal handler to ensure that
 * temporary files are deleted if the program is interrupted.  See libjpeg.doc.
 */
static int
LoadJPEG(buffer_t *src, PMWIMAGEHDR pimage, PSD psd, MWBOOL fast_grayscale)
{
  int       i;
  int ret = 2;    /* image load error*/
  unsigned char magic[4];

#if FASTJPEG
  extern MWPALENTRY mwstdpal8[256];
#else
  MWPALENTRY palette[256];
#endif

  struct jpeg_source_mgr smgr;
  struct jpeg_decompress_struct cinfo;
  struct jpeg_error_mgr jerr;
  
  static void init_source(j_compress_ptr dinfo) {
    smgr.next_input_byte = src->start;
    smgr.bytes_in_buffer = src->size;
  }

  static void fill_input_buffer(j_compress_ptr dinfo) {
    return;
  }

  static void skip_input_data(j_compress_ptr dinfo, int num_bytes) {
    if (num_bytes >= src->size) return;
    smgr.next_input_byte += num_bytes;
    smgr.bytes_in_buffer -= num_bytes;
  }

  static int resync_to_restart(j_compress_ptr dinfo, int desired ) {
    return(jpeg_resync_to_restart(dinfo, desired));
  }

  static void term_source(j_compress_ptr dinfo) {
    return;
  }
            
  /* first determine if JPEG file since decoder will error if not*/
  bseek(src, 0, SEEK_SET);
  
  if (!bread(src, magic, 2)) 
    return(0);
  
  if (magic[0] != 0xFF || magic[1] != 0xD8) 
    return(0);          /* not JPEG image*/
  
  
  bread(src, magic, 4);
  bread(src, magic, 4);
  
  if (strncmp(magic, "JFIF", 4) != 0) 
    return(0);          /* not JPEG image*/
  
  bread(src, 0, SEEK_SET);
  pimage->imagebits = NULL;
  pimage->palette = NULL;
  
  /* Step 1: allocate and initialize JPEG decompression object */
  
  /* We set up the normal JPEG error routines. */
  cinfo.err = jpeg_std_error (&jerr);
  
  /* Now we can initialize the JPEG decompression object. */
  jpeg_create_decompress (&cinfo);
     
  
  /* Step 2:  Setup the source manager */

  smgr.init_source = init_source;
  smgr.fill_input_buffer = fill_input_buffer;
  smgr.skip_input_data = skip_input_data;
  smgr.resync_to_restart = resync_to_restart;
  smgr.term_source = term_source;
  
  cinfo.src = &smgr;

  /* Step 2: specify data source (eg, a file) */
  /* jpeg_stdio_src (&cinfo, fp); */
  
  /* Step 3: read file parameters with jpeg_read_header() */
  jpeg_read_header (&cinfo, TRUE);

      /* Step 4: set parameters for decompression */
      cinfo.out_color_space = fast_grayscale? JCS_GRAYSCALE: JCS_RGB;
      cinfo.quantize_colors = FALSE;

#if FASTJPEG
      goto fastjpeg;
#endif
      if (!fast_grayscale)
      {
            if (psd->pixtype == MWPF_PALETTE)
            {
fastjpeg:
                  cinfo.quantize_colors = TRUE;

#if FASTJPEG
                  cinfo.actual_number_of_colors = 256;
#else
                  /* Get system palette */
                  cinfo.actual_number_of_colors = 
                        GdGetPalette(psd, 0, psd->ncolors, palette);
#endif
      
                  /* Allocate jpeg colormap space */
                  cinfo.colormap = (*cinfo.mem->alloc_sarray)
                        ((j_common_ptr) &cinfo, JPOOL_IMAGE,
                              (JDIMENSION)cinfo.actual_number_of_colors,
                        (JDIMENSION)3);

                  /* Set colormap from system palette */
                  for(i = 0; i < cinfo.actual_number_of_colors; ++i)
                  {
#if FASTJPEG
                        cinfo.colormap[0][i] = mwstdpal8[i].r;
                        cinfo.colormap[1][i] = mwstdpal8[i].g;
                        cinfo.colormap[2][i] = mwstdpal8[i].b;
#else
                        cinfo.colormap[0][i] = palette[i].r;
                        cinfo.colormap[1][i] = palette[i].g;
                        cinfo.colormap[2][i] = palette[i].b;
#endif
                  }
            }
      }
      else 
      {
            /* Grayscale output asked */
            cinfo.quantize_colors = TRUE;
            cinfo.out_color_space = JCS_GRAYSCALE;
            cinfo.desired_number_of_colors = psd->ncolors;
      }
      jpeg_calc_output_dimensions(&cinfo);

      pimage->width = cinfo.output_width;
      pimage->height = cinfo.output_height;
      pimage->planes = 1;
#if FASTJPEG
      pimage->bpp = 8;
#else
      pimage->bpp = (fast_grayscale || psd->pixtype == MWPF_PALETTE)?
            8: cinfo.output_components*8;
#endif
      ComputePitch(pimage->bpp, pimage->width, &pimage->pitch,
            &pimage->bytesperpixel);
      pimage->compression = MWIMAGE_RGB;  /* RGB not BGR order*/
      pimage->palsize = (pimage->bpp == 8)? 256: 0;
      pimage->imagebits = malloc(pimage->pitch * pimage->height);
      if(!pimage->imagebits)
            goto err;
      pimage->palette = NULL;
#if FASTJPEG
      if(pimage->bpp == 8) {
            pimage->palette = malloc(256*sizeof(MWPALENTRY));
            if(!pimage->palette)
                  goto err;
            for (i=0; i<256; ++i)
                  pimage->palette[i] = mwstdpal8[i];
      }
#endif

      /* Step 5: Start decompressor */
      jpeg_start_decompress (&cinfo);

      /* Step 6: while (scan lines remain to be read) */
      while(cinfo.output_scanline < cinfo.output_height) {
            JSAMPROW rowptr[1];
            rowptr[0] = (JSAMPROW)(pimage->imagebits +
                  cinfo.output_scanline * pimage->pitch);
            jpeg_read_scanlines (&cinfo, rowptr, 1);
      }
      ret = 1;

err:
      /* Step 7: Finish decompression */
      jpeg_finish_decompress (&cinfo);

      /* Step 8: Release JPEG decompression object */
      jpeg_destroy_decompress (&cinfo);

      /* May want to check to see whether any corrupt-data
       * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
       */
      return ret;
}
#endif /* defined(HAVE_FILEIO) && defined(HAVE_JPEG_SUPPORT)*/

#if defined(HAVE_FILEIO) && defined(HAVE_PNG_SUPPORT)
#include "png.h"
/* png_jmpbuf() macro is not defined prior to libpng-1.0.6*/
#ifndef png_jmpbuf
#define png_jmpbuf(png_ptr)   ((png_ptr)->jmpbuf)
#endif
/*
 * Load a PNG file.
 * Currently for simplicity we get the PNG library to convert the file to
 * 24 bit RGB format with no alpha channel information even if we could
 * potentially store the image more efficiently by taking note of the image
 * type and depth and acting accordingly. Similarly, > 8 bits per channel,
 * gamma correction, etc. are not supported.
 */
static int
LoadPNG(buffer_t * src, PMWIMAGEHDR pimage)
{
      unsigned char hdr[8], **rows;
      png_structp state;
      png_infop pnginfo;
      png_uint_32 width, height;
      int bit_depth, colourtype, i;

      bseek(src, 0L, 0);

      if(bread(src, hdr, 8) != 8) return 0;

      if(png_sig_cmp(hdr, 0, 8)) return 0;

      if(!(state = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, 
                                    NULL, NULL))) goto nomem;

      if(!(pnginfo = png_create_info_struct(state))) {
            png_destroy_read_struct(&state, NULL, NULL);
            goto nomem;
      }

      if(setjmp(png_jmpbuf(state))) {
            png_destroy_read_struct(&state, &pnginfo, NULL);
            return 2;
      }

      png_init_io(state, fp);
      png_set_sig_bytes(state, 8);
      png_read_info(state, pnginfo);
      png_get_IHDR(state, pnginfo, &width, &height, &bit_depth, &colourtype,
                                          NULL, NULL, NULL);

      pimage->width = width;
      pimage->height = height;
      pimage->bpp = 24;
      pimage->planes = 1;
      ComputePitch(pimage->bpp, pimage->width, &pimage->pitch,
                                    &pimage->bytesperpixel);
      pimage->compression = MWIMAGE_RGB;
        if(!(pimage->imagebits = malloc(pimage->pitch * pimage->height))) {
            png_destroy_read_struct(&state, &pnginfo, NULL);
            goto nomem;
        }
        if(!(rows = malloc(pimage->height * sizeof(unsigned char *)))) {
            png_destroy_read_struct(&state, &pnginfo, NULL);
            goto nomem;
        }
      for(i = 0; i < pimage->height; i++)
            rows[i] = pimage->imagebits + (i * pimage->pitch);

      png_set_expand(state);
      if(bit_depth == 16)
            png_set_strip_16(state);
      if(colourtype & PNG_COLOR_MASK_ALPHA)
            png_set_strip_alpha(state);
      if(colourtype == PNG_COLOR_TYPE_GRAY ||
                  colourtype == PNG_COLOR_TYPE_GRAY_ALPHA)
            png_set_gray_to_rgb(state);

      png_read_image(state, rows);

      png_read_end(state, NULL);
      free(rows);
      png_destroy_read_struct(&state, &pnginfo, NULL);

      return 1;

nomem:
      EPRINTF("LoadPNG: Out of memory\n");
      return 2;
}
#endif /* defined(HAVE_FILEIO) && defined(HAVE_PNG_SUPPORT)*/

#if defined(HAVE_FILEIO) && defined(HAVE_BMP_SUPPORT)
/* BMP stuff*/
#define BI_RGB          0L
#define BI_RLE8         1L
#define BI_RLE4         2L
#define BI_BITFIELDS    3L

typedef unsigned char   BYTE;
typedef unsigned short  WORD;
typedef unsigned long   DWORD;
typedef long            LONG;

typedef struct {
      /* BITMAPFILEHEADER*/
      BYTE  bfType[2];
      DWORD bfSize;
      WORD  bfReserved1;
      WORD  bfReserved2;
      DWORD bfOffBits;
} BMPFILEHEAD;

#define FILEHEADSIZE 14

/* windows style*/
typedef struct {
      /* BITMAPINFOHEADER*/
      DWORD BiSize;
      DWORD BiWidth;
      DWORD BiHeight;
      WORD  BiPlanes;
      WORD  BiBitCount;
      DWORD BiCompression;
      DWORD BiSizeImage;
      DWORD BiXpelsPerMeter;
      DWORD BiYpelsPerMeter;
      DWORD BiClrUsed;
      DWORD BiClrImportant;
} BMPINFOHEAD;

#define INFOHEADSIZE 40

/* os/2 style*/
typedef struct {
      /* BITMAPCOREHEADER*/
      DWORD bcSize;
      WORD  bcWidth;
      WORD  bcHeight;
      WORD  bcPlanes;
      WORD  bcBitCount;
} BMPCOREHEAD;

#define COREHEADSIZE 12

static int  DecodeRLE8(MWUCHAR *buf, buffer_t *src);
static int  DecodeRLE4(MWUCHAR *buf, buffer_t *src);
static void put4(int b);

/*
 * BMP decoding routine
 */

/* Changed by JHC to allow a buffer instead of a filename */

static int
LoadBMP(buffer_t *src, PMWIMAGEHDR pimage)
{
      int         h, i, compression;
      int         headsize;
      MWUCHAR           *imagebits;
      BMPFILEHEAD bmpf;
      BMPINFOHEAD bmpi;
      BMPCOREHEAD bmpc;
      MWUCHAR     headbuffer[INFOHEADSIZE];

      bseek(src, 0, SEEK_SET);

      pimage->imagebits = NULL;
      pimage->palette = NULL;

      /* read BMP file header*/
      if (bread(src, &headbuffer, FILEHEADSIZE) != FILEHEADSIZE)
        return(0);

      bmpf.bfType[0] = headbuffer[0];
      bmpf.bfType[1] = headbuffer[1];

      /* Is it really a bmp file ? */
      if (*(WORD*)&bmpf.bfType[0] != wswap(0x4D42)) /* 'BM' */
            return 0;   /* not bmp image*/

      /*bmpf.bfSize = dwswap(dwread(&headbuffer[2]));*/
      bmpf.bfOffBits = dwswap(dwread(&headbuffer[10]));

      /* Read remaining header size */
      if (bread(src,&headsize,sizeof(DWORD)) != sizeof(DWORD))
            return 0;   /* not bmp image*/
      headsize = dwswap(headsize);

      /* might be windows or os/2 header */
      if(headsize == COREHEADSIZE) {

            /* read os/2 header */
            if(bread(src, &headbuffer, COREHEADSIZE-sizeof(DWORD)) !=
                  COREHEADSIZE-sizeof(DWORD))
                        return 0;   /* not bmp image*/

            /* Get data */
            bmpc.bcWidth = wswap(*(WORD*)&headbuffer[0]);
            bmpc.bcHeight = wswap(*(WORD*)&headbuffer[2]);
            bmpc.bcPlanes = wswap(*(WORD*)&headbuffer[4]);
            bmpc.bcBitCount = wswap(*(WORD*)&headbuffer[6]);
            
            pimage->width = (int)bmpc.bcWidth;
            pimage->height = (int)bmpc.bcHeight;
            pimage->bpp = bmpc.bcBitCount;
            if (pimage->bpp <= 8)
                  pimage->palsize = 1 << pimage->bpp;
            else pimage->palsize = 0;
            compression = BI_RGB;
      } else {
            /* read windows header */
            if(bread(src, &headbuffer, INFOHEADSIZE-sizeof(DWORD)) !=
                  INFOHEADSIZE-sizeof(DWORD))
                        return 0;   /* not bmp image*/

            /* Get data */
            bmpi.BiWidth = dwswap(*(DWORD*)&headbuffer[0]);
            bmpi.BiHeight = dwswap(*(DWORD*)&headbuffer[4]);
            bmpi.BiPlanes = wswap(*(WORD*)&headbuffer[8]);
            bmpi.BiBitCount = wswap(*(WORD*)&headbuffer[10]);
            bmpi.BiCompression = dwswap(*(DWORD*)&headbuffer[12]);
            bmpi.BiSizeImage = dwswap(*(DWORD*)&headbuffer[16]);
            bmpi.BiXpelsPerMeter = dwswap(*(DWORD*)&headbuffer[20]);
            bmpi.BiYpelsPerMeter = dwswap(*(DWORD*)&headbuffer[24]);
            bmpi.BiClrUsed = dwswap(*(DWORD*)&headbuffer[28]);
            bmpi.BiClrImportant = dwswap(*(DWORD*)&headbuffer[32]);

            pimage->width = (int)bmpi.BiWidth;
            pimage->height = (int)bmpi.BiHeight;
            pimage->bpp = bmpi.BiBitCount;
            pimage->palsize = (int)bmpi.BiClrUsed;
            if (pimage->palsize > 256)
                  pimage->palsize = 0;
            else if(pimage->palsize == 0 && pimage->bpp <= 8)
                  pimage->palsize = 1 << pimage->bpp;
            compression = bmpi.BiCompression;
      }
      pimage->compression = MWIMAGE_BGR;  /* right side up, BGR order*/
      pimage->planes = 1;

      /* currently only 1, 4, 8 and 24 bpp bitmaps*/
      if(pimage->bpp > 8 && pimage->bpp != 24) {
            EPRINTF("LoadBMP: image bpp not 1, 4, 8 or 24\n");
            return 2;   /* image loading error*/
      }

      /* compute byte line size and bytes per pixel*/
      ComputePitch(pimage->bpp, pimage->width, &pimage->pitch,
            &pimage->bytesperpixel);

      /* Allocate image */
      if( (pimage->imagebits = malloc(pimage->pitch*pimage->height)) == NULL)
            goto err;
      if( (pimage->palette = malloc(256*sizeof(MWPALENTRY))) == NULL)
            goto err;

      /* get colormap*/
      if(pimage->bpp <= 8) {
            for(i=0; i<pimage->palsize; i++) {
                  pimage->palette[i].b = bgetc(src);
                  pimage->palette[i].g = bgetc(src);
                  pimage->palette[i].r = bgetc(src);
                  if(headsize != COREHEADSIZE)
                        bgetc(src);
            }
      }

      /* decode image data*/
      bseek(src, bmpf.bfOffBits, SEEK_SET);

      h = pimage->height;
      /* For every row ... */
      while (--h >= 0) {
            /* turn image rightside up*/
            imagebits = pimage->imagebits + h*pimage->pitch;

            /* Get row data from file */
            if(compression == BI_RLE8) {
                  if(!DecodeRLE8(imagebits, src))
                        break;
            } else if(compression == BI_RLE4) {
                  if(!DecodeRLE4(imagebits, src))
                        break;
            } else {
                  if(bread(src, imagebits, pimage->pitch) !=
                        pimage->pitch)
                              goto err;
            }
      }
      return 1;         /* bmp image ok*/
      
err:
      EPRINTF("LoadBMP: image loading error\n");
      if(pimage->imagebits)
            free(pimage->imagebits);
      if(pimage->palette)
            free(pimage->palette);
      return 2;         /* bmp image error*/
}

/*
 * Decode one line of RLE8, return 0 when done with all bitmap data
 */
static int
DecodeRLE8(MWUCHAR *buf, buffer_t *src)
{
      int         c, n;
      MWUCHAR *   p = buf;

      for( ;;) {
        switch( n = bgetc(src)) {
        case EOF:
          return( 0);
        case 0:               /* 0 = escape*/
          switch( n = bgetc(src)) {
          case 0:       /* 0 0 = end of current scan line*/
            return( 1);
          case 1:       /* 0 1 = end of data*/
            return( 1);
          case 2:       /* 0 2 xx yy delta mode NOT SUPPORTED*/
            (void)bgetc(src);
            (void)bgetc(src);
            continue;
          default:      /* 0 3..255 xx nn uncompressed data*/
            for( c=0; c<n; c++)
            *p++ = bgetc(src);
            if( n & 1)
            (void)bgetc(src);
            continue;
          }
        default:
          c = bgetc(src);
          while( n--)
            *p++ = c;
          continue;
        }
      }
}

/*
 * Decode one line of RLE4, return 0 when done with all bitmap data
 */
static MWUCHAR *p;
static int  once;

static void
put4(int b)
{
      static int  last;

      last = (last << 4) | b;
      if( ++once == 2) {
            *p++ = last;
            once = 0;
      }
}
      
static int
DecodeRLE4(MWUCHAR *buf, buffer_t *src)
{
      int         c, n, c1, c2;

      p = buf;
      once = 0;
      c1 = 0;

      for( ;;) {
        switch( n = bgetc(src)) {
        case EOF:
          return( 0);
        case 0:               /* 0 = escape*/
          switch( n = bgetc(src)) {
          case 0:       /* 0 0 = end of current scan line*/
            if( once)
            put4( 0);
            return( 1);
          case 1:       /* 0 1 = end of data*/
            if( once)
            put4( 0);
            return( 1);
          case 2:       /* 0 2 xx yy delta mode NOT SUPPORTED*/
            (void)bgetc(src);
            (void)bgetc(src);
            continue;
          default:      /* 0 3..255 xx nn uncompressed data*/
            c2 = (n+3) & ~3;
            for( c=0; c<c2; c++) {
            if( (c & 1) == 0)
              c1 = bgetc(src);
            if( c < n)
              put4( (c1 >> 4) & 0x0f);
            c1 <<= 4;
            }
            continue;
          }
        default:
          c = bgetc(src);
          c1 = (c >> 4) & 0x0f;
          c2 = c & 0x0f;
          for( c=0; c<n; c++)
            put4( (c&1)? c2: c1);
          continue;
        }
      }
}
#endif /* defined(HAVE_FILEIO) && defined(HAVE_BMP_SUPPORT)*/

#if 0
void print_image(PMWIMAGEHDR image)
{
      int i;

      DPRINTF("Image:\n\n");
      DPRINTF("height: %d\n", image->height);
      DPRINTF("width: %d\n", image->width);
      DPRINTF("planes: %d\n", image->planes);
      DPRINTF("bpp: %d\n", image->bpp);
      DPRINTF("compression: %d\n", image->compression);
      DPRINTF("palsize: %d\n", image->palsize);

      for (i=0;i<image->palsize;i++)
            DPRINTF("palette: %d, %d, %d\n", image->palette[i].r,
                  image->palette[i].g, image->palette[i].b);

      for(i=0;i<(image->width*image->height);i++)
            DPRINTF("imagebits: %d\n", image->imagebits[i]);
}
#endif

#if defined(HAVE_FILEIO) && defined(HAVE_GIF_SUPPORT)
/* Code for GIF decoding has been adapted from XPaint:                   */
/* +-------------------------------------------------------------------+ */
/* | Copyright 1990, 1991, 1993 David Koblas.                      | */
/* | Copyright 1996 Torsten Martinsen.                             | */
/* |   Permission to use, copy, modify, and distribute this software   | */
/* |   and its documentation for any purpose and without fee is hereby | */
/* |   granted, provided that the above copyright notice appear in all | */
/* |   copies and that both that copyright notice and this permission  | */
/* |   notice appear in supporting documentation.  This software is    | */
/* |   provided "as is" without express or implied warranty.             | */
/* +-------------------------------------------------------------------+ */
/* Portions Copyright (C) 1999  Sam Lantinga*/
/* Adapted for use in SDL by Sam Lantinga -- 7/20/98 */
/*
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
/* GIF stuff*/
/*
 * GIF decoding routine
 */
#define     MAXCOLORMAPSIZE         256
#define     MAX_LWZ_BITS            12
#define INTERLACE       0x40
#define LOCALCOLORMAP         0x80

#define CM_RED          0
#define CM_GREEN  1
#define CM_BLUE         2

#define BitSet(byte, bit)     (((byte) & (bit)) == (bit))
#define     ReadOK(src,buffer,len)  bread(src, buffer, len)
#define LM_to_uint(a,b)       (((b)<<8)|(a))

struct {
    unsigned int Width;
    unsigned int Height;
    unsigned char ColorMap[3][MAXCOLORMAPSIZE];
    unsigned int BitPixel;
    unsigned int ColorResolution;
    unsigned int Background;
    unsigned int AspectRatio;
    int GrayScale;
} GifScreen;

static struct {
    int transparent;
    int delayTime;
    int inputFlag;
    int disposal;
} Gif89;

static int ReadColorMap(buffer_t *src, int number,
            unsigned char buffer[3][MAXCOLORMAPSIZE], int *flag);
static int DoExtension(buffer_t *src, int label);
static int GetDataBlock(buffer_t *src, unsigned char *buf);
static int GetCode(buffer_t *src, int code_size, int flag);
static int LWZReadByte(buffer_t *src, int flag, int input_code_size);
static int ReadImage(buffer_t *src, PMWIMAGEHDR pimage, int len, int height, int,
            unsigned char cmap[3][MAXCOLORMAPSIZE],
            int gray, int interlace, int ignore);

static int
LoadGIF(buffer_t *src, PMWIMAGEHDR pimage)
{
    unsigned char buf[16];
    unsigned char c;
    unsigned char localColorMap[3][MAXCOLORMAPSIZE];
    int grayScale;
    int useGlobalColormap;
    int bitPixel;
    int imageCount = 0;
    char version[4];
    int imageNumber = 1;
    int ok = 0;

    bseek(src, 0, SEEK_SET);

    pimage->imagebits = NULL;
    pimage->palette = NULL;

    if (!ReadOK(src, buf, 6))
        return 0;       /* not gif image*/
    if (strncmp((char *) buf, "GIF", 3) != 0)
        return 0;
    strncpy(version, (char *) buf + 3, 3);
    version[3] = '\0';

    if (strcmp(version, "87a") != 0 && strcmp(version, "89a") != 0) {
      EPRINTF("LoadGIF: GIF version number not 87a or 89a\n");
        return 2;       /* image loading error*/
    }
    Gif89.transparent = -1;
    Gif89.delayTime = -1;
    Gif89.inputFlag = -1;
    Gif89.disposal = 0;

    if (!ReadOK(src, buf, 7)) {
      EPRINTF("LoadGIF: bad screen descriptor\n");
        return 2;       /* image loading error*/
    }
    GifScreen.Width = LM_to_uint(buf[0], buf[1]);
    GifScreen.Height = LM_to_uint(buf[2], buf[3]);
    GifScreen.BitPixel = 2 << (buf[4] & 0x07);
    GifScreen.ColorResolution = (((buf[4] & 0x70) >> 3) + 1);
    GifScreen.Background = buf[5];
    GifScreen.AspectRatio = buf[6];

    if (BitSet(buf[4], LOCALCOLORMAP)) {  /* Global Colormap */
      if (ReadColorMap(src, GifScreen.BitPixel, GifScreen.ColorMap,
                   &GifScreen.GrayScale)) {
          EPRINTF("LoadGIF: bad global colormap\n");
            return 2;         /* image loading error*/
      }
    }

    do {
      if (!ReadOK(src, &c, 1)) {
          EPRINTF("LoadGIF: EOF on image data\n");
            goto done;
      }
      if (c == ';') {         /* GIF terminator */
          if (imageCount < imageNumber) {
            EPRINTF("LoadGIF: no image %d of %d\n", imageNumber,imageCount);
                goto done;
          }
      }
      if (c == '!') {         /* Extension */
          if (!ReadOK(src, &c, 1)) {
            EPRINTF("LoadGIF: EOF on extension function code\n");
                goto done;
          }
          DoExtension(src, c);
          continue;
      }
      if (c != ',') {         /* Not a valid start character */
          continue;
      }
      ++imageCount;

      if (!ReadOK(src, buf, 9)) {
          EPRINTF("LoadGIF: bad image size\n");
            goto done;
      }
      useGlobalColormap = !BitSet(buf[8], LOCALCOLORMAP);

      bitPixel = 1 << ((buf[8] & 0x07) + 1);

      if (!useGlobalColormap) {
          if (ReadColorMap(src, bitPixel, localColorMap, &grayScale)) {
            EPRINTF("LoadGIF: bad local colormap\n");
                goto done;
          }
          ok = ReadImage(src, pimage, LM_to_uint(buf[4], buf[5]),
                        LM_to_uint(buf[6], buf[7]),
                        bitPixel, localColorMap, grayScale,
                        BitSet(buf[8], INTERLACE),
                        imageCount != imageNumber);
      } else {
          ok = ReadImage(src, pimage, LM_to_uint(buf[4], buf[5]),
                        LM_to_uint(buf[6], buf[7]),
                        GifScreen.BitPixel, GifScreen.ColorMap,
                        GifScreen.GrayScale, BitSet(buf[8], INTERLACE),
                        imageCount != imageNumber);
      }
    } while (ok == 0);

    /* set transparent color, if any*/
    pimage->transcolor = Gif89.transparent;

    if (ok)
          return 1;           /* image load ok*/

done:
    if (pimage->imagebits)
          free(pimage->imagebits);
    if (pimage->palette)
          free(pimage->palette);
    return 2;                 /* image load error*/
}

static int
ReadColorMap(buffer_t *src, int number, unsigned char buffer[3][MAXCOLORMAPSIZE],
    int *gray)
{
    int i;
    unsigned char rgb[3];
    int flag;

    flag = TRUE;

    for (i = 0; i < number; ++i) {
      if (!ReadOK(src, rgb, sizeof(rgb)))
          return 1;
      buffer[CM_RED][i] = rgb[0];
      buffer[CM_GREEN][i] = rgb[1];
      buffer[CM_BLUE][i] = rgb[2];
      flag &= (rgb[0] == rgb[1] && rgb[1] == rgb[2]);
    }

#if 0
    if (flag)
      *gray = (number == 2) ? PBM_TYPE : PGM_TYPE;
    else
      *gray = PPM_TYPE;
#else
    *gray = 0;
#endif

    return FALSE;
}

static int
DoExtension(buffer_t *src, int label)
{
    static unsigned char buf[256];

    switch (label) {
    case 0x01:                /* Plain Text Extension */
      break;
    case 0xff:                /* Application Extension */
      break;
    case 0xfe:                /* Comment Extension */
      while (GetDataBlock(src, (unsigned char *) buf) != 0);
      return FALSE;
    case 0xf9:                /* Graphic Control Extension */
      GetDataBlock(src, (unsigned char *) buf);
      Gif89.disposal = (buf[0] >> 2) & 0x7;
      Gif89.inputFlag = (buf[0] >> 1) & 0x1;
      Gif89.delayTime = LM_to_uint(buf[1], buf[2]);
      if ((buf[0] & 0x1) != 0)
          Gif89.transparent = buf[3];

      while (GetDataBlock(src, (unsigned char *) buf) != 0);
      return FALSE;
    default:
      break;
    }

    while (GetDataBlock(src, (unsigned char *) buf) != 0);

    return FALSE;
}

static int ZeroDataBlock = FALSE;

static int
GetDataBlock(buffer_t *src, unsigned char *buf)
{
    unsigned char count;

    if (!ReadOK(src, &count, 1))
      return -1;
    ZeroDataBlock = count == 0;

    if ((count != 0) && (!ReadOK(src, buf, count)))
      return -1;
    return count;
}

static int
GetCode(buffer_t *src, int code_size, int flag)
{
    static unsigned char buf[280];
    static int curbit, lastbit, done, last_byte;
    int i, j, ret;
    unsigned char count;

    if (flag) {
      curbit = 0;
      lastbit = 0;
      done = FALSE;
      return 0;
    }
    if ((curbit + code_size) >= lastbit) {
      if (done) {
          if (curbit >= lastbit)
            EPRINTF("LoadGIF: bad decode\n");
          return -1;
      }
      buf[0] = buf[last_byte - 2];
      buf[1] = buf[last_byte - 1];

      if ((count = GetDataBlock(src, &buf[2])) == 0)
          done = TRUE;

      last_byte = 2 + count;
      curbit = (curbit - lastbit) + 16;
      lastbit = (2 + count) * 8;
    }
    ret = 0;
    for (i = curbit, j = 0; j < code_size; ++i, ++j)
      ret |= ((buf[i / 8] & (1 << (i % 8))) != 0) << j;

    curbit += code_size;

    return ret;
}

static int
LWZReadByte(buffer_t *src, int flag, int input_code_size)
{
    int code, incode;
    register int i;
    static int fresh = FALSE;
    static int code_size, set_code_size;
    static int max_code, max_code_size;
    static int firstcode, oldcode;
    static int clear_code, end_code;
    static int table[2][(1 << MAX_LWZ_BITS)];
    static int stack[(1 << (MAX_LWZ_BITS)) * 2], *sp;

    if (flag) {
      set_code_size = input_code_size;
      code_size = set_code_size + 1;
      clear_code = 1 << set_code_size;
      end_code = clear_code + 1;
      max_code_size = 2 * clear_code;
      max_code = clear_code + 2;

      GetCode(src, 0, TRUE);

      fresh = TRUE;

      for (i = 0; i < clear_code; ++i) {
          table[0][i] = 0;
          table[1][i] = i;
      }
      for (; i < (1 << MAX_LWZ_BITS); ++i)
          table[0][i] = table[1][0] = 0;

      sp = stack;

      return 0;
    } else if (fresh) {
      fresh = FALSE;
      do {
          firstcode = oldcode = GetCode(src, code_size, FALSE);
      } while (firstcode == clear_code);
      return firstcode;
    }
    if (sp > stack)
      return *--sp;

    while ((code = GetCode(src, code_size, FALSE)) >= 0) {
      if (code == clear_code) {
          for (i = 0; i < clear_code; ++i) {
            table[0][i] = 0;
            table[1][i] = i;
          }
          for (; i < (1 << MAX_LWZ_BITS); ++i)
            table[0][i] = table[1][i] = 0;
          code_size = set_code_size + 1;
          max_code_size = 2 * clear_code;
          max_code = clear_code + 2;
          sp = stack;
          firstcode = oldcode = GetCode(src, code_size, FALSE);
          return firstcode;
      } else if (code == end_code) {
          int count;
          unsigned char buf[260];

          if (ZeroDataBlock)
            return -2;

          while ((count = GetDataBlock(src, buf)) > 0);

          if (count != 0) {
            /*
             * EPRINTF("missing EOD in data stream (common occurence)");
             */
          }
          return -2;
      }
      incode = code;

      if (code >= max_code) {
          *sp++ = firstcode;
          code = oldcode;
      }
      while (code >= clear_code) {
          *sp++ = table[1][code];
          if (code == table[0][code])
            EPRINTF("LoadGIF: circular table entry\n");
          code = table[0][code];
      }

      *sp++ = firstcode = table[1][code];

      if ((code = max_code) < (1 << MAX_LWZ_BITS)) {
          table[0][code] = oldcode;
          table[1][code] = firstcode;
          ++max_code;
          if ((max_code >= max_code_size) &&
            (max_code_size < (1 << MAX_LWZ_BITS))) {
            max_code_size *= 2;
            ++code_size;
          }
      }
      oldcode = incode;

      if (sp > stack)
          return *--sp;
    }
    return code;
}

static int
ReadImage(buffer_t* src, PMWIMAGEHDR pimage, int len, int height, int cmapSize,
        unsigned char cmap[3][MAXCOLORMAPSIZE],
        int gray, int interlace, int ignore)
{
    unsigned char c;
    int i, v;
    int xpos = 0, ypos = 0, pass = 0;

    /*
     *      Initialize the compression routines
     */
    if (!ReadOK(src, &c, 1)) {
      EPRINTF("LoadGIF: EOF on image data\n");
      return 0;
    }
    if (LWZReadByte(src, TRUE, c) < 0) {
      EPRINTF("LoadGIF: error reading image\n");
      return 0;
    }

    /*
     *      If this is an "uninteresting picture" ignore it.
     */
    if (ignore) {
      while (LWZReadByte(src, FALSE, c) >= 0);
      return 0;
    }
    /*image = ImageNewCmap(len, height, cmapSize);*/
    pimage->width = len;
    pimage->height = height;
    pimage->planes = 1;
    pimage->bpp = 8;
    ComputePitch(8, len, &pimage->pitch, &pimage->bytesperpixel);
    pimage->compression = 0;
    pimage->palsize = cmapSize;
    pimage->palette = malloc(256*sizeof(MWPALENTRY));
    pimage->imagebits = malloc(height*pimage->pitch);
    if(!pimage->imagebits || !pimage->palette)
          return 0;

    for (i = 0; i < cmapSize; i++) {
      /*ImageSetCmap(image, i, cmap[CM_RED][i],
                 cmap[CM_GREEN][i], cmap[CM_BLUE][i]);*/
      pimage->palette[i].r = cmap[CM_RED][i];
      pimage->palette[i].g = cmap[CM_GREEN][i];
      pimage->palette[i].b = cmap[CM_BLUE][i];
    }

    while ((v = LWZReadByte(src, FALSE, c)) >= 0) {
      pimage->imagebits[ypos * pimage->pitch + xpos] = v;

      ++xpos;
      if (xpos == len) {
          xpos = 0;
          if (interlace) {
            switch (pass) {
            case 0:
            case 1:
                ypos += 8;
                break;
            case 2:
                ypos += 4;
                break;
            case 3:
                ypos += 2;
                break;
            }

            if (ypos >= height) {
                ++pass;
                switch (pass) {
                case 1:
                  ypos = 4;
                  break;
                case 2:
                  ypos = 2;
                  break;
                case 3:
                  ypos = 1;
                  break;
                default:
                  goto fini;
                }
            }
          } else {
            ++ypos;
          }
      }
      if (ypos >= height)
          break;
    }

fini:
    return 1;
}
#endif /* defined(HAVE_FILEIO) && defined(HAVE_GIF_SUPPORT)*/

#if defined(HAVE_FILEIO) && defined(HAVE_PNM_SUPPORT)
enum {
      PNM_TYPE_NOTPNM,
      PNM_TYPE_PBM,
      PNM_TYPE_PGM,
      PNM_TYPE_PPM
};
static int LoadPNM(buffer_t *src, PMWIMAGEHDR pimage)
{
      char buf[256], *p;
      int type = PNM_TYPE_NOTPNM, binary = 0, gothdrs = 0, scale = 0;
      int ch, x = 0, y = 0, i, n, mask, col1, col2, col3;

      bseek(src, 0L, 0);

      if(!bgets(src,buf, 4)) return 0;

      if(!strcmp("P1\n", buf)) type = PNM_TYPE_PBM;
      else if(!strcmp("P2\n", buf)) type = PNM_TYPE_PGM;
      else if(!strcmp("P3\n", buf)) type = PNM_TYPE_PPM;
      else if(!strcmp("P4\n", buf)) {
            type = PNM_TYPE_PBM;
            binary = 1;
      }
      else if(!strcmp("P5\n", buf)) {
            type = PNM_TYPE_PGM;
            binary = 1;
      }
      else if(!strcmp("P6\n", buf)) {
            type = PNM_TYPE_PPM;
            binary = 1;
      }

      if(type == PNM_TYPE_NOTPNM) return 0;

      n = 0;
      while((p = bgets(src, buf, 256))) {
            if(*buf == '#') continue;
            if(type == PNM_TYPE_PBM) {
                  if(sscanf(buf, "%i %i", &pimage->width,
                              &pimage->height) == 2) {
                        pimage->bpp = 1;
                        gothdrs = 1;
                        if(!(pimage->palette = malloc(
                                    sizeof(MWPALENTRY) * 2))) {
                              EPRINTF("Out of memory\n");
                              return 2;
                        }
                        pimage->palsize = 2;
                        pimage->palette[0].r = 0xff;
                        pimage->palette[0].g = 0xff;
                        pimage->palette[0].b = 0xff;
                        pimage->palette[1].r = 0;
                        pimage->palette[1].g = 0;
                        pimage->palette[1].b = 0;
                  }
                  break;
            }
            if((type == PNM_TYPE_PGM) || (type == PNM_TYPE_PPM)) {
                  if(!n++) {
                        if(sscanf(buf, "%i %i", &pimage->width,
                              &pimage->height) != 2) break;
                  } else {
                        if(sscanf(buf, "%i", &i) != 1) break;
                        pimage->bpp = 24;
                        if(i > 255) {
                              EPRINTF("LoadPNM: PPM files must be "
                                    "24bpp\n");
                              return 2;
                        }
                        for(scale = 7, n = 2; scale; scale--, n *= 2)
                              if(i < n) break;
                        gothdrs = 1;
                        break;
                  }
            }
      }

      if(!gothdrs) {
            EPRINTF("LoadPNM: bad image headers\n");
            if(pimage->palette) free(pimage->palette);
            return 2;
      }

      pimage->planes = 1;
      ComputePitch(pimage->bpp, pimage->width, &pimage->pitch,
                                    &pimage->bytesperpixel);
      pimage->compression = MWIMAGE_RGB;
      if(!(pimage->imagebits = malloc(pimage->pitch * pimage->height))) {
            EPRINTF("LoadPNM: couldn't allocate memory for image\n");
            if(pimage->palette) free(pimage->palette);
            return 2;
      }

      p = pimage->imagebits;

      if(type == PNM_TYPE_PBM) {
            if(binary) {
                  x = 0;
                  y = 0;
                  while((ch = bgetc(src)) != EOF) {
                        for(i = 0; i < 8; i++) {
                              mask = 0x80 >> i;
                              if(ch & mask) *p |= mask;
                              else *p &= ~mask;
                              if(++x == pimage->width) {
                                    if(++y == pimage->height)
                                          return 1;
                                    p = pimage->imagebits - 1 +
                                          (y * pimage->pitch);
                                    x = 0;
                                    break;
                              }
                        }
                        p++;
                  }
            } else {
                  n = 0;
                  while((ch = bgetc(src)) != EOF) {
                        if(isspace(ch)) continue;
                        mask = 0x80 >> n;
                        if(ch == '1') *p |= mask;
                        else if(ch == '0') *p &= ~mask;
                        else goto baddata;
                        if(++n == 8) {
                              n = 0;
                              p++;
                        }
                        if(++x == pimage->width) {
                              if(++y == pimage->height)
                                    return 1;
                              p = pimage->imagebits +
                                    (y * pimage->pitch);
                              n = 0;
                              x = 0;
                        }
                  }
            }
      } else {
            while(1) {
                  if(type == PNM_TYPE_PGM) {
                        if(binary) {
                              if((ch = bgetc(src)) == EOF)
                                    goto baddata;
                        } else {
                          //                          if(fscanf(fp, "%i", &ch) != 1)
                                    goto baddata;
                        }
                        *p++ = ch << scale;
                        *p++ = ch << scale;
                        *p++ = ch << scale;
                  } else {
                        if(binary) {
                              if(((col1 = bgetc(src)) == EOF) ||
                                    ((col2 = bgetc(src)) == EOF) ||
                                    ((col3 = bgetc(src)) == EOF))
                                    goto baddata;
                        } else {
                          //                          if(fscanf(fp, "%i %i %i", &col1, &col2,
                          //                                            &col3) != 3)
                                    goto baddata;
                        }
                        *p++ = col1 << scale;
                        *p++ = col2 << scale;
                        *p++ = col3 << scale;
                  }
                  if(++x == pimage->width) {
                        if(++y == pimage->height) return 1;
                        p = pimage->imagebits + (y * pimage->pitch);
                        x = 0;
                  }
            }
      }

baddata:
      EPRINTF("LoadPNM: bad image data\n");
      free(pimage->imagebits);
      if(pimage->palette) free(pimage->palette);
      return 2;
}
#endif /* defined(HAVE_FILEIO) && defined(HAVE_PNM_SUPPORT) */

#if defined(HAVE_FILEIO) && defined(HAVE_XPM_SUPPORT)
struct xpm_cmap {
  char mapstr[3];
  long palette_entry;
  long color;
  struct xpm_cmap *next;
};

 
static long XPM_parse_color(char *color)
{
  /* This will parse the string into a color value of some sort */

  if (color[0] != '#')
    {
      if (!strcmp(color, "None"))
      return(-1); /* Transparent */
      else
      return(0); /* If its an X color, then we bail */
    }
  else
    {
      /* This is ugly! */

      char *sptr = color + 1;
      char rstr[5], gstr[5], bstr[5];
      long r,g,b;

      switch(strlen(sptr))
      {
      case 6:
        return(strtol(sptr, NULL, 16));

      case 9: /* RRRGGGBBB */
        strncpy(rstr, sptr, 3);
        strncpy(gstr, sptr + 3, 3);
        strncpy(bstr, sptr + 6, 3);

        rstr[3] = 0;
        gstr[3] = 0;
        bstr[3] = 0;

        r = strtol(rstr, NULL, 16) >> 4;
        g = strtol(gstr, NULL, 16) >> 4;
        b = strtol(bstr, NULL, 16) >> 4;

        return( (long) ( r << 16 | g << 8 | b));

      case 12:
        strncpy(rstr, sptr, 4);
        strncpy(gstr, sptr + 4, 4);
        strncpy(bstr, sptr + 8, 4);
        
        rstr[4] = 0;
        gstr[4] = 0;
        bstr[4] = 0;

        r = strtol(rstr, NULL, 16) >> 8;
        g = strtol(gstr, NULL, 16) >> 8;
        b = strtol(bstr, NULL, 16) >> 8;
        
        return( (long) ( (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF)));
      }
    }

  return(0);
}

/* A series of status indicators that let us know whats going on */
/* It could be an enum if you want */

#define LOAD_HEADER 1
#define LOAD_COLORS 2
#define LOAD_PALETTE 3
#define LOAD_PIXELS 4
#define LOAD_DONE 5

/* The magic that "should" indicate an XPM (does it really?) */
#define XPM_MAGIC "/* XPM */"
#define XPM_TRANSCOLOR 0x01000000

static int LoadXPM(buffer_t *src, PMWIMAGEHDR pimage, PSD psd) 
{
  struct xpm_cmap *colorheap = 0;  /* A "heap" of color structs */
  struct xpm_cmap *colormap[256];  /* A quick hash of 256 spots for colors */
  
  unsigned char *imageptr = 0;

  MWSCREENINFO sinfo;

  char xline[300];
  char dline[300];

  char *c;
  int a;

  int col, row, colors, cpp;
  int in_color = 0;
  int read_xline = 0;

  int status = LOAD_HEADER;

  /* Very first thing, get the screen info */
  GdGetScreenInfo(psd, &sinfo);

  for(a = 0; a < 256; a++)
    colormap[a] = 0;

  pimage->imagebits = NULL;
  pimage->palette = NULL;

  /* Start over at the beginning with the file */
  bseek(src, 0, SEEK_SET);
 
  bgets(src, xline, 300);
 
  /* Chop the EOL */
  xline[strlen(xline) - 1] = 0;

  /* Check the magic */
  if (strncmp(xline, XPM_MAGIC, sizeof(XPM_MAGIC))) return(0);

  while(!beof(src))
    {
      /* Get the next line from the file */
      bgets(src,xline, 300);
      xline[strlen(xline) - 1] = 0;

      /* Check it out */
      if (xline[0] == '/' && xline[1] == '*') /* Comment */
      continue;

      if (xline[0] != '\"')
      continue;

      /* remove the quotes from the line */
      for(c = xline + 1, a = 0; *c != '\"' && *c != 0; c++, a++)
      dline[a] = *c;

      dline[a] = 0;

      /* Is it the header? */
      if (status == LOAD_HEADER)
      {
        sscanf(dline, "%i %i %i %i", &col, &row, &colors, &cpp);

        pimage->width = col;
        pimage->height = row;
        pimage->planes = 1;

        if (sinfo.bpp <= 8)
          {
            pimage->bpp = sinfo.bpp;
            pimage->compression = 0;
            pimage->transcolor = -1;
          }
        else
          {
            pimage->bpp = 32;
            pimage->transcolor = XPM_TRANSCOLOR;
            pimage->compression = MWIMAGE_BGR;    
          }

        pimage->palsize = colors;

        ComputePitch(pimage->bpp, col, &pimage->pitch, &pimage->bytesperpixel);

        pimage->imagebits = malloc(pimage->pitch * pimage->height); 
        imageptr = (unsigned char *) pimage->imagebits;

        /* Allocate enough room for all the colors */
        colorheap = (struct xpm_cmap *) malloc(colors * sizeof(struct xpm_cmap));

        /* Allocate the palette space (if required) */

        if (sinfo.bpp <= 8)
            pimage->palette = malloc(256*sizeof(MWPALENTRY));

        if (!colorheap)
          {
            EPRINTF("Couldn't allocate any memory for the colors\n");
            return(0);
          }

        status = LOAD_COLORS;
        in_color = 0;
        continue;
      }

      /* Are we in load colors? */
      if (status == LOAD_COLORS)
      {
        struct xpm_cmap *n;

        char tstr[5];
        char cstr[256];

        unsigned char m;

        c = dline;

        /* Go at at least 1 charater, and then count until we have
           two spaces in a row */

        strncpy(tstr, c, cpp);

        c += cpp;   
        for(; *c == '\t' || *c == ' '; c++); /* Skip over whitespace */

        /* FIXME: We assume that a 'c' follows.  What if it doesn't? */
        c +=2;
        
        tstr[cpp] = 0;

        /* Now we put it into the array for easy lookup   */
        /* We base it off the first charater, even though */
        /* there may be up to 4                           */

        m = tstr[0];
        
        if (colormap[m])
          {
            n = colormap[m];
            
            while(n->next) n = n->next;
            n->next = &colorheap[in_color];
            n = n->next;
          }
        else
          {
            colormap[m] = &colorheap[in_color];
            n = colormap[m];
          }
        
        n->next = 0;

        /* Record the string */
        strncpy(n->mapstr, tstr, cpp);
        n->mapstr[cpp] = 0;

        /* Now record the palette entry */
        n->palette_entry = (long) in_color;

        /* This is the color */
        sscanf(c, "%65535s", cstr);

        /* Turn it into a real value */
        n->color = XPM_parse_color(cstr);

        /* If we are in palette mode, then we need to */
        /* load the palette (duh..) */

        if (sinfo.bpp <= 8)
          {
            if (n->color == -1)
            {
              pimage->transcolor = in_color;
              n->color = -1;
            }
            
            pimage->palette[in_color].r = (n->color >> 16) & 0xFF;
            pimage->palette[in_color].g = (n->color >> 8) & 0xFF;
            pimage->palette[in_color].b = n->color & 0xFF;  
          }
        else
          {
            if (n->color == -1)
            n->color = XPM_TRANSCOLOR;
          }

        if (++in_color == colors)
          {
            read_xline = 0;
            status = LOAD_PIXELS;
          }

        continue;  
      }
      
      if (status == LOAD_PIXELS)
      {
      int bytecount = 0;
      int bitcount = 0;
      long dwordcolor = 0;
      int i;
      char pxlstr[3];

      c = dline;
      
      while(*c)
        {
          unsigned char z = 0;

          if (cpp == 1)
            {           
            z = *c;
            
            if (!colormap[z])
              {
                EPRINTF("No color entry for (%c)\n", z);
                return(0);
              }

            if (sinfo.bpp <= 8)
              dwordcolor = (long) colormap[z]->palette_entry;
            else
              dwordcolor = colormap[z]->color;  

            c++;
            }
          else
            {
            struct xpm_cmap *n; 

            /* We grab the largest possible, and then compare */

            strncpy(pxlstr, c, cpp);
            z = pxlstr[0];

            if (!colormap[z])
              {
                EPRINTF("No color entry for (%s)\n", pxlstr);
                return(0);
              }
                  
            n = colormap[z];

            while(n)
              {
                if (!strncmp(n->mapstr, pxlstr, cpp))
                  break;

                n = n->next;
              }

            if (!n)
              {
                EPRINTF("No color found for (%s)\n", pxlstr);         
                return(0);
              }

            if (sinfo.bpp <= 8)
              dwordcolor = (long) n->palette_entry;
            else
              dwordcolor = n->color;
            
            c += cpp;
            }

          /* 
           * This ugly thing is needed to ensure that we
           * work well in all modes.
           */
          switch(sinfo.bpp)
            {
            case 2:
            if (bitcount == 0)
              imageptr[0] = 0;
            
            imageptr[0] |= (dwordcolor & 0x3) << (4 - bitcount);
            bitcount++;
            
            if (bitcount == 4)
              {
                imageptr++;
                bytecount += pimage->bytesperpixel;
                bitcount = 0;
              }
            
            break;

            case 4:
            if (bitcount == 0)
              imageptr[0] = 0;
            
            imageptr[0] |= (dwordcolor & 0xF) << (2 - bitcount);
            bitcount++;
            
            if (bitcount == 2)
              {
                imageptr++;
                bytecount += pimage->bytesperpixel;
                bitcount = 0;
              }
            
            break;

            case 8:
            case 16:
            case 24:
            case 32:
            
            for(i = 0; i < pimage->bytesperpixel; i++)
              imageptr[i] = (dwordcolor >> (8 * i)) & 0xFF;
            
            imageptr += pimage->bytesperpixel;
            bytecount += pimage->bytesperpixel;
            break;

#ifdef NOTUSED
            case 8:
            imageptr[0] = (unsigned char) (dwordcolor & 0xFF);
            imageptr += pimage->bytesperpixel;
            bytecount += pimage->bytesperpixel;
            break;

            case 16:
            case 24:
            case 32:
            imageptr[0] = (unsigned char) (dwordcolor >> 24) & 0xFF;
            imageptr[1] = (unsigned char) (dwordcolor >> 16) & 0xFF;
            imageptr[2] = (unsigned char) (dwordcolor >> 8) & 0xFF;
            imageptr[3] = (unsigned char) (dwordcolor & 0xFF);
            imageptr += pimage->bytesperpixel;
            bytecount += pimage->bytesperpixel;
            break;
#endif
            }
        }

      /* Pad to the end of the line */
      if (bytecount < pimage->pitch)
        for(i = 0; i < (pimage->pitch - bytecount); i++)
          *imageptr++ = 0x00;

      read_xline++;
      
      if (read_xline == row)
        status = LOAD_DONE;

      continue;
      }
    }

  free(colorheap);

  if (status != LOAD_DONE)
    return(-1);
  return(1);
}
#endif /* defined(HAVE_FILEIO) && defined(HAVE_XPM_SUPPORT)*/

#endif /* defined(HAVE_FILEIO)*/

Generated by  Doxygen 1.6.0   Back to index