This is dither.c in view mode; [Download] [Up]
/*
* This software is copyrighted as noted below. It may be freely copied,
* modified, and redistributed, provided that the copyright notice is
* preserved on all copies.
*
* There is no warranty or other guarantee of fitness for this software,
* it is provided solely "as is". Bug reports or fixes may be sent
* to the author, who may or may not act on them as he desires.
*
* You may not include this software in a program or other software product
* without supplying the source, or without informing the end-user that the
* source is available for no extra charge.
*
* If you modify this software, you should include a notice giving the
* name of the person performing the modification, the date of modification,
* and the reason for such modification.
*
* Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
* to have all "void" functions so declared.
*/
/*
* dither.c - Functions for RGB color dithering.
*
* Author: Spencer W. Thomas
* Computer Science Dept.
* University of Utah
* Date: Mon Feb 2 1987
* Copyright (c) 1987, University of Utah
*/
#include <math.h>
#ifdef USE_PROTOTYPES
void make_square( double, int [256], int [256], int [16][16] );
#else
void make_square();
#endif
static int magic4x4[4][4] = {
0, 14, 3, 13,
11, 5, 8, 6,
12, 2, 15, 1,
7, 9, 4, 10
};
/* basic dithering macro */
#define DMAP(v,x,y) (modN[v]>magic[x][y] ? divN[v] + 1 : divN[v])
/*****************************************************************
* TAG( dithermap )
*
* Create a color dithering map with a specified number of intensity levels.
* Inputs:
* levels: Intensity levels per primary.
* gamma: Display gamma value.
* Outputs:
* rgbmap: Generated color map.
* divN: "div" function for dithering.
* modN: "mod" function for dithering.
* Assumptions:
* rgbmap will hold levels^3 entries.
* Algorithm:
* Compute gamma compensation map.
* N = 255.0 / (levels - 1) is number of pixel values per level.
* Compute rgbmap with red ramping fastest, green slower, and blue
* slowest (treat it as if it were rgbmap[levels][levels][levels][3]).
* Call make_square to get divN, modN, and magic
*
* Note:
* Call dithergb( x, y, r, g, b, levels, divN, modN, magic ) to get index
* into rgbmap for a given color/location pair, or use
* row = y % 16; col = x % 16;
* DMAP(v,col,row) =def (divN[v] + (modN[v]>magic[col][row] ? 1 : 0))
* DMAP(r,col,row) + DMAP(g,col,row)*levels + DMAP(b,col,row)*levels^2
* if you don't want function call overhead.
*/
void
dithermap( levels, gamma, rgbmap, divN, modN, magic )
double gamma;
int rgbmap[][3];
int divN[256];
int modN[256];
int magic[16][16];
{
double N;
register int i;
int levelsq, levelsc;
int gammamap[256];
for ( i = 0; i < 256; i++ )
gammamap[i] = (int)(0.5 + 255 * pow( i / 255.0, 1.0/gamma ));
levelsq = levels*levels; /* squared */
levelsc = levels*levelsq; /* and cubed */
N = 255.0 / (levels - 1); /* Get size of each step */
/*
* Set up the color map entries.
*/
for(i = 0; i < levelsc; i++) {
rgbmap[i][0] = gammamap[(int)(0.5 + (i%levels) * N)];
rgbmap[i][1] = gammamap[(int)(0.5 + ((i/levels)%levels) * N)];
rgbmap[i][2] = gammamap[(int)(0.5 + ((i/levelsq)%levels) * N)];
}
make_square( N, divN, modN, magic );
}
/*****************************************************************
* TAG( bwdithermap )
*
* Create a color dithering map with a specified number of intensity levels.
* Inputs:
* levels: Intensity levels.
* gamma: Display gamma value.
* Outputs:
* bwmap: Generated black & white map.
* divN: "div" function for dithering.
* modN: "mod" function for dithering.
* Assumptions:
* bwmap will hold levels entries.
* Algorithm:
* Compute gamma compensation map.
* N = 255.0 / (levels - 1) is number of pixel values per level.
* Compute bwmap for levels entries.
* Call make_square to get divN, modN, and magic.
* Note:
* Call ditherbw( x, y, val, divN, modN, magic ) to get index into
* bwmap for a given color/location pair, or use
* row = y % 16; col = x % 16;
* divN[val] + (modN[val]>magic[col][row] ? 1 : 0)
* if you don't want function call overhead.
* On a 1-bit display, use
* divN[val] > magic[col][row] ? 1 : 0
*/
void
bwdithermap( levels, gamma, bwmap, divN, modN, magic )
double gamma;
int bwmap[];
int divN[256];
int modN[256];
int magic[16][16];
{
double N;
register int i;
int gammamap[256];
for ( i = 0; i < 256; i++ )
gammamap[i] = (int)(0.5 + 255 * pow( i / 255.0, 1.0/gamma ));
N = 255.0 / (levels - 1); /* Get size of each step */
/*
* Set up the color map entries.
*/
for(i = 0; i < levels; i++)
bwmap[i] = gammamap[(int)(0.5 + i * N)];
make_square( N, divN, modN, magic );
}
/*****************************************************************
* TAG( make_square )
*
* Build the magic square for a given number of levels.
* Inputs:
* N: Pixel values per level (255.0 / levels).
* Outputs:
* divN: Integer value of pixval / N
* modN: Integer remainder between pixval and divN[pixval]*N
* magic: Magic square for dithering to N sublevels.
* Assumptions:
*
* Algorithm:
* divN[pixval] = (int)(pixval / N) maps pixval to its appropriate level.
* modN[pixval] = pixval - (int)(N * divN[pixval]) maps pixval to
* its sublevel, and is used in the dithering computation.
* The magic square is computed as the (modified) outer product of
* a 4x4 magic square with itself.
* magic[4*k + i][4*l + j] = (magic4x4[i][j] + magic4x4[k][l]/16.0)
* multiplied by an appropriate factor to get the correct dithering
* range.
*/
void
make_square( N, divN, modN, magic )
double N;
int divN[256];
int modN[256];
int magic[16][16] ;
{
register int i, j, k, l;
double magicfact;
for ( i = 0; i < 256; i++ )
{
divN[i] = (int)(i / N);
modN[i] = i - (int)(N * divN[i]);
}
modN[255] = 0; /* always */
/*
* Expand 4x4 dither pattern to 16x16. 4x4 leaves obvious patterning,
* and doesn't give us full intensity range (only 17 sublevels).
*
* magicfact is (N - 1)/16 so that we get numbers in the matrix from 0 to
* N - 1: mod N gives numbers in 0 to N - 1, don't ever want all
* pixels incremented to the next level (this is reserved for the
* pixel value with mod N == 0 at the next level).
*/
magicfact = (N - 1) / 16.;
for ( i = 0; i < 4; i++ )
for ( j = 0; j < 4; j++ )
for ( k = 0; k < 4; k++ )
for ( l = 0; l < 4; l++ )
magic[4*k+i][4*l+j] =
(int)(0.5 + magic4x4[i][j] * magicfact +
(magic4x4[k][l] / 16.) * magicfact);
}
/*****************************************************************
* TAG( dithergb )
*
* Return dithered RGB value.
* Inputs:
* x: X location on screen of this pixel.
* y: Y location on screen of this pixel.
* r, g, b: Color at this pixel (0 - 255 range).
* levels: Number of levels in this map.
* divN, modN: From dithermap.
* magic: Magic square from dithermap.
* Outputs:
* Returns color map index for dithered pixelv value.
* Assumptions:
* divN, modN, magic were set up properly.
* Algorithm:
* see "Note:" in dithermap comment.
*/
dithergb( x, y, r, g, b, levels, divN, modN, magic )
int divN[256];
int modN[256];
int magic[16][16];
{
int col = x % 16, row = y % 16;
return DMAP(r, col, row) +
DMAP(g, col, row) * levels +
DMAP(b, col, row) * levels*levels;
}
/*****************************************************************
* TAG( ditherbw )
*
* Return dithered black & white value.
* Inputs:
* x: X location on screen of this pixel.
* y: Y location on screen of this pixel.
* val: Intensity at this pixel (0 - 255 range).
* divN, modN: From dithermap.
* magic: Magic square from dithermap.
* Outputs:
* Returns color map index for dithered pixel value.
* Assumptions:
* divN, modN, magic were set up properly.
* Algorithm:
* see "Note:" in bwdithermap comment.
*/
ditherbw( x, y, val, divN, modN, magic )
int divN[256];
int modN[256];
int magic[16][16];
{
int col = x % 16, row = y % 16;
return DMAP(val, col, row);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.