home *** CD-ROM | disk | FTP | other *** search
/ Photo CD Demo 1 / Demo.bin / fbm / src / flblue.c < prev    next >
C/C++ Source or Header  |  1990-06-24  |  6KB  |  221 lines

  1. /*****************************************************************
  2.  * flblue.c: FBM Release 1.0 25-Feb-90 Michael Mauldin
  3.  *
  4.  * Copyright (C) 1989,1990 by Michael Mauldin.  Permission is granted
  5.  * to use this file in whole or in part for any purpose, educational,
  6.  * recreational or commercial, provided that this copyright notice
  7.  * is retained unchanged.  This software is available to all free of
  8.  * charge by anonymous FTP and in the UUNET archives.
  9.  *
  10.  * flblue.c: Blue noise dithering
  11.  *
  12.  * CONTENTS
  13.  *    bluenoise_fbm (input, output, noiselevel)
  14.  *
  15.  * EDITLOG
  16.  *    LastEditDate = Mon Jun 25 00:04:47 1990 - Michael Mauldin
  17.  *    LastFileName = /usr2/mlm/src/misc/fbm/flblue.c
  18.  *
  19.  * HISTORY
  20.  * 25-Jun-90  Michael Mauldin (mlm@cs.cmu.edu) Carnegie Mellon
  21.  *    Package for Release 1.0
  22.  *
  23.  * 20-May-89  Michael Mauldin (mlm) at Carnegie Mellon University
  24.  *    Bug fix from Dave Cohrs <dave@cs.wisc.edu>
  25.  *
  26.  * 07-Mar-89  Michael Mauldin (mlm) at Carnegie Mellon University
  27.  *    Beta release (version 0.9) mlm@cs.cmu.edu
  28.  *
  29.  * 12-Nov-88  Michael Mauldin (mlm) at Carnegie-Mellon University
  30.  *    Created.
  31.  *****************************************************************/
  32.  
  33. # include <stdio.h>
  34. # include <math.h>
  35. # include <ctype.h>
  36. # include "fbm.h"
  37.  
  38. /*****************************************************************
  39.  * bluenoise_fbm:  Do Floyd-Steinberg halftoning with serpentine
  40.  *           raster and 'noiselevel' random weights.
  41.  *           (noise level runs from 0 to 100 percent)
  42.  *
  43.  * REFERENCES
  44.  *    Digital Halftoning, by Robert Ulichney (1986 MIT Press)
  45.  *****************************************************************/
  46.  
  47. # define RAND(RN) (((seed = 1103515245 * seed + 12345) >> 12) % (RN))
  48. # define INITERR(X,Y) \
  49.     (((int) X) - (((int) Y)?WHITE:BLACK) + ((WHITE/2)-((int) X))/2)
  50.  
  51. #ifndef lint
  52. static char *fbmid =
  53. "$FBM flblue.c <1.0> 25-Jun-90  (C) 1989,1990 by Michael Mauldin, source \
  54. code available free from MLM@CS.CMU.EDU and from UUNET archives$";
  55. #endif
  56.  
  57. bluenoise_fbm (input, output, noiselevel)
  58. FBM *input, *output;
  59. double noiselevel;
  60. { register unsigned char *bmp, *obm;
  61.   register unsigned seed = 0;
  62.   register int i, j, rowlen, gray, error, w, h, den, outrow;
  63.   int w1, w3, w5, w7, smrange, lgrange, smnoise, lgnoise;
  64.   int *eerr, *oerr;
  65.  
  66.   if (input->hdr.planes != 1)
  67.   { fprintf (stderr, "bluenoise_fbm: can't halftone color images\n");
  68.     return (0);
  69.   }
  70.  
  71.   fprintf (stderr, "Blue noise, %1.2lf%% weights\n", noiselevel);
  72.  
  73.   /* Allocate output */
  74.   free_fbm (output);
  75.   output->hdr = input->hdr;
  76.   output->hdr.bits = 1;
  77.   output->hdr.physbits = 8;
  78.   outrow = 16 * ((input->hdr.cols + 15) / 16); /* Pad to even byte boundary */
  79.   output->hdr.rowlen = outrow;
  80.   output->hdr.plnlen = outrow*output->hdr.rows;
  81.   alloc_fbm (output);
  82.  
  83.   w = input->hdr.cols;
  84.   h = input->hdr.rows;
  85.   rowlen = input->hdr.rowlen;
  86.   
  87.   /* Allocate space for error arrays */
  88.   eerr = (int *) malloc ((unsigned) w * sizeof (*eerr));
  89.   oerr = (int *) malloc ((unsigned) w * sizeof (*oerr));
  90.   for (i=0; i<w; i++) eerr[i] = oerr[i] = 0;
  91.  
  92.     /* The left border */
  93.   error = 0;
  94.   for (j=0; j<h; j++)
  95.   { register int thresh = (WHITE/2 + RAND (129) - 64);
  96.  
  97.     gray = input->bm[j*rowlen] + error;
  98.     den = gray > thresh ? WHITE : BLACK;
  99.     error = gray - den;
  100.     output->bm[j*outrow] = den;
  101.   }
  102.  
  103.   /* The right border */
  104.   error = 0;
  105.   for (j=0; j<h; j++)
  106.   { register int thresh = (WHITE/2 + RAND (129) - 64);
  107.  
  108.     gray = input->bm[j*rowlen + (w-1)] + error;
  109.     den = gray > thresh ? WHITE : BLACK;
  110.     error = gray - den;
  111.     output->bm[j*outrow + (w-1)] = den;
  112.   }
  113.  
  114.   /* The top border */
  115.   error = 0;
  116.   for (i=0; i<w; i++)
  117.   { register int inp = input->bm[i], thresh = (WHITE/2 + RAND (129) - 64);
  118.  
  119.     gray = inp + error;
  120.     den = gray > thresh ? WHITE : BLACK;
  121.     error = gray - den;
  122.     output->bm[i] = den;
  123.     eerr[i] = INITERR (inp, den);
  124.   }
  125.  
  126.   /*
  127.    * Now process the interior bits
  128.    *
  129.    *  Weights:            1+n1  5+n5  3-n1
  130.    *                7-n5    *
  131.    *
  132.    * n1 and n5 are random noise from -0.5 to 0.5 and -2.5 to 2.5
  133.    */
  134.    
  135.   smrange = 2000 * noiselevel/100.0; smrange += 1;
  136.   lgrange = 10000 * noiselevel/100.0; lgrange += 1;
  137.   
  138. # ifdef DEBUG
  139.   fprintf (stderr, "Blue noise level %6.2lf (small %d..%d, large %d..%d)\n",
  140.       noiselevel, -(smrange/2), smrange/2, -(lgrange/2), lgrange/2);
  141. # endif
  142.  
  143.   for (j=1; j<h; j++)
  144.   { bmp = &input->bm[j*rowlen];
  145.     obm = &output->bm[j*outrow];
  146.  
  147.     if (j&1)                /* Odd rows */
  148.     { oerr[0] = INITERR (bmp[0], obm[0]);
  149.  
  150.       for (i=1; i<w-1; i++)
  151.       { /* Set random weights */
  152.     w1 = 1000; w3 = 3000; w5 = 5000; w7 = 7000;
  153.   
  154.     smnoise = RAND (smrange) - smrange/2;
  155.     w1 += smnoise; w3 -= smnoise;
  156.   
  157.     lgnoise = RAND (lgrange) - lgrange/2;
  158.     w5 += lgnoise; w7 -= lgnoise;
  159.   
  160.     error =  (w1 * eerr[i-1] +
  161.           w5 * eerr[i] +
  162.           w3 * eerr[i+1] +
  163.           w7 * oerr[i-1]) / 16000;
  164.     gray = bmp[i] + error;
  165.   
  166. # ifdef DEBUG
  167.     if (j>10 && j<14 && i>40 && i<44)
  168.     { fprintf (stderr,
  169.            "\n<%3d,%3d> input %d, error %d\n",
  170.            i, j, bmp[i], error);
  171.       fprintf (stderr, "Noise {%d,%d} Weights {%d,%d,%d,%d}\n",
  172.            smnoise, lgnoise, w1, w3, w5, w7);
  173.       fprintf (stderr,
  174.            "Errs:\t%5d  %5d  %5d\n\t%5d      *\n",
  175.            eerr[i-1], eerr[i], eerr[i+1], oerr[i-1]);
  176.     }
  177. # endif
  178.  
  179.     if (gray > (WHITE/2))
  180.     { obm[i] = 1;    oerr[i] = gray - WHITE; }
  181.     else
  182.     { obm[i] = 0;    oerr[i] = gray; }
  183.       }
  184.       
  185.       /* Set errors for ends of this row */
  186.       oerr[0]   = INITERR (bmp[0], obm[0]);
  187.       oerr[w-1] = INITERR (bmp[w-1], obm[w-1]);
  188.     }
  189.     else
  190.     { eerr[w-1] = INITERR (bmp[w-1], obm[w-1]);
  191.  
  192.       for (i=w-2; i>0; i--)
  193.       { /* Set random weights */
  194.     w1 = 1000; w3 = 3000; w5 = 5000; w7 = 7000;
  195.   
  196.     smnoise = RAND (smrange) - smrange/2;
  197.     w1 += smnoise; w3 -= smnoise;
  198.   
  199.     lgnoise = RAND (lgrange) - lgrange/2;
  200.     w5 += lgnoise; w7 -= lgnoise;
  201.   
  202.     error =  (w1 * oerr[i+1] +
  203.           w5 * oerr[i] +
  204.           w3 * oerr[i-1] +
  205.           w7 * eerr[i+1]) / 16000;
  206.     gray = bmp[i] + error;
  207.   
  208.     if (gray > (WHITE/2))
  209.     { obm[i] = 1;    eerr[i] = gray - WHITE; }
  210.     else
  211.     { obm[i] = 0;    eerr[i] = gray; }
  212.       }
  213.  
  214.       /* Set errors for ends of this row */
  215.       eerr[0]   = INITERR (bmp[0], obm[0]);
  216.       eerr[w-1] = INITERR (bmp[w-1], obm[w-1]);
  217.     }
  218.   }
  219.   return (1);
  220. }
  221.