diff options
Diffstat (limited to 'src/xpm/converters/xpmtoppm.c')
-rw-r--r-- | src/xpm/converters/xpmtoppm.c | 433 |
1 files changed, 433 insertions, 0 deletions
diff --git a/src/xpm/converters/xpmtoppm.c b/src/xpm/converters/xpmtoppm.c new file mode 100644 index 0000000..9842267 --- /dev/null +++ b/src/xpm/converters/xpmtoppm.c @@ -0,0 +1,433 @@ +/* xpmtoppm.c - read an X11 pixmap file and produce a portable pixmap +** +** Copyright (C) 1991 by Jef Poskanzer. +** +** 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. +** +** Upgraded to support XPM version 3 by +** Arnaud Le Hors (lehors@mirsa.inria.fr) +** Tue Apr 9 1991 +** +** Rainer Sinkwitz sinkwitz@ifi.unizh.ch - 21 Nov 91: +** - Bug fix, no advance of read ptr, would not read +** colors like "ac c black" because it would find +** the "c" of "ac" and then had problems with "c" +** as color. +** +** - Now understands multword X11 color names +** +** - Now reads multiple color keys. Takes the color +** of the hightest available key. Lines no longer need +** to begin with key 'c'. +** +** - expanded line buffer to from 500 to 2048 for bigger files +*/ + +#include "ppm.h" + +void ReadXPMFile(); +static void getline(); + +/* number of xpmColorKeys */ +#define NKEYS 5 + +char *xpmColorKeys[] = +{ + "s", /* key #1: symbol */ + "m", /* key #2: mono visual */ + "g4", /* key #3: 4 grays visual */ + "g", /* key #4: gray visual */ + "c", /* key #5: color visual */ +}; + +#ifdef NEED_STRSTR +/* for systems which do not provide it */ +static char * +strstr(s1, s2) + char *s1, *s2; +{ + int ls2 = strlen(s2); + + if (ls2 == 0) + return (s1); + while (strlen(s1) >= ls2) { + if (strncmp(s1, s2, ls2) == 0) + return (s1); + s1++; + } + return (0); +} + +#endif + +void +main(argc, argv) + int argc; + char *argv[]; + +{ + FILE *ifp; + pixel *pixrow, *colors; + register pixel *pP; + int rows, cols, ncolors, chars_per_pixel, row; + register int col; + int *data; + register int *ptr; + + ppm_init(&argc, argv); + + if (argc > 2) + pm_usage("[xpmfile]"); + + if (argc == 2) + ifp = pm_openr(argv[1]); + else + ifp = stdin; + + ReadXPMFile( + ifp, &cols, &rows, &ncolors, &chars_per_pixel, &colors, &data); + + pm_close(ifp); + + ppm_writeppminit(stdout, cols, rows, (pixval) PPM_MAXMAXVAL, 0); + pixrow = ppm_allocrow(cols); + + for (row = 0, ptr = data; row < rows; ++row) { + for (col = 0, pP = pixrow; col < cols; ++col, ++pP, ++ptr) + *pP = colors[*ptr]; + ppm_writeppmrow(stdout, pixrow, cols, (pixval) PPM_MAXMAXVAL, 0); + } + + exit(0); +} + +#define MAX_LINE 2048 + +void +ReadXPMFile(stream, widthP, heightP, ncolorsP, + chars_per_pixelP, colorsP, dataP) + FILE *stream; + int *widthP; + int *heightP; + int *ncolorsP; + int *chars_per_pixelP; + pixel **colorsP; + int **dataP; +{ + char line[MAX_LINE], str1[MAX_LINE], str2[MAX_LINE]; + char *t1; + char *t2; + int format, v, datasize; + int *ptr; + int *ptab; + register int i, j; + int flag; + + unsigned int curkey, key, highkey; /* current color key */ + unsigned int lastwaskey; /* key read */ + char curbuf[BUFSIZ]; /* current buffer */ + + *widthP = *heightP = *ncolorsP = *chars_per_pixelP = format = -1; + flag = 0; /* to avoid getting twice a line */ + + /* First try to read as an XPM version 3 file */ + + /* Read the header line */ + getline(line, sizeof(line), stream); + if (sscanf(line, "/* %s */", str1) == 1 + && !strncmp(str1, "XPM", 3)) { + + /* Read the assignment line */ + getline(line, sizeof(line), stream); + if (strncmp(line, "static char", 11)) + pm_error("error scanning assignment line", 0, 0, 0, 0, 0); + + /* Read the hints line */ + getline(line, sizeof(line), stream); + /* skip the comment line if any */ + if (!strncmp(line, "/*", 2)) { + while (!strstr(line, "*/")) + getline(line, sizeof(line), stream); + getline(line, sizeof(line), stream); + } + if (sscanf(line, "\"%d %d %d %d\",", widthP, heightP, + ncolorsP, chars_per_pixelP) != 4) + pm_error("error scanning hints line", 0, 0, 0, 0, 0); + + /* Allocate space for color table. */ + if (*chars_per_pixelP <= 2) { + /* Up to two chars per pixel, we can use an indexed table. */ + v = 1; + for (i = 0; i < *chars_per_pixelP; ++i) + v *= 256; + *colorsP = ppm_allocrow(v); + } else { + /* Over two chars per pixel, we fall back on linear search. */ + *colorsP = ppm_allocrow(*ncolorsP); + ptab = (int *) malloc(*ncolorsP * sizeof(int)); + } + + /* Read the color table */ + for (i = 0; i < *ncolorsP; i++) { + getline(line, sizeof(line), stream); + /* skip the comment line if any */ + if (!strncmp(line, "/*", 2)) + getline(line, sizeof(line), stream); + + /* read the chars */ + if ((t1 = index(line, '"')) == NULL) + pm_error("error scanning color table", 0, 0, 0, 0, 0); + else + t1++; + strncpy(str1, t1, *chars_per_pixelP); + str1[*chars_per_pixelP] = '\0'; + t1++; t1++; + + v = 0; + for (j = 0; j < *chars_per_pixelP; ++j) + v = (v << 8) + str1[j]; + /* + * read color keys and values + */ + curkey = 0; + highkey = 1; + lastwaskey = 0; + t2 = t1; + while ( 1 ) { + for (t1=t2 ;; t1++) + if (*t1 != ' ' && *t1 != ' ') + break; + for (t2 = t1;; t2++) + if (*t2 == ' ' || *t2 == ' ' || *t2 == '"') + break; + if (t2 == t1) break; + strncpy(str2, t1, t2 - t1); + str2[t2 - t1] = '\0'; + + if (!lastwaskey) { + for (key = 1; key < NKEYS + 1; key++) + if (!strcmp(xpmColorKeys[key - 1], str2)) + break; + } else + key = NKEYS + 1; + if (key > NKEYS) { /* append name */ + if (!curkey) + pm_error("error scanning color table", 0, 0, 0, 0, 0); + if (!lastwaskey) + strcat(curbuf, " "); /* append space */ + strcat(curbuf, str2); /* append buf */ + lastwaskey = 0; + } + if (key <= NKEYS) { /* new key */ + if (curkey > highkey) { /* flush string */ + if (*chars_per_pixelP <= 2) + /* Index into table. */ + (*colorsP)[v] = ppm_parsecolor(curbuf, + (pixval) PPM_MAXMAXVAL); + else { + /* Set up linear search table. */ + (*colorsP)[i] = ppm_parsecolor(curbuf, + (pixval) PPM_MAXMAXVAL); + ptab[i] = v; + } + highkey = curkey; + } + curkey = key; /* set new key */ + curbuf[0] = '\0'; /* reset curbuf */ + lastwaskey = 1; + } + if (*t2 == '"') break; + } + if (curkey > highkey) { + if (*chars_per_pixelP <= 2) + /* Index into table. */ + (*colorsP)[v] = ppm_parsecolor(curbuf, + (pixval) PPM_MAXMAXVAL); + else { + /* Set up linear search table. */ + (*colorsP)[i] = ppm_parsecolor(curbuf, + (pixval) PPM_MAXMAXVAL); + ptab[i] = v; + } + highkey = curkey; + } + if (highkey == 1) + pm_error("error scanning color table", 0, 0, 0, 0, 0); + } + /* Read pixels. */ + getline(line, sizeof(line), stream); + /* skip the comment line if any */ + if (!strncmp(line, "/*", 2)) + getline(line, sizeof(line), stream); + + } else { /* try as an XPM version 1 file */ + + /* Read the initial defines. */ + for (;;) { + if (flag) + getline(line, sizeof(line), stream); + else + flag++; + + if (sscanf(line, "#define %s %d", str1, &v) == 2) { + if ((t1 = rindex(str1, '_')) == NULL) + t1 = str1; + else + ++t1; + if (!strcmp(t1, "format")) + format = v; + else if (!strcmp(t1, "width")) + *widthP = v; + else if (!strcmp(t1, "height")) + *heightP = v; + else if (!strcmp(t1, "ncolors")) + *ncolorsP = v; + else if (!strcmp(t1, "pixel")) + *chars_per_pixelP = v; + } else if (!strncmp(line, "static char", 11)) { + if ((t1 = rindex(line, '_')) == NULL) + t1 = line; + else + ++t1; + break; + } + } + if (format == -1) + pm_error("missing or invalid format", 0, 0, 0, 0, 0); + if (format != 1) + pm_error("can't handle XPM version %d", format, 0, 0, 0, 0); + if (*widthP == -1) + pm_error("missing or invalid width", 0, 0, 0, 0, 0); + if (*heightP == -1) + pm_error("missing or invalid height", 0, 0, 0, 0, 0); + if (*ncolorsP == -1) + pm_error("missing or invalid ncolors", 0, 0, 0, 0, 0); + if (*chars_per_pixelP == -1) + pm_error("missing or invalid chars_per_pixel", 0, 0, 0, 0, 0); + if (*chars_per_pixelP > 2) + pm_message("warning, chars_per_pixel > 2 uses a lot of memory" + ,0, 0, 0, 0, 0); + + /* If there's a monochrome color table, skip it. */ + if (!strncmp(t1, "mono", 4)) { + for (;;) { + getline(line, sizeof(line), stream); + if (!strncmp(line, "static char", 11)) + break; + } + } + /* Allocate space for color table. */ + if (*chars_per_pixelP <= 2) { + /* Up to two chars per pixel, we can use an indexed table. */ + v = 1; + for (i = 0; i < *chars_per_pixelP; ++i) + v *= 256; + *colorsP = ppm_allocrow(v); + } else { + /* Over two chars per pixel, we fall back on linear search. */ + *colorsP = ppm_allocrow(*ncolorsP); + ptab = (int *) malloc(*ncolorsP * sizeof(int)); + } + + /* Read color table. */ + for (i = 0; i < *ncolorsP; ++i) { + getline(line, sizeof(line), stream); + + if ((t1 = index(line, '"')) == NULL) + pm_error("error scanning color table", 0, 0, 0, 0, 0); + if ((t2 = index(t1 + 1, '"')) == NULL) + pm_error("error scanning color table", 0, 0, 0, 0, 0); + if (t2 - t1 - 1 != *chars_per_pixelP) + pm_error("wrong number of chars per pixel in color table", + 0, 0, 0, 0, 0); + strncpy(str1, t1 + 1, t2 - t1 - 1); + str1[t2 - t1 - 1] = '\0'; + + if ((t1 = index(t2 + 1, '"')) == NULL) + pm_error("error scanning color table", 0, 0, 0, 0, 0); + if ((t2 = index(t1 + 1, '"')) == NULL) + pm_error("error scanning color table", 0, 0, 0, 0, 0); + strncpy(str2, t1 + 1, t2 - t1 - 1); + str2[t2 - t1 - 1] = '\0'; + + v = 0; + for (j = 0; j < *chars_per_pixelP; ++j) + v = (v << 8) + str1[j]; + if (*chars_per_pixelP <= 2) + /* Index into table. */ + (*colorsP)[v] = ppm_parsecolor(str2, + (pixval) PPM_MAXMAXVAL); + else { + /* Set up linear search table. */ + (*colorsP)[i] = ppm_parsecolor(str2, + (pixval) PPM_MAXMAXVAL); + ptab[i] = v; + } + } + + /* Read pixels. */ + for (;;) { + getline(line, sizeof(line), stream); + if (!strncmp(line, "static char", 11)) + break; + } + } + datasize = *widthP * *heightP; + *dataP = (int *) malloc(datasize * sizeof(int)); + if (*dataP == 0) + pm_error("out of memory", 0, 0, 0, 0, 0); + i = 0; + ptr = *dataP; + for (;;) { + if (flag) + getline(line, sizeof(line), stream); + else + flag++; + + /* Find the open quote. */ + if ((t1 = index(line, '"')) == NULL) + pm_error("error scanning pixels", 0, 0, 0, 0, 0); + ++t1; + + /* Handle pixels until a close quote or the end of the image. */ + while (*t1 != '"') { + v = 0; + for (j = 0; j < *chars_per_pixelP; ++j) + v = (v << 8) + *t1++; + if (*chars_per_pixelP <= 2) + /* Index into table. */ + *ptr++ = v; + else { + /* Linear search into table. */ + for (j = 0; j < *ncolorsP; ++j) + if (ptab[j] == v) + goto gotit; + pm_error("unrecognized pixel in line \"%s\"", line, + 0, 0, 0, 0); + gotit: + *ptr++ = j; + } + ++i; + if (i >= datasize) + return; + } + } +} + + +static void +getline(line, size, stream) + char *line; + int size; + FILE *stream; +{ + if (fgets(line, MAX_LINE, stream) == NULL) + pm_error("EOF / read error", 0, 0, 0, 0, 0); + if (strlen(line) == MAX_LINE - 1) + pm_error("line too long", 0, 0, 0, 0, 0); +} |