home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume14 / ataritoppm / part01 / ppmtospu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-15  |  8.5 KB  |  570 lines

  1. #include <stdio.h>
  2.  
  3. /*
  4.  *  ppmtpspu.c - Reads a raw portable pixmap (ppm) file on stdin and
  5.  *  writes an uncompressed Spectrum file on stdout.
  6.  *
  7.  *  Copyright (C) 1990, Steve Belczyk
  8.  */
  9.  
  10. /* These are the palettes, 3 16-color palettes per each of 200
  11.    scan lines */
  12. int pal[200][48];
  13.  
  14. /* This is the ST's video RAM */
  15. short screen[16000];
  16.  
  17. /* This is the stuff to remember about each pixel */
  18. struct pixel_type
  19. {
  20.     int index4;     /* 4-bit color, used in bitmap */
  21.     int x;         /* Pixel's original x-position */
  22.     int pop;     /* Popularity of this pixel's color */
  23.     int color9;     /* 9-bit color this pixel actually got */
  24. } pixel[320];
  25.  
  26. int index48[320][16];    /* Indices into the 48 color entries */
  27.  
  28. /* Histogram for counting color occurences */
  29. int hist[512];        /* Count for each color */
  30.  
  31. /* RAWBITS flag */
  32. int rawbits;
  33.  
  34. /* Dithering flag */
  35. int dithflag = 2;
  36.  
  37. main (argc, argv)
  38. int argc;
  39. char *argv[];
  40. {
  41.     char magic[10];
  42.     int xres, yres, maxpix, y, i;
  43.  
  44.     /* Parse arguments */
  45.     for (i=1; i<argc; i++)
  46.     {
  47.         if (!strcmp (argv[i], "-d0"))
  48.         {
  49.             dithflag = 0;
  50.         }
  51.         else if (!strcmp (argv[i], "-d2"))
  52.         {
  53.             dithflag = 2;
  54.         }
  55.         else if (!strcmp (argv[i], "-d4"))
  56.         {
  57.             dithflag = 4;
  58.         }
  59.         else
  60.         {
  61.             fprintf (stderr,
  62.               "usage: %s <ppmfile >spufile [-d0|-d2|-d4]\n",
  63.               argv[0]);
  64.             exit (-1);
  65.         }
  66.     }
  67.  
  68.     /* Read ppm header, validate fields */
  69.     GetPPMHeader (magic, &xres, &yres, &maxpix);
  70.  
  71.     if ( (magic[0] != 'P') && (magic[0] != 'p') )
  72.     {
  73.         fprintf (stderr, "Not a ppm file.\n");
  74.         exit (-1);
  75.     }
  76.     if (magic[1] == '3')
  77.     {
  78.         rawbits = 0;
  79.     }
  80.     else if (magic[1] == '6')
  81.     {
  82.         rawbits = 1;
  83.     }
  84.     else
  85.     {
  86.         fprintf (stderr, "Not a ppm file.\n");
  87.         exit (-1);
  88.     }
  89.  
  90.     if ( (xres != 320) || (yres != 200) )
  91.     {
  92.         fprintf (stderr,
  93.             "Resolution must be 320x200. Sorry.\n");
  94.         exit (-1);
  95.     }
  96.  
  97.     /* Clear the bitmap */
  98.     for (i=0; i<16000; screen[i++]=0);
  99.  
  100.     /* Set up the index48 variables */
  101.     Setup48();
  102.  
  103.     /* Process each row */
  104.     for (y=0; y<200; y++)
  105.     {
  106.         DoRow (y);
  107.     }
  108.  
  109.     /* Write the SPU file */
  110.     WriteSPU();
  111. }
  112.  
  113. DoRow (r)
  114. int r;
  115. {
  116.     int i, j;
  117.     char row[320][3];
  118.  
  119.     /* First row is special */
  120.     if (r == 0)
  121.     {
  122.         for (i=0; i<320; i++)
  123.         {
  124.             /* Skip image data */
  125.             if (rawbits)
  126.             {
  127.                 getchar(); getchar(); getchar();
  128.             }
  129.             else
  130.             {
  131.                 scanf ("%d %d %d", &j, &j, &j);
  132.             }
  133.         }
  134.  
  135.         /* Set palettes to zero */
  136.         for (i=0; i<200; i++)
  137.         {
  138.             for (j=0; j<48; pal[i][j++]=0);
  139.         }
  140.  
  141.         /* Set first row of screen data to black */
  142.         for (i=0; i<80; screen[i++]=0);
  143.  
  144.         return;
  145.     }
  146.  
  147.     /* Else read the screen data */
  148.     for (i=0; i<320; i++)
  149.     {
  150.         for (j=0; j<3; j++)
  151.         {
  152.             if (rawbits)
  153.             {
  154.                 row[i][j] = getchar();
  155.             }
  156.             else
  157.             {
  158.                 scanf ("%d", &row[i][j]);
  159.             }
  160.         }
  161.     }
  162.  
  163.     /* Dither and reduce to 9 bits */
  164.     Dither (r, row);
  165.  
  166.     /* Compute the best colors for this row */
  167.     ComputePalette ();
  168.  
  169.     /* Convert this row */
  170.     ConvertRow (r);
  171. }
  172.  
  173. ComputePalette ()
  174. {
  175.     int i, j, c;
  176.  
  177.     /* Uses popularity algorithm */
  178.  
  179.     /* Clear the histogram */
  180.     for (i=0; i<512; i++)
  181.     {
  182.         hist[i] = 0;
  183.     }
  184.  
  185.     /* Count the occurences of each color */
  186.     for (i=0; i<320; i++)
  187.     {
  188.         hist[pixel[i].color9]++;
  189.     }
  190.  
  191.     /* Set the popularity of each pixel's color */
  192.     for (i=0; i<320; i++)
  193.     {
  194.         pixel[i].pop = hist[pixel[i].color9];
  195.     }
  196.  
  197.     /* Sort to find the most popular colors */
  198.     Sort (0, 319);
  199. }
  200.  
  201. Setup48 ()
  202. /*
  203.  *  For each pixel position, set up the indices into the 48-color
  204.  *  palette
  205.  */
  206. {
  207.     int i, j;
  208.  
  209.     for (j=0; j<320; j++)
  210.     {
  211.         for (i=0; i<16; i++)
  212.         {
  213.             index48[j][i] = FindIndex (j, i);
  214.         }
  215.     }
  216. }
  217.  
  218. int FindIndex (x, c)
  219. /*
  220.  *  Given an x-coordinate and a color index, returns the corresponding
  221.  *  Spectrum palette index.
  222.  */
  223. {
  224.     int r, x1;
  225.     
  226.     x1 = 10*c;
  227.     if (1&c)
  228.     {
  229.         x1 -= 5;
  230.     }
  231.     else
  232.     {
  233.         x1++;
  234.     }
  235.     r = c;
  236.     if ( (x >= x1) && (x < (x1+160)) ) r += 16;
  237.     if (x >= (x1+160)) r += 32;
  238.     
  239.     return (r);
  240. }
  241.  
  242. Dither (y, row)
  243. int y;
  244. char row[320][3];
  245. {
  246.     static int dith4[4][4] = { 0, 8, 2,10,
  247.                   12, 4,14, 6,
  248.                    3,11, 1, 9,
  249.                   15, 7,13, 5 };
  250.  
  251.     static int dith2[2][2] = { 0, 2,
  252.                    3, 1 };
  253.  
  254.     int c[3], i, x, t;
  255.  
  256.     for (x=0; x<320; x++)
  257.     {
  258.         for (i=0; i<3; i++)
  259.         {
  260.             c[i] = 7 & ((0xe0 & row[x][i]) >> 5);
  261.  
  262.             switch (dithflag)
  263.             {
  264.             case 0:    break;
  265.  
  266.             case 2:    t = (0x18 & row[x][i]) >> 3;
  267.                 if (t > dith2[x%2][y%2]) c[i]++;
  268.                 break;
  269.  
  270.             case 4:    t = (0x1e & row[x][i]) >> 1;
  271.                 if (t > dith4[x%4][y%4]) c[i]++;
  272.                 break;
  273.             }
  274.             if (c[i] > 7) c[i] = 7;
  275.         }
  276.         pixel[x].color9 = (c[0] << 6) | (c[1] << 3) | c[2];
  277.         pixel[x].x = x;
  278.     }
  279. }
  280.  
  281. int dist9 (x, y)
  282. int x, y;
  283. /*
  284.  *  Returns the distance between two 9-bit colors.
  285.  */
  286. {
  287.     int d, i, t, x0[3], y0[3];
  288.  
  289.     x0[0] = (x & 0x007);
  290.     x0[1] = (x & 0x038) >> 3;
  291.     x0[2] = (x & 0x1c0) >> 6;
  292.  
  293.     y0[0] = (y & 0x007);
  294.     y0[1] = (y & 0x038) >> 3;
  295.     y0[2] = (y & 0x1c0) >> 6;
  296.  
  297.     d = 0;
  298.  
  299.     for (i=0; i<3; i++)
  300.     {
  301.         t = x0[i] - y0[i];
  302.         d += t * t;
  303.     }
  304.  
  305.     return (d);
  306. }
  307.  
  308. ConvertRow (y)
  309. int y;
  310. {
  311.     int i;
  312.  
  313.     /* Mark palette entries as all free */
  314.     for (i=0; i<48; i++)
  315.     {
  316.         pal[y][i] = (-1);
  317.     }
  318.  
  319.     /* Mark reserved palette entries */
  320.     pal[y][0]  = pal[y][15] = pal[y][16] = 0;
  321.     pal[y][31] = pal[y][32] = pal[y][47] = 0;
  322.  
  323.     /* Convert each pixel */
  324.  
  325.     /* Process the pixels in order of the popularity of the
  326.        desired color */
  327.     for (i=319; i>=0; i--)
  328.     {
  329.         ConvertPixel (i, y);
  330.         SetPixel (pixel[i].x, y, pixel[i].index4);
  331.     }
  332. }
  333.  
  334. ConvertPixel (p, y)
  335. int p, y;
  336. {
  337.     int i, ifree, d, b, t, x, c;
  338.  
  339.     x = pixel[p].x;
  340.     c = pixel[p].color9;
  341.  
  342.     ifree = (-1);        /* Set if free slot found */
  343.  
  344.     /*
  345.      *  Handle each possible case, from easiest to hardest,
  346.      *  in the hopes the easy ones are more frequent.
  347.      */
  348.  
  349.     /* If it wants black, it gets it */
  350.     if (c == 0)
  351.     {
  352.         pixel[p].index4 = 0;
  353.         return;
  354.     }
  355.  
  356.     /* If another pixel is using this color, it gets it */
  357.     for (i=1; i<15; i++)
  358.     {
  359.         /* Check for free slots while we're here */
  360.         if ( (ifree < 0) &&
  361.              (pal[y][index48[x][i]] == (-1) ) )
  362.         {
  363.             ifree = i;
  364.         }
  365.         else if (c == pal[y][index48[x][i]])
  366.         {
  367.             pixel[p].index4 = i;
  368.             return;
  369.         }
  370.     }
  371.  
  372.     /* If there are no free slots, we must use the closest
  373.        entry in use so far */
  374.     if (ifree < 0)
  375.     {
  376.         d = 1000;
  377.         for (i=1; i<15; i++)
  378.         {
  379.             t = dist9 (c, pal[y][index48[x][i]]);
  380.             if (t < d)
  381.             {
  382.                 d = t;
  383.                 b = i;
  384.             }
  385.         }
  386.  
  387.         /* See if it would be better off with black */
  388.         if (d > dist9(c,0)) b = 0;
  389.  
  390.         pixel[p].index4 = b;
  391.         return;
  392.     }
  393.  
  394.     /* Else use up a slot and give it what it wants */
  395.     pal[y][index48[x][ifree]] = c;
  396.     pixel[p].index4 = ifree;
  397.  
  398.     return;
  399. }
  400.  
  401. WriteSPU ()
  402. {
  403.     int i, p, q, y;
  404.  
  405.     /* Write the bitmap */
  406.     WriteScreen();
  407.  
  408.     /* Write the palettes */
  409.     for (y=1; y<200; y++)
  410.     {
  411.         for (i=0; i<48; i++)
  412.         {
  413.             p = pal[y][i];
  414.             q = ( (p & 0x1c0) << 2) +
  415.                 ( (p & 0x038) << 1) +
  416.                   (p & 0x007);
  417.             putchar (0xff & (q >> 8));
  418.             putchar (q & 0xff);
  419.         }
  420.     }
  421. }
  422.  
  423. Sort (l, r)
  424. int l, r;
  425. /*
  426.  *  Good ol' Quicksort
  427.  */
  428. {
  429.     struct pixel_type x, w;
  430.     int i, j;
  431.     
  432.     i = l;
  433.     j = r;
  434.     x = pixel[(l+r)/2];
  435.     
  436.     do
  437.     {
  438.         while (pixel[i].pop < x.pop) i++;
  439.         while (x.pop < pixel[j].pop) j--;
  440.         
  441.         if (i <= j)
  442.         {
  443.             w = pixel[i];
  444.             pixel[i] = pixel[j];
  445.             pixel[j] = w;
  446.             i++;
  447.             j--;
  448.         }
  449.     } while (i <= j);
  450.     
  451.     if (l < j) Sort (l, j);
  452.     if (i < r) Sort (i, r);
  453. }
  454.  
  455. SetPixel (x, y, c)
  456. int x, y, c;
  457. {
  458.     int index, bit, plane;
  459.  
  460.     /* In the next few statements, the bit operations are a little
  461.        quicker, but the arithmetic versions are easier to read and
  462.        maybe more portable.  Please try swapping them if you have
  463.        trouble on your machine. */
  464.  
  465. /*    index = (80 * y) + 4 * (x / 16);    */
  466.     index = (y << 6) + (y << 4) + ((x >> 4) << 2);
  467.  
  468. /*    bit = 0x8000 >> (x % 16);    */
  469.     bit = 0x8000 >> (x & 0x0f);
  470.  
  471.     for (plane=0; plane<4; plane++)
  472.     {
  473.         if (c & (1 << plane))
  474.         {
  475.             screen[index+plane] |= bit;
  476.         }
  477.     }
  478. }
  479.  
  480. WriteScreen ()
  481. {
  482.     int i;
  483.     char c0, c1;
  484.  
  485.     for (i=0; i<16000; i++)
  486.     {
  487.         c0 = 0xff & (screen[i] >> 8);
  488.         c1 = 0xff & screen[i];
  489.         putchar (c0);
  490.         putchar (c1);
  491.     }
  492. }
  493.  
  494. GetString (s)
  495. char *s;
  496. {
  497.     int i;
  498.     char c;
  499.  
  500.     /* Skip leading white space */
  501.     do
  502.     {
  503.         c = GetChar();
  504.     } while ( (c == ' ') || (c == '\t') || (c == '\n') );
  505.  
  506.     /* Build string */
  507.     i = 0;
  508.     do
  509.     {
  510.         s[i++] = c;
  511.         if (i > 8) break;
  512.         c = GetChar();
  513.     } while ( (c != ' ') && (c != '\t') && (c != '\n') );
  514.  
  515.     s[i] = 0;
  516.     return;
  517. }
  518.  
  519. int GetChar()
  520. {
  521.     int c;
  522.  
  523.     c = getchar();
  524.  
  525.     if (c == EOF)
  526.     {
  527.         fprintf (stderr, "Premature EOF.\n");
  528.         exit (-1);
  529.     }
  530.  
  531.     do
  532.     {
  533.         if (c == '#')    /* Comment character */
  534.         {
  535.             do    /* Skip to end-of-line */
  536.             {
  537.                 c = getchar();
  538.                 if (c == EOF)
  539.                 {
  540.                     fprintf (stderr,
  541.                       "Premature EOF.\n");
  542.                     exit (-1);
  543.                 }
  544.             } while (c != '\n');
  545.  
  546.             c = getchar();
  547.         }
  548.     } while (c == '#');    /* In case there's another comment */
  549.  
  550.     return (c);
  551. }
  552.  
  553. GetPPMHeader (magic, xres, yres, maxpix)
  554. char *magic;
  555. int *xres, *yres, *maxpix;
  556. {
  557.     char s[10];
  558.  
  559.     GetString (magic);
  560.  
  561.     GetString (s);
  562.     *xres = atoi(s);
  563.  
  564.     GetString (s);
  565.     *yres = atoi(s);
  566.  
  567.     GetString (s);
  568.     *maxpix = atoi(s);
  569. }
  570.