text: /*
   *   BMP image routines for CUPS.
   *
   *   Copyright 2007-2011 by Apple Inc.
   *   Copyright 1993-2007 by Easy Software Products.
   *
   *   These coded instructions, statements, and computer programs are the
   *   property of Apple Inc. and are protected by Federal copyright
   *   law.  Distribution and use rights are outlined in the file "COPYING"
   *   which should have been included with this file.
   *
   * Contents:
   *
   *   _cfImageReadBMP() - Read a BMP image file.
   *   read_word()         - Read a 16-bit unsigned integer.
   *   read_dword()        - Read a 32-bit unsigned integer.
   *   read_long()         - Read a 32-bit signed integer.
   */
  
  /*
   * Include necessary headers...
   */
  
  #include "image-private.h"
  
  
  /*
   * Constants for the bitmap compression...
   */
  
  #  define BI_RGB	0		/* No compression - straight BGR data */
  #  define BI_RLE8	1		/* 8-bit run-length compression */
  #  define BI_RLE4	2		/* 4-bit run-length compression */
  #  define BI_BITFIELDS	3		/* RGB bitmap with RGB masks */
  
  
  /*
   * Local functions...
   */
  
  static unsigned short	read_word(FILE *fp);
  static unsigned int	read_dword(FILE *fp);
  static int		read_long(FILE *fp);
  
  
  /*
   * '_cfImageReadBMP()' - Read a BMP image file.
   */
  
  int					/* O - Read status */
  _cfImageReadBMP(
      cf_image_t    *img,		/* IO - Image */
      FILE            *fp,		/* I - Image file */
      cf_icspace_t  primary,		/* I - Primary choice for colorspace */
      cf_icspace_t  secondary,		/* I - Secondary choice for colorspace */
      int             saturation,		/* I - Color saturation (%) */
      int             hue,		/* I - Color hue (degrees) */
      const cf_ib_t *lut)		/* I - Lookup table for gamma/brightness */
  {
    int		offset,			/* Offset to bitmap data */
  		info_size,		/* Size of info header */
  		planes,			/* Number of planes (always 1) */
  		depth,			/* Depth of image (bits) */
  		compression,		/* Type of compression */
  		image_size,		/* Size of image in bytes */
  		colors_used,		/* Number of colors used */
  		colors_important,	/* Number of important colors */
  		bpp,			/* Bytes per pixel */
  		x, y,			/* Looping vars */
  		color,			/* Color of RLE pixel */
  		count,			/* Number of times to repeat */
  		temp,			/* Temporary color */
  		align;			/* Alignment bytes */
    cf_ib_t	bit,			/* Bit in image */
  		byte;			/* Byte in image */
    cf_ib_t	*in,			/* Input pixels */
  		*out,			/* Output pixels */
  		*ptr;			/* Pointer into pixels */
    cf_ib_t	colormap[256][4];	/* Colormap */
  
  
    (void)secondary;
  
    (void)planes;
    (void)image_size;
    (void)colors_important;
  
   /*
    * Get the header...
    */
  
    getc(fp);		/* Skip "BM" sync chars */
    getc(fp);
    read_dword(fp);	/* Skip size */
    read_word(fp);	/* Skip reserved stuff */
    read_word(fp);
    offset = read_dword(fp);
  
    DEBUG_printf(("DEBUG: offset = %d\n", offset));
  
    if (offset < 0)
    {
      DEBUG_printf(("DEBUG: Bad BMP offset %d\n", offset));
      fclose(fp);
      return (1);
    }
  
   /*
    * Then the bitmap information...
    */
  
    info_size        = read_dword(fp);
    img->xsize       = read_long(fp);
    img->ysize       = read_long(fp);
    planes           = read_word(fp);
    depth            = read_word(fp);
    compression      = read_dword(fp);
    image_size       = read_dword(fp);
    img->xppi        = read_long(fp) * 0.0254 + 0.5;
    img->yppi        = read_long(fp) * 0.0254 + 0.5;
    colors_used      = read_dword(fp);
    colors_important = read_dword(fp);
  
    if (img->xsize == 0 || img->xsize > CF_IMAGE_MAX_WIDTH ||
        img->ysize == 0 || img->ysize > CF_IMAGE_MAX_HEIGHT ||
        (depth != 1 && depth != 4 && depth != 8 && depth != 24))
    {
      DEBUG_printf(("DEBUG: Bad BMP dimensions %ux%ux%d\n",
  		  img->xsize, img->ysize, depth));
      fclose(fp);
      return (1);
    }
  
    if (colors_used < 0 || colors_used > 256)
    {
      DEBUG_printf(("DEBUG: Bad BMP colormap size %d\n", colors_used));
      fclose(fp);
      return (1);
    }
  
    if (img->xppi == 0 || img->yppi == 0)
    {
      DEBUG_printf(("DEBUG: Bad BMP resolution %dx%d PPI.\n",
  		  img->xppi, img->yppi));
      img->xppi = img->yppi = 200;
    }
  
   /*
    * Make sure the resolution info is valid...
    */
  
    DEBUG_printf(("info_size = %d, xsize = %d, ysize = %d, planes = %d, depth = %d\n",
  		info_size, img->xsize, img->ysize, planes, depth));
    DEBUG_printf(("compression = %d, image_size = %d, xppi = %d, yppi = %d\n",
  		compression, image_size, img->xppi, img->yppi));
    DEBUG_printf(("colors_used = %d, colors_important = %d\n", colors_used,
  		colors_important));
  
    if (info_size > 40)
      for (info_size -= 40; info_size > 0; info_size --)
        getc(fp);
  
   /*
    * Get colormap...
    */
  
    if (colors_used == 0 && depth <= 8)
      colors_used = 1 << depth;
  
    if (colors_used > 0) {
      if (fread(colormap, colors_used, 4, fp) == 0 && ferror(fp))
        DEBUG_printf(("Error reading file!"));
    } else
      memset(colormap, 0, sizeof(colormap));
  
   /*
    * Setup image and buffers...
    */
  
    img->colorspace = (primary == CF_IMAGE_RGB_CMYK) ? CF_IMAGE_RGB : primary;
  
    cfImageSetMaxTiles(img, 0);
  
    bpp = cfImageGetDepth(img);
  
    if ((in = malloc(img->xsize * 3)) == NULL)
    {
      DEBUG_puts("DEBUG: Unable to allocate memory!\n");
      fclose(fp);
      return (1);
    }
  
    if ((out = malloc(img->xsize * bpp)) == NULL)
    {
      DEBUG_puts("DEBUG: Unable to allocate memory!\n");
      free(in);
      fclose(fp);
      return (1);
    }
  
   /*
    * Read the image data...
    */
  
    color = 0;
    count = 0;
    align = 0;
  
    for (y = img->ysize - 1; y >= 0; y --)
    {
      ptr = in;
  
      switch (depth)
      {
        case 1 : /* Bitmap */
            for (x = img->xsize, bit = 128, byte = 0; x > 0; x --)
  	  {
  	    if (bit == 128)
  	      byte = getc(fp);
  
  	    if (byte & bit)
  	    {
  	      *ptr++ = colormap[1][2];
  	      *ptr++ = colormap[1][1];
  	      *ptr++ = colormap[1][0];
  	    }
  	    else
  	    {
  	      *ptr++ = colormap[0][2];
  	      *ptr++ = colormap[0][1];
  	      *ptr++ = colormap[0][0];
  	    }
  
  	    if (bit > 1)
  	      bit >>= 1;
  	    else
  	      bit = 128;
  	  }
  
           /*
  	  * Read remaining bytes to align to 32 bits...
  	  */
  
  	  for (temp = (img->xsize + 7) / 8; temp & 3; temp ++)
  	    getc(fp);
            break;
  
        case 4 : /* 16-color */
            for (x = img->xsize, bit = 0xf0, temp = 0; x > 0; x --)
  	  {
  	   /*
  	    * Get a new count as needed...
  	    */
  
              if (compression != BI_RLE4 && count == 0)
  	    {
  	      count = 2;
  	      color = -1;
              }
  
  	    if (count == 0)
  	    {
  	      while (align > 0)
  	      {
  	        align --;
  		getc(fp);
                }
  
  	      if ((count = getc(fp)) == 0)
  	      {
  		if ((count = getc(fp)) == 0)
  		{
  		 /*
  		  * End of line...
  		  */
  
                    x ++;
  		  continue;
  		}
  		else if (count == 1)
  		{
  		 /*
  		  * End of image...
  		  */
  
  		  break;
  		}
  		else if (count == 2)
  		{
  		 /*
  		  * Delta...
  		  */
  
  		  count = getc(fp) * getc(fp) * img->xsize;
  		  color = 0;
  		}
  		else
  		{
  		 /*
  		  * Absolute...
  		  */
  
  		  color = -1;
  		  align = ((4 - (count & 3)) / 2) & 1;
  		}
  	      }
  	      else
  	        color = getc(fp);
              }
  
             /*
  	    * Get a new color as needed...
  	    */
  
  	    count --;
  
              if (bit == 0xf0)
  	    {
                if (color < 0)
  		temp = getc(fp);
  	      else
  		temp = color;
  
               /*
  	      * Copy the color value...
  	      */
  
  	      *ptr++ = colormap[temp >> 4][2];
  	      *ptr++ = colormap[temp >> 4][1];
  	      *ptr++ = colormap[temp >> 4][0];
  	      bit    = 0x0f;
              }
  	    else
  	    {
               /*
  	      * Copy the color value...
  	      */
  
  	      *ptr++ = colormap[temp & 15][2];
  	      *ptr++ = colormap[temp & 15][1];
  	      *ptr++ = colormap[temp & 15][0];
  	      bit    = 0xf0;
  	    }
  	  }
            break;
  
        case 8 : /* 256-color */
            for (x = img->xsize; x > 0; x --)
  	  {
  	   /*
  	    * Get a new count as needed...
  	    */
  
              if (compression != BI_RLE8)
  	    {
  	      count = 1;
  	      color = -1;
              }
  
  	    if (count == 0)
  	    {
  	      while (align > 0)
  	      {
  	        align --;
  		getc(fp);
                }
  
  	      if ((count = getc(fp)) == 0)
  	      {
  		if ((count = getc(fp)) == 0)
  		{
  		 /*
  		  * End of line...
  		  */
  
                    x ++;
  		  continue;
  		}
  		else if (count == 1)
  		{
  		 /*
  		  * End of image...
  		  */
  
  		  break;
  		}
  		else if (count == 2)
  		{
  		 /*
  		  * Delta...
  		  */
  
  		  count = getc(fp) * getc(fp) * img->xsize;
  		  color = 0;
  		}
  		else
  		{
  		 /*
  		  * Absolute...
  		  */
  
  		  color = -1;
  		  align = (2 - (count & 1)) & 1;
  		}
  	      }
  	      else
  	        color = getc(fp);
              }
  
             /*
  	    * Get a new color as needed...
  	    */
  
              if (color < 0)
  	      temp = getc(fp);
  	    else
  	      temp = color;
  
              count --;
  
             /*
  	    * Copy the color value...
  	    */
  
  	    *ptr++ = colormap[temp][2];
  	    *ptr++ = colormap[temp][1];
  	    *ptr++ = colormap[temp][0];
  	  }
            break;
  
        case 24 : /* 24-bit RGB */
            for (x = img->xsize; x > 0; x --, ptr += 3)
  	  {
  	    ptr[2] = getc(fp);
  	    ptr[1] = getc(fp);
  	    ptr[0] = getc(fp);
  	  }
  
           /*
  	  * Read remaining bytes to align to 32 bits...
  	  */
  
  	  for (temp = img->xsize * 3; temp & 3; temp ++)
  	    getc(fp);
            break;
      }
  
      if (saturation != 100 || hue != 0)
        cfImageRGBAdjust(in, img->xsize, saturation, hue);
  
      switch (img->colorspace)
      {
        default :
  	  break;
  
        case CF_IMAGE_WHITE :
  	  cfImageRGBToWhite(in, out, img->xsize);
  	  break;
  
        case CF_IMAGE_RGB :
  	  cfImageRGBToRGB(in, out, img->xsize);
  	  break;
  
        case CF_IMAGE_BLACK :
  	  cfImageRGBToBlack(in, out, img->xsize);
  	  break;
  
        case CF_IMAGE_CMY :
  	  cfImageRGBToCMY(in, out, img->xsize);
  	  break;
  
        case CF_IMAGE_CMYK :
  	  cfImageRGBToCMYK(in, out, img->xsize);
  	  break;
      }
  
      if (lut)
        cfImageLut(out, img->xsize * bpp, lut);
  
      _cfImagePutRow(img, 0, y, img->xsize, out);
    }
  
    fclose(fp);
    free(in);
    free(out);
  
    return (0);
  }
  
  
  /*
   * 'read_word()' - Read a 16-bit unsigned integer.
   */
  
  static unsigned short     /* O - 16-bit unsigned integer */
  read_word(FILE *fp)       /* I - File to read from */
  {
    unsigned char b0, b1; /* Bytes from file */
  
    b0 = getc(fp);
    b1 = getc(fp);
  
    return ((b1 << 8) | b0);
  }
  
  
  /*
   * 'read_dword()' - Read a 32-bit unsigned integer.
   */
  
  static unsigned int               /* O - 32-bit unsigned integer */
  read_dword(FILE *fp)              /* I - File to read from */
  {
    unsigned char b0, b1, b2, b3; /* Bytes from file */
  
    b0 = getc(fp);
    b1 = getc(fp);
    b2 = getc(fp);
    b3 = getc(fp);
  
    return ((((((b3 << 8) | b2) << 8) | b1) << 8) | b0);
  }
  
  
  /*
   * 'read_long()' - Read a 32-bit signed integer.
   */
  
  static int                        /* O - 32-bit signed integer */
  read_long(FILE *fp)               /* I - File to read from */
  {
    unsigned char b0, b1, b2, b3; /* Bytes from file */
  
    b0 = getc(fp);
    b1 = getc(fp);
    b2 = getc(fp);
    b3 = getc(fp);
  
    return ((int)(((((b3 << 8) | b2) << 8) | b1) << 8) | b0);
  }
  
  