home *** CD-ROM | disk | FTP | other *** search
- /*
- NAME
- dither - routines to do Floyd-Steinberg dithering
-
- DESCRIPTION
- The assumption is that you have input values in the range
- minIn..maxIn that you want to reduce to the range
- minOut..maxOut. (For color images, you would dither each color
- component separately.)
-
- Dither a serpentine version of Floyd-Steinberg dithering. The
- skeleton code to use these routines is:
-
- DitherInit();
- onOddRow = FALSE;
- for (each row) {
- Dither(row, onOddRow);
- onOddRow = !onOddRow;
- }
- DitherTerm();
- */
-
- #include "jinclude.h"
- #include "jmemsys.h"
- #include "viewer.h"
- #include "hicolor.h"
- #include "dither.h"
-
-
- #define DInflateBase 15
-
- extern BYTE ColorLUT256[];
- /*
- NAME
- Dither - apply Floyd-Steinberg dithering to one row
-
- DESCRIPTION
- Adapted from the JPEG source code.
-
- Note that it is acceptable to have pIn == pOut, i.e., to do the
- dithering in place.
- */
-
- void
- Dither (
- DCtrlType * pCtrl, /* structure with control parameters */
- int *pIn, /* input values */
- int *pOut, /* output values */
- int onOddRow /* TRUE => current row is odd-numbered */
- )
- {
- int col; /* column counter */
- int dir; /* direction flag */
- int error; /* value of current error */
- int *nextRowErr; /* pointer to error buffer for next row */
- int *thisRowErr; /* pointer to error buffer for this row */
- ulong scale = pCtrl->scale;
- ulong invscale = pCtrl->invscale;
- int val; /* holds dithered value */
- int width = pCtrl->numCols;
-
- if (onOddRow)
- { /* work right to left in this row */
- pIn += width - 1;
- pOut += width - 1;
- dir = -1;
- thisRowErr = pCtrl->oddRowErrs + 1;
- nextRowErr = pCtrl->evenRowErrs + width;
- }
- else
- { /* work left to right in this row */
- dir = 1;
- thisRowErr = pCtrl->evenRowErrs + 1;
- nextRowErr = pCtrl->oddRowErrs + width;
- }
- nextRowErr[0] = 0; /* need only initialize this one entry */
- for (col = width; col > 0; col--)
- {
-
- /* get current value and adjust for accumulated error */
- val = ((*pIn) << 4) + thisRowErr[0]; /* errors are in units of 1/16 */
- if (val < 0)
- val = 0;
- else
- {
- val += 8; /* for rounding */
- val >>= 4;
- if (val > pCtrl->maxIn)
- val = pCtrl->maxIn;
- }
-
- /* reduce input value to dithered value */
- *pOut = (int) (pCtrl->minOut +
- ((scale * (val - pCtrl->minIn) + (1L << (DInflateBase - 1))) >> DInflateBase));
-
- /* calculate error (in units of 1/16 value) in dithered value */
- error = -(int) (pCtrl->minIn + (((*pOut - pCtrl->minOut) * invscale
- + (1L << (DInflateBase - 1))) >> DInflateBase) - val);
-
- /* store the error */
- val = 2 * error;
- nextRowErr[-1] = error; /* not +=, since not initialized yet */
- error += val; /* form error * 3 */
- nextRowErr[1] += error;
- error += val; /* form error * 5 */
- nextRowErr[0] += error;
- error += val; /* form error * 7 */
- thisRowErr[1] += error;
- pIn += dir;
- pOut += dir;
- thisRowErr += 1;
- nextRowErr -= 1;
- }
- }
-
- void
- DitherChar (
- DCtrlType * pCtrl, /* structure with control parameters */
- JSAMPLE *pIn, /* input values */
- JSAMPLE *pOut, /* output values */
- int onOddRow /* TRUE => current row is odd-numbered */
- )
- {
- int col; /* column counter */
- int dir; /* direction flag */
- int error; /* value of current error */
- int *nextRowErr; /* pointer to error buffer for next row */
- int *thisRowErr; /* pointer to error buffer for this row */
- ulong scale = pCtrl->scale;
- ulong invscale = pCtrl->invscale;
- int val; /* holds dithered value */
- int width = pCtrl->numCols;
-
- if (onOddRow)
- { /* work right to left in this row */
- pIn += width - 1;
- pOut += width - 1;
- dir = -1;
- thisRowErr = pCtrl->oddRowErrs + 1;
- nextRowErr = pCtrl->evenRowErrs + width;
- }
- else
- { /* work left to right in this row */
- dir = 1;
- thisRowErr = pCtrl->evenRowErrs + 1;
- nextRowErr = pCtrl->oddRowErrs + width;
- }
- nextRowErr[0] = 0; /* need only initialize this one entry */
- for (col = width; col > 0; col--)
- {
-
- /* get current value and adjust for accumulated error */
- val = ((ColorLUT256[GETJSAMPLE(*pIn)]) << 4) + thisRowErr[0]; /* errors are in units of 1/16 */
- if (val < 0)
- val = 0;
- else
- {
- val += 8; /* for rounding */
- val >>= 4;
- if (val > pCtrl->maxIn)
- val = pCtrl->maxIn;
- }
-
- /* reduce input value to dithered value */
- *pOut = (JSAMPLE) (pCtrl->minOut +
- ((scale * (val - pCtrl->minIn) + (1L << (DInflateBase - 1))) >> DInflateBase));
-
- /* calculate error (in units of 1/16 value) in dithered value */
- error = -(int) (pCtrl->minIn + (((*pOut - pCtrl->minOut) * invscale
- + (1L << (DInflateBase - 1))) >> DInflateBase) - val);
-
- /* store the error */
- val = 2 * error;
- nextRowErr[-1] = error; /* not +=, since not initialized yet */
- error += val; /* form error * 3 */
- nextRowErr[1] += error;
- error += val; /* form error * 5 */
- nextRowErr[0] += error;
- error += val; /* form error * 7 */
- thisRowErr[1] += error;
- pIn += dir;
- pOut += dir;
- thisRowErr += 1;
- nextRowErr -= 1;
- }
- }
-
- /*
- NAME
- DitherInit - initialize dither buffers and control parameters
-
- RETURN VALUES
- 0 if all OK
- 1 on error (probably insufficient memory)
- */
-
- int
- DitherInit (
- BYTE minIn, /* minimum input value */
- BYTE maxIn, /* maximum input value */
- BYTE minOut, /* minimum output value */
- BYTE maxOut, /* maximum output value */
- int numCols, /* number of columns in each row */
- DCtrlType * pCtrl /* structure with control parameters */
- )
- {
- pCtrl->minIn = minIn;
- pCtrl->maxIn = maxIn;
- pCtrl->minOut = minOut;
- pCtrl->maxOut = maxOut;
- pCtrl->numCols = numCols;
- pCtrl->scale = ((maxOut - minOut) << DInflateBase) / (maxIn - minIn);
- pCtrl->invscale = ((maxIn - minIn) << DInflateBase) / (maxOut - minOut);
- pCtrl->oddRowErrs = (int *) jget_small ((numCols + 2) * sizeof (int));
- if (pCtrl->oddRowErrs == NULL)
- return 1;
- memset (pCtrl->oddRowErrs, 0, (numCols + 2) * sizeof (int));
- pCtrl->evenRowErrs = (int *) jget_small ((numCols + 2) * sizeof (int));
- if (pCtrl->evenRowErrs == NULL)
- return 1;
- memset (pCtrl->evenRowErrs, 0, (numCols + 2) * sizeof (int));
- return 0;
- }
-
- /*
- NAME
- DitherTerm - clean up after dither operation
-
- DESCRIPTION
- Frees up memory used for error buffers.
- */
-
- void
- DitherTerm (
- DCtrlType * pCtrl /* structure with control parameters */
- )
- {
- jfree_small (pCtrl->oddRowErrs);
- jfree_small (pCtrl->evenRowErrs);
- }
-