ref: 90204e60f5b1e8fb734f99898e7128052b47d869
parent: bf1934aa4a1bbc6b13d8008c4a044a0d66dbadb7
author: phil9 <telephil9@gmail.com>
date: Wed Dec 7 04:07:27 EST 2022
add dither program to perform dithering using Floyd-Steinberg algorithm
--- a/README
+++ b/README
@@ -31,4 +31,9 @@
- gaussian: Gaussian blur using `-s` as the convolution kernel radius (ie kernel will be a matrix r*r with r=2*size+1)
- pixelate: a simple pixelation filter using `-s` argument as pixel size
+dither:
+-------
+Floyd-Steinberg dithering algorithm.
+
+Usage: dither
--- /dev/null
+++ b/dither.c
@@ -1,0 +1,91 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <memdraw.h>
+
+int
+clamp(int n)
+{
+ if(n < 0)
+ n = 0;
+ else if(n > 255)
+ n = 255;
+ return n;
+}
+
+uchar*
+dither(uchar *data, int w, int h, int depth)
+{
+#define P(X,Y,C) out[((X) + w*(Y))*depth + C]
+#define SETP(X,Y,C,E) out[((X) + w*(Y))*depth + C] = clamp(out[((X) + w*(Y))*depth + C] + E)
+ uchar *out;
+ int x, y, c, o, n, q;
+
+ out = malloc(depth*w*h*sizeof(uchar));
+ if(out == nil)
+ return nil;
+ for(y = 0; y < depth*w*h; y++)
+ out[y] = data[y];
+ for(y = 0; y < h; y++){
+ for(x = 0; x < w; x++){
+ for(c = 0; c < 3; c++){ /* B G R */
+ o = P(x, y, c);
+ n = 255*floor(o/255.0 + 0.5);
+ q = o - n;
+ P(x, y, c) = n;
+ if(x + 1 < w) SETP(x + 1, y , c, q * 7.0/16.0);
+ if(x - 1 >= 0 && y + 1 < h) SETP(x - 1, y + 1, c, q * 3.0/16.0);
+ if(y + 1 < h) SETP(x , y + 1, c, q * 5.0/16.0);
+ if(x + 1 < w && y + 1 < h) SETP(x + 1, y + 1, c, q * 1.0/16.0);
+ }
+ }
+ }
+ return out;
+#undef SETP
+#undef P
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s\n", argv0);
+ exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+ Memimage *o, *i;
+ int w, h, n;
+ uchar *buf, *out;
+
+ ARGBEGIN{
+ default:
+ usage();
+ break;
+ }ARGEND;
+ if(memimageinit()<0)
+ sysfatal("memimageinit: %r");
+ o = readmemimage(0);
+ if(o==nil)
+ sysfatal("readmemimage: %r");
+ i = allocmemimage(rectsubpt(o->r, o->r.min), XRGB32);
+ memimagedraw(i, i->r, o, o->r.min, nil, ZP, S);
+ freememimage(o);
+ w = Dx(i->r);
+ h = Dy(i->r);
+ n = 4*w*h*sizeof(uchar);
+ buf = malloc(n);
+ if(buf==nil)
+ sysfatal("malloc: %r");
+ if(unloadmemimage(i, i->r, buf, n)<0)
+ sysfatal("unloadmemimage: %r");
+ freememimage(i);
+ out = dither(buf, w, h, 4);
+ if(out == nil)
+ sysfatal("dither failed: %r");
+ print(" x8r8g8b8 %11d %11d %11d %11d ", 0, 0, w, h);
+ write(1, out, n);
+ exits(nil);
+}
+
--- a/mkfile
+++ b/mkfile
@@ -2,7 +2,7 @@
BIN=/$objtype/bin
CFLAGS=-FTVw
-TARG=cfilter blur
+TARG=cfilter blur dither
default:V: all