home *** CD-ROM | disk | FTP | other *** search
- /*
- * flicker.c - display grayscale image with flicker mode
- *
- * modified for dl/gl files. pimg points to all the raw images and
- * nframes is the number of frames. no histogram stuff at all. handles
- * dl commands (which is a list of frame indices in order).
- *
- * note: I16 is 16 bit integer so we don't care what an "int" is
- * external to this routine. when u see 96000, it is really
- * 48000 * sizeof(I16). most things here are actually tuned to 16 bit
- * ints.
- *
- * now ansi for gcc. -mshort not needed.
- *
- * compilation control:
- * NEW_RANDOM def to use new random noise code
- * NO_INVERT def to invert pixel intensities (normally
- * undefined)
- */
-
- typedef short I16;
- typedef unsigned short UI16;
-
- #ifndef lint
- static char *rcsid = "$Id: flicker.c,v 1.3 1991/07/24 17:13:48 rosenkra Exp $";
- #endif
-
- /*
- * $Log: flicker.c,v $
- * Revision 1.3 1991/07/24 17:13:48 rosenkra
- * now RCS. fix flicker for SimpConv2Gray so image is not so dark. also
- * make sure last work in each pixel row gets dumped to screen when
- * using SimpConv2Gray (e.g. during cut or zoom).
- *
- * Revision 1.2 1991/07/16 23:24:48 rosenkra
- * released june 91 to usenet. first RCS revision.
- *
- */
-
- /*
- * this is for screen-switching on mono to simulate grayscale. it
- * uses a combination of floyd-steinberg and simulate "planes" which
- * get displayed each vblank. the image it works from should be
- * grayscale, i.e. each pixel is represented by an 8-bit (0 to 255)
- * intensity. since GIF images come with a color table, it is first
- * required to map each GIF pixel to the color table which has been
- * first changed to grayscale, either by averaging the rgb values
- * or by using the NTSC intensity equation.
- *
- * note that i think the f-s algorithm employed here sweeps each row
- * left to right rather than alternating directions. that is why there
- * is spurious info in areas otherwise supposed to be white.
- *
- * also, all points where chars are used in a calculation, they MUST
- * be unsigned.
- *
- * return ptr to screens.
- */
-
- /* written by Klaus Pedersen (micro@imada.dk) */
- /* modified by Bill Rosenkranz (rosenkra@convex.com) */
-
- #include <stdio.h>
- #include <types.h>
- #include <stdlib.h> /* for malloc */
- #include <string.h> /* for bzero */
- #include <osbind.h>
-
-
- #define LEVELS 4
- #define NUMERRS 1024
- #define SCRNSPACE 48256L /* now per frame */
- #define MAXFRAMES 25 /* 25 needs 2.4 MB (96000B/frame) */
-
-
- /*
- * globals.
- *
- * these are the thresholds for quantizing. 0,85,170,255 seem best
- */
- static I16 _Levels[LEVELS] = { 0, 85, 170, 255};
- static I16 _SimpLevels[LEVELS] = { 0, 255};
-
- static int _Show; /* print progress to stdout if !=0 */
- static int _Delay; /* ms delay between frames (if +ve) */
- static I16 _Nframes; /* number of frames in raster */
- static I16 _Ncommands; /* number of commands */
- static I16 _Width; /* image size */
- static I16 _Hight;
- static I16 _Beta; /* for the Laplace filter */
- static I16 _MaxRandom; /* for adding random noise */
- static I16 *_Err1, /* the error propagation arrays */
- *_Err2;
- static I16 _Err1Array[NUMERRS],
- _Err2Array[NUMERRS];
-
- static I16 *_Scrn, /* we malloc space here */
- *_Scrn1[MAXFRAMES],
- *_Scrn2[MAXFRAMES],
- *_Scrn3[MAXFRAMES];
-
-
-
- /*
- * local functions
- */
- static void _Conv2Gray (unsigned char *, int *);
- static void _SimpConv2Gray (unsigned char *, int *);
- static I16 _GenConvPix (unsigned char *, int, int);
- static I16 _SimpGenConvPix (unsigned char *, int, int);
- static I16 _Laplace (unsigned char *);
- static void _ClearErr (void);
- static I16 _Rand (I16);
-
-
-
-
- /*------------------------------*/
- /* dl_flicker */
- /*------------------------------*/
- int dl_flicker (unsigned char *pimg, int nframes, int width, int hight,
- int beta, int maxrandom, int opt, int delay, int *cmd,
- int ncommands, int show)
-
- /* pimg -> raster image sequence (intensities) */
- /* nframes number of frames in pimg */
- /* width width, pixels */
- /* hight height, pixels */
- /* beta for laplace filter */
- /* maxrandom for random noise */
- /* opt 0=no flicker, 1=flicker */
- /* delay ms delay between images */
- /* cmd -> commands (order to display frames) */
- /* ncommands number of commands (total frames in loop) */
- /* show print info to stdout if != 0 */
- {
-
- /*
- * this is the main entry point. complete grayscale raster image
- * comes from pimg with height and width specified. if beta != 0,
- * do Laplace filter with that beta. if maxrandom != 0, add some
- * random noise with that value (see below).
- *
- * pimg contains each basic frame in succession.
- *
- * dl commands are used. do this in loop showing the basic screens
- * by indexing into _Scrn* as _Scrn*[cmd[i]].
- *
- * return 0 if ok. 1 if error.
- */
-
-
-
- /*
- * set our globals
- */
- _Show = show;
- _Nframes = (I16) nframes; /* number of frames in raster */
- _Ncommands = (I16) ncommands; /* number of commands in animation */
- _Delay = delay; /* ms delay between frames */
- _Hight = (I16) hight; /* its height... */
- _Width = (I16) width; /* ...and width */
- _Beta = (I16) beta; /* Laplace filter coefficient */
- /* 1=0.25, 2=0.50, 3=0.75... (Try 4) */
- _MaxRandom = (I16) maxrandom; /* amount of random noise, 0-255 */
- /* for 0% to 100% noise. (Try 10) */
-
-
-
- /*
- * check nframes.
- */
- if (_Show)
- printf ("flicker: num frames = %d, max allowed = %d\n",
- _Nframes, MAXFRAMES);
- if (_Nframes > MAXFRAMES)
- _Nframes = MAXFRAMES;
-
-
-
- /*
- * allocate space for all screens. note that sizeof(I16) is 2.
- */
- if (opt)
- {
- if (_Show)
- printf ("flicker: allocating memory, flicker mode (%ld bytes)\n",
- 96000L * (long)_Nframes);
- _Scrn = (I16 *) malloc (96000 * (size_t) _Nframes + 256);
- }
- else
- {
- if (_Show)
- printf ("flicker: allocating memory, not flicker (%ld bytes)\n",
- 32000L * (long)_Nframes);
- _Scrn = (I16 *) malloc (32000 * (size_t) _Nframes + 256);
- }
- if (_Scrn == (I16 *) NULL)
- {
- if (_Show)
- printf ("flicker: memory allocation failed\n");
- return (1);
- }
-
-
-
- /*
- * make sure screen is aligned on 256-byte boundary.
- */
- _Scrn = (I16 *) (((long) _Scrn + 256L) & 0xFFFFFF00L);
-
-
-
- /*
- * clear screens. this may not have to be done if malloc clears
- * or if the dithering touches everything
- */
- if (_Show)
- printf ("flicker: clearing memory...\n");
- if (opt)
- bzero (_Scrn, (size_t) (96000 * _Nframes));
- else
- bzero (_Scrn, (size_t) (32000 * _Nframes));
-
-
-
- /*
- * do it!
- */
- if (opt)
- _Conv2Gray (pimg, cmd);
- else
- _SimpConv2Gray (pimg, cmd);
-
-
- return (0);
- }
-
-
-
-
- /*------------------------------*/
- /* _Conv2Gray */
- /*------------------------------*/
- static void _Conv2Gray (unsigned char *pic, int *cmd)
- {
- unsigned char *ppic;
- register int i;
- int j;
- register I16 x;
- I16 y;
- I16 w;
- I16 h;
- register long yoffset;
- I16 *TmpErr;
- register I16 q;
- I16 rover1;
- I16 rover2;
- register UI16 pix;
- unsigned char *p;
- char *old1;
- char *old2;
- int rpt;
- int done;
-
-
-
-
- /*
- * number of times to repeat inner display loop showing a single
- * frame. this is to deal with different frame rates. 40 ms for
- * three Setscreen/Vsync is about right on 8MHz ST...
- */
- rpt = _Delay / 40;
-
-
-
- /*
- * save old screen info
- */
- old1 = (char *) Logbase ();
- old2 = (char *) Physbase ();
-
-
-
- /*
- * clear...
- */
- if (_Show)
- printf ("flicker: clear screen...\n");
- bzero (old1, (size_t) 32000);
- bzero (old2, (size_t) 32000);
-
-
-
- /*
- * we will set physbase to our buffer and _Scrn1[0] points to it.
- * set the other screen pointers. _Scrn is a buffer large enuf
- * to hold all 3 screens for every frame. it would obviously be
- * more efficient to blit the images rather than store the entire
- * screen if the image is smaller than the entire screen.
- */
- _Scrn1[0] = _Scrn;
- _Scrn2[0] = _Scrn1[0] + 16000L;
- _Scrn3[0] = _Scrn2[0] + 16000L;
- for (i = 1; i < _Nframes; i++)
- {
- _Scrn1[i] = _Scrn3[i-1] + 16000L;
- _Scrn2[i] = _Scrn1[i] + 16000L;
- _Scrn3[i] = _Scrn2[i] + 16000L;
- }
-
-
-
- /*
- * we have to dither each frame so be patient...
- */
- for (ppic = pic, i = 0; i < _Nframes; i++, ppic += _Hight*_Width)
- {
- /*
- * monitor the progress of dithering.
- * set logbase to old physbase and physbase to first
- * screen buffer. we *should* never see logbase in the
- * displayed image since we never display logbase.
- */
- Setscreen (old2, (long) _Scrn1[i], -1); Vsync ();
-
-
- /*
- * first clear the error arrays
- */
- _ClearErr ();
-
-
- /*
- * initialize some things. yoffset positions us into each
- * screen which are int arrays. each scan line in the
- * screen is thus 40 words long.
- */
- yoffset = 0L;
- rover1 = 0;
- rover2 = 0;
-
-
- /*
- * loop over all rows in image
- */
- h = (_Hight > 400) ? 400 : _Hight;
- for (y = 1; y < h - 1; y++)
- {
- /*
- * set ptr to this pixel row
- */
- p = ppic + ((long) y * (long) _Width);
-
- /*
- * loop over all pixels in the row
- */
- w = (_Width > 640) ? 640 : _Width;
- for (x = 0; x < w - 1; x++)
- {
- pix = (0x8000 >> (x & 0x000f));
-
- /*
- * get new pixel value, with f-s error.
- * this is actually an index into the
- * _Levels array.
- */
- if (y & 1)
- q = _GenConvPix (p, (int) x, 0);
- else
- q = _GenConvPix (p, (int) x, 1);
-
-
- /*
- * set screen pixels based on this index
- */
- if (q == 1)
- {
- switch (rover1)
- {
- case 0:
- _Scrn1[i][yoffset + (x >> 4)] |= pix;
- rover1 = 1;
- rover2 = 1;
- break;
- case 1:
- _Scrn2[i][yoffset + (x >> 4)] |= pix;
- rover1 = 2;
- rover2 = 2;
- break;
- case 2:
- _Scrn3[i][yoffset + (x >> 4)] |= pix;
- rover1 = 0;
- rover2 = 0;
- break;
- }
- }
- else if (q == 2)
- {
- switch (rover2)
- {
- case 0:
- _Scrn1[i][yoffset + (x >> 4)] |= pix;
- _Scrn2[i][yoffset + (x >> 4)] |= pix;
- rover2 = 1;
- rover1 = 2;
- break;
- case 1:
- _Scrn2[i][yoffset + (x >> 4)] |= pix;
- _Scrn3[i][yoffset + (x >> 4)] |= pix;
- rover2 = 2;
- rover1 = 0;
- break;
- case 2:
- _Scrn1[i][yoffset + (x >> 4)] |= pix;
- _Scrn3[i][yoffset + (x >> 4)] |= pix;
- rover2 = 0;
- rover1 = 1;
- break;
- }
- }
- else if (q == 3)
- {
- _Scrn1[i][yoffset + (x >> 4)] |= pix;
- _Scrn2[i][yoffset + (x >> 4)] |= pix;
- _Scrn3[i][yoffset + (x >> 4)] |= pix;
- }
- }
-
-
- /*
- * get ready for next row by incrementing offset
- * into the screens (640 dots = 40 words)
- */
- yoffset += 40;
-
-
- /*
- * exchange error arrays
- */
- TmpErr = _Err1;
- _Err1 = _Err2;
- _Err2 = TmpErr;
-
-
- /*
- * check for early withdrawal...
- */
- if (Bconstat (2))
- {
- while (Bconstat (2))
- (void) Bconin (2);
- Setscreen ((long) old1, (long) old2, -1);
- return;
- }
- }
- }
-
-
-
- /*
- * now set screen to first image...
- */
- Setscreen (old2, (long) _Scrn, -1); Vsync ();
-
-
-
- /*
- * with that all done, now we can display the screens. only
- * phys screen is displayed (at next vblank). the Vsync waits
- * for the vblank. we display screens 1,2,3. any char stops the
- * loop.
- *
- * it goes like this ("screen" is the dithered flicker screen):
- *
- * frame cmd[0] screen 1
- * screen 2
- * screen 3
- * frame cmd[1] screen 1
- * screen 2
- * screen 3
- * ...
- *
- * show screens at speed. wait for keypress (which ends the loop)...
- */
- done = 0;
- do
- {
- /*
- * loop over commands. each cmd is a frame number.
- */
- for (i = 0; i < _Ncommands; i++)
- {
- /*
- * best way to do the delay seems to be display the
- * same frame in a loop then move to the next. the
- * trick is to find how long Setscreen/Vsync takes.
- */
- for (j = 0; j < rpt; j++)
- {
- Setscreen (old2, _Scrn1[cmd[i]], -1); Vsync ();
- Setscreen (old2, _Scrn2[cmd[i]], -1); Vsync ();
- Setscreen (old2, _Scrn3[cmd[i]], -1); Vsync ();
- }
- if (Bconstat (2))
- {
- done = 1;
- break;
- }
- }
-
- } while (!done);
-
-
-
-
- /*
- * reset screens back to what they were
- */
- Setscreen ((long) old1, (long) old2, -1);
-
-
-
- /*
- * clear any waiting keys...
- */
- while (Bconstat (2))
- (void) Bconin (2);
- }
-
-
-
-
- /*------------------------------*/
- /* _SimpConv2Gray */
- /*------------------------------*/
- static void _SimpConv2Gray (unsigned char *pic, int *cmd)
- {
-
- /*
- * I have also made a version of "Convert2Gray", that don't use
- * flicker - this allows the pictures to be saved, and used in windows,
- * and honest - the build-in test-picture looks as good, or even better,
- * without the flicker... (this is not true for any *real* pictures
- * that I have tested the program with). Here it is :
- */
-
- unsigned char *ppic;
- int i;
- int j;
- long x,
- y,
- yoffset,
- wordpos;
- I16 w,
- h;
- I16 *TmpErr;
- UI16 pix;
- unsigned char *p;
- char *old1;
- char *old2;
- int rpt;
- int done;
-
-
-
- /*
- * 15 ms for one Setscreen/Vsync is about right on 8MHz
- * ST...
- */
- rpt = _Delay / 15;
-
-
-
- /*
- * save old screen info
- */
- old1 = (char *) Logbase ();
- old2 = (char *) Physbase ();
-
-
-
- /*
- * clear...
- */
- if (_Show)
- printf ("flicker: clear screen...\n");
- bzero (old1, (size_t) 32000);
- bzero (old2, (size_t) 32000);
-
-
-
- /*
- * there is only one screen. we use existing physbase
- */
- _Scrn1[0] = _Scrn;
- for (i = 1; i < _Nframes; i++)
- {
- _Scrn1[i] = _Scrn1[i-1] + 16000L;
- }
-
-
-
- /*
- * we have to dither each frame so be patient...
- */
- for (ppic = pic, i = 0; i < _Nframes; i++, ppic += _Hight*_Width)
- {
- /*
- * monitor the progress of dithering.
- * set logbase to old physbase and physbase to first
- * screen buffer. we *should* never see logbase in the
- * displayed image since we never display logbase.
- */
- Setscreen (old2, (long) _Scrn1[i], -1); Vsync ();
-
-
-
- /*
- * first clear the error arrays
- */
- _ClearErr ();
-
-
- /*
- * yoffset positions us into the screen which is an int
- * arrays.each scan line in the screen is thus 40 words
- * long.
- */
- yoffset = 0;
- pix = 0;
-
-
- /*
- * loop over all rows in image
- */
- h = (_Hight > 400) ? 400 : _Hight;
- for (y = 1; y < h - 1; y++)
- {
- /*
- * set ptr to this pixel row
- */
- p = ppic + ((long) y * (long) _Width);
- wordpos = yoffset;
-
-
- /*
- * loop over all pixels in the row
- */
- w = (_Width > 640) ? 640 : _Width;
- for (x = 0L; x < w; x++)
- {
- pix <<= 1;
- if (_SimpGenConvPix (p, (int) x, 0))
- pix++;
- if ((x & 0x0f) == 0x0f)
- _Scrn1[i][wordpos++] = pix;
- }
-
-
- /*
- * clean up last word if any
- */
- if (w % 16)
- {
- int shft;
-
- shft = 16 - (w % 16);
- pix <<= shft;
- _Scrn1[i][wordpos++] = pix;
- }
-
-
- /*
- * get ready for next row by incrementing offset
- * into the screens (640 dots = 40 words)
- */
- yoffset += 40;
-
-
- /*
- * exchange error arrays
- */
- TmpErr = _Err1;
- _Err1 = _Err2;
- _Err2 = TmpErr;
-
-
- /*
- * check for early withdrawal...
- */
- if (Bconstat (2))
- {
- while (Bconstat (2))
- (void) Bconin (2);
- Setscreen ((long) old1, (long) old2, -1);
- return;
- }
- }
- }
-
-
-
- /*
- * now set screen to first image...
- */
- Setscreen (old2, (long) _Scrn, -1); Vsync ();
-
-
-
- /*
- * do it...
- */
- done = 0;
- do
- {
- /*
- * loop over commands. each cmd is a frame number.
- */
- for (i = 0; i < _Ncommands; i++)
- {
- /*
- * the best way to do the delay seems to display the
- * same frame in a loop then move to the next. the
- * trick is to find how long a Setscreen/Vsync
- * takes.
- */
- for (j = 0; j < rpt; j++)
- {
- Setscreen (old2, _Scrn1[cmd[i]], -1); Vsync ();
- }
- if (Bconstat (2))
- {
- done = 1;
- break;
- }
- }
-
- } while (!done);
-
-
-
- /*
- * reset screens back to what they were
- */
- Setscreen ((long) old1, (long) old2, -1);
-
-
-
- /*
- * clear any waiting keys...
- */
- while (Bconstat (2))
- (void) Bconin (2);
- }
-
-
-
-
- /*------------------------------*/
- /* _GenConvPix */
- /*------------------------------*/
- static I16 _GenConvPix (unsigned char *pic, int x, int opt)
-
- /* pic -> image pixel array */
- /* x the current pixel */
- /* opt 0=l to r, 1=r to l */
- {
-
- /*
- * This routine converts a point in the 'real' image to
- * a point in the screen image. The procedure uses error-
- * diffusion to determine the state of the new pixel.
- * The Error filter is that of Floyd & Steinberg :
- *
- * / 1 5 3 \ /
- * \ 7 X / / 16
- *
- * This rutine uses a table of levels to make the convertion.
- *
- * It returns the index for the pixel from the quantizing Level
- * array, i.e. the new pixel intensity is Level[i].
- */
-
- register I16 *p_levels;
- register I16 p;
- register I16 e;
- register I16 i;
- register I16 err;
- I16 lev = 0;
-
-
- p_levels = _Levels;
-
-
- #ifdef NEW_RANDOM
- /*
- The noise is here added to the picture, this means that the noise
- isn't cancled out again, and that is NOT intended, the noise should
- only act as some kind of *catalysator* (verb. is stolen from
- chemistry - something that start a reaction).
- */
-
- /*
- * first do the weighted average. _Err1 is the current line,
- * _Err2 is the previous line.
- */
- if (x == 0)
- {
- # ifdef NO_INVERT
- /*!!! next line was actually: */
-
- p = *pic;
-
- /*!!! but that inverted the image. it was assumed that 0xff
- was black. we insist that black is 0x00 (low intensity)*/
- # else /*!NO_INVERT*/
- p = 255 - *pic;
- # endif /*NO_INVERT*/
- }
- else if (_Beta)
- {
- p = ((7*_Err1[x - 1]
- + _Err2[x - 1] + 5*_Err2[x] + 3*_Err2[x + 1]) >> 4)
- + _Laplace (pic + x);
- }
- else
- {
- p = ((7*_Err1[x - 1]
- + _Err2[x - 1] + 5*_Err2[x] + 3*_Err2[x + 1]) >> 4)
- # ifdef NO_INVERT
- + *(pic + x);
- # else /*!NO_INVERT*/
- + (255 - *(pic + x));
- # endif /*NO_INVERT*/
- }
-
-
- /*
- * now calculate the residual errors
- */
- err = NUMERRS;
- for (i = 0; i < LEVELS; i++)
- {
- if (_MaxRandom)
- e = p + _Rand (_MaxRandom) - p_levels[i];
- else
- e = p - p_levels[i];
-
- if (e < 0)
- e = -e;
- if (e < err)
- {
- err = e;
- lev = (I16) i;
- }
- }
- _Err1[x] = p - p_levels[lev];
-
- #else /*!NEW_RANDOM*/
-
- if (x == 0)
- {
- # ifdef NO_INVERT
- p = *pic;
- # else /*!NO_INVERT*/
- p = 255 - *pic;
- # endif /*NO_INVERT*/
- }
- else if (_Beta)
- {
- if (_MaxRandom)
- p = ((7 * _Err1[x - 1] + _Err2[x - 1]
- + 5 * _Err2[x] + 3 * _Err2[x + 1]) >> 4)
- + _Laplace (pic + x) + _Rand (_MaxRandom);
- else
- p = ((7 * _Err1[x - 1] + _Err2[x - 1]
- + 5 * _Err2[x] + 3 * _Err2[x + 1]) >> 4)
- + _Laplace (pic + x);
- }
- else
- {
- if (_MaxRandom)
- {
- p = ((7 * _Err1[x - 1] + _Err2[x - 1]
- + 5 * _Err2[x] + 3 * _Err2[x + 1]) >> 4)
- # ifdef NO_INVERT
- + *(pic + x) + _Rand (_MaxRandom);
- # else /*!NO_INVERT*/
- + (255 - *(pic + x)) + _Rand (_MaxRandom);
- # endif /*NO_INVERT*/
- }
- else
- {
- p = ((7 * _Err1[x - 1] + _Err2[x - 1]
- + 5 * _Err2[x] + 3 * _Err2[x + 1]) >> 4)
- # ifdef NO_INVERT
- + *(pic + x);
- # else /*!NO_INVERT*/
- + (255 - *(pic + x));
- # endif /*NO_INVERT*/
- }
- }
- err = NUMERRS;
- for (i = 0; i < LEVELS; i++)
- {
- e = p - p_levels[i];
- if (e < 0)
- e = -e;
- if (e < err)
- {
- err = e;
- lev = (I16) i;
- }
- }
- _Err1[x] = p - p_levels[lev];
-
- #endif /*NEW_RANDOM*/
-
- return (lev);
- }
-
-
-
-
- /*------------------------------*/
- /* _SimpGenConvPix */
- /*------------------------------*/
- static I16 _SimpGenConvPix (unsigned char *pic, int x, int opt)
-
- /* pic -> image pixel array */
- /* x the current pixel */
- /* opt 0=l to r, 1=r to l */
- {
-
- /*
- * This version is for SimpConv2Gray. no laplace, no noise...
- *
- * This rutine converts a point in the 'real' image to
- * a point in the screen image. The procedure uses error-
- * diffusion to determine the state of the new pixel.
- * The Error filter is that of Floyd & Steinberg :
- *
- * / 1 5 3 \ /
- * \ 7 X / / 16
- *
- * This rutine uses a table of levels to make the convertion.
- *
- * It returns the index for the pixel from the quantizing Level
- * array, i.e. the new pixel intensity is Level[i].
- */
-
- register I16 *p_levels;
- register I16 p;
- register I16 e;
- register I16 i;
- register I16 err;
- I16 lev = 0;
-
-
- p_levels = _SimpLevels;
-
-
- /*
- * first do the weighted average. _Err1 is the current line,
- * _Err2 is the previous line.
- */
- if (x == 0)
- {
- # ifdef NO_INVERT
- /*!!! next line was actually: */
-
- p = *pic;
-
- /*!!! but that inverted the image. it was assumed that 0xff
- was black. we insist that black is 0x00 (low intensity)*/
- # else
- p = 255 - *pic;
- # endif
- }
- else
- {
- # ifdef NO_INVERT
- p = ((7*_Err1[x - 1]
- + _Err2[x - 1] + 5*_Err2[x] + 3*_Err2[x + 1]) >> 4)
- + *(pic + x);
- # else
- p = ((7*_Err1[x - 1]
- + _Err2[x - 1] + 5*_Err2[x] + 3*_Err2[x + 1]) >> 4)
- + (255 - *(pic + x));
- # endif
- }
-
-
- /*
- * now calculate the residual errors
- */
- err = NUMERRS;
- for (i = 0; i < 2; i++)
- {
- e = p - p_levels[i];
-
- if (e < 0)
- e = -e;
- if (e < err)
- {
- err = e;
- lev = i;
- }
- }
- _Err1[x] = p - p_levels[lev];
-
- return (lev);
- }
-
-
-
-
- /*------------------------------*/
- /* _Laplace */
- /*------------------------------*/
- static I16 _Laplace (unsigned char *Pic)
- {
-
- /*
- * this is a Laplacian filter, a simple edge detector/enhancer.
- *
- * -1
- * -1 4 -1
- * -1
- */
-
- register unsigned char *pc;
- register I16 lp;
- register I16 b;
- register I16 w;
-
-
- pc = Pic;
- b = _Beta;
- w = _Width;
-
-
-
- /*
- * if _Beta 0, formula reduces to just the pixel
- */
- #ifdef NO_INVERT
- if (b == 0)
- return ((I16) *pc);
-
- lp = (*pc << 2) /* this pixel */
- - *(pc - 1) - *(pc + 1) /* left/right */
- - *(pc + w) - *(pc - w); /* top/bottom */
- lp = ((b * lp) >> 2) + *pc;
- #else /*!NO_INVERT*/
- if (b == 0)
- return ((I16) (255 - *pc));
-
- lp = (255 - *pc) << 2; /* this pixel */
- lp -= (255 - *(pc - 1)); /* left/right */
- lp -= (255 - *(pc + 1));
- lp -= (255 - *(pc + w)); /* top/bottom */
- lp -= (255 - *(pc - w));
- lp = ((b * lp) >> 2);
- lp += (255 - *pc); /* self */
- #endif /*NO_INVERT*/
-
- /*
- * check limits and force result to 8 bits
- */
- if (lp < 0)
- lp = 0;
- if (lp > 255)
- lp = 255;
-
- return (lp);
- }
-
-
-
-
- /*------------------------------*/
- /* _ClearErr */
- /*------------------------------*/
- static void _ClearErr (void)
- {
- register int i;
- register I16 w;
- register I16 *pe1;
- register I16 *pe2;
-
-
- _Err1 = _Err1Array;
- _Err2 = _Err2Array;
-
- pe1 = _Err1Array;
- pe2 = _Err2Array;
- w = _Width;
- for (i = 0; i < w; i++)
- {
- *pe1++ = 0;
- *pe2++ = 0;
- }
- }
-
-
-
-
- /*------------------------------*/
- /* _Rand */
- /*------------------------------*/
- static I16 _Rand (I16 mx)
- {
-
- /*
- * returns random number 0 <= x < mx. no real need to initialize this.
- */
-
- static long Seed = 0;
-
- if (mx == 0)
- return (0);
-
- Seed += (Seed << 2) + 37;
- /* Seed &= 0x00007fffL;*/ /* should prevent overflow */
-
- return (((I16) Seed) % mx);
- }
-
-