home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / netpbma.zip / ppm / xpmtoppm.c < prev    next >
C/C++ Source or Header  |  1994-01-31  |  11KB  |  416 lines

  1. /* xpmtoppm.c - read an X11 pixmap file and produce a portable pixmap
  2. **
  3. ** Copyright (C) 1991 by Jef Poskanzer.
  4. **
  5. ** Permission to use, copy, modify, and distribute this software and its
  6. ** documentation for any purpose and without fee is hereby granted, provided
  7. ** that the above copyright notice appear in all copies and that both that
  8. ** copyright notice and this permission notice appear in supporting
  9. ** documentation.  This software is provided "as is" without express or
  10. ** implied warranty.
  11. **
  12. ** Upgraded to support XPM version 3 by
  13. **   Arnaud Le Hors (lehors@mirsa.inria.fr)
  14. **   Tue Apr 9 1991
  15. **
  16. ** Rainer Sinkwitz sinkwitz@ifi.unizh.ch - 21 Nov 91:
  17. **  - Bug fix, no advance of read ptr, would not read 
  18. **    colors like "ac c black" because it would find 
  19. **    the "c" of "ac" and then had problems with "c"
  20. **    as color.
  21. **    
  22. **  - Now understands multword X11 color names
  23. **  
  24. **  - Now reads multiple color keys. Takes the color
  25. **    of the hightest available key. Lines no longer need
  26. **    to begin with key 'c'.
  27. **    
  28. **  - expanded line buffer to from 500 to 2048 for bigger files
  29. */
  30.  
  31. #include "ppm.h"
  32.  
  33. static void ReadXPMFile ARGS((FILE *stream, int *widthP, int *heightP,
  34.     int *ncolorsP, int *chars_per_pixelP, pixel **colorsP, int **dataP));
  35. static void getline ARGS((char *line, int size, FILE *stream));
  36.  
  37. /* number of xpmColorKeys */
  38. #define NKEYS 5
  39.  
  40. char *xpmColorKeys[] =
  41. {
  42.  "s",                    /* key #1: symbol */
  43.  "m",                    /* key #2: mono visual */
  44.  "g4",                    /* key #3: 4 grays visual */
  45.  "g",                    /* key #4: gray visual */
  46.  "c",                    /* key #5: color visual */
  47. };
  48.  
  49. int
  50. main(argc, argv)
  51.     int argc;
  52.     char *argv[];
  53.  
  54. {
  55.     FILE *ifp;
  56.     pixel *pixrow, *colors;
  57.     register pixel *pP;
  58.     int rows, cols, ncolors, chars_per_pixel, row;
  59.     register int col;
  60.     int *data;
  61.     register int *ptr;
  62.  
  63.     ppm_init(&argc, argv);
  64.  
  65.     if (argc > 2)
  66.     pm_usage("[xpmfile]");
  67.  
  68.     if (argc == 2)
  69.     ifp = pm_openr(argv[1]);
  70.     else
  71.     ifp = stdin;
  72.  
  73.     ReadXPMFile(
  74.         ifp, &cols, &rows, &ncolors, &chars_per_pixel, &colors, &data);
  75.  
  76.     pm_close(ifp);
  77.  
  78.     ppm_writeppminit(stdout, cols, rows, (pixval) PPM_MAXMAXVAL, 0);
  79.     pixrow = ppm_allocrow(cols);
  80.  
  81.     for (row = 0, ptr = data; row < rows; ++row) {
  82.     for (col = 0, pP = pixrow; col < cols; ++col, ++pP, ++ptr)
  83.         *pP = colors[*ptr];
  84.     ppm_writeppmrow(stdout, pixrow, cols, (pixval) PPM_MAXMAXVAL, 0);
  85.     }
  86.  
  87.     exit(0);
  88. }
  89.  
  90. #define MAX_LINE 2048
  91.  
  92. static
  93. void
  94. ReadXPMFile(stream, widthP, heightP, ncolorsP,
  95.         chars_per_pixelP, colorsP, dataP)
  96.     FILE *stream;
  97.     int *widthP;
  98.     int *heightP;
  99.     int *ncolorsP;
  100.     int *chars_per_pixelP;
  101.     pixel **colorsP;
  102.     int **dataP;
  103. {
  104.     char line[MAX_LINE], str1[MAX_LINE], str2[MAX_LINE];
  105.     char *t1;
  106.     char *t2;
  107.     int format, v, datasize;
  108.     int *ptr;
  109.     int *ptab;
  110.     register int i, j;
  111.     int flag;
  112.  
  113.     unsigned int curkey, key, highkey;    /* current color key */
  114.     unsigned int lastwaskey;        /* key read */
  115.     char curbuf[BUFSIZ];        /* current buffer */
  116.  
  117.     *widthP = *heightP = *ncolorsP = *chars_per_pixelP = format = -1;
  118.     flag = 0;                /* to avoid getting twice a line */
  119.  
  120.     /* First try to read as an XPM version 3 file */
  121.  
  122.     /* Read the header line */
  123.     getline(line, sizeof(line), stream);
  124.     if (sscanf(line, "/* %s */", str1) == 1
  125.     && !strncmp(str1, "XPM", 3)) {
  126.  
  127.     /* Read the assignment line */
  128.     getline(line, sizeof(line), stream);
  129.     if (strncmp(line, "static char", 11))
  130.         pm_error("error scanning assignment line", 0, 0, 0, 0, 0);
  131.  
  132.     /* Read the hints line */
  133.     getline(line, sizeof(line), stream);
  134.     /* skip the comment line if any */
  135.     if (!strncmp(line, "/*", 2)) {
  136.         while (!strstr(line, "*/"))
  137.         getline(line, sizeof(line), stream);
  138.         getline(line, sizeof(line), stream);
  139.     }
  140.     if (sscanf(line, "\"%d %d %d %d\",", widthP, heightP,
  141.            ncolorsP, chars_per_pixelP) != 4)
  142.         pm_error("error scanning hints line", 0, 0, 0, 0, 0);
  143.  
  144.     /* Allocate space for color table. */
  145.     if (*chars_per_pixelP <= 2) {
  146.         /* Up to two chars per pixel, we can use an indexed table. */
  147.         v = 1;
  148.         for (i = 0; i < *chars_per_pixelP; ++i)
  149.         v *= 256;
  150.         *colorsP = ppm_allocrow(v);
  151.     } else {
  152.         /* Over two chars per pixel, we fall back on linear search. */
  153.         *colorsP = ppm_allocrow(*ncolorsP);
  154.         ptab = (int *) malloc(*ncolorsP * sizeof(int));
  155.     }
  156.  
  157.     /* Read the color table */
  158.     for (i = 0; i < *ncolorsP; i++) {
  159.         getline(line, sizeof(line), stream);
  160.         /* skip the comment line if any */
  161.         if (!strncmp(line, "/*", 2))
  162.         getline(line, sizeof(line), stream);
  163.  
  164.         /* read the chars */
  165.         if ((t1 = index(line, '"')) == NULL)
  166.         pm_error("error scanning color table", 0, 0, 0, 0, 0);
  167.         else
  168.         t1++;
  169.         strncpy(str1, t1, *chars_per_pixelP);
  170.         str1[*chars_per_pixelP] = '\0';
  171.         t1++; t1++;
  172.  
  173.         v = 0;
  174.         for (j = 0; j < *chars_per_pixelP; ++j)
  175.         v = (v << 8) + str1[j];
  176.         /*
  177.          * read color keys and values 
  178.          */
  179.         curkey = 0; 
  180.         highkey = 1;
  181.         lastwaskey = 0;
  182.         t2 = t1;
  183.         while ( 1 ) {
  184.         for (t1=t2 ;; t1++)
  185.             if (*t1 != ' ' && *t1 != '    ')
  186.             break;
  187.         for (t2 = t1;; t2++)
  188.             if (*t2 == ' ' || *t2 == '    ' || *t2 == '"')
  189.             break;
  190.         if (t2 == t1) break;
  191.         strncpy(str2, t1, t2 - t1);
  192.         str2[t2 - t1] = '\0';
  193.             
  194.         if (!lastwaskey) {
  195.             for (key = 1; key < NKEYS + 1; key++)
  196.             if (!strcmp(xpmColorKeys[key - 1], str2))
  197.                 break;
  198.         } else 
  199.             key = NKEYS + 1;
  200.         if (key > NKEYS) {            /* append name */
  201.             if (!curkey) 
  202.             pm_error("error scanning color table", 0, 0, 0, 0, 0);
  203.             if (!lastwaskey) 
  204.             strcat(curbuf, " ");        /* append space */
  205.             strcat(curbuf, str2);        /* append buf */
  206.             lastwaskey = 0;
  207.         }
  208.         if (key <= NKEYS) {             /* new key */
  209.             if (curkey > highkey) {    /* flush string */
  210.             if (*chars_per_pixelP <= 2)
  211.                 /* Index into table. */
  212.                 (*colorsP)[v] = ppm_parsecolor(curbuf,
  213.                         (pixval) PPM_MAXMAXVAL);
  214.             else {
  215.                 /* Set up linear search table. */
  216.                 (*colorsP)[i] = ppm_parsecolor(curbuf,
  217.                         (pixval) PPM_MAXMAXVAL);
  218.                 ptab[i] = v;
  219.             }
  220.             highkey = curkey;
  221.             }
  222.             curkey = key;            /* set new key  */
  223.             curbuf[0] = '\0';        /* reset curbuf */
  224.             lastwaskey = 1;
  225.         }
  226.         if (*t2 == '"') break;
  227.         }
  228.         if (curkey > highkey) {
  229.         if (*chars_per_pixelP <= 2)
  230.             /* Index into table. */
  231.             (*colorsP)[v] = ppm_parsecolor(curbuf,
  232.                     (pixval) PPM_MAXMAXVAL);
  233.         else {
  234.             /* Set up linear search table. */
  235.             (*colorsP)[i] = ppm_parsecolor(curbuf,
  236.                     (pixval) PPM_MAXMAXVAL);
  237.             ptab[i] = v;
  238.         }
  239.         highkey = curkey;
  240.         }
  241.         if (highkey == 1) 
  242.         pm_error("error scanning color table", 0, 0, 0, 0, 0);
  243.     }
  244.     /* Read pixels. */
  245.     getline(line, sizeof(line), stream);
  246.     /* skip the comment line if any */
  247.     if (!strncmp(line, "/*", 2))
  248.         getline(line, sizeof(line), stream);
  249.  
  250.     } else {                /* try as an XPM version 1 file */
  251.  
  252.     /* Read the initial defines. */
  253.     for (;;) {
  254.         if (flag)
  255.         getline(line, sizeof(line), stream);
  256.         else
  257.         flag++;
  258.  
  259.         if (sscanf(line, "#define %s %d", str1, &v) == 2) {
  260.         if ((t1 = rindex(str1, '_')) == NULL)
  261.             t1 = str1;
  262.         else
  263.             ++t1;
  264.         if (!strcmp(t1, "format"))
  265.             format = v;
  266.         else if (!strcmp(t1, "width"))
  267.             *widthP = v;
  268.         else if (!strcmp(t1, "height"))
  269.             *heightP = v;
  270.         else if (!strcmp(t1, "ncolors"))
  271.             *ncolorsP = v;
  272.         else if (!strcmp(t1, "pixel"))
  273.             *chars_per_pixelP = v;
  274.         } else if (!strncmp(line, "static char", 11)) {
  275.         if ((t1 = rindex(line, '_')) == NULL)
  276.             t1 = line;
  277.         else
  278.             ++t1;
  279.         break;
  280.         }
  281.     }
  282.     if (format == -1)
  283.         pm_error("missing or invalid format", 0, 0, 0, 0, 0);
  284.     if (format != 1)
  285.         pm_error("can't handle XPM version %d", format, 0, 0, 0, 0);
  286.     if (*widthP == -1)
  287.         pm_error("missing or invalid width", 0, 0, 0, 0, 0);
  288.     if (*heightP == -1)
  289.         pm_error("missing or invalid height", 0, 0, 0, 0, 0);
  290.     if (*ncolorsP == -1)
  291.         pm_error("missing or invalid ncolors", 0, 0, 0, 0, 0);
  292.     if (*chars_per_pixelP == -1)
  293.         pm_error("missing or invalid chars_per_pixel", 0, 0, 0, 0, 0);
  294.     if (*chars_per_pixelP > 2)
  295.         pm_message("warning, chars_per_pixel > 2 uses a lot of memory"
  296.                ,0, 0, 0, 0, 0);
  297.  
  298.     /* If there's a monochrome color table, skip it. */
  299.     if (!strncmp(t1, "mono", 4)) {
  300.         for (;;) {
  301.         getline(line, sizeof(line), stream);
  302.         if (!strncmp(line, "static char", 11))
  303.             break;
  304.         }
  305.     }
  306.     /* Allocate space for color table. */
  307.     if (*chars_per_pixelP <= 2) {
  308.         /* Up to two chars per pixel, we can use an indexed table. */
  309.         v = 1;
  310.         for (i = 0; i < *chars_per_pixelP; ++i)
  311.         v *= 256;
  312.         *colorsP = ppm_allocrow(v);
  313.     } else {
  314.         /* Over two chars per pixel, we fall back on linear search. */
  315.         *colorsP = ppm_allocrow(*ncolorsP);
  316.         ptab = (int *) malloc(*ncolorsP * sizeof(int));
  317.     }
  318.  
  319.     /* Read color table. */
  320.     for (i = 0; i < *ncolorsP; ++i) {
  321.         getline(line, sizeof(line), stream);
  322.  
  323.         if ((t1 = index(line, '"')) == NULL)
  324.         pm_error("error scanning color table", 0, 0, 0, 0, 0);
  325.         if ((t2 = index(t1 + 1, '"')) == NULL)
  326.         pm_error("error scanning color table", 0, 0, 0, 0, 0);
  327.         if (t2 - t1 - 1 != *chars_per_pixelP)
  328.         pm_error("wrong number of chars per pixel in color table",
  329.              0, 0, 0, 0, 0);
  330.         strncpy(str1, t1 + 1, t2 - t1 - 1);
  331.         str1[t2 - t1 - 1] = '\0';
  332.  
  333.         if ((t1 = index(t2 + 1, '"')) == NULL)
  334.         pm_error("error scanning color table", 0, 0, 0, 0, 0);
  335.         if ((t2 = index(t1 + 1, '"')) == NULL)
  336.         pm_error("error scanning color table", 0, 0, 0, 0, 0);
  337.         strncpy(str2, t1 + 1, t2 - t1 - 1);
  338.         str2[t2 - t1 - 1] = '\0';
  339.  
  340.         v = 0;
  341.         for (j = 0; j < *chars_per_pixelP; ++j)
  342.         v = (v << 8) + str1[j];
  343.         if (*chars_per_pixelP <= 2)
  344.         /* Index into table. */
  345.         (*colorsP)[v] = ppm_parsecolor(str2,
  346.                            (pixval) PPM_MAXMAXVAL);
  347.         else {
  348.         /* Set up linear search table. */
  349.         (*colorsP)[i] = ppm_parsecolor(str2,
  350.                            (pixval) PPM_MAXMAXVAL);
  351.         ptab[i] = v;
  352.         }
  353.     }
  354.  
  355.     /* Read pixels. */
  356.     for (;;) {
  357.         getline(line, sizeof(line), stream);
  358.         if (!strncmp(line, "static char", 11))
  359.         break;
  360.     }
  361.     }
  362.     datasize = *widthP * *heightP;
  363.     *dataP = (int *) malloc(datasize * sizeof(int));
  364.     if (*dataP == 0)
  365.     pm_error("out of memory", 0, 0, 0, 0, 0);
  366.     i = 0;
  367.     ptr = *dataP;
  368.     for (;;) {
  369.     if (flag)
  370.         getline(line, sizeof(line), stream);
  371.     else
  372.         flag++;
  373.  
  374.     /* Find the open quote. */
  375.     if ((t1 = index(line, '"')) == NULL)
  376.         pm_error("error scanning pixels", 0, 0, 0, 0, 0);
  377.     ++t1;
  378.  
  379.     /* Handle pixels until a close quote or the end of the image. */
  380.     while (*t1 != '"') {
  381.         v = 0;
  382.         for (j = 0; j < *chars_per_pixelP; ++j)
  383.         v = (v << 8) + *t1++;
  384.         if (*chars_per_pixelP <= 2)
  385.         /* Index into table. */
  386.         *ptr++ = v;
  387.         else {
  388.         /* Linear search into table. */
  389.         for (j = 0; j < *ncolorsP; ++j)
  390.             if (ptab[j] == v)
  391.             goto gotit;
  392.         pm_error("unrecognized pixel in line \"%s\"", line,
  393.              0, 0, 0, 0);
  394.     gotit:
  395.         *ptr++ = j;
  396.         }
  397.         ++i;
  398.         if (i >= datasize)
  399.         return;
  400.     }
  401.     }
  402. }
  403.  
  404.  
  405. static void
  406. getline(line, size, stream)
  407.     char *line;
  408.     int size;
  409.     FILE *stream;
  410. {
  411.     if (fgets(line, MAX_LINE, stream) == NULL)
  412.     pm_error("EOF / read error", 0, 0, 0, 0, 0);
  413.     if (strlen(line) == MAX_LINE - 1)
  414.     pm_error("line too long", 0, 0, 0, 0, 0);
  415. }
  416.