home *** CD-ROM | disk | FTP | other *** search
- /*
- * floydstein.c -- perform Floyd-Steinberg dithering on an in-memory image.
- *
- * This is designed around the NeWS colour map and is for colour mapped
- * images. Beware.
- *
- * This code is based on ppmquant from Jef Poskanzer's PBM+ package which is
- *
- * Copyright (C) 1989 by Jef Poskanzer.
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for any purpose and without fee is hereby granted, provided
- * that the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation. This software is provided "as is" without express or
- * implied warranty.
- */
-
- #include <stdio.h>
- #include <malloc.h>
-
- #include "mem_image.h"
- #include "newsmap.h"
-
- long* long_alloc();
-
- unsigned char red[256], green[256], blue[256];
- unsigned short news_red[256];
- unsigned short news_green[256];
- unsigned short news_blue[256];
- long *thisrerr, *nextrerr, *thisgerr, *nextgerr, *thisberr, *nextberr;
- int fs_direction;
-
- void init_floydstein(img)
- struct mem_image* img;
- {
- register int col;
- #define FS_SCALE 1024
- int i;
-
- /* Build a local colour map for convenience */
- for (i = 0; i < img->maplen; i++) {
- red[i] = img->colourmap[i] & 255;
- green[i] = (img->colourmap[i] >> 8) & 255;
- blue[i] = (img->colourmap[i] >> 16) & 255;
- }
-
- for (i = 0; i < 256; i++)
- getmcolor(i, news_red + i, news_green + i, news_blue + i);
-
- /* Initialize Floyd-Steinberg error vectors. */
- thisrerr = long_alloc(img->width + 2);
- nextrerr = long_alloc(img->width + 2);
- thisgerr = long_alloc(img->width + 2);
- nextgerr = long_alloc(img->width + 2);
- thisberr = long_alloc(img->width + 2);
- nextberr = long_alloc(img->width + 2);
-
- srand((int)time(0));
-
- for (col = 0; col < img->width + 2; col++) {
- thisrerr[col] = rand() % (FS_SCALE * 2) - FS_SCALE;
- thisgerr[col] = rand() % (FS_SCALE * 2) - FS_SCALE;
- thisberr[col] = rand() % (FS_SCALE * 2) - FS_SCALE;
- /* (random errors in [-1 .. 1]) */
- }
- fs_direction = 1;
- }
-
- void floydstein(img, row)
- struct mem_image* img;
- int row;
- {
- register unsigned char* pP;
- int rows, cols;
- register int col, limitcol;
- long* temperr;
- register long sr, sg, sb;
- int r, g, b;
- #define FS_SCALE 1024
- int err;
- int i;
-
- for (col = 0; col < img->width + 2; col++)
- nextrerr[col] = nextgerr[col] = nextberr[col] = 0;
-
- if (fs_direction ) {
- col = 0;
- limitcol = img->width;
- pP = img->data + row * img->width;
- }
- else {
- col = img->width - 1;
- limitcol = -1;
- pP = img->data + row * img->width + img->width - 1;
- }
-
- do {
- /* Use Floyd-Steinberg errors to adjust actual color. */
- sr = red[*pP] * FS_SCALE + thisrerr[col + 1];
- sg = green[*pP] * FS_SCALE + thisgerr[col + 1];
- sb = blue[*pP] * FS_SCALE + thisberr[col + 1];
- r = sr / FS_SCALE; if (r < 0) r = 0; else if (r > 255) r = 255;
- g = sg / FS_SCALE; if (g < 0) g = 0; else if (g > 255) g = 255;
- b = sb / FS_SCALE; if (b < 0) b = 0; else if (b > 255) b = 255;
- /* just for fun, replace the previous 3 lines with these */
- /*r = (sr / FS_SCALE) & 255;
- g = (sg / FS_SCALE) & 255;
- b = (sb / FS_SCALE) & 255;*/
- *pP = rgb2newsmap(r, g, b);
-
- if (fs_direction) {
- err = sr - news_red[*pP] * FS_SCALE;
- thisrerr[col + 2] += ( err * 7 ) / 16;
- nextrerr[col ] += ( err * 3 ) / 16;
- nextrerr[col + 1] += ( err * 5 ) / 16;
- nextrerr[col + 2] += ( err ) / 16;
- err = sg - news_green[*pP] * FS_SCALE;
- thisgerr[col + 2] += ( err * 7 ) / 16;
- nextgerr[col ] += ( err * 3 ) / 16;
- nextgerr[col + 1] += ( err * 5 ) / 16;
- nextgerr[col + 2] += ( err ) / 16;
- err = sb - news_blue[*pP] * FS_SCALE;
- thisberr[col + 2] += ( err * 7 ) / 16;
- nextberr[col ] += ( err * 3 ) / 16;
- nextberr[col + 1] += ( err * 5 ) / 16;
- nextberr[col + 2] += ( err ) / 16;
- }
- else {
- err = sr - news_red[*pP] * FS_SCALE;
- thisrerr[col ] += ( err * 7 ) / 16;
- nextrerr[col + 2] += ( err * 3 ) / 16;
- nextrerr[col + 1] += ( err * 5 ) / 16;
- nextrerr[col ] += ( err ) / 16;
- err = sg - news_green[*pP] * FS_SCALE;
- thisgerr[col ] += ( err * 7 ) / 16;
- nextgerr[col + 2] += ( err * 3 ) / 16;
- nextgerr[col + 1] += ( err * 5 ) / 16;
- nextgerr[col ] += ( err ) / 16;
- err = sb - news_blue[*pP] * FS_SCALE;
- thisberr[col ] += ( err * 7 ) / 16;
- nextberr[col + 2] += ( err * 3 ) / 16;
- nextberr[col + 1] += ( err * 5 ) / 16;
- nextberr[col ] += ( err ) / 16;
- }
- if (fs_direction) {
- col++;
- pP++;
- }
- else {
- col--;
- pP--;
- }
- } while (col != limitcol);
-
- temperr = thisrerr;
- thisrerr = nextrerr;
- nextrerr = temperr;
- temperr = thisgerr;
- thisgerr = nextgerr;
- nextgerr = temperr;
- temperr = thisberr;
- thisberr = nextberr;
- nextberr = temperr;
- fs_direction = !fs_direction;
- }
-
- clean_floyd()
- {
- free(thisrerr);
- free(nextrerr);
- free(thisgerr);
- free(nextgerr);
- free(thisberr);
- free(nextberr);
- }
-
- long* long_alloc(n)
- int n;
- {
- long* l;
-
- l = (long*)malloc(n * sizeof(long));
-
- if (l == NULL)
- no_mem();
-
- return(l);
- }
-