ref: 27ab378bba094b64ecd9e681ef30637cfbf3d9e8
parent: fd5885e44a6599011679f70fb701280b77748992
author: sirjofri <sirjofri@sirjofri.de>
date: Tue Mar 3 14:27:56 EST 2026
adds better subpixelize version. Adds sand.bit as a test case
--- a/README
+++ b/README
@@ -7,24 +7,27 @@
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:
+The program expects an image three times the size of the target image. Each group of 3x3 pixels will be converted to a single pixel that is composed out of the three subpixels.
-- Black: < 64
-- Low: ≥ 64 and < 128
-- High: ≥ 128 and < 192
-- White: ≥ 192
+It is possible to scale the value by using grayscale values. The subpixel will be filled with the average value of its column. For example, both
-Depending on the surrounding two pixels (left and right), Low and High values will be replaced by colored pixels.
+000 128 000
+000 128 000
+000 128 000
+and
-BUGS
+000 255 000
+000 128 000
+000 000 000
-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.
+will be converted to rgb(0, 128, 0).
-Only images with (mostly) pure black and (mostly) pure white areas are supported.
+BUGS
+
+The groups of 3x3 pixels need to be aligned to the grid.
+
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.
--- a/mkfile
+++ b/mkfile
@@ -7,4 +7,4 @@
</sys/src/cmd/mkone
t:V: $O.out
- $O.out < test.bit > testout.bit
+ $O.out < sand.bit > sandout.bit
binary files /dev/null b/sand.bit differ
--- a/subpixelize.c
+++ b/subpixelize.c
@@ -3,189 +3,68 @@
#include <draw.h>
#include <memdraw.h>
-void
-usage(void)
+static void
+transformpx(Memimage *src, Memimage *dst, Point p)
{- 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;
+ uchar *t;
+ uchar *s1, *s2, *s3;
+ uchar *s4, *s5, *s6;
+ uchar *s7, *s8, *s9;
- v = 0;
- for (i = 0; i < nchan-1; i++)
- v += val[i];
+ t = byteaddr(dst, p);
- return v/i;
-}
-
-Type
-checkrow(Memimage *src, Point p2, uchar *ival)
-{- Point p1, p3;
- int v1, v2, v3;
+ p.x *= 3;
+ p.y *= 3;
- p1 = p2;
- p3 = p2;
- p1.x--;
- p3.x++;
+ s1 = byteaddr(src, Pt(p.x , p.y ));
+ s2 = byteaddr(src, Pt(p.x+1, p.y ));
+ s3 = byteaddr(src, Pt(p.x+2, p.y ));
+ s4 = byteaddr(src, Pt(p.x , p.y+1));
+ s5 = byteaddr(src, Pt(p.x+1, p.y+1));
+ s6 = byteaddr(src, Pt(p.x+2, p.y+1));
+ s7 = byteaddr(src, Pt(p.x , p.y+2));
+ s8 = byteaddr(src, Pt(p.x+1, p.y+2));
+ s9 = byteaddr(src, Pt(p.x+2, p.y+2));
- 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;
+ t[2] = (*s1 + *s4 + *s7) / 3;
+ t[1] = (*s2 + *s5 + *s8) / 3;
+ t[0] = (*s3 + *s6 + *s9) / 3;
}
-void
-handlepixel(Memimage *tgt, Memimage *src, Point p)
+static void
+transform(Memimage *src, Memimage *dst)
{- uchar *t, *s;
- int i;
- Type tp;
- uchar ival;
- uchar col[4]; /* bgra */
+ int x, y;
- 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];
- }
+ for (y = dst->r.min.y; y < dst->r.max.y; y++)
+ for (x = dst->r.min.x; x < dst->r.max.x; x++)
+ transformpx(src, dst, Pt(x, y));
}
void
-subpixelize(Memimage *tgt, Memimage *src)
+main(void)
{- long x, y;
+ Memimage *in, *out;
+ Rectangle r;
- 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");+ in = readmemimage(0);
+ if (!in)
+ sysfatal("%r");- if (!(src->nchan == 3 || src->nchan == 4))
- sysfatal("unsupported chan");+ r.min.x = in->r.min.x/3;
+ r.min.y = in->r.min.y/3;
+ r.max.x = r.min.x + Dx(in->r)/3;
+ r.max.y = r.min.y + Dy(in->r)/3;
- tgt = allocmemimage(src->r, src->chan);
- if (!tgt)
- sysfatal("allocmemimage: %r");- memfillcolor(tgt, DTransparent);
+ out = allocmemimage(r, RGB24);
+ if (!out)
+ sysfatal("%r");- subpixelize(tgt, src);
- if (writememimage(1, tgt) < 0)
- sysfatal("writememimage");+ transform(in, out);
+
+ writememimage(1, out);
exits(nil);
-}
\ No newline at end of file
+}
binary files a/test.bit /dev/null differ
--
⑨