home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / graphic / dwb / convert / display2.c next >
Text File  |  1990-05-30  |  21KB  |  745 lines

  1. /*************************************************************/
  2. /*                                                           */
  3. /*   DISPLAY                                                 */
  4. /*                                                           */
  5. /*   10/31/89  ver 1.02 - allow for new maxcol and maxrow    */
  6. /*             integers at front of temp file.  They are     */
  7. /*             scanned off & ignored, for now                */
  8. /*                                                           */
  9. /*   DISPLAY2                                                */
  10. /*                                                           */
  11. /*   05/07/90  Use TC's BGI and VGA256.BGI for SVGA support. */
  12. /*             The size of the image (as specified by        */
  13. /*             "D xres yres" in the DAT file) is no longer   */
  14. /*             ignored - it's now used to determine a        */
  15. /*             suitable SuperVGA mode.  (640x480x256 is a    */
  16. /*             good size, but remember that 640x480 takes    */
  17. /*             4+ times longer than 320x200 to calculate -   */
  18. /*             so get those math chips revved up.            */
  19. /*               Steve Enns                                  */
  20. /*                                                           */
  21. /*************************************************************/
  22.  
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <fcntl.h>
  26. #include <io.h>
  27. #include <sys\types.h>
  28. #include <sys\stat.h>
  29. #include <conio.h>
  30. #include <dos.h>
  31. #include <graphics.h>
  32.  
  33. #include "display2.h"
  34.  
  35. #define VERSION "\nDISPLAY v1.5 (IBM MCGA/VGA/SVGA)\nCopyright (C) 1989 J. Lowery/S. Enns  All rights reserved.\n\n"
  36.  
  37. struct {
  38.      int       curr;
  39.      int       fp;
  40.        } ifil[10];
  41.  
  42. static int     numfiles = 0;
  43. static int     colorstats[TMPCOLORS][2];
  44. static int     image[MAXCOL];
  45. static char    fname[40],outname[40],str[40];
  46. static int     usedColors;
  47. static int     giffile;
  48. static short   xRes, yRes;
  49.  
  50. /* 'ofil' must be accessable to gif output functions in another module */
  51.        int     ofil;
  52.  
  53. /* buffer for a single scan line */
  54. static scanlinetype linebuf;
  55.  
  56. /* GIF header mode byte definitions */
  57.  
  58. #define GLOBALCOLORMAP 0x80
  59. #define COLORRES       ((DEPTH-1) << 4)
  60. #define BITSPERPIXEL   (BITS-1)
  61.  
  62. /*
  63.  *   the following structures are odd lengths and mix byte- and
  64.  *   word-length objects, so MUST be packed on 1-byte boundaries,
  65.  *   or file operations break.
  66.  */
  67.  
  68. #pragma pack(1)
  69.  
  70. struct {
  71.      char signature[6];
  72.      int  screenWidth;
  73.      int  screenHeight;
  74.  
  75.      byte mode;
  76.      byte background;
  77.      byte empty;
  78.  
  79.      } gifHeader = { "GIF87a", 0,0,
  80.                      GLOBALCOLORMAP | COLORRES | BITSPERPIXEL, 0, 0 };
  81.  
  82.  
  83. struct {
  84.      char separator;
  85.      int  imageLeft;
  86.      int  imageTop;
  87.      int  imageWidth;
  88.      int  imageHeight;
  89.      byte mode;
  90.      byte codeSize;      /* this is actually part of the image data stream */
  91.  
  92.      } imageHeader = { ',', 0, 0, 0, 0, BITSPERPIXEL, BITS };
  93.  
  94. /* back to normal structure packing */
  95. #pragma pack()
  96.  
  97. /*
  98.  *   display write error, wait for operator acknowledge,
  99.  *   reset video & return.  This is used while video is in 320x200
  100.  *   mode.
  101.  */
  102.  
  103. int writeError()
  104. {
  105.      close( ofil );           /* close the file   */
  106.  
  107.      gotoxy( 16, 0 );
  108.      printf("Write error in file %s\n", outname);
  109.      printf("Press any key to exit...");
  110.      while (!kbhit())
  111.           ;
  112.      getch();
  113.      return( TRUE );
  114. }
  115.  
  116. int gifHdr()      /* create a GIF file from screen */
  117. {
  118.      byte colorValue[3];      /* a single rgb triplet */
  119.      int  i;
  120.  
  121.      /* write the header information */
  122.      if (write(ofil, (char *)&gifHeader, sizeof(gifHeader)) != sizeof(gifHeader))
  123.           return( writeError() );
  124.  
  125.      /* write the global color map   */
  126.      for (i=0; i<COLORS; i++)
  127.      {
  128.           /*
  129.            *   for each of our 256 possible colors,
  130.            *   map the color's 3 primary intesities (0..15) into
  131.            *   the gif color map color intensities (0..255).
  132.            *   Note that i==0 defines the MCGA border color.
  133.            */
  134.  
  135.       if (i < usedColors)
  136.           {
  137.                colorValue[2] = ((long)(colorstats[i][0] & 0x0F00) >> 4); /* blue  */
  138.                colorValue[1] = ((long)(colorstats[i][0] & 0x00F0) );     /* green */
  139.                colorValue[0] = ((long)(colorstats[i][0] & 0x000F) << 4 ); /* red   */
  140.           }
  141.           else
  142.           {
  143.                colorValue[0] = 0;
  144.                colorValue[1] = 0;
  145.                colorValue[2] = 0;
  146.           }
  147.  
  148.           if (write( ofil, colorValue, sizeof(colorValue)) != sizeof(colorValue))
  149.                return( writeError() );
  150.      }
  151.      /* write the image descriptor */
  152.      if (write(ofil, (char *)&imageHeader, sizeof(imageHeader)) != sizeof(imageHeader))
  153.           return( writeError() );
  154.  
  155.      return(0);       /* header complete, return ok */
  156. }
  157.  
  158.  
  159. char terminal[2] = { 0, ';' };     /* image terminator sequence */
  160.  
  161. int gifClose()
  162. {
  163.  
  164.      if (gifFlush())
  165.           return(TRUE);
  166.      if (write( ofil, terminal, sizeof( terminal )) != sizeof( terminal ))
  167.           return( writeError() );
  168.  
  169.      close( ofil );
  170.      return(FALSE);      /* no error */
  171. }
  172.  
  173. /* reset video mode, print error message and exit */
  174.  
  175. void error( msg )
  176. char *msg;
  177. {
  178.      textmode(LASTMODE);
  179.      printf( "ERROR: %s\n", msg );
  180.      exit( -1 );
  181. }
  182.  
  183. /* print error message and exit.  Used in 80-column text mode */
  184.  
  185. void usageExit( msg )
  186. char *msg;
  187. {
  188.      if (msg)
  189.           printf("ERROR: %s\n",msg);
  190.  
  191.      printf("\nUsage: display2 [-g outfile] infile [infile [...]] \n");
  192.      printf("\nWhere: -g       Creates GIF file from screen display");
  193.      printf("\n       outfile  GIF output file name.");
  194.      printf("\n       infile   Input DBW_Render .TMP file.\n");
  195.      printf("\nDisplays a DBW_Render output file, and optionally ");
  196.      printf("\nconverts it to Compuserve (tm) GIF format.\n\n");
  197.      exit(-1);
  198. }
  199.  
  200. read_scanline(pass,row)
  201. int pass,row;
  202. {
  203.      int i,j,x,val,good;
  204.  
  205.      if (pass < 2)
  206.      {    if ((row % 50) == 0)
  207.                printf("\nRow: %4d ",row);
  208.           printf(".");
  209.           fflush(stdout);
  210.      }
  211.  
  212.      good = 0;
  213.  
  214.      for (i = 0; i < numfiles && good == 0; i++)
  215.      {
  216.           while (ifil[i].curr < row)
  217.           {
  218.            if (read(ifil[i].fp,(char *)&ifil[i].curr,sizeof(int))!=sizeof(int))
  219.                {
  220.                     ifil[i].curr = 9999;
  221.                     continue;
  222.                }
  223.  
  224.            if (read(ifil[i].fp,(char *)linebuf[RED],(xRes/PPW)*sizeof(int))!=((xRes/PPW)*sizeof(int)))
  225.                {
  226.                     ifil[i].curr = 9999;
  227.                     continue;
  228.                }
  229.  
  230.            if (read(ifil[i].fp,(char *)linebuf[GREEN],(xRes/PPW)*sizeof(int))!=((xRes/PPW)*sizeof(int)))
  231.                {
  232.                     ifil[i].curr = 9999;
  233.                     continue;
  234.                }
  235.  
  236.            if (read(ifil[i].fp,(char *)linebuf[BLUE],(xRes/PPW)*sizeof(int))!=((xRes/PPW)*sizeof(int)))
  237.                {
  238.                     ifil[i].curr = 9999;
  239.                     continue;
  240.                }
  241.  
  242.            if (ifil[i].curr == row)
  243.                {
  244.                     good = 1;
  245.                     break;
  246.                }
  247.           }
  248.      }
  249.  
  250.     /* couldn't find this scan line in any file */
  251.  
  252.      if (good == 0)
  253.           return(0);
  254.  
  255.      x = 0;
  256.      for (i = 0; i < (xRes/PPW) /* WPSL */; i++)
  257.      {
  258.           for (j = 0; j < PPW; j++)
  259.           {
  260.           /*--- TMP file has red, green, then blue nibbles.  Palette
  261.                 needs them as blue (MSB), green, red (LSB) ----------*/
  262.  
  263.                val = (  ((linebuf[RED  ][i] >> (BPP * j)) & (MAXGRAY-1))               /* red   */
  264.                      + (((linebuf[GREEN][i] >> (BPP * j)) & (MAXGRAY-1)) <<  BPP)      /* green */
  265.                      + (((linebuf[BLUE ][i] >> (BPP * j)) & (MAXGRAY-1)) << (BPP*2))); /* blue  */
  266.  
  267.                val %= TMPCOLORS;
  268.  
  269.                if (pass == 1)      /* histogram count on pass 1 */
  270.                {
  271.                     if (colorstats[val][1] < 32767)
  272.                          colorstats[val][1]++;
  273.                }
  274.                else
  275.                     image[x++] = val;
  276.           }
  277.      }
  278.      return(1);
  279. }
  280.  
  281. /*
  282.  *   find the darkest color in colorstats[], and make it
  283.  *   colorstats[0], for use as a border color
  284.  */
  285.  
  286. getBackground()
  287. {
  288.      /* scan the color table for minimal distance to r,g,b = {0,0,0} */
  289.  
  290.      int i, j;
  291.      short best, dist;
  292.      short t0, t1;
  293.  
  294.      for ( i=0, best=0, dist=32000; i < usedColors; i++)
  295.      {
  296.           j = distance( colorstats[i][0], 0 );
  297.           if ( j < dist)
  298.           {
  299.                best = i;
  300.                dist = j;
  301.           }
  302.      }
  303.  
  304.      /* colorstats[0] gets darkest color for background */
  305.  
  306.      t0 = colorstats[ best ][ 0 ];
  307.      t1 = colorstats[ best ][ 1 ];
  308.      colorstats[ best ][ 0 ] = colorstats[ 0 ][ 0 ];
  309.      colorstats[ best ][ 1 ] = colorstats[ 0 ][ 1 ];
  310.      colorstats[ 0 ][ 0 ] = t0;
  311.      colorstats[ 0 ][ 1 ] = t1;
  312.  
  313.  
  314. }
  315.  
  316. int driver,mode;
  317.  
  318. int huge detectsvga(void)
  319. {
  320.     int found,defaultmode;
  321.  
  322.     int detect,smode;
  323.  
  324.     detectgraph(&detect,&smode);
  325.  
  326.     if ((detect==VGA) || (detect==MCGA))
  327.         return(0);
  328.     else
  329.         return(grError);
  330. }
  331.  
  332. void setrgb13h(unsigned int index,unsigned char red,unsigned char green,unsigned char blue)
  333. {
  334.    union REGS reg;
  335.  
  336.    reg.x.ax=0x1010;
  337.    reg.x.bx=index;
  338.    reg.h.ch=green; reg.h.cl=blue; reg.h.dh=red;
  339.    int86(0x10,®,®);
  340. }
  341.  
  342. void _Cdecl VGA256_driver(void);
  343.  
  344.  
  345. main(argc,argv)
  346. int        argc;
  347. char        **argv;
  348. {
  349.      int i, j, k;
  350.      short  gap;
  351.      short  t0, t1, prgb, crgb, cpix, ppix, maxdis;
  352.      char   *s;
  353.      char   errmsg[80];
  354.      byte   r,g,b;
  355.  
  356.      printf(VERSION);
  357.  
  358.      fname[0] = '\0';
  359.  
  360.      for (i=1; i<argc; i++)
  361.      {
  362.           if (*argv[i] == '-')
  363.           {
  364.                argv[i]++;
  365.  
  366.                if (toupper(*argv[i]) == 'G')
  367.                {
  368.                     /*
  369.                      *   the output filename may be part of the current
  370.                      *   argv, or may be the next, depending on exactly
  371.                      *   how the operator typed it.
  372.                      */
  373.  
  374.                     giffile = TRUE;
  375.                     argv[i]++;
  376.                     if (*argv[i] == '\0')    /* name isn't here   */
  377.                          i++;                /* try the next argv */
  378.  
  379.                     if (i<argc)
  380.                     {
  381.                          /*
  382.                           *   get the output filename, if present,
  383.                           *   leaving room for possible concatination
  384.                           *   of a filetype
  385.                           */
  386.                          strncpy( outname, argv[i], sizeof(outname)-5 );
  387.  
  388.                          /* if no filetype, default to .GIF */
  389.                          if ( strchr( outname, '.' ) == NULL )
  390.                               strcat( outname, ".GIF" );
  391.                     }
  392.                     else
  393.                          outname[0] = '\0';  /* no output filename */
  394.                }
  395.                else
  396.                {
  397.                     sprintf( errmsg, "unrecognized command line option: -%c",*argv[i]);
  398.                     usageExit( errmsg );
  399.                }
  400.           }
  401.           else
  402.           {
  403.                if (numfiles > 9)
  404.                     usageExit("too many input files supplied (9 max.)");
  405.  
  406.                strcpy( str, argv[i] );  /* filename into our temp buf */
  407.  
  408.                if ( strchr( str, '.' ) == NULL )  /* if no filetype */
  409.                     strcat( str, ".TMP" );        /* ..provide one  */
  410.  
  411.                ifil[numfiles].fp = open(str,O_RDONLY | O_BINARY,0);
  412.                if (ifil[numfiles].fp == -1)
  413.                {
  414.                     printf("ERROR: Can't find input file '%s'.",str);
  415.                     continue;
  416.                }
  417.                else
  418.                {    /*
  419.                      *   read and check the row, col spec
  420.                      *   if not 320x200, bail out.
  421.                      */
  422.                     if ( read(ifil[numfiles].fp, (char *)&xRes, sizeof( short ))
  423.                               != sizeof( short ) ||
  424.                          read(ifil[numfiles].fp, (char *)&yRes, sizeof( short ))
  425.                               != sizeof( short )  )
  426.                     {
  427.                          printf("ERROR: Can't read file '%s' - ignored.\n",str);
  428.                          continue;
  429.                     }
  430.  
  431. /*            if ( xRes != 320 || yRes != 200 )
  432.                     {
  433.                          printf("ERROR: %s is not a 320x200 MCGA data file - ignored\n",str);
  434.                          continue;
  435.                     }
  436. */
  437.            }
  438.  
  439.                ifil[numfiles].curr = -9999;
  440.                numfiles++;
  441.           }
  442.      }
  443.  
  444.      if (numfiles == 0)
  445.           usageExit( "no valid input file(s) specified." );
  446.  
  447.      if ( giffile && outname[0] == '\0' )
  448.           usageExit( "no GIF output filename specified." );
  449.  
  450.      if (giffile)
  451.      {
  452.           /* check to see if output file exists */
  453.           ofil = open(outname, O_RDONLY);
  454.           close( ofil );
  455.  
  456.           if (ofil != -1)          /* yes, warn them */
  457.           {
  458.                printf("Output file \"%s\" exists.  Replace it (y/N)? ",outname);
  459.                if (toupper(getch()) != 'Y')
  460.                     exit( -1 );       /* no further message, just exit */
  461.           }
  462.  
  463.           /* now, open it for real... */
  464.           ofil = open(outname, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC,
  465.                                   S_IREAD | S_IWRITE );
  466.           if (ofil == -1)
  467.                error( "can't create output file." );
  468.  
  469.           printf("\n");
  470.      }
  471.  
  472.      printf("Building a color histogram:\n");
  473.  
  474.      for (i = 0; i < TMPCOLORS; i++)
  475.      {
  476.           colorstats[i][0] = i;
  477.           colorstats[i][1] = 0;
  478.      }
  479.  
  480.      /* read through the input file list, building the color table */
  481.      for (i = 0; i < yRes; i++ )
  482.           read_scanline(1,i);
  483.  
  484.      printf("\n");
  485.  
  486.      /* reset the input file list */
  487.      for (i = 0; i < numfiles; i++)
  488.      {
  489.           lseek(ifil[i].fp,(long)(2*sizeof(int)),0);
  490.           ifil[i].curr = -9999;
  491.      }
  492.  
  493.      /*
  494.       *   we now sort the color table in descending order
  495.       *   of quantity of pixels of each color
  496.       */
  497.  
  498.      for (gap = TMPCOLORS/2; gap > 0; gap /=2)
  499.      {
  500.           for (i = gap; i < TMPCOLORS; i++)
  501.           {
  502.                for (j = i-gap;
  503.                      j >= 0 && colorstats[j][1] < colorstats[j+gap][1];
  504.                       j -= gap)
  505.                {
  506.                     t0                  = colorstats[j][0];
  507.                     t1                  = colorstats[j][1];
  508.                     colorstats[j][0]    = colorstats[j+gap][0];
  509.                     colorstats[j][1]    = colorstats[j+gap][1];
  510.                     colorstats[j+gap][0]= t0;
  511.             colorstats[j+gap][1]= t1;
  512.                }
  513.           }
  514.      }
  515.  
  516.      /* count colors with a population > 0 */
  517.      for (usedColors = 0 ;
  518.                usedColors < TMPCOLORS && colorstats[usedColors][1] > 0;
  519.                     usedColors++)
  520.           ;
  521.  
  522. /* debug ----------------
  523.      printf("post-sort - Colors:population \n\t");
  524.      for (i = 0; i < usedColors; i++)
  525.      {
  526.           printf("%03x:%05d ",colorstats[i][0],colorstats[i][1]);
  527.           if ((i % 7) == 7)
  528.                printf("\n\t");
  529.      }
  530.      printf("Press any key to continue...");
  531.      while (!kbhit())
  532.           ;
  533.      getch();
  534. -------------- debug */
  535.  
  536.      if (usedColors == 0)
  537.      {
  538.           error( "\nInput file error, no color data." );
  539.      }
  540.      else if (usedColors < COLORS)
  541.      {
  542.           printf("\n%d colors used\n",usedColors);
  543.      }
  544.      else
  545.      {
  546.           printf("\nMapping %d colors into %d\n", usedColors, COLORS);
  547.  
  548.           for (maxdis = 2; maxdis < (TMPCOLORS/4); maxdis *= 2)
  549.           {
  550.                for (i=usedColors/2; i < usedColors; i++)
  551.                {
  552.                     for (j = 0; j < i; j++)
  553.                     {
  554.                          if (distance(colorstats[i][0],colorstats[j][0]) < maxdis)
  555.                          {
  556.                               /* delete colorstat[i][] */
  557.                               for (k=i+1; k<usedColors; k++)
  558.                               {
  559.                                    colorstats[k-1][0] = colorstats[k][0];
  560.                                    colorstats[k-1][1] = colorstats[k][1];
  561.                               }
  562.                               --usedColors;
  563.                               --i;
  564.                               break;
  565.                          }
  566.                     }
  567.                     if (usedColors <= COLORS) break;
  568.                }
  569.                if (usedColors <= COLORS) break;
  570.           }
  571.      }
  572.  
  573.      /* set up to display the image */
  574.  
  575.      /*******         BGI        *******/
  576.  
  577.      driver=installuserdriver("VGA256",detectsvga);
  578.      if (graphresult()!=grOk)
  579.     error("Can't install BGI");
  580.  
  581.      if (registerbgidriver(VGA256_driver)<0)
  582.     error("VGA256 not linked!");
  583.  
  584.      driver=11;
  585.  
  586.      if ((xRes<=320)&&(yRes<=200))
  587.     mode=0;
  588.      else if ((xRes<=640)&&(yRes<=400))
  589.          mode=1;
  590.     else if ((xRes<=640)&&(yRes<=480))
  591.         mode=2;
  592.        else if ((xRes<=800)&&(yRes<=600))
  593.            mode=3;
  594.  
  595.      initgraph(&driver,&mode,getenv("BGIDIR"));
  596.  
  597.      if (graphresult()!=grOk)
  598.     error("Can't initialize graphics.");
  599.  
  600.      gifHeader.screenWidth=xRes;
  601.      gifHeader.screenHeight=yRes;
  602.  
  603.      imageHeader.imageWidth=xRes;
  604.      imageHeader.imageHeight=yRes;
  605.  
  606.      /* now set up the palette      */
  607.  
  608.      getBackground();    /* force darkest color to colorstats[0] */
  609.  
  610.      for (i = 0; i < usedColors; i++)
  611.      {
  612.       b = (long)(colorstats[i][0] & 0x0F00) >> 4;
  613.       g = (long)(colorstats[i][0] & 0x00F0) ;
  614.       r = (long)(colorstats[i][0] & 0x000F) << 4 ;
  615.       setrgb13h( i, r>>2,g>>2,b>>2);
  616.      }
  617.  
  618.      /* if a GIF file was requested, write the header here */
  619.  
  620.      if ( giffile && gifHdr())        /* GIF file is no good  */
  621.      {
  622.           exit( -1 );
  623.      }
  624.  
  625.     /* now figure out the pixels to display */
  626.  
  627.     cpix    = 0;
  628.     crgb    = colorstats[0][1];
  629.  
  630.     for (i = 0; i < yRes; i++)
  631.     {
  632.      /* check if there was an attempt to abort */
  633.  
  634.           if (kbhit() && getch() == 0x1B)    /* ESC? */
  635.                error( "ABORT at operator request.");
  636.  
  637.           if (read_scanline(2,i))
  638.           {
  639.            for (j = 0 ; j < xRes; j++)
  640.                {
  641.                     prgb = crgb;
  642.                     crgb = image[j];
  643.                     ppix = cpix;
  644.  
  645.                     if (j == 0)
  646.                          cpix = getrgbcolor(ppix,&crgb,-1);
  647.                     else
  648.                          cpix = getrgbcolor(ppix,&crgb,prgb);
  649.  
  650.                 /* display the computed pixel */
  651.  
  652.             putpixel( j, i, cpix );
  653.  
  654.                     if (giffile)             /* gif file? */
  655.                          if (gifPixel( cpix ))
  656.                          {
  657.                               exit( -1 );
  658.                          }
  659.                }
  660.           }
  661.           else if (giffile)
  662.           {
  663.                /* no line 'i' - write a dummy to the GIF output file */
  664.  
  665.                cpix = 0;      /* background */
  666.  
  667.            for (j = 0 ; j < xRes; j++)
  668.                     if (gifPixel( cpix ))
  669.                     {
  670.                          exit( -1 );
  671.                     }
  672.           }
  673.      }
  674.      printf("\n");
  675.  
  676.      if (giffile)             /* gif file is complete */
  677.           gifClose();         /* wrap it up           */
  678.  
  679.      /* wait here until we get a Return key hit */
  680.  
  681.      putch( 0x07 );      /* go "beep"   */
  682.      while (1)
  683.           if (kbhit() && getch() == 0x0D)
  684.                break;
  685.  
  686.      /* complete, return display to normal text mode */
  687.  
  688.      textmode( LASTMODE );
  689. }
  690.  
  691. /* get the next encoding for a pixel */
  692.  
  693. int getrgbcolor(ppix,crgb,prgb)
  694. int ppix, *crgb, prgb;
  695. {
  696.      short i,j,val,best,dist,nrgb;
  697.  
  698.      /* if same color, then return same as previous pixel */
  699.  
  700.      if (*crgb == prgb)
  701.           return((int)ppix);
  702.  
  703.      /* look for an exact match in the color table (or minimal distance) */
  704.  
  705.      for (i=0; i < usedColors; i++)
  706.      {
  707.           if (colorstats[i][0] == *crgb)
  708.                return (i);
  709.           if (i == 0)
  710.           {
  711.                best = 0;
  712.                dist = distance(colorstats[i][0],*crgb);
  713.           }
  714.           else if ((j=distance(colorstats[i][0],*crgb)) < dist)
  715.           {
  716.                best = i;
  717.                dist = j;
  718.           }
  719.      }
  720.  
  721.      /* do a best absolute */
  722.  
  723.      *crgb = colorstats[best][0];
  724.      return(best);
  725. }
  726.  
  727.  
  728. int distance(argb, brgb)
  729. int argb, brgb;
  730. {
  731.      short b,g,r;
  732.  
  733.      /* set up for comparisons */
  734.  
  735.      r = argb & (MAXGRAY-1);
  736.      g = (argb >> BPP) & (MAXGRAY-1);
  737.      b = (argb >> (BPP*2)) & (MAXGRAY-1);
  738.  
  739.      r -= brgb & (MAXGRAY-1);
  740.      g -= (brgb >> BPP) & (MAXGRAY-1);
  741.      b -= (brgb >> (BPP*2)) & (MAXGRAY-1);
  742.  
  743.      return((int)(r*r + g*g + b*b));
  744. }
  745.