[net.graphics] 24bit -> 8 bit dithering algorithm

thomas@utah-gr.UUCP (Spencer W. Thomas) (10/15/84)

Here is a very simple dithering algorithm which will take a 24 bit full
color image and turn it into an 8 bit image with a fixed color lookup
table.  The author is {harpo,ihnp4,decvax}!utah-cs!utah-gr!kitaoka.  It
is presented here in terms of a complete program, but it should be easy
to extract the relevant code as a subroutine.  It produces amazingly
good images, considering the apparent coarseness of the approximation.

=Spencer

================================ cut here ================================
/*
 * cvt_aed512.c -- convert standard file format to aed format
 *
 * Author   Shoichi KITAOKA
 *          Computer Science Department
 *          University of Utah
 * Date     April 10 1984
 *
 * Copyright (c) 1984 Shoichi Kitaoka
 *--------------------------------------------------------------------
 *     Purpose of the program is convert 24bit images into 8bit image
 * without changing look up table on each images.
 * Basic idea is transform 0..255 value into 0..5 value for each RGB.
 * To randomize this procedure 4*4 threshold matrix (dither matrix)
 * is used.
 *--------------------------------------------------------------------
 *     USAGE : cvt_aed512 < *.std > *.aed
 * Here *.std means standard format image file which consists of
 * 512*480*24 bit data. (First 512 byte of Red value for first scanline comes
 * then 512 byte of Green value, 512 byte of Blue value, then next scanline
 * data and so on.)
 * *.aed means AED512 format data which actually 8bit/pixel image. (512*
 * 480*8 bit = 512*480 bytes)
 * Each byte of *.aed file means the look up table number.
 * Look up table value should be set up as following:
 *
 * (I assume look up each look up table can contain 8bit for each RGB.
 *  And SETC(n,r,g,b) means set n-th look up table with RGB value (r,g,b). )
 *
 *     for (i=0;i<6;i++)
 *         for (j=0;j<6;j++)
 *             for (k=0;k<6;k++)
 *             SETC (i+j*6+k*36,i*51,j*51,k*51) ;
 *-----------------------------------------------------------------------
 * Since this program assign 0..5 value for each RGB value, 216 look up
 * tables are used and 40 tables are not used.
 * Also since the look up table is fixed, if the original image has
 * some special tendency (ex. alomost all pixel is red.), only few of
 * look up tbale are used.
 *------------------------------------------------------------------------
 */

#include <stdio.h>
#define XMAX 512
#define YMAX 480

/* threshold matrix for coloe value 0..51  (255 / 5 = 51) */
int dm[4][4] = { 0 , 37 ,  9 , 47 ,
		25 , 12 , 35 , 22 ,
		 6 , 44 ,  3 , 41 ,
		31 , 19 , 28 , 16} ;

/* buffers for one scanline */
char image_red[512],image_gre[512],image_blu[512] ; /* original image */
char image_aed[512] ;  /* converted image */

/*----------------------------------------------------------------*/
main()
{
    int i,j ;

    for (i=0;i<YMAX;i++)
    {
        /* read original images */
	fread( image_red,sizeof(char),XMAX,stdin) ;
	fread( image_gre,sizeof(char),XMAX,stdin) ;
	fread( image_blu,sizeof(char),XMAX,stdin) ;

	/* convert */
	for (j=0;j<XMAX;j++)
	    image_aed[j] = dmap((short)image_red[j],j,i) +
			   dmap((short)image_gre[j],j,i) * 6 +
			   dmap((short)image_blu[j],j,i) * 36 ;

	/* output */
	fwrite( image_aed,sizeof(char),XMAX,stdout) ;
    }
}

/* get the 'randomized' value for the pixel(x,y) */
dmap(v,x,y)
    short v ;
    int x,y ;
{
    int d ;

    if (v<0) v += 256 ;
    d = dm[x%4][y%4] ;  /* threshold value */
    if ((v%51)>d) return (v/51)+1 ;
             else return (v/51) ;
}