Blame converter/ppm/xpmtoppm.c

Packit 78deda
/* xpmtoppm.c - convert XPM file (X11 pixmap) to PPM
Packit 78deda
Packit 78deda
   Copyright and history information is at end of file
Packit 78deda
*/
Packit 78deda
Packit 78deda
#define _DEFAULT_SOURCE /* New name for SVID & BSD source defines */
Packit 78deda
#define _BSD_SOURCE   /* Make sure strdup() is in string.h */
Packit 78deda
#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
Packit 78deda
Packit 78deda
#include <assert.h>
Packit 78deda
#include <string.h>
Packit 78deda
Packit 78deda
#include "pm_c_util.h"
Packit 78deda
#include "mallocvar.h"
Packit 78deda
#include "shhopt.h"
Packit 78deda
#include "nstring.h"
Packit 78deda
#include "ppm.h"
Packit 78deda
Packit 78deda
#define MAX_LINE (8 * 1024)
Packit 78deda
  /* The maximum size XPM input line we can handle. */
Packit 78deda
Packit 78deda
/* number of xpmColorKeys */
Packit 78deda
#define NKEYS 5
Packit 78deda
Packit 78deda
const char *xpmColorKeys[] =
Packit 78deda
{
Packit 78deda
 "s",                   /* key #1: symbol */
Packit 78deda
 "m",                   /* key #2: mono visual */
Packit 78deda
 "g4",                  /* key #3: 4 grays visual */
Packit 78deda
 "g",                   /* key #4: gray visual */
Packit 78deda
 "c",                   /* key #5: color visual */
Packit 78deda
};
Packit 78deda
Packit 78deda
struct cmdlineInfo {
Packit 78deda
    /* All the information the user supplied in the command line,
Packit 78deda
       in a form easy for the program to use.
Packit 78deda
    */
Packit 78deda
    const char * input_filespec;  /* Filespecs of input files */
Packit 78deda
    const char * alpha_filename;
Packit 78deda
    int alpha_stdout;
Packit 78deda
    int verbose;
Packit 78deda
};
Packit 78deda
Packit 78deda
Packit 78deda
static bool verbose;
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
parseCommandLine(int argc, char ** argv,
Packit 78deda
                 struct cmdlineInfo *cmdlineP) {
Packit 78deda
/*----------------------------------------------------------------------------
Packit 78deda
   Note that the file spec array we return is stored in the storage that
Packit 78deda
   was passed to us as the argv array.
Packit 78deda
-----------------------------------------------------------------------------*/
Packit 78deda
    optEntry * option_def;
Packit 78deda
        /* Instructions to OptParseOptions2 on how to parse our options.
Packit 78deda
         */
Packit 78deda
    optStruct3 opt;
Packit 78deda
Packit 78deda
    unsigned int option_def_index;
Packit 78deda
Packit 78deda
    MALLOCARRAY_NOFAIL(option_def, 100);
Packit 78deda
Packit 78deda
    option_def_index = 0;   /* incremented by OPTENT3 */
Packit 78deda
    OPTENT3(0,   "alphaout",   OPT_STRING, &cmdlineP->alpha_filename,
Packit 78deda
            NULL, 0);
Packit 78deda
    OPTENT3(0,   "verbose",    OPT_FLAG,   &cmdlineP->verbose,
Packit 78deda
            NULL, 0);
Packit 78deda
Packit 78deda
    cmdlineP->alpha_filename = NULL;
Packit 78deda
    cmdlineP->verbose = FALSE;
Packit 78deda
Packit 78deda
    opt.opt_table = option_def;
Packit 78deda
    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
Packit 78deda
    opt.allowNegNum = TRUE;  /* We may have parms that are negative numbers */
Packit 78deda
Packit 78deda
    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
Packit 78deda
        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
Packit 78deda
Packit 78deda
    if (argc - 1 == 0)
Packit 78deda
        cmdlineP->input_filespec = NULL;  /* he wants stdin */
Packit 78deda
    else if (argc - 1 == 1)
Packit 78deda
        cmdlineP->input_filespec = strdup(argv[1]);
Packit 78deda
    else 
Packit 78deda
        pm_error("Too many arguments.  The only argument accepted\n"
Packit 78deda
                 "is the input file specification");
Packit 78deda
Packit 78deda
    if (cmdlineP->alpha_filename && 
Packit 78deda
        streq(cmdlineP->alpha_filename, "-"))
Packit 78deda
        cmdlineP->alpha_stdout = TRUE;
Packit 78deda
    else 
Packit 78deda
        cmdlineP->alpha_stdout = FALSE;
Packit 78deda
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
struct ColorNameHashTableEntry {
Packit 78deda
/*----------------------------------------------------------------------------
Packit 78deda
   An entry in the color name hash table.  It maps a color name to a
Packit 78deda
   color, or is empty.
Packit 78deda
-----------------------------------------------------------------------------*/
Packit 78deda
    bool empty;
Packit 78deda
    char colorName[3];
Packit 78deda
        /* Actual length 0-3.  NOT NUL-terminated */
Packit 78deda
    pixel color;
Packit 78deda
};
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
typedef struct {
Packit 78deda
/*----------------------------------------------------------------------------
Packit 78deda
   This is a color map which is primarily a hash table that maps an XPM
Packit 78deda
   color name to a color.  An XPM color name is a 0-3 character name that
Packit 78deda
   appears in the raster of an XPM image to uniquely identify a color.
Packit 78deda
   The header of the XPM contains a listing of all the color names that
Packit 78deda
   appear in the raster, identifying a color for each.
Packit 78deda
Packit 78deda
   We represent a color as a 'pixel'.
Packit 78deda
-----------------------------------------------------------------------------*/
Packit 78deda
    unsigned int nameSize;
Packit 78deda
        /* Size of color names in this hash.  0-3 */
Packit 78deda
    struct ColorNameHashTableEntry * transparentP;
Packit 78deda
        /* The element of 'table' that is for the transparent color.
Packit 78deda
           NULL if there is none.
Packit 78deda
        */
Packit 78deda
Packit 78deda
    /* This is an internally chained hash table, i.e. there are no linked
Packit 78deda
       lists.  You use the hash function to get an index into the hash table.
Packit 78deda
       If the entry indexed by that is not for the color name you're looking
Packit 78deda
       for, you look at the next entry down, and keep going down until you
Packit 78deda
       either find the color name you're looking for or hit an empty entry.
Packit 78deda
Packit 78deda
       So that we never run out of space for new color names, we make the
Packit 78deda
       creator of the hash table tell us the maximum number of colors there
Packit 78deda
       will be.  We allocate twice that size in order to reduce average hash
Packit 78deda
       chain length.
Packit 78deda
    */
Packit 78deda
    unsigned int size;
Packit 78deda
    struct ColorNameHashTableEntry * table;
Packit 78deda
} ColorNameHash;
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static ColorNameHash *
Packit 78deda
hash_create(unsigned int const nColors,
Packit 78deda
            unsigned int const nameSize) {
Packit 78deda
Packit 78deda
    ColorNameHash * hashP;
Packit 78deda
Packit 78deda
    MALLOCVAR_NOFAIL(hashP);
Packit 78deda
Packit 78deda
    hashP->nameSize = nameSize;
Packit 78deda
Packit 78deda
    hashP->size = nColors * 2;
Packit 78deda
Packit 78deda
    MALLOCARRAY(hashP->table, hashP->size);
Packit 78deda
Packit 78deda
    if (!hashP->table)
Packit 78deda
        pm_error("Failed to allocate memory for a %u-entry "
Packit 78deda
                 "color name hash table.", hashP->size);
Packit 78deda
Packit 78deda
    {
Packit 78deda
        unsigned int i;
Packit 78deda
        for (i = 0; i < hashP->size; ++i)
Packit 78deda
            hashP->table[i].empty = true;
Packit 78deda
    }
Packit 78deda
Packit 78deda
    hashP->transparentP = NULL;
Packit 78deda
Packit 78deda
    return hashP;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
hash_destroy(ColorNameHash * const hashP) {
Packit 78deda
Packit 78deda
    free(hashP->table);
Packit 78deda
Packit 78deda
    free(hashP);
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static unsigned int
Packit 78deda
hashColorName(const char * const name,
Packit 78deda
              unsigned int const size,
Packit 78deda
              unsigned int const hashTableSize) {
Packit 78deda
/*----------------------------------------------------------------------------
Packit 78deda
   Return the hash value (initial index into the color name hash table)
Packit 78deda
   for the color name 'name', which is 'size' characters long.  The hash
Packit 78deda
   is to be in the range [0, hashTableSize).
Packit 78deda
-----------------------------------------------------------------------------*/
Packit 78deda
    /* I have no idea if this is an appropriate hash function.  I borrowed
Packit 78deda
       it from pnm_hashTuple()
Packit 78deda
    */
Packit 78deda
Packit 78deda
    unsigned int const hash_factor[] = {1, 33, 33*33};
Packit 78deda
Packit 78deda
    unsigned int i;
Packit 78deda
    unsigned int hash;
Packit 78deda
Packit 78deda
    hash = 0;  /* initial value */
Packit 78deda
    for (i = 0; i < size; ++i) {
Packit 78deda
        hash += name[i] * hash_factor[i];
Packit 78deda
    }
Packit 78deda
    hash %= hashTableSize;
Packit 78deda
    return hash;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static bool
Packit 78deda
entryMatch(struct ColorNameHashTableEntry const entry,
Packit 78deda
           const char *                   const name,
Packit 78deda
           unsigned int                   const size) {
Packit 78deda
Packit 78deda
    if (entry.empty)
Packit 78deda
        return true;
Packit 78deda
Packit 78deda
    assert(size <= ARRAY_SIZE(entry.colorName));
Packit 78deda
Packit 78deda
    {
Packit 78deda
        unsigned int i;
Packit 78deda
        
Packit 78deda
        for (i = 0; i < size; ++i) {
Packit 78deda
            if (name[i] != entry.colorName[i])
Packit 78deda
                return false;
Packit 78deda
        }
Packit 78deda
    }
Packit 78deda
Packit 78deda
    return true;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
bumpIndex(unsigned int * const indexP,
Packit 78deda
          unsigned int   const tableSize,
Packit 78deda
          unsigned int   const limit) {
Packit 78deda
/*----------------------------------------------------------------------------
Packit 78deda
   Bump *indexP to the next entry in a table of size 'tableSize', in a
Packit 78deda
   circular fashion.  But abort the program if this would take us to
Packit 78deda
   'limit'.
Packit 78deda
-----------------------------------------------------------------------------*/
Packit 78deda
    *indexP += 1;
Packit 78deda
    if (*indexP >= tableSize)
Packit 78deda
        *indexP = 0;
Packit 78deda
Packit 78deda
    if (*indexP == limit)
Packit 78deda
        pm_error("INTERNAL ERROR: color name hash table is full");
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
hash_find(const ColorNameHash *             const hashP,
Packit 78deda
          const char *                      const name,
Packit 78deda
          struct ColorNameHashTableEntry ** const entryPP) {
Packit 78deda
/*----------------------------------------------------------------------------
Packit 78deda
   Find the entry in the color hash table *hashP for the color
Packit 78deda
   named 'name' in the lexicon of this XPM file.  If the color is in the
Packit 78deda
   table, this is where it is.  If it isn't, this is where it should go.
Packit 78deda
-----------------------------------------------------------------------------*/
Packit 78deda
    unsigned int const initialIndex  =
Packit 78deda
        hashColorName(name, hashP->nameSize, hashP->size);
Packit 78deda
Packit 78deda
    unsigned int i;
Packit 78deda
Packit 78deda
    for (i = initialIndex;
Packit 78deda
         !entryMatch(hashP->table[i], name, hashP->nameSize);
Packit 78deda
         bumpIndex(&i, hashP->size, initialIndex));
Packit 78deda
         
Packit 78deda
    *entryPP = &hashP->table[i];
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
hash_add(ColorNameHash * const hashP,
Packit 78deda
         const char *    const name,
Packit 78deda
         pixel           const color,
Packit 78deda
         bool            const isTransparent) {
Packit 78deda
Packit 78deda
    struct ColorNameHashTableEntry * entryP;
Packit 78deda
Packit 78deda
    hash_find(hashP, name, &entryP);
Packit 78deda
Packit 78deda
    if (!entryP->empty)
Packit 78deda
        pm_error("Color name appears multiple times in color map");
Packit 78deda
Packit 78deda
    entryP->empty = false;
Packit 78deda
    {
Packit 78deda
        unsigned int i;
Packit 78deda
        for (i = 0; i < hashP->nameSize; ++i)
Packit 78deda
            entryP->colorName[i] = name[i];
Packit 78deda
    }
Packit 78deda
    entryP->color = color;
Packit 78deda
Packit 78deda
    if (isTransparent) {
Packit 78deda
        if (hashP->transparentP)
Packit 78deda
            pm_error("There are multiple NONE (transparent) entries in "
Packit 78deda
                     "the XPM color map");
Packit 78deda
        else
Packit 78deda
            hashP->transparentP = entryP;
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static pixel
Packit 78deda
hash_color(const ColorNameHash * const hashP,
Packit 78deda
           const char *          const name) {
Packit 78deda
Packit 78deda
    struct ColorNameHashTableEntry * entryP;
Packit 78deda
Packit 78deda
    hash_find(hashP, name, &entryP);
Packit 78deda
Packit 78deda
    if (entryP->empty)
Packit 78deda
        pm_error("Color name in raster is not in color map");
Packit 78deda
Packit 78deda
    return entryP->color;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static bool
Packit 78deda
hash_isTransparent(const ColorNameHash * const hashP,
Packit 78deda
                   const char *          const name) {
Packit 78deda
Packit 78deda
    struct ColorNameHashTableEntry * entryP;
Packit 78deda
Packit 78deda
    hash_find(hashP, name, &entryP);
Packit 78deda
Packit 78deda
    return (entryP == hashP->transparentP);
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static char lastInputLine[MAX_LINE+1];
Packit 78deda
    /* contents of line most recently read from input */
Packit 78deda
static bool backup;
Packit 78deda
    /* TRUE means next read should be a reread of the most recently read
Packit 78deda
       line, i.e. lastInputLine, instead of a read from the input file.
Packit 78deda
    */
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
getLine(char * const line,
Packit 78deda
        size_t const size,
Packit 78deda
        FILE * const stream) {
Packit 78deda
/*----------------------------------------------------------------------------
Packit 78deda
   Read the next line from the input file 'stream', through the one-line
Packit 78deda
   buffer lastInputLine[].
Packit 78deda
Packit 78deda
   If 'backup' is true, the "next line" is the previously read line, i.e.
Packit 78deda
   the one in that one-line buffer.  Otherwise, the "next line" is the next
Packit 78deda
   line from the real file.  After reading the backed up line, we reset 
Packit 78deda
   'backup' to false.
Packit 78deda
Packit 78deda
   Return the line as a null terminated string in *line, which is an
Packit 78deda
   array of 'size' bytes.
Packit 78deda
Packit 78deda
   Exit program if the line doesn't fit in the buffer.
Packit 78deda
-----------------------------------------------------------------------------*/
Packit 78deda
    if (size > sizeof(lastInputLine))
Packit 78deda
        pm_error("INTERNAL ERROR: getLine() received 'size' parameter "
Packit 78deda
                 "which is out of bounds");
Packit 78deda
Packit 78deda
    if (backup) {
Packit 78deda
        strncpy(line, lastInputLine, size); 
Packit 78deda
        backup = FALSE;
Packit 78deda
    } else {
Packit 78deda
        if (fgets(line, size, stream) == NULL)
Packit 78deda
            pm_error("EOF or read error on input file");
Packit 78deda
        if (strlen(line) == size - 1)
Packit 78deda
            pm_error("Input file has line that is too long (longer than "
Packit 78deda
                     "%u bytes).", (unsigned)size - 1);
Packit 78deda
        STRSCPY(lastInputLine, line);
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
getword(char * const output, char ** const cursorP) {
Packit 78deda
Packit 78deda
    char *t1;
Packit 78deda
    char *t2;
Packit 78deda
Packit 78deda
    for (t1=*cursorP; ISSPACE(*t1); t1++); /* skip white space */
Packit 78deda
    for (t2 = t1; !ISSPACE(*t2) && *t2 != '"' && *t2 != '\0'; t2++);
Packit 78deda
        /* Move to next white space, ", or eol */
Packit 78deda
    if (t2 > t1)
Packit 78deda
        strncpy(output, t1, t2 - t1);
Packit 78deda
    output[t2 - t1] = '\0';
Packit 78deda
    *cursorP = t2;
Packit 78deda
}    
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
addToColorMap(ColorNameHash * const hashP,
Packit 78deda
              const char *    const colorName,
Packit 78deda
              char            const colorspec[],
Packit 78deda
              bool            const isTransparent) {
Packit 78deda
/*----------------------------------------------------------------------------
Packit 78deda
   Add the color named by colorspec[] to the colormap represented by *hashP,
Packit 78deda
   as the color associated with XPM color name 'colorNumber'.
Packit 78deda
Packit 78deda
   Note that *hashP determines how long 'colorName' is.
Packit 78deda
-----------------------------------------------------------------------------*/
Packit 78deda
    hash_add(hashP, colorName, ppm_parsecolor(colorspec, PPM_MAXMAXVAL),
Packit 78deda
             isTransparent);
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
validateColorName(const char * const name,
Packit 78deda
                  unsigned int const charsPerPixel) {
Packit 78deda
Packit 78deda
    unsigned int i;
Packit 78deda
Packit 78deda
    for (i = 0; i < charsPerPixel; ++i) {
Packit 78deda
        if (name[i] == '"')
Packit 78deda
            pm_error("A color map entry ends in the middle of the colormap "
Packit 78deda
                     "index");
Packit 78deda
        else if (name[i] == '\0')
Packit 78deda
            pm_error("The XPM file ends in the middle of a color map entry");
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
interpretXpm3ColorTableLine(char               const line[],
Packit 78deda
                            unsigned int       const seqNum, 
Packit 78deda
                            unsigned int       const charsPerPixel,
Packit 78deda
                            ColorNameHash *    const hashP) {
Packit 78deda
/*----------------------------------------------------------------------------
Packit 78deda
   Interpret one line of the color table in the XPM header.  'line' is the
Packit 78deda
   line from the XPM file.  It is the seqNum'th color table entry in the file.
Packit 78deda
   The raster in the file uses 'charsPerPixel' characters per pixel (i.e.
Packit 78deda
   a an XPM color name is 'charsPerPixel' characters).
Packit 78deda
Packit 78deda
   Add the information from this color table entry to the color name hash
Packit 78deda
   *hashP.
Packit 78deda
Packit 78deda
   The line may include values for multiple kinds of color (grayscale,
Packit 78deda
   color, etc.).  We take the highest of these (e.g. color over grayscale).
Packit 78deda
Packit 78deda
   If a color table entry indicates transparency, set *transparentP
Packit 78deda
   to indicate the XPM color name.
Packit 78deda
-----------------------------------------------------------------------------*/
Packit 78deda
    /* Note: this code seems to allow for multi-word color specifications,
Packit 78deda
       but I'm not aware that such are legal.  Ultimately, ppm_parsecolor()
Packit 78deda
       interprets the name, and I believe it takes only single word 
Packit 78deda
       color specifications.  -Bryan 2001.05.06.
Packit 78deda
    */
Packit 78deda
    char str2[MAX_LINE+1];    
Packit 78deda
    char * t1;
Packit 78deda
    char * t2;
Packit 78deda
    int endOfEntry;   /* boolean */
Packit 78deda
    
Packit 78deda
    unsigned int curkey, key, highkey;  /* current color key */
Packit 78deda
    bool lastwaskey;    
Packit 78deda
        /* The last token we processes was a key, and we have processed
Packit 78deda
           at least one token.
Packit 78deda
        */
Packit 78deda
    char curbuf[BUFSIZ];        /* current buffer */
Packit 78deda
    bool isTransparent;
Packit 78deda
    
Packit 78deda
    const char * colorName;
Packit 78deda
        /* The 0-3 character name this color map line gives the color
Packit 78deda
           (i.e. the name that the raster uses).  This is NOT NUL-terminated.
Packit 78deda
           It's length is bytesPerPixel.
Packit 78deda
        */
Packit 78deda
Packit 78deda
    /* read the chars */
Packit 78deda
    t1 = strchr(line, '"');
Packit 78deda
    if (t1 == NULL)
Packit 78deda
        pm_error("A line that is supposed to be an entry in the color "
Packit 78deda
                 "table does not start with a quote.  The line is '%s'.  "
Packit 78deda
                 "It is the %uth entry in the color table.", 
Packit 78deda
                 line, seqNum);
Packit 78deda
    else
Packit 78deda
        ++t1;  /* Points now to first color number character */
Packit 78deda
    
Packit 78deda
    validateColorName(t1, charsPerPixel);
Packit 78deda
    colorName = t1;
Packit 78deda
Packit 78deda
    t1 += charsPerPixel;
Packit 78deda
Packit 78deda
    /*
Packit 78deda
     * read color keys and values 
Packit 78deda
     */
Packit 78deda
    curkey = 0; 
Packit 78deda
    highkey = 1;
Packit 78deda
    lastwaskey = FALSE;
Packit 78deda
    t2 = t1;
Packit 78deda
    endOfEntry = FALSE;
Packit 78deda
    while ( !endOfEntry ) {
Packit 78deda
        int isKey;   /* boolean */
Packit 78deda
        getword(str2, &t2;;
Packit 78deda
        if (strlen(str2) == 0)
Packit 78deda
            endOfEntry = TRUE;
Packit 78deda
        else {
Packit 78deda
            /* See if the word we got is a valid key (and get its key
Packit 78deda
               number if so)
Packit 78deda
            */
Packit 78deda
            for (key = 1; 
Packit 78deda
                 key <= NKEYS && !streq(xpmColorKeys[key - 1], str2); 
Packit 78deda
                 key++);
Packit 78deda
            isKey = (key <= NKEYS);
Packit 78deda
Packit 78deda
            if (lastwaskey || !isKey) {
Packit 78deda
                /* This word is a color specification (or "none" for
Packit 78deda
                   transparent).
Packit 78deda
                */
Packit 78deda
                if (!curkey) 
Packit 78deda
                    pm_error("Missing color key token in color table line "
Packit 78deda
                             "'%s' before '%s'.", line, str2);
Packit 78deda
                if (!lastwaskey) 
Packit 78deda
                    strcat(curbuf, " ");        /* append space */
Packit 78deda
                if ( (strneq(str2, "None", 4)) 
Packit 78deda
                     || (strneq(str2, "none", 4)) ) {
Packit 78deda
                    /* This entry identifies the transparent color number */
Packit 78deda
                    strcat(curbuf, "#000000");  /* Make it black */
Packit 78deda
                    isTransparent = TRUE;
Packit 78deda
                } else 
Packit 78deda
                    strcat(curbuf, str2);       /* append buf */
Packit 78deda
                lastwaskey = FALSE;
Packit 78deda
            } else { 
Packit 78deda
                /* This word is a key.  So we've seen the last of the 
Packit 78deda
                   info for the previous key, and we must either put it
Packit 78deda
                   in the color map or ignore it if we already have a higher
Packit 78deda
                   color form in the colormap for this colormap entry.
Packit 78deda
                */
Packit 78deda
                if (curkey > highkey) { /* flush string */
Packit 78deda
                    addToColorMap(hashP, colorName, curbuf, isTransparent);
Packit 78deda
                    highkey = curkey;
Packit 78deda
                }
Packit 78deda
                /* intialize state to process this new key */
Packit 78deda
                curkey = key;
Packit 78deda
                curbuf[0] = '\0';
Packit 78deda
                isTransparent = FALSE;
Packit 78deda
                lastwaskey = TRUE;
Packit 78deda
            }
Packit 78deda
            if (*t2 == '"') break;
Packit 78deda
        }
Packit 78deda
    }
Packit 78deda
    /* Put the info for the last key in the line into the colormap (or
Packit 78deda
       ignore it if there's already a higher color form for this colormap
Packit 78deda
       entry in it)
Packit 78deda
    */
Packit 78deda
    if (curkey > highkey) {
Packit 78deda
        addToColorMap(hashP, colorName, curbuf, isTransparent);
Packit 78deda
        highkey = curkey;
Packit 78deda
    }
Packit 78deda
    if (highkey == 1) 
Packit 78deda
        pm_error("C error scanning color table");
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
readV3ColorTable(FILE *             const ifP,
Packit 78deda
                 ColorNameHash **   const colorNameHashPP,
Packit 78deda
                 unsigned int       const nColors,
Packit 78deda
                 unsigned int       const charsPerPixel) {
Packit 78deda
/*----------------------------------------------------------------------------
Packit 78deda
   Read the color table from the XPM Version 3 header.
Packit 78deda
Packit 78deda
   Assume *ifP is positioned to the color table; leave it positioned after.
Packit 78deda
-----------------------------------------------------------------------------*/
Packit 78deda
    ColorNameHash * const colorNameHashP = hash_create(nColors, charsPerPixel);
Packit 78deda
Packit 78deda
    unsigned int seqNum;
Packit 78deda
        /* Sequence number of entry within color table in XPM header */
Packit 78deda
Packit 78deda
    for (seqNum = 0; seqNum < nColors; ++seqNum) {
Packit 78deda
        char line[MAX_LINE+1];
Packit 78deda
        getLine(line, sizeof(line), ifP);
Packit 78deda
        /* skip the comment line if any */
Packit 78deda
        if (strneq(line, "/*", 2))
Packit 78deda
            getLine(line, sizeof(line), ifP);
Packit 78deda
            
Packit 78deda
        interpretXpm3ColorTableLine(line, seqNum, charsPerPixel,
Packit 78deda
                                    colorNameHashP);
Packit 78deda
                                    
Packit 78deda
    }
Packit 78deda
    *colorNameHashPP = colorNameHashP;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
readXpm3Header(FILE *             const ifP,
Packit 78deda
               unsigned int *     const widthP,
Packit 78deda
               unsigned int *     const heightP, 
Packit 78deda
               unsigned int *     const charsPerPixelP,
Packit 78deda
               ColorNameHash **   const colorNameHashPP) {
Packit 78deda
/*----------------------------------------------------------------------------
Packit 78deda
  Read the header of the XPM file on stream *ifP.  Assume the
Packit 78deda
  getLine() stream is presently positioned to the beginning of the
Packit 78deda
  file and it is a Version 3 XPM file.  Leave the stream positioned
Packit 78deda
  after the header.
Packit 78deda
Packit 78deda
  Return as *widthP and *heightP the dimensions of the image indicated
Packit 78deda
  by the header.
Packit 78deda
Packit 78deda
  Return as *charsPerPixelP the number of characters the header says the
Packit 78deda
  raster uses for each pixel, i.e. the XPM color name length.
Packit 78deda
Packit 78deda
  Return the color map as *colorNameHashPP.
Packit 78deda
-----------------------------------------------------------------------------*/
Packit 78deda
    char line[MAX_LINE+1];
Packit 78deda
    const char * xpm3_signature = "/* XPM */";
Packit 78deda
    
Packit 78deda
    unsigned int width, height;
Packit 78deda
    unsigned int nColors;
Packit 78deda
    unsigned int charsPerPixel;
Packit 78deda
Packit 78deda
    /* Read the XPM signature comment */
Packit 78deda
    getLine(line, sizeof(line), ifP);
Packit 78deda
    if (!strneq(line, xpm3_signature, strlen(xpm3_signature))) 
Packit 78deda
        pm_error("Apparent XPM 3 file does not start with '/* XPM */'.  "
Packit 78deda
                 "First line is '%s'", xpm3_signature);
Packit 78deda
Packit 78deda
    /* Read the assignment line */
Packit 78deda
    getLine(line, sizeof(line), ifP);
Packit 78deda
    if (!strneq(line, "static char", 11))
Packit 78deda
        pm_error("Cannot find data structure declaration.  Expected a "
Packit 78deda
                 "line starting with 'static char', but found the line "
Packit 78deda
                 "'%s'.", line);
Packit 78deda
Packit 78deda
    getLine(line, sizeof(line), ifP);
Packit 78deda
Packit 78deda
    /* Skip the comment block, if one starts here */
Packit 78deda
    if (strneq(line, "/*", 2)) {
Packit 78deda
        while (!strstr(line, "*/"))
Packit 78deda
            getLine(line, sizeof(line), ifP);
Packit 78deda
        getLine(line, sizeof(line), ifP);
Packit 78deda
    }
Packit 78deda
Packit 78deda
    /* Parse the hints line */
Packit 78deda
    if (sscanf(line, "\"%u %u %u %u\",", &width, &height,
Packit 78deda
               &nColors, &charsPerPixel) != 4)
Packit 78deda
        pm_error("error scanning hints line");
Packit 78deda
Packit 78deda
    if (verbose) {
Packit 78deda
        pm_message("Width x Height:  %u x %u", width, height);
Packit 78deda
        pm_message("no. of colors:  %u", nColors);
Packit 78deda
        pm_message("chars per pixel:  %u", charsPerPixel);
Packit 78deda
    }
Packit 78deda
Packit 78deda
    readV3ColorTable(ifP, colorNameHashPP, nColors, charsPerPixel);
Packit 78deda
Packit 78deda
    *widthP         = width;
Packit 78deda
    *heightP        = height;
Packit 78deda
    *charsPerPixelP = charsPerPixel;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
readV1ColorTable(FILE *           const ifP,
Packit 78deda
                 ColorNameHash ** const colorNameHashPP,
Packit 78deda
                 unsigned int     const nColors,
Packit 78deda
                 unsigned int     const charsPerPixel) {
Packit 78deda
/*----------------------------------------------------------------------------
Packit 78deda
   Read the color table from the XPM Version 1 header.
Packit 78deda
Packit 78deda
   Assume *ifP is positioned to the color table; leave it positioned after.
Packit 78deda
-----------------------------------------------------------------------------*/
Packit 78deda
    ColorNameHash * const colorNameHashP = hash_create(nColors, charsPerPixel);
Packit 78deda
Packit 78deda
    unsigned int i;
Packit 78deda
Packit 78deda
    for (i = 0; i < nColors; ++i) {
Packit 78deda
        char line[MAX_LINE+1];
Packit 78deda
        char str1[MAX_LINE+1];
Packit 78deda
        char str2[MAX_LINE+1];
Packit 78deda
        char * t1;
Packit 78deda
        char * t2;
Packit 78deda
Packit 78deda
        getLine(line, sizeof(line), ifP);
Packit 78deda
Packit 78deda
        if ((t1 = strchr(line, '"')) == NULL)
Packit 78deda
            pm_error("D error scanning color table");
Packit 78deda
        if ((t2 = strchr(t1 + 1, '"')) == NULL)
Packit 78deda
            pm_error("E error scanning color table");
Packit 78deda
        if (t2 - t1 - 1 != charsPerPixel)
Packit 78deda
            pm_error("wrong number of chars per pixel in color table");
Packit 78deda
        strncpy(str1, t1 + 1, t2 - t1 - 1);
Packit 78deda
        str1[t2 - t1 - 1] = '\0';
Packit 78deda
Packit 78deda
        if ((t1 = strchr(t2 + 1, '"')) == NULL)
Packit 78deda
            pm_error("F error scanning color table");
Packit 78deda
        if ((t2 = strchr(t1 + 1, '"')) == NULL)
Packit 78deda
            pm_error("G error scanning color table");
Packit 78deda
        strncpy(str2, t1 + 1, t2 - t1 - 1);
Packit 78deda
        str2[t2 - t1 - 1] = '\0';
Packit 78deda
Packit 78deda
        addToColorMap(colorNameHashP, str1, str2, false);
Packit 78deda
    }
Packit 78deda
    *colorNameHashPP = colorNameHashP;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
readXpm1Header(FILE *           const ifP,
Packit 78deda
               unsigned int *   const widthP,
Packit 78deda
               unsigned int *   const heightP, 
Packit 78deda
               unsigned int *   const charsPerPixelP,
Packit 78deda
               ColorNameHash ** const colorNameHashPP) {
Packit 78deda
/*----------------------------------------------------------------------------
Packit 78deda
  Read the header of the XPM file on stream *ifP.  Assume the
Packit 78deda
  getLine() stream is presently positioned to the beginning of the
Packit 78deda
  file and it is a Version 1 XPM file.  Leave the stream positioned
Packit 78deda
  after the header.
Packit 78deda
  
Packit 78deda
  Return the information from the header the same as for readXpm3Header.
Packit 78deda
-----------------------------------------------------------------------------*/
Packit 78deda
    int format, v;
Packit 78deda
    bool processedStaticChar;  
Packit 78deda
        /* We have read up to and interpreted the "static char..." line */
Packit 78deda
    char * t1;
Packit 78deda
    unsigned int nColors;
Packit 78deda
    bool gotPixel, gotNColors, gotWidth, gotHeight, gotFormat;
Packit 78deda
Packit 78deda
    gotNColors = false;
Packit 78deda
    gotWidth   = false;
Packit 78deda
    gotHeight  = false;
Packit 78deda
    gotFormat  = false;
Packit 78deda
    gotPixel   = false;
Packit 78deda
Packit 78deda
    /* Read the initial defines. */
Packit 78deda
    processedStaticChar = FALSE;
Packit 78deda
    while (!processedStaticChar) {
Packit 78deda
        char line[MAX_LINE+1];
Packit 78deda
        char str1[MAX_LINE+1];
Packit 78deda
Packit 78deda
        getLine(line, sizeof(line), ifP);
Packit 78deda
Packit 78deda
        if (sscanf(line, "#define %s %d", str1, &v) == 2) {
Packit 78deda
            if ((t1 = strrchr(str1, '_')) == NULL)
Packit 78deda
                t1 = str1;
Packit 78deda
            else
Packit 78deda
                ++t1;
Packit 78deda
            if (streq(t1, "format")) {
Packit 78deda
                gotFormat = true;
Packit 78deda
                format = v;
Packit 78deda
            } else if (streq(t1, "width")) {
Packit 78deda
                gotWidth = true;
Packit 78deda
                *widthP = v;
Packit 78deda
            } else if (streq(t1, "height")) {
Packit 78deda
                gotHeight = true;
Packit 78deda
                *heightP = v;
Packit 78deda
            } else if (streq(t1, "nColors")) {
Packit 78deda
                gotNColors = true;
Packit 78deda
                nColors = v;
Packit 78deda
            } else if (streq(t1, "pixel")) {
Packit 78deda
                gotPixel = TRUE;
Packit 78deda
                *charsPerPixelP = v;
Packit 78deda
            }
Packit 78deda
        } else if (strneq(line, "static char", 11)) {
Packit 78deda
            if ((t1 = strrchr(line, '_')) == NULL)
Packit 78deda
                t1 = line;
Packit 78deda
            else
Packit 78deda
                ++t1;
Packit 78deda
            processedStaticChar = TRUE;
Packit 78deda
        }
Packit 78deda
    }
Packit 78deda
    /* File is positioned to "static char" line, which is in line[] and
Packit 78deda
       t1 points to position of last "_" in the line, or the beginning of
Packit 78deda
       the line if there is no "_"
Packit 78deda
    */
Packit 78deda
    if (!gotPixel)
Packit 78deda
        pm_error("No 'pixel' value (characters per pixel)");
Packit 78deda
    if (!gotFormat)
Packit 78deda
        pm_error("missing or invalid format");
Packit 78deda
    if (format != 1)
Packit 78deda
        pm_error("can't handle XPM version %d", format);
Packit 78deda
    if (!gotWidth)
Packit 78deda
        pm_error("missing or invalid width");
Packit 78deda
    if (!gotHeight)
Packit 78deda
        pm_error("missing or invalid height");
Packit 78deda
    if (!gotNColors)
Packit 78deda
        pm_error("missing or invalid nColors");
Packit 78deda
Packit 78deda
    if (*charsPerPixelP > 2)
Packit 78deda
        pm_message("WARNING: > 2 characters per pixel uses a lot of memory");
Packit 78deda
Packit 78deda
    /* If there's a monochrome color table, skip it. */
Packit 78deda
    if (strneq(t1, "mono", 4)) {
Packit 78deda
        for (;;) {
Packit 78deda
            char line[MAX_LINE+1];
Packit 78deda
            getLine(line, sizeof(line), ifP);
Packit 78deda
            if (strneq(line, "static char", 11))
Packit 78deda
                break;
Packit 78deda
        }
Packit 78deda
    }
Packit 78deda
    readV1ColorTable(ifP, colorNameHashPP, nColors, *charsPerPixelP);
Packit 78deda
Packit 78deda
    /* Position to first line of raster (which is the line after
Packit 78deda
       "static char ...").
Packit 78deda
    */
Packit 78deda
    for (;;) {
Packit 78deda
        char line[MAX_LINE+1];
Packit 78deda
        getLine(line, sizeof(line), ifP);
Packit 78deda
        if (strneq(line, "static char", 11))
Packit 78deda
            break;
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
validateRasterPixel(const char * const pixelChars,
Packit 78deda
                    unsigned int const charsPerPixel) {
Packit 78deda
Packit 78deda
    unsigned int i;
Packit 78deda
Packit 78deda
    for (i = 0; i < charsPerPixel; ++i) {
Packit 78deda
        if (pixelChars[i] == '\0')
Packit 78deda
            pm_error("XPM input file ends in the middle of a string "
Packit 78deda
                     "that represents a raster line");
Packit 78deda
        else if (pixelChars[i] == '"')
Packit 78deda
            pm_error("A string that represents a raster line in the "
Packit 78deda
                     "XPM input file is too short to contain all the "
Packit 78deda
                     "pixels (%u characters each)",
Packit 78deda
                     charsPerPixel);
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
convertRow(char                  const line[],
Packit 78deda
           unsigned int          const width,
Packit 78deda
           unsigned int          const charsPerPixel,
Packit 78deda
           const ColorNameHash * const colorNameHashP,
Packit 78deda
           pixel *               const pixrow,
Packit 78deda
           bit *                 const alpharow) {
Packit 78deda
/*----------------------------------------------------------------------------
Packit 78deda
   Convert one row from XPM input, which describes one raster line of the
Packit 78deda
   image, to PPM.  The XPM line is in 'line', and its format is 'width' pixel,
Packit 78deda
   'charsPerPixel' characters per pixel.  *colorNameHashP is the color table
Packit 78deda
   that applies to the line.
Packit 78deda
Packit 78deda
   Put the PPM pixels in 'pixrow'.
Packit 78deda
Packit 78deda
   Also produce PBM row 'alpharow' with the transparency information from the
Packit 78deda
   row.
Packit 78deda
Packit 78deda
   If the line doesn't start with a quote (e.g. it is empty), we issue
Packit 78deda
   a warning and just treat the line as one that describes no pixels.
Packit 78deda
Packit 78deda
   Abort program if there aren't exactly 'width' pixels in the line.
Packit 78deda
-----------------------------------------------------------------------------*/
Packit 78deda
    const char * lineCursor;
Packit 78deda
Packit 78deda
    lineCursor = strchr(line, '"');  /* position to 1st quote in line */
Packit 78deda
    if (lineCursor == NULL) {
Packit 78deda
        /* We've seen a purported XPM that had a blank line in it.  Just
Packit 78deda
           ignoring it was the right thing to do.  05.05.27.
Packit 78deda
        */
Packit 78deda
        pm_message("WARNING:  No opening quotation mark in XPM input "
Packit 78deda
                   "line which is supposed to be a line of raster data: "
Packit 78deda
                   "'%s'.  Ignoring this line.", line);
Packit 78deda
    } else {
Packit 78deda
        unsigned int col;
Packit 78deda
    
Packit 78deda
        ++lineCursor; /* Skip to first character after quote */
Packit 78deda
Packit 78deda
        /* Handle pixels until a close quote, eol, or we've returned all
Packit 78deda
           the pixels Caller wants.
Packit 78deda
        */
Packit 78deda
        for (col = 0; col < width; ++col) {
Packit 78deda
Packit 78deda
            validateRasterPixel(lineCursor, charsPerPixel);
Packit 78deda
Packit 78deda
            pixrow[col] = hash_color(colorNameHashP, lineCursor);
Packit 78deda
Packit 78deda
            alpharow[col] = hash_isTransparent(colorNameHashP, lineCursor) ?
Packit 78deda
                PBM_BLACK : PBM_WHITE;
Packit 78deda
            
Packit 78deda
            lineCursor += charsPerPixel;
Packit 78deda
        }
Packit 78deda
        if (*lineCursor != '"')
Packit 78deda
            pm_error("A raster line continues past width of image");
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
convertRaster(FILE *                const ifP,
Packit 78deda
              unsigned int          const cols,
Packit 78deda
              unsigned int          const rows, 
Packit 78deda
              unsigned int          const charsPerPixel,
Packit 78deda
              const ColorNameHash * const colorNameHashP,
Packit 78deda
              FILE *                const imageOutFileP,
Packit 78deda
              FILE *                const alphaOutFileP) {
Packit 78deda
/*----------------------------------------------------------------------------
Packit 78deda
  Read the XPM raster from *ifP and write the PPM raster to *imageOutFileP
Packit 78deda
  and the alpha channel to *alphaOutFileP (where those are, respectively,
Packit 78deda
  non-null).
Packit 78deda
Packit 78deda
  The dimensions are 'cols' by 'rows' and the color map for the XPM
Packit 78deda
  raster is *colorNameHashP.
Packit 78deda
-----------------------------------------------------------------------------*/
Packit 78deda
    char line[MAX_LINE+1];
Packit 78deda
    pixel * pixrow;
Packit 78deda
    bit * alpharow;
Packit 78deda
    unsigned int row;
Packit 78deda
Packit 78deda
    pixrow   = ppm_allocrow(cols);
Packit 78deda
    alpharow = pbm_allocrow(cols);
Packit 78deda
Packit 78deda
    for (row = 0; row < rows; ++row) {
Packit 78deda
        bool haveLine;
Packit 78deda
Packit 78deda
        for (haveLine = false; !haveLine; ) {
Packit 78deda
            getLine(line, sizeof(line), ifP); 
Packit 78deda
Packit 78deda
            if (strneq(line, "/*", 2)) {
Packit 78deda
                /* It's a comment.  Ignore it. */
Packit 78deda
            } else
Packit 78deda
                haveLine = true;
Packit 78deda
        }
Packit 78deda
        convertRow(line, cols, charsPerPixel, colorNameHashP,
Packit 78deda
                   pixrow, alpharow);
Packit 78deda
Packit 78deda
        if (imageOutFileP)
Packit 78deda
            ppm_writeppmrow(imageOutFileP, 
Packit 78deda
                            pixrow, cols, PPM_MAXMAXVAL, 0);
Packit Service 2370ca
            if (alphaOutFileP)
Packit Service 2370ca
                pbm_writepbmrow(alphaOutFileP, alpharow, cols, 0);
Packit 78deda
    }
Packit 78deda
Packit 78deda
    pbm_freerow(alpharow);
Packit 78deda
    ppm_freerow(pixrow);
Packit 78deda
}
Packit 78deda
 
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
readXpmHeader(FILE *           const ifP,
Packit 78deda
              unsigned int *   const widthP,
Packit 78deda
              unsigned int *   const heightP, 
Packit 78deda
              unsigned int *   const charsPerPixelP,
Packit 78deda
              ColorNameHash ** const colorNameHashPP) {
Packit 78deda
/*----------------------------------------------------------------------------
Packit 78deda
  Read the XPM header, including color map.
Packit 78deda
Packit 78deda
  In the colormap, put black for the transparent color, if the XPM image
Packit 78deda
  contains one.
Packit 78deda
-----------------------------------------------------------------------------*/
Packit 78deda
    char line[MAX_LINE+1];
Packit 78deda
    char str1[MAX_LINE+1];
Packit 78deda
    int rc;
Packit 78deda
    unsigned int charsPerPixel;
Packit 78deda
    unsigned int width, height;
Packit 78deda
Packit 78deda
    backup = FALSE;
Packit 78deda
Packit 78deda
    /* Read the header line */
Packit 78deda
    getLine(line, sizeof(line), ifP);
Packit 78deda
    backup = TRUE;  /* back up so next read reads this line again */
Packit 78deda
    
Packit 78deda
    rc = sscanf(line, "/* %s */", str1);
Packit 78deda
    if (rc == 1 && strneq(str1, "XPM", 3)) {
Packit 78deda
        /* It's an XPM version 3 file */
Packit 78deda
        readXpm3Header(ifP, &width, &height, &charsPerPixel, colorNameHashPP);
Packit 78deda
    } else {
Packit 78deda
        /* Assume it's an XPM version 1 file */
Packit 78deda
        readXpm1Header(ifP, &width, &height, &charsPerPixel, colorNameHashPP);
Packit 78deda
    }
Packit 78deda
    *widthP         = width;
Packit 78deda
    *heightP        = height;
Packit 78deda
    *charsPerPixelP = charsPerPixel;
Packit 78deda
}
Packit 78deda
 
Packit 78deda
Packit 78deda
Packit 78deda
int
Packit 78deda
main(int argc, char *argv[]) {
Packit 78deda
Packit 78deda
    FILE * ifP;
Packit 78deda
    FILE * alphaOutFileP;
Packit 78deda
    FILE * imageOutFileP;
Packit 78deda
    unsigned int cols, rows;
Packit 78deda
    unsigned int charsPerPixel;
Packit 78deda
    ColorNameHash * colorNameHashP;
Packit 78deda
Packit 78deda
    struct cmdlineInfo cmdline;
Packit 78deda
Packit 78deda
    ppm_init(&argc, argv);
Packit 78deda
Packit 78deda
    parseCommandLine(argc, argv, &cmdline);
Packit 78deda
Packit 78deda
    verbose = cmdline.verbose;
Packit 78deda
Packit 78deda
    if ( cmdline.input_filespec != NULL ) 
Packit 78deda
        ifP = pm_openr( cmdline.input_filespec);
Packit 78deda
    else
Packit 78deda
        ifP = stdin;
Packit 78deda
Packit 78deda
    if (cmdline.alpha_stdout)
Packit 78deda
        alphaOutFileP = stdout;
Packit 78deda
    else if (cmdline.alpha_filename == NULL) 
Packit 78deda
        alphaOutFileP = NULL;
Packit 78deda
    else {
Packit 78deda
        alphaOutFileP = pm_openw(cmdline.alpha_filename);
Packit 78deda
    }
Packit 78deda
Packit 78deda
    if (cmdline.alpha_stdout) 
Packit 78deda
        imageOutFileP = NULL;
Packit 78deda
    else
Packit 78deda
        imageOutFileP = stdout;
Packit 78deda
Packit 78deda
    readXpmHeader(ifP, &cols, &rows, &charsPerPixel, &colorNameHashP);
Packit 78deda
Packit 78deda
    if (imageOutFileP)
Packit 78deda
        ppm_writeppminit(imageOutFileP, cols, rows, PPM_MAXMAXVAL, 0);
Packit 78deda
    if (alphaOutFileP)
Packit 78deda
        pbm_writepbminit(alphaOutFileP, cols, rows, 0);
Packit 78deda
Packit 78deda
Packit 78deda
    convertRaster(ifP, cols, rows, charsPerPixel, colorNameHashP,
Packit 78deda
                  imageOutFileP, alphaOutFileP);
Packit 78deda
    
Packit 78deda
    pm_close(ifP);
Packit 78deda
    if (imageOutFileP)
Packit 78deda
        pm_close(imageOutFileP);
Packit 78deda
    if (alphaOutFileP)
Packit 78deda
        pm_close(alphaOutFileP);
Packit 78deda
Packit 78deda
    hash_destroy(colorNameHashP);
Packit 78deda
    
Packit 78deda
    return 0;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
/*
Packit 78deda
**
Packit 78deda
** Copyright (C) 1991 by Jef Poskanzer.
Packit 78deda
**
Packit 78deda
** Permission to use, copy, modify, and distribute this software and its
Packit 78deda
** documentation for any purpose and without fee is hereby granted, provided
Packit 78deda
** that the above copyright notice appear in all copies and that both that
Packit 78deda
** copyright notice and this permission notice appear in supporting
Packit 78deda
** documentation.  This software is provided "as is" without express or
Packit 78deda
** implied warranty.
Packit 78deda
**
Packit 78deda
** Upgraded to handle XPM version 3 by
Packit 78deda
**   Arnaud Le Hors (lehors@mirsa.inria.fr)
Packit 78deda
**   Tue Apr 9 1991
Packit 78deda
**
Packit 78deda
** Rainer Sinkwitz sinkwitz@ifi.unizh.ch - 21 Nov 91:
Packit 78deda
**  - Bug fix, no advance of read ptr, would not read 
Packit 78deda
**    colors like "ac c black" because it would find 
Packit 78deda
**    the "c" of "ac" and then had problems with "c"
Packit 78deda
**    as color.
Packit 78deda
**    
Packit 78deda
**  - Now understands multiword X11 color names
Packit 78deda
**  
Packit 78deda
**  - Now reads multiple color keys. Takes the color
Packit 78deda
**    of the hightest available key. Lines no longer need
Packit 78deda
**    to begin with key 'c'.
Packit 78deda
**    
Packit 78deda
**  - expanded line buffer to from 500 to 2048 for bigger files
Packit 78deda
*/
Packit 78deda