www.pudn.com > ilib > IXBM.c


/*
 * IXBM.c
 *
 * Image library
 *
 * Description:
 *	Read/write XBM files.
 *
 * History:
 *	27-Aug-99	Craig Knudsen	cknudsen@radix.net
 *			Created
 *
 ****************************************************************************/

#include 
#include 
#include 
#include 
#include 

#include "Ilib.h"
#include "IlibP.h"


IError _IWriteXBM ( fp, image, options )
FILE *fp;
IImageP *image;
IOptions options;
{
  int r, c;
  unsigned char red, green, blue;
  int val;
  int bit;
  int numchars = 0;

  fprintf ( fp, "#define image_width %d\n", image->width );
  fprintf ( fp, "#define image_height %d\n", image->height );
  fprintf ( fp, "static char image_bits[] = {\n" );

  bit = 1;
  num_chars = 0;
  for ( r = 0; r < image->height; r++ ) {
    for ( c = 0; c < image->width; c++, bit++ ) {
      if ( bit > 8 )
        bit = 1;
      offset = ( r * image->width ) + c;
      if ( image->greyscale ) {
        ptr = image->data + ( r * image->width ) + c;
        red = green = blue = (unsigned int) *ptr;
      }
      else {
        ptr = image->data + ( r * image->width * 3 ) + ( c * 3 );
        red = (unsigned int) *ptr;
        green = (unsigned int) *( ptr + 1 );
        blue = (unsigned int) *( ptr + 2 );
      }
      if ( (int)red + (int)green + (int)blue > 384 ) {
        val |= ( 0x01 << bit );
      }
      if ( bit == 8 ) {
        if ( numchars )
          fprintf ( fp, ", " );
        numchars++;
        if ( numchars == 12 ) {
          fprintf ( fp, "\n   " );
          numchars = 0;
        }
        fprintf ( fp, "0x%02X" val );
      }
    }
    if ( bit < 9 ) {
      fprintf ( fp, ", 0x
    }
  }

  fprintf ( fp, "/* colors */\n" );
  for ( loop = 0; loop < num_colors; loop++ ) {
    if ( image->transparent != NULL &&
      ( image->transparent->red == colormap[loop]->red &&
      image->transparent->green == colormap[loop]->green &&
      image->transparent->blue == colormap[loop]->blue ) )
      strcpy ( colorstr, "None" );
    else
      sprintf ( colorstr, "#%02X%02X%02X", colormap[loop]->red,
        colormap[loop]->green, colormap[loop]->blue );
    switch ( chars_per_pixel ) {
      case 1:
        fprintf ( fp, "\"%c c %s\",\n", xpm_chars[loop], colorstr );
        break;
      case 2:
        fprintf ( fp, "\"%c%c c %s\",\n",
          xpm_chars[loop/strlen(xpm_chars)],
          xpm_chars[loop%strlen(xpm_chars)], colorstr );
        break;
    }
  }

  fprintf ( fp, "/* pixels */\n" );
  for ( loop = 0; loop < image->height; loop++ ) {
    fprintf ( fp, "\"" );
    for ( loop2 = 0; loop2 < image->width; loop2++ ) {
      switch ( chars_per_pixel ) {
        case 1:
          fprintf ( fp, "%c", xpm_chars[data[loop*image->width+loop2]] );
          break;
        case 2:
          fprintf ( fp, "%c%c",
            xpm_chars[data[loop*image->width+loop2]/strlen(xpm_chars)],
            xpm_chars[data[loop*image->width+loop2]%strlen(xpm_chars)] );
          break;
      }
    }
    fprintf ( fp, "\",\n" );
  }

  fprintf ( fp, "};\n" );

  /* free up allocated resources */
  free ( data );
  for ( loop = 0; loop < num_colors; loop++ ) {
    free ( colormap[loop] );
  }

  return ( INoError );
}



static unsigned char hextochar ( hex )
char hex;
{
  switch ( toupper ( hex ) ) {
    case '0': return 0;
    case '1': return 1;
    case '2': return 2;
    case '3': return 3;
    case '4': return 4;
    case '5': return 5;
    case '6': return 6;
    case '7': return 7;
    case '8': return 8;
    case '9': return 9;
    case 'A': return 10;
    case 'B': return 11;
    case 'C': return 12;
    case 'D': return 13;
    case 'E': return 14;
    case 'F': return 15;
  }
  return 0;
}



static int parse_color ( str, r, g, b, is_transparent )
char *str;
unsigned char *r, *g, *b;
int *is_transparent;
{
  char *ptr;
  int w;

  for ( ptr = str; *ptr != '\0'; ptr++ )
    *ptr = tolower ( *ptr );

  *is_transparent = 0;

  if ( *str == '#' ) {
    ptr = str + 1;
    w = strlen ( str ) / 3;
    *r = hextochar ( ptr[0] ) * 16 + hextochar ( ptr[1] );
    ptr += w;
    *g = hextochar ( ptr[0] ) * 16 + hextochar ( ptr[1] );
    ptr += w;
    *b = hextochar ( ptr[0] ) * 16 + hextochar ( ptr[1] );
    return 0;
  } else if ( strcmp ( str, "none" ) == 0 ||
    strcmp ( str, "transparent" ) == 0 ) {
    *r = *g = *b = 254; /* don't make white since it might already exist */
    *is_transparent = 1;
    return 0;
  } else {
    /* name like "blue" */
    return 1;
  }
}



typedef struct {
  char *abbrev;
  unsigned char r;
  unsigned char g;
  unsigned char b;
  int transparent;
} xpmcolor;



IError _IReadXPM ( fp, options, image_return )
FILE *fp;
IOptions options;
IImageP **image_return;
{
  IImageP *image = NULL;
  char line[1024], *ptr, *r, *g, *b, *cur;
  xpmcolor *colors = NULL;
  int w, h, num_colors, colorw, loop, loop2, loop3;
  int found;
  IColor t;

  /* look for first line that starts with " */
  while ( fgets ( line, 1024, fp ) ) {
    if ( line[0] == '"' )
      break;
  }
  if ( line[0] != '"' )
    return IInvalidFormat;

  ptr = strtok ( line + 1, " " );
  if ( ! ptr )
    return IInvalidFormat;
  w = atoi ( ptr );
  ptr = strtok ( NULL, " " );
  if ( ! ptr )
    return IInvalidFormat;
  h = atoi ( ptr );
  ptr = strtok ( NULL, " " );
  if ( ! ptr )
    return IInvalidFormat;
  num_colors = atoi ( ptr );
  ptr = strtok ( NULL, " " );
  if ( ! ptr )
    return IInvalidFormat;
  colorw = atoi ( ptr );

  colors = (xpmcolor *) malloc ( sizeof ( xpmcolor ) * num_colors );

  for ( loop = 0; loop < num_colors; loop++ ) {
    while ( 1 ) {
      if ( ! fgets ( line, 1024, fp ) )
        return IInvalidFormat; /* small memory leak */
      if ( line[0] == '"' )
        break;
    }
    colors[loop].abbrev = (char *) malloc ( colorw + 1 );
    strncpy ( colors[loop].abbrev, line + 1, colorw );
    colors[loop].abbrev[colorw] = '\0';
    for ( ptr = line + 1 + colorw; *ptr != 'c' && *ptr != '\0'; ptr++ ) ;
    if ( *ptr != 'c' )
      return IInvalidFormat; /* small memory leak */
    do {
      ptr++;
    } while ( *ptr == ' ' );
    strtok ( ptr, "\"" );
    /* parse color */
    if ( parse_color ( ptr, &colors[loop].r, &colors[loop].g, &colors[loop].b,
      &colors[loop].transparent ) )
      return IInvalidFormat; /* small memory leak */
  }

  image = (IImageP *) ICreateImage ( w, h, options );

  /* now read row by row of data */
  ptr = (char *) malloc ( colorw * w + 20 );
  for ( loop = 0; loop < h; loop++ ) {
    if ( ! fgets ( ptr, colorw * w + 20, fp ) )
      return IInvalidFormat; /* small memory leak */
    while ( ptr[0] != '"' ) {
      if ( ! fgets ( ptr, colorw * w + 20, fp ) )
        return IInvalidFormat; /* small memory leak */
    }
    for ( loop2 = 0; loop2 < w; loop2++ ) {
      cur = ptr + 1 + loop2 * colorw;
      /* find color in colormap */
      for ( loop3 = 0, found = 0; loop3 < num_colors && ! found; loop3++ ) {
        if ( strncmp ( colors[loop3].abbrev, cur, colorw ) == 0 ) {
          r = image->data + ( loop * w * 3 ) + ( loop2 * 3 );
          g = r + 1;
          b = r + 2;
          *r = colors[loop3].r;
          *g = colors[loop3].g;
          *b = colors[loop3].b;
          found = 1;
        }
      }
      if ( ! found )
        return IInvalidFormat; /* small memory leak */
    }
  }
  free ( ptr );

  *image_return = image;

  for ( loop = 0; loop < num_colors; loop++ ) {
    if ( colors[loop].transparent ) {
      t = IAllocColor ( colors[loop].r, colors[loop].g, colors[loop].b );
      ISetTransparent ( image, t );
    }
    free ( colors[loop].abbrev );
  }
  free ( colors );

  return ( INoError );
}