shithub: subpixelize

ref: fd5885e44a6599011679f70fb701280b77748992
dir: /subpixelize.c/

View raw version
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>

void
usage(void)
{
	fprint(2, "usage: %s\n", argv0);
	exits("usage");
}

#define LOWVAL   (255/4)
#define HIGHVAL  (255/4*3)
#define LOW(A)   ((A) >= LOWVAL && (A) < 128)
#define HIGH(A)  ((A) < HIGHVAL && (A) >= 128)
#define BLACK(A)  ((A) < LOWVAL)
#define WHITE(A) ((A) >= HIGHVAL)

typedef enum {
	Equal,
	Low,
	High,
	Rise,
	Fall,
} Type;

int
getbyteval(uchar *val, int nchan)
{
	int v, i;
	
	v = 0;
	for (i = 0; i < nchan-1; i++)
		v += val[i];
	
	return v/i;
}

Type
checkrow(Memimage *src, Point p2, uchar *ival)
{
	Point p1, p3;
	int v1, v2, v3;
	
	p1 = p2;
	p3 = p2;
	p1.x--;
	p3.x++;
	
	if (!ptinrect(p1, src->r))
		return Equal;
	if (!ptinrect(p2, src->r))
		return Equal;
	if (!ptinrect(p3, src->r))
		return Equal;
	
	v1 = getbyteval(byteaddr(src, p1), src->nchan);
	v2 = getbyteval(byteaddr(src, p2), src->nchan);
	v3 = getbyteval(byteaddr(src, p3), src->nchan);
	
	*ival = v2;
	
	if (BLACK(v2) || WHITE(v2))
		return Equal;
	
	if (BLACK(v1) && BLACK(v3))
		return Low;
	if (WHITE(v1) && WHITE(v3))
		return High;
	if (BLACK(v1) && WHITE(v3))
		return Rise;
	if (WHITE(v1) && BLACK(v3))
		return Fall;
	if (BLACK(v1) &&   LOW(v3))
		return Rise;
	if (BLACK(v1) &&  HIGH(v3))
		return Rise;
	if ( HIGH(v1) && BLACK(v3))
		return Fall;
	if (  LOW(v1) && BLACK(v3))
		return Fall;
	
	fprint(2, "unhandled case! %3d %3d %3d\n", v1, v2, v3);
	return Equal;
}

void
handlepixel(Memimage *tgt, Memimage *src, Point p)
{
	uchar *t, *s;
	int i;
	Type tp;
	uchar ival;
	uchar col[4]; /* bgra */
	
	t = byteaddr(tgt, p);
	s = byteaddr(src, p);
	
	for (i = 0; i < tgt->nchan; i++) {
		t[i] = s[i];
	}
	
	tp = checkrow(src, p, &ival);
	
	if (tp == Equal)
		return;
	
	if (BLACK(ival))
		return;
	if (WHITE(ival)) /* considered white */
		return;
	
	/* green value */
	col[1] = LOW(ival) ? 0 : 255;
	
	col[3] = 255;
	switch (tp) {
	case Rise:
		//fprint(2, "case r √\n");
		col[0] = 255;
		col[2] =   0;
		goto Fill;
	case Fall:
		//fprint(2, "case f √\n");
		col[0] =   0;
		col[2] = 255;
		goto Fill;
	case High:
		//fprint(2, "case h √\n");
		col[0] = 255;
		col[1] = LOW(ival) ? 0 : 128;
		col[2] = 255;
		goto Fill;
	case Low:
		//fprint(2, "case l √\n");
		col[0] =   0;
		col[1] = LOW(ival) ? 128 : 255;
		col[2] =   0;
		goto Fill;
	}
	fprint(2, "should never happen!\n");
	return;
Fill:
	for (i = 0; i < tgt->nchan; i++) {
		t[i] = col[i];
	}
}

void
subpixelize(Memimage *tgt, Memimage *src)
{
	long x, y;
	
	for (y = tgt->r.min.y; y < tgt->r.max.y; y++)
		for (x = tgt->r.min.x; x < tgt->r.max.x; x++)
			handlepixel(tgt, src, Pt(x, y));
}

void
main(int argc, char **argv)
{
	Memimage *src;
	Memimage *tgt;
	
	ARGBEGIN{
	case 'h':
		usage();
		break;
	}ARGEND;
	
	if (memimageinit() < 0)
		sysfatal("%r");
	
	src = readmemimage(0);
	if (!src)
		sysfatal("readmemimage: %r");
	
	if (!(src->nchan == 3 || src->nchan == 4))
		sysfatal("unsupported chan");
	
	tgt = allocmemimage(src->r, src->chan);
	if (!tgt)
		sysfatal("allocmemimage: %r");
	memfillcolor(tgt, DTransparent);
	
	subpixelize(tgt, src);
	if (writememimage(1, tgt) < 0)
		sysfatal("writememimage");
	exits(nil);
}