ref: fd5885e44a6599011679f70fb701280b77748992
dir: /subpixelize.c/
#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);
}