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

xbm.c

/*
 * Danpei -- a GTK+ based Image Viewer
 * Copyright (C) 2001-2003 Shinji Moiino
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
/* These codes are mostly taken from:
 * X10 and X11 bitmap (XBM) loading and saving file filter for the GIMP.
 * XBM code Copyright (C) 1998 Gordon Matzigkeit
 */
/* These codes are mostly taken from:
 * gimageview-0.1.7 Copyright (C) 2001 Takuro Ashie
 */
/* xbm.c */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <gtk/gtk.h>

#include "config.h"
#include "xbm.h"

/* Constant definitions. */
#define XBM_BLACK (0x00)
#define XBM_WHITE (0xff)

/* Static function decralations. */
static gboolean xbm_get_header (const gchar*, xbm_info*);

static gint     xbm_getval     (gint        , gint     );

static gint     xbm_fgetc      (FILE*                  );

static gboolean xbm_match      (FILE*       , guchar*  );

static gboolean xbm_get_int    (FILE*       , gint*    );

/*
 * @xbm_load
 *
 *
 *
 */
guchar *xbm_load(const gchar *filename,
                 gint        *widthp  ,
                 gint        *heightp   ) {
  FILE   *fp;
  gint   width, height, intbits;
  gint   c, i, j, ptr;
  guchar *data;

  if (!filename || !widthp || !heightp)    { return NULL; }
  if ((fp = fopen(filename, "r")) == NULL) { return NULL; }

  /* Initialize the local variables. */
  intbits = height = width = 0;
  c = ' ';

  do {
    if (isspace(c)) {
      if(xbm_match(fp, "char")) {
        c = fgetc(fp);
        if (isspace(c)) {
          intbits = 8;
          continue;
        }
      } 
      else {
        if (xbm_match(fp, "short")) {
          c = fgetc(fp);
          if (isspace(c)) {
            intbits = 16;
            continue;
          }
        }
      }
    }

    if (c == '_') {
      if (xbm_match(fp, "width")) {
        c = fgetc(fp);
        if (isspace(c)) {
          if (!xbm_get_int(fp, &width)) { break; }
          continue;
        }
      } 
      else {
        if (xbm_match(fp, "height")) {
          c = fgetc(fp);
          if (isspace (c)) {
            if (!xbm_get_int(fp, &height)) { break; }
            continue;
          }
        }
      }
    }
    c = xbm_fgetc(fp);
  } while (c != '{' && c != EOF);
      
  if (c == EOF || width == 0 || height == 0 || intbits == 0) {
    return NULL;
  }

  *widthp  = width;
  *heightp = height;
  data = g_new0 (guchar, width * height * 3);
  ptr = 0;

  for (i = 0; i < height; i++) {
    for (j = 0; j < width; j++) {
      if (j % intbits == 0) {
        if (!xbm_get_int(fp, &c)) {
          g_free(data);
          fclose(fp);
          return NULL;
        }
      }
      data[ptr++] = (c & 1) ? XBM_BLACK : XBM_WHITE;
      data[ptr++] = (c & 1) ? XBM_BLACK : XBM_WHITE;
      data[ptr++] = (c & 1) ? XBM_BLACK : XBM_WHITE;
      c >>= 1;
    }
  }
      
  fclose(fp);

  return data;
}

/* Static function definitions. */
/*
 * @xbm_get_header
 *
 *
 *
 */
static gboolean xbm_get_header(const gchar *filename,
                               xbm_info    *info      ) {
  FILE *fp;
  gint width, height, intbits;
  gint c;
      
  if ((fp = fopen(filename, "r")) == NULL) { return FALSE; }

  intbits = height = width = 0;
  c = ' ';
  do {
    if (isspace(c)) {
      if(xbm_match(fp, "char")) {
        c = fgetc(fp);
        if (isspace(c)) {
          intbits = 8;
          continue;
        }
      } 
      else {
        if (xbm_match(fp, "short")) {
          c = fgetc(fp);
          if (isspace(c)) {
            intbits = 16;
            continue;
          }
        }
      }
    }

    if (c == '_') {
      if (xbm_match(fp, "width")) {
        c = fgetc(fp);
        if (isspace(c)) {
          if (!xbm_get_int(fp, &width)) { break; }
          continue;
        }
      }
      else {
        if (xbm_match(fp, "height")) {
          c = fgetc(fp);
          if (isspace (c)) {
            if (!xbm_get_int(fp, &height)) { break; }
            continue;
          }
        }
      }
    }
    c = xbm_fgetc (fp);
  } while (c != '{' && c != EOF);
      
  fclose(fp);
      
  if (c == EOF || width == 0 || height == 0 || intbits == 0) {
    return FALSE;
  }

  info->width = width;
  info->height = height;

  return TRUE;
}

/*
 * @xbm_getval
 *
 *
 *
 */
static gint xbm_getval(gint c   , 
                       gint base  ) {
  static guchar *digits = "0123456789abcdefABCDEF";
  gint val;

  if (base == 16) { base = 22; }

  for (val = 0; val < base; val ++) {
    if (c == digits[val]) {
      return (val < 16) ? val : (val - 6);
    }
  }

  return -1;
}

/*
 * @xbm_fgetc
 *
 *  Same as fgetc, but skip C-style comments and insert whitespace. 
 *
 */
static gint xbm_fgetc(FILE *fp) {
  gint comment, c;

  comment = 0;
  do {
    c = fgetc (fp);
    if (comment) {
      if (c == '*') {
        comment = 1;
      }
      else {
        if (comment == 1 && c == '/') {
          comment = 0;
        }
        else {
          comment = 2;
        }
      }
    } 
    else {
      if (c == '/') {
        c = fgetc (fp);
        if (c == '*') {
          comment = 2;
        } 
        else {
          ungetc (c, fp);
          c = '/';
        }
      }
    }
  } while (comment && c != EOF);
      
  return c;
}

/*
 * @xbm_match
 *
 *  Match a string with a file.
 *
 */
static gboolean xbm_match(FILE   *fp,
                          guchar *s   ) {
  gint c;

  do {
    c = fgetc (fp);
    if (c == *s) {
      s++;
    }
    else {
      break;
    }
  } while (c != EOF && *s);

  if (!*s) return TRUE;

  if (c != EOF) { ungetc (c, fp); }

  return FALSE;
}

/*
 * @xbm_get_init
 *
 *  Read the next integer from the file, skipping all non-integers.
 *
 */
static gboolean xbm_get_int(FILE *fp ,
                            gint *val  ) {
  gint digval, base, c;

  do {
    c = xbm_fgetc(fp);
  } while (c != EOF && !isdigit (c));

  if (c == EOF) return FALSE;

  if (c == '0') {
    c = fgetc (fp);
    if (c == 'x' || c == 'X') {
      c = fgetc (fp);
      base = 16;
    }
    else {
      if (isdigit (c)) {
        base = 8;
      } 
      else {
        ungetc (c, fp);
        return FALSE;
      }
    }
  }
  else {
    base = 10;
  }

  *val = 0;
  for (;;) {
    digval = xbm_getval(c, base);
    if (digval < 0) {
      ungetc (c, fp);
      break;
    }
    *val *= base;
    *val += digval;
    c = fgetc (fp);
  }

  return TRUE;
}


Generated by  Doxygen 1.6.0   Back to index