shithub: ifilter

ref: 90204e60f5b1e8fb734f99898e7128052b47d869
dir: /dither.c/

View raw version
#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);
}