about summary refs log tree commit diff
path: root/lib/libppmfloyd.c
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2006-08-19 03:12:28 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2006-08-19 03:12:28 +0000
commit1fd361a1ea06e44286c213ca1f814f49306fdc43 (patch)
tree64c8c96cf54d8718847339a403e5e67b922e8c3f /lib/libppmfloyd.c
downloadnetpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.tar.gz
netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.tar.xz
netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.zip
Create Subversion repository
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@1 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'lib/libppmfloyd.c')
-rw-r--r--lib/libppmfloyd.c270
1 files changed, 270 insertions, 0 deletions
diff --git a/lib/libppmfloyd.c b/lib/libppmfloyd.c
new file mode 100644
index 00000000..071c3c36
--- /dev/null
+++ b/lib/libppmfloyd.c
@@ -0,0 +1,270 @@
+/* 
+These functions were taken from Ingo Wilken's ilbm package by Bryan
+Henderson on 01.03.10.  Because ppmtoilbm and ilbmtoppm are the only
+programs that will use these in the foreseeable future, they remain
+lightly documented and tested. 
+
+But they look like they would be useful in other Netpbm programs that
+do Floyd-Steinberg.
+*/
+
+
+
+/* libfloyd.c - generic Floyd-Steinberg error distribution routines for PBMPlus
+**
+** Copyright (C) 1994 Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
+**
+** 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 "ppm.h"
+#include "ppmfloyd.h"
+#include "mallocvar.h"
+
+
+
+static void
+fs_adjust(ppm_fs_info * const fi, 
+          int           const col) {
+
+    int     const errcol = col+1;
+    pixel * const pP     = &(fi->pixrow[col]);
+    pixval  const maxval = fi->maxval;
+
+    long r, g, b;
+
+    /* Use Floyd-Steinberg errors to adjust actual color. */
+    r = fi->thisrederr  [errcol]; if( r < 0 ) r -= 8; else r += 8; r /= 16;
+    g = fi->thisgreenerr[errcol]; if( g < 0 ) g -= 8; else g += 8; g /= 16;
+    b = fi->thisblueerr [errcol]; if( b < 0 ) b -= 8; else b += 8; b /= 16;
+
+    r += PPM_GETR(*pP); if ( r < 0 ) r = 0; else if ( r > maxval ) r = maxval;
+    g += PPM_GETG(*pP); if ( g < 0 ) g = 0; else if ( g > maxval ) g = maxval;
+    b += PPM_GETB(*pP); if ( b < 0 ) b = 0; else if ( b > maxval ) b = maxval;
+
+    PPM_ASSIGN(*pP, r, g, b);
+    fi->red = r; fi->green = g; fi->blue = b;
+}
+
+
+
+static ppm_fs_info *
+allocateFi(int const cols) {
+
+    ppm_fs_info * fi;
+
+    MALLOCVAR(fi);
+    
+    if (fi != NULL) {
+        MALLOCARRAY(fi->thisrederr  , cols + 2);
+        MALLOCARRAY(fi->thisgreenerr, cols + 2);
+        MALLOCARRAY(fi->thisblueerr , cols + 2);
+        MALLOCARRAY(fi->nextrederr  , cols + 2);
+        MALLOCARRAY(fi->nextgreenerr, cols + 2);
+        MALLOCARRAY(fi->nextblueerr , cols + 2);
+        
+        if (fi->thisrederr   == NULL || 
+            fi->thisgreenerr == NULL || 
+            fi->thisblueerr  == NULL ||
+            fi->nextrederr   == NULL || 
+            fi->nextgreenerr == NULL || 
+            fi->nextblueerr  == NULL)
+            pm_error("out of memory allocating "
+                     "Floyd-Steinberg control structure");
+    } else
+        pm_error("out of memory allocating Floyd-Steinberg control structure");
+
+    return(fi);
+}
+
+
+
+ppm_fs_info *
+ppm_fs_init(int cols, pixval maxval, int flags) {
+
+    ppm_fs_info *fi;
+    
+    fi = allocateFi(cols);
+
+    fi->lefttoright = 1;
+    fi->cols = cols;
+    fi->maxval = maxval;
+    fi->flags = flags;
+    
+    if( flags & FS_RANDOMINIT ) {
+        unsigned int i;
+        srand((int)(time(0) ^ getpid()));
+        for( i = 0; i < cols +2; i++ ) {
+            /* random errors in [-1..+1] */
+            fi->thisrederr[i]   = rand() % 32 - 16;
+            fi->thisgreenerr[i] = rand() % 32 - 16;
+            fi->thisblueerr[i]  = rand() % 32 - 16;
+        }
+    }
+    else {
+        unsigned int i;
+
+        for( i = 0; i < cols + 2; i++ )
+            fi->thisrederr[i] = fi->thisgreenerr[i] = 
+                fi->thisblueerr[i] = 0;
+    }
+    return fi;
+}
+
+
+
+void
+ppm_fs_free(fi)
+    ppm_fs_info *fi;
+{
+    if( fi ) {
+        free(fi->thisrederr); free(fi->thisgreenerr); free(fi->thisblueerr);
+        free(fi->nextrederr); free(fi->nextgreenerr); free(fi->nextblueerr);
+        free(fi);
+    }
+}
+
+
+int
+ppm_fs_startrow(fi, pixrow)
+    ppm_fs_info *fi;
+    pixel *pixrow;
+{
+    register int col;
+
+    if( !fi )
+        return 0;
+
+    fi->pixrow = pixrow;
+
+    for( col = 0; col < fi->cols + 2; col++ )
+        fi->nextrederr[col] = fi->nextgreenerr[col] = fi->nextblueerr[col] = 0;
+
+    if( fi->lefttoright ) {
+        fi->col_end = fi->cols;
+        col = 0;
+    }
+    else {
+        fi->col_end = -1;
+        col = fi->cols - 1;
+    }
+    fs_adjust(fi, col);
+    return col;
+}
+
+
+int
+ppm_fs_next(fi, col)
+    ppm_fs_info *fi;
+    int col;
+{
+    if( !fi )
+        ++col;
+    else {
+        if( fi->lefttoright )
+            ++col;
+        else
+            --col;
+        if( col == fi->col_end )
+            col = fi->cols;
+        else
+            fs_adjust(fi, col);
+    }
+    return col;
+}
+
+
+void
+ppm_fs_endrow(fi)
+    ppm_fs_info *fi;
+{
+    long *tmp;
+
+    if( fi ) {
+        tmp = fi->thisrederr;   fi->thisrederr   = fi->nextrederr;   fi->nextrederr   = tmp;
+        tmp = fi->thisgreenerr; fi->thisgreenerr = fi->nextgreenerr; fi->nextgreenerr = tmp;
+        tmp = fi->thisblueerr;  fi->thisblueerr  = fi->nextblueerr;  fi->nextblueerr  = tmp;
+        if( fi->flags & FS_ALTERNATE )
+            fi->lefttoright = !(fi->lefttoright);
+    }
+}
+
+
+void
+ppm_fs_update(fi, col, pP)
+    ppm_fs_info *fi;
+    int col;
+    pixel *pP;
+{
+    if( fi )
+        ppm_fs_update3(fi, col, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP));
+}
+
+
+void
+ppm_fs_update3(ppm_fs_info * const fi, 
+               int           const col, 
+               pixval        const r, 
+               pixval        const g, 
+               pixval        const b) {
+
+    int const errcol = col + 1;
+    long err;
+
+    if (fi) {
+        long const rerr = (long)(fi->red)   - (long)r;
+        long const gerr = (long)(fi->green) - (long)g;
+        long const berr = (long)(fi->blue)  - (long)b;
+    
+        if ( fi->lefttoright ) {
+            long two_err;
+
+            two_err = 2*rerr;
+            err = rerr;     fi->nextrederr[errcol+1] += err;    /* 1/16 */
+            err += two_err; fi->nextrederr[errcol-1] += err;    /* 3/16 */
+            err += two_err; fi->nextrederr[errcol  ] += err;    /* 5/16 */
+            err += two_err; fi->thisrederr[errcol+1] += err;    /* 7/16 */
+
+            two_err = 2*gerr;
+            err = gerr;     fi->nextgreenerr[errcol+1] += err;    /* 1/16 */
+            err += two_err; fi->nextgreenerr[errcol-1] += err;    /* 3/16 */
+            err += two_err; fi->nextgreenerr[errcol  ] += err;    /* 5/16 */
+            err += two_err; fi->thisgreenerr[errcol+1] += err;    /* 7/16 */
+
+            two_err = 2*berr;
+            err = berr;     fi->nextblueerr[errcol+1] += err;    /* 1/16 */
+            err += two_err; fi->nextblueerr[errcol-1] += err;    /* 3/16 */
+            err += two_err; fi->nextblueerr[errcol  ] += err;    /* 5/16 */
+            err += two_err; fi->thisblueerr[errcol+1] += err;    /* 7/16 */
+        }
+        else {
+            long two_err;
+
+            two_err = 2*rerr;
+            err = rerr;     fi->nextrederr[errcol-1] += err;    /* 1/16 */
+            err += two_err; fi->nextrederr[errcol+1] += err;    /* 3/16 */
+            err += two_err; fi->nextrederr[errcol  ] += err;    /* 5/16 */
+            err += two_err; fi->thisrederr[errcol-1] += err;    /* 7/16 */
+
+            two_err = 2*gerr;
+            err = gerr;     fi->nextgreenerr[errcol-1] += err;    /* 1/16 */
+            err += two_err; fi->nextgreenerr[errcol+1] += err;    /* 3/16 */
+            err += two_err; fi->nextgreenerr[errcol  ] += err;    /* 5/16 */
+            err += two_err; fi->thisgreenerr[errcol-1] += err;    /* 7/16 */
+
+            two_err = 2*berr;
+            err = berr;     fi->nextblueerr[errcol-1] += err;    /* 1/16 */
+            err += two_err; fi->nextblueerr[errcol+1] += err;    /* 3/16 */
+            err += two_err; fi->nextblueerr[errcol  ] += err;    /* 5/16 */
+            err += two_err; fi->thisblueerr[errcol-1] += err;    /* 7/16 */
+        }
+    }
+}
+
+
+