home *** CD-ROM | disk | FTP | other *** search
/ AMIGA PD 1 / AMIGA-PD-1.iso / Programme_zum_Heft / Anwendungen / Kurztests / PBM / ILBMTOPPM.LHA / src / libfloyd.c < prev    next >
C/C++ Source or Header  |  1994-10-25  |  7KB  |  241 lines

  1. /* libfloyd.c - generic Floyd-Steinberg error distribution routines for PBMPlus
  2. **
  3. ** Copyright (C) 1994 Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
  4. **
  5. ** Permission to use, copy, modify, and distribute this software and its
  6. ** documentation for any purpose and without fee is hereby granted, provided
  7. ** that the above copyright notice appear in all copies and that both that
  8. ** copyright notice and this permission notice appear in supporting
  9. ** documentation.  This software is provided "as is" without express or
  10. ** implied warranty.
  11. */
  12.  
  13. #include "ppmfloyd.h"
  14.  
  15. static void fs_adjust ARGS((ppm_fs_info *fi, int col));
  16.  
  17.  
  18. ppm_fs_info *
  19. #if __STDC__
  20. ppm_fs_init(int cols, pixval maxval, int flags)
  21. #else
  22. ppm_fs_init(cols, maxval, flags)
  23.     int cols;
  24.     pixval maxval;
  25.     int flags;
  26. #endif
  27. {
  28.     ppm_fs_info *fi;
  29.     int i;
  30.  
  31.     if( (fi = (ppm_fs_info *)malloc(sizeof(ppm_fs_info))) &&
  32.         (fi->thisrederr   = (long *)malloc((cols+2) * sizeof(long))) &&
  33.         (fi->thisgreenerr = (long *)malloc((cols+2) * sizeof(long))) &&
  34.         (fi->thisblueerr  = (long *)malloc((cols+2) * sizeof(long))) &&
  35.         (fi->nextrederr   = (long *)malloc((cols+2) * sizeof(long))) &&
  36.         (fi->nextgreenerr = (long *)malloc((cols+2) * sizeof(long))) &&
  37.         (fi->nextblueerr  = (long *)malloc((cols+2) * sizeof(long))) ) {
  38.  
  39.         fi->lefttoright = 1;
  40.         fi->cols = cols;
  41.         fi->maxval = maxval;
  42.         fi->flags = flags;
  43.  
  44.         if( flags & FS_RANDOMINIT ) {
  45.             srandom((int)(time(0) ^ getpid()));
  46.             for( i = 0; i < cols +2; i++ ) {
  47.                 /* random errors in [-1..+1] */
  48.                 fi->thisrederr[i]   = random() % 32 - 16;
  49.                 fi->thisgreenerr[i] = random() % 32 - 16;
  50.                 fi->thisblueerr[i]  = random() % 32 - 16;
  51.             }
  52.         }
  53.         else {
  54.             for( i = 0; i < cols + 2; i++ )
  55.                 fi->thisrederr[i] = fi->thisgreenerr[i] = fi->thisblueerr[i] = 0;
  56.         }
  57.         return fi;
  58.     }
  59.     pm_error("out of memory allocating Floyd-Steinberg control structure");
  60. }
  61.  
  62.  
  63. void
  64. ppm_fs_free(fi)
  65.     ppm_fs_info *fi;
  66. {
  67.     if( fi ) {
  68.         free(fi->thisrederr); free(fi->thisgreenerr); free(fi->thisblueerr);
  69.         free(fi->nextrederr); free(fi->nextgreenerr); free(fi->nextblueerr);
  70.         free(fi);
  71.     }
  72. }
  73.  
  74.  
  75. int
  76. ppm_fs_startrow(fi, pixrow)
  77.     ppm_fs_info *fi;
  78.     pixel *pixrow;
  79. {
  80.     register int col;
  81.  
  82.     if( !fi )
  83.         return 0;
  84.  
  85.     fi->pixrow = pixrow;
  86.  
  87.     for( col = 0; col < fi->cols + 2; col++ )
  88.         fi->nextrederr[col] = fi->nextgreenerr[col] = fi->nextblueerr[col] = 0;
  89.  
  90.     if( fi->lefttoright ) {
  91.         fi->col_end = fi->cols;
  92.         col = 0;
  93.     }
  94.     else {
  95.         fi->col_end = -1;
  96.         col = fi->cols - 1;
  97.     }
  98.     fs_adjust(fi, col);
  99.     return col;
  100. }
  101.  
  102.  
  103. int
  104. ppm_fs_next(fi, col)
  105.     ppm_fs_info *fi;
  106.     int col;
  107. {
  108.     if( !fi )
  109.         ++col;
  110.     else {
  111.         if( fi->lefttoright )
  112.             ++col;
  113.         else
  114.             --col;
  115.         if( col == fi->col_end )
  116.             col = fi->cols;
  117.         else
  118.             fs_adjust(fi, col);
  119.     }
  120.     return col;
  121. }
  122.  
  123.  
  124. void
  125. ppm_fs_endrow(fi)
  126.     ppm_fs_info *fi;
  127. {
  128.     long *tmp;
  129.  
  130.     if( fi ) {
  131.         tmp = fi->thisrederr;   fi->thisrederr   = fi->nextrederr;   fi->nextrederr   = tmp;
  132.         tmp = fi->thisgreenerr; fi->thisgreenerr = fi->nextgreenerr; fi->nextgreenerr = tmp;
  133.         tmp = fi->thisblueerr;  fi->thisblueerr  = fi->nextblueerr;  fi->nextblueerr  = tmp;
  134.         if( fi->flags & FS_ALTERNATE )
  135.             fi->lefttoright = !(fi->lefttoright);
  136.     }
  137. }
  138.  
  139.  
  140. void
  141. ppm_fs_update(fi, col, pP)
  142.     ppm_fs_info *fi;
  143.     int col;
  144.     pixel *pP;
  145. {
  146.     if( fi )
  147.         ppm_fs_update3(fi, col, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP));
  148. }
  149.  
  150.  
  151. void
  152. #if __STDC__
  153. ppm_fs_update3(ppm_fs_info *fi, int col, pixval r, pixval g, pixval b)
  154. #else
  155. ppm_fs_update3(fi, col, r, g, b)
  156.     ppm_fs_info *fs;
  157.     int col;
  158.     pixval r, g, b;
  159. #endif
  160. {
  161.     register long rerr, gerr, berr, err;
  162.     int errcol = col+1;
  163.  
  164.     if( !fi )
  165.         return;
  166.  
  167.     rerr = (long)(fi->red)   - r;
  168.     gerr = (long)(fi->green) - g;
  169.     berr = (long)(fi->blue)  - b;
  170.  
  171.     if( fi->lefttoright ) {
  172.         register long two_err;
  173.  
  174.         two_err = 2*rerr;
  175.         err = rerr;     fi->nextrederr[errcol+1] += err;    /* 1/16 */
  176.         err += two_err; fi->nextrederr[errcol-1] += err;    /* 3/16 */
  177.         err += two_err; fi->nextrederr[errcol  ] += err;    /* 5/16 */
  178.         err += two_err; fi->thisrederr[errcol+1] += err;    /* 7/16 */
  179.  
  180.         two_err = 2*gerr;
  181.         err = gerr;     fi->nextgreenerr[errcol+1] += err;    /* 1/16 */
  182.         err += two_err; fi->nextgreenerr[errcol-1] += err;    /* 3/16 */
  183.         err += two_err; fi->nextgreenerr[errcol  ] += err;    /* 5/16 */
  184.         err += two_err; fi->thisgreenerr[errcol+1] += err;    /* 7/16 */
  185.  
  186.         two_err = 2*berr;
  187.         err = berr;     fi->nextblueerr[errcol+1] += err;    /* 1/16 */
  188.         err += two_err; fi->nextblueerr[errcol-1] += err;    /* 3/16 */
  189.         err += two_err; fi->nextblueerr[errcol  ] += err;    /* 5/16 */
  190.         err += two_err; fi->thisblueerr[errcol+1] += err;    /* 7/16 */
  191.     }
  192.     else {
  193.         register long two_err;
  194.  
  195.         two_err = 2*rerr;
  196.         err = rerr;     fi->nextrederr[errcol-1] += err;    /* 1/16 */
  197.         err += two_err; fi->nextrederr[errcol+1] += err;    /* 3/16 */
  198.         err += two_err; fi->nextrederr[errcol  ] += err;    /* 5/16 */
  199.         err += two_err; fi->thisrederr[errcol-1] += err;    /* 7/16 */
  200.  
  201.         two_err = 2*gerr;
  202.         err = gerr;     fi->nextgreenerr[errcol-1] += err;    /* 1/16 */
  203.         err += two_err; fi->nextgreenerr[errcol+1] += err;    /* 3/16 */
  204.         err += two_err; fi->nextgreenerr[errcol  ] += err;    /* 5/16 */
  205.         err += two_err; fi->thisgreenerr[errcol-1] += err;    /* 7/16 */
  206.  
  207.         two_err = 2*berr;
  208.         err = berr;     fi->nextblueerr[errcol-1] += err;    /* 1/16 */
  209.         err += two_err; fi->nextblueerr[errcol+1] += err;    /* 3/16 */
  210.         err += two_err; fi->nextblueerr[errcol  ] += err;    /* 5/16 */
  211.         err += two_err; fi->thisblueerr[errcol-1] += err;    /* 7/16 */
  212.     }
  213. }
  214.  
  215.  
  216. static void
  217. fs_adjust(fi, col)
  218.     ppm_fs_info *fi;
  219.     int col;
  220. {
  221.     register long r, g, b;
  222.     register pixel *pP;
  223.     int errcol = col+1;
  224.     pixval maxval = fi->maxval;
  225.  
  226.     pP = &(fi->pixrow[col]);
  227.  
  228.     /* Use Floyd-Steinberg errors to adjust actual color. */
  229.     r = fi->thisrederr  [errcol]; if( r < 0 ) r -= 8; else r += 8; r /= 16;
  230.     g = fi->thisgreenerr[errcol]; if( g < 0 ) g -= 8; else g += 8; g /= 16;
  231.     b = fi->thisblueerr [errcol]; if( b < 0 ) b -= 8; else b += 8; b /= 16;
  232.  
  233.     r += PPM_GETR(*pP); if ( r < 0 ) r = 0; else if ( r > maxval ) r = maxval;
  234.     g += PPM_GETG(*pP); if ( g < 0 ) g = 0; else if ( g > maxval ) g = maxval;
  235.     b += PPM_GETB(*pP); if ( b < 0 ) b = 0; else if ( b > maxval ) b = maxval;
  236.  
  237.     PPM_ASSIGN(*pP, r, g, b);
  238.     fi->red = r; fi->green = g; fi->blue = b;
  239. }
  240.  
  241.