ref: 02dddea65e3534fc7cbb101b62136e419718a2ab
author: sirjofri <sirjofri@sirjofri.de>
date: Sun Feb 15 08:00:36 EST 2026
adds subpixelize program
--- /dev/null
+++ b/Readme
@@ -1,0 +1,30 @@
+subpixelize image filter
+
+USAGE
+
+ subpixelize < input.bit > output.bit
+
+
+This program converts a grayscale image to a colored image that makes use of subpixels to add fine details.
+
+The program defines three levels of gray:
+
+- Black: < 64
+- Low: ≥ 64 and < 128
+- High: ≥ 128 and < 192
+- White: ≥ 192
+
+Depending on the surrounding two pixels (left and right), Low and High values will be replaced by colored pixels.
+
+
+BUGS
+
+Right now, the input image needs to have 3 or 4 channels (alpha is ignored/will be passed through). Single-channel images must be converted before use, e. g. using iconv.
+
+Only images with (mostly) pure black and (mostly) pure white areas are supported.
+
+Subpixelize supports only horizontal subpixels (RGB in a row).
+
+Some people don't like subpixels.
+
+The quality of the results isn't visually perfect and might need manual fixup.
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,10 @@
+</$objtype/mkfile
+
+BIN=/$objtype/bin
+TARG=subpixelize
+OFILES=subpixelize.$O
+
+</sys/src/cmd/mkone
+
+t:V: $O.out
+ $O.out < test.bit > testout.bit
--- /dev/null
+++ b/subpixelize.c
@@ -1,0 +1,191 @@
+#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);
+}
\ No newline at end of file
binary files /dev/null b/test.bit differ
--
⑨