9front - general discussion about 9front
 help / color / mirror / Atom feed
* [9front] Truetypefs anti-aliasing
@ 2025-01-20  1:40 Paul Lalonde
  2025-01-20  2:17 ` B. Atticus Grobe
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Paul Lalonde @ 2025-01-20  1:40 UTC (permalink / raw)
  To: 9front


[-- Attachment #1.1.1: Type: text/plain, Size: 1266 bytes --]

I posted this earlier on 9fans, but I should do it here:
I've made a modification to truetypefs to do what ttfrender does: render
the font at higher resolution and filter down to a good looking 8 bit font.

This is a significant improvement in the appearance of the fonts from
truetypefs, as seen in the image below.  Left is the one-bit font, right is
the filtered font.
[image: image.png]
I've attached the change, and I have questions.
I believe in being opinionated: the 8 bit version is so much better for
every font I've compared that I don't see any use for the 1 bit versions
anymore.
How do other users feel about ditching the 1 bit code path and having only
the 8 bit code path?  This is the cleanest/smallest change.
The alternatives would be to have a switch to truetypefs so that it always
returns either 1 bit or 8 bit fonts; a switch in the fs setup to choose
based on font size; a way to tell the fs what font depth to return
(probably a hack like the font size now, very ugly).
The cost of the filtering is low in compute for smaller point sizes, but
starts to lag a bit at 30 point or so.  It probably also blurs out very
small sizes.  I don't know that anyone chooses TrueType fonts for text
under ~10pt however.
[image: image.png]
Thoughts?
Paul

[-- Attachment #1.1.2: Type: text/html, Size: 1493 bytes --]

[-- Attachment #1.2: image.png --]
[-- Type: image/png, Size: 100138 bytes --]

[-- Attachment #1.3: image.png --]
[-- Type: image/png, Size: 29331 bytes --]

[-- Attachment #2: aatt.patch --]
[-- Type: application/octet-stream, Size: 4770 bytes --]

From: Paul Lalonde <plalonde@acm.org>
Date: Mon, 20 Jan 2025 01:29:09 +0000
Subject: [PATCH] Anti-alias/filter fonts from truetypefs


This makes TrueType fonts actually usable and attractive.
---
diff 6929781254e5c9ba711aec98bec81ebba947eabf 62441b383fa1274037427b4f7aea1d24a2ca0407
--- a/sys/man/4/truetypefs
+++ b/sys/man/4/truetypefs
@@ -29,6 +29,8 @@
 is a
 .IR font (6)
 file generated for GNU Unifont at a size of 16.
+The generated fonts are supersampled to generate filtered 8 bit fonts instead of the
+1 bit fonts libttf generates.
 
 .SH EXAMPLES
 Use size 16 GNU Unifont for
@@ -48,3 +50,8 @@
 .SH HISTORY
 .I Truetypefs
 first appeared in 9front (October, 2018).
+.SH BUGS
+The filtering generates blurry fonts for small point sizes.
+At small point sizes it is better to use a specialty bitmapped font.
+
+The filtering should happen natively in libttf, not in its dependents.
--- a/sys/src/cmd/truetypefs.c
+++ b/sys/src/cmd/truetypefs.c
@@ -126,10 +126,9 @@
 }
 
 static void
-blit(uchar *t, int x, int y, int tstride, uchar *s, int w, int h)
+blit8(uchar *t, int x, int y, int tstride, uchar *s, int w, int h)
 {
 	int tx, ty, sx, sy;
-	u16int b;
 	uchar *tp, *sp;
 	
 	if(y < 0) y = 0;
@@ -137,26 +136,81 @@
 	sp = s;
 	for(sy = 0; sy < h; sy++, ty++){
 		tx = x;
-		tp = t + ty * tstride + (tx >> 3);
-		b = 0;
-		for(sx = 0; sx < w; sx += 8){
-			b |= *sp++ << 8 - (tx & 7);
-			*tp++ |= b >> 8;
-			b <<= 8;
+		tp = t + ty * tstride + (tx);
+		for(sx = 0; sx < w; sx ++){
+			*tp++ = *sp++;
 		}
-		*tp |= b >> 8;
 	}
 }
 
+// Allocate an 8bpp bitmap.  We can remove this if we update libttf to support 8 bit bitmaps.
+static TTBitmap *
+newbitmap8(int w, int h, int depth) 
+{
+	TTBitmap *b;
+	if(!(depth == 1 || depth == 8)) {
+		return nil;
+	}
+	b = mallocz(sizeof(TTBitmap), 1);
+	if(b == nil) return nil;
+	b->width = w;
+	b->height = h;
+	switch (depth) {
+	case 1:
+		b->stride = (w + 7) >> 3;
+		break;
+	case 8:
+		b->stride = w;
+		break;
+	}
+	
+	b->bit = mallocz(b->stride * h, 1);
+	if(b->bit == nil){
+		free(b);
+		return nil;
+	}
+	return b;
+}
+
 static void
+freebitmap8(TTBitmap *b) {
+	if(b == nil) return;
+	free(b->bit);
+	free(b);
+}
+
+
+TTBitmap *
+scaledown(TTBitmap *b)
+{
+	TTBitmap *a;
+	int i, j;
+	int scale;
+
+	scale = 8;
+	a = newbitmap8((b->width + 7)>>3 , (b->height +7)>>3, 8);
+	if(a == nil) sysfatal("ttfnewbitmap: %r");
+	for(j = 0; j < b->height; j++)
+		for(i = 0; i < b->width; i++){
+			if((b->bit[j * b->stride + (i>>3)] >> 7 - (i & 7) & 1) != 0)
+				a->bit[j/scale * a->stride + i/scale]++;
+			if(j % scale == scale - 1 && i % scale == scale - 1)
+				a->bit[j/scale * a->stride + i/scale] = ((a->bit[j/scale * a->stride + i/scale] * 255 + scale * scale / 2) / (scale * scale));
+		}
+	return a;
+}
+
+static void
 compilesub(TFont *f, TSubfont *s)
 {
 	int n, i, w, x, h, g, sz;
 	char *d, *p;
-	TTGlyph **gs;
-	TTFont *t;
+	TTGlyph **gs, *gts;
+	TTFont *t, *tscaled;
+	TTBitmap *scaleddown;
 	
 	t = f->ttf;
+	tscaled = ttfscale(t, t->ppem * 8, 0);
 	n = s->end - s->start + 1;
 	gs = emalloc9p(sizeof(TTGlyph *) * n);
 	w = 0;
@@ -166,20 +220,22 @@
 			g = 0;
 		else
 			g = ttffindchar(t, s->start + i);
-		if((gs[i] = ttfgetglyph(t, g, 1)) == nil && g != 0)
-			gs[i] = ttfgetglyph(t, 0, 1);
+		if((gs[i] = ttfgetglyph(tscaled, g, 1)) == nil && g != 0)
+			gs[i] = ttfgetglyph(tscaled, 0, 1);
 		assert(gs[i] != nil);
-	   w += gs[i]->width;
+	   	w += (gs[i]->width + 7)>>3;
 	}
-	sz = 5 * 12 + (w+7>>3) * h + 3 * 12 + (n + 1) * 6;
+	sz = 5 * 12 + w  * h + 3 * 12 + (n + 1) * 6;
 	d = emalloc(sz);
-	p = d + sprint(d, "%11s %11d %11d %11d %11d ", "k1", 0, 0, w, h);
+	p = d + sprint(d, "%11s %11d %11d %11d %11d ", "k8", 0, 0, w, h);
 	x = 0;
 	for(i = 0; i < n; i++){
-		blit((uchar*)p, x, t->ascentpx - gs[i]->ymaxpx, w+7>>3, gs[i]->bit, gs[i]->width, gs[i]->height);
-		x += gs[i]->width;
+		scaleddown = scaledown(gs[i]);
+		blit8((uchar*)p, x, t->ascentpx - ((gs[i]->ymaxpx+7)>>3), w, scaleddown->bit, scaleddown->width, scaleddown->height);
+		x += scaleddown->width;
+		freebitmap8(scaleddown);
 	}
-	p += (w+7>>3) * h;
+	p += w * h;
 	p += sprint(p, "%11d %11d %11d ", n, h, t->ascentpx);
 	x = 0;
 	for(i = 0; i < n; i++){
@@ -187,12 +243,12 @@
 		*p++ = x >> 8;
 		*p++ = 0;
 		*p++ = h;
-		*p++ = gs[i]->xminpx;
+		*p++ = (gs[i]->xminpx+7)>>3;
 		if(gs[i]->advanceWidthpx != 0)
-			*p++ = gs[i]->advanceWidthpx;
+			*p++ = (gs[i]->advanceWidthpx + 7)>>3; // Already at the right scale from when we grabbed it from gts
 		else
-			*p++ = gs[i]->width;
-		x += gs[i]->width;
+			*p++ = (gs[i]->width+7)>>3;
+		x += (gs[i]->width+7)>>3;
 	}
 	*p++ = x;
 	*p = x >> 8;
@@ -200,7 +256,7 @@
 	s->ndata = sz;
 	for(i = 0; i < n; i++)
 		ttfputglyph(gs[i]);
-	free(gs);
+	free(gs); 
 }
 
 

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [9front] Truetypefs anti-aliasing
  2025-01-20  1:40 [9front] Truetypefs anti-aliasing Paul Lalonde
@ 2025-01-20  2:17 ` B. Atticus Grobe
  2025-01-20  4:36 ` [9front] Truetypefs anti-aliasings ori
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: B. Atticus Grobe @ 2025-01-20  2:17 UTC (permalink / raw)
  To: 9front

[-- Attachment #1: Type: text/plain, Size: 1631 bytes --]

On Sun Jan 19, 2025 at 7:40 PM CST, Paul Lalonde wrote:
> I posted this earlier on 9fans, but I should do it here:
> I've made a modification to truetypefs to do what ttfrender does: render
> the font at higher resolution and filter down to a good looking 8 bit font.
>
> This is a significant improvement in the appearance of the fonts from
> truetypefs, as seen in the image below.  Left is the one-bit font, right is
> the filtered font.
> [image: image.png]
> I've attached the change, and I have questions.
> I believe in being opinionated: the 8 bit version is so much better for
> every font I've compared that I don't see any use for the 1 bit versions
> anymore.
> How do other users feel about ditching the 1 bit code path and having only
> the 8 bit code path?  This is the cleanest/smallest change.
> The alternatives would be to have a switch to truetypefs so that it always
> returns either 1 bit or 8 bit fonts; a switch in the fs setup to choose
> based on font size; a way to tell the fs what font depth to return
> (probably a hack like the font size now, very ugly).
> The cost of the filtering is low in compute for smaller point sizes, but
> starts to lag a bit at 30 point or so.  It probably also blurs out very
> small sizes.  I don't know that anyone chooses TrueType fonts for text
> under ~10pt however.
> [image: image.png]
> Thoughts?
> Paul

Paul, Sigrid would like you to take a look at the font renderer she's been
working on at https://git.sr.ht/~ft/fnt . She's currently experiencing e-mail
issues and asked me to relay this. All mistakes in this message are my own.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [9front] Truetypefs anti-aliasings
  2025-01-20  1:40 [9front] Truetypefs anti-aliasing Paul Lalonde
  2025-01-20  2:17 ` B. Atticus Grobe
@ 2025-01-20  4:36 ` ori
  2025-01-20  6:30 ` [9front] Truetypefs anti-aliasing Blue-Maned_Hawk
  2025-01-30  5:32 ` ori
  3 siblings, 0 replies; 5+ messages in thread
From: ori @ 2025-01-20  4:36 UTC (permalink / raw)
  To: 9front

No objection to doing this, or to only doing the 8 bit path.

I think libttf is likely to get replaced, as mentioned, but until
that happens, I think this makes sense.

Quoth Paul Lalonde <paul.a.lalonde@gmail.com>:
> I posted this earlier on 9fans, but I should do it here:
> I've made a modification to truetypefs to do what ttfrender does: render
> the font at higher resolution and filter down to a good looking 8 bit font.
> 
> This is a significant improvement in the appearance of the fonts from
> truetypefs, as seen in the image below.  Left is the one-bit font, right is
> the filtered font.
> [image: image.png]
> I've attached the change, and I have questions.
> I believe in being opinionated: the 8 bit version is so much better for
> every font I've compared that I don't see any use for the 1 bit versions
> anymore.
> How do other users feel about ditching the 1 bit code path and having only
> the 8 bit code path?  This is the cleanest/smallest change.
> The alternatives would be to have a switch to truetypefs so that it always
> returns either 1 bit or 8 bit fonts; a switch in the fs setup to choose
> based on font size; a way to tell the fs what font depth to return
> (probably a hack like the font size now, very ugly).
> The cost of the filtering is low in compute for smaller point sizes, but
> starts to lag a bit at 30 point or so.  It probably also blurs out very
> small sizes.  I don't know that anyone chooses TrueType fonts for text
> under ~10pt however.
> [image: image.png]
> Thoughts?
> Paul
> 


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [9front] Truetypefs anti-aliasing
  2025-01-20  1:40 [9front] Truetypefs anti-aliasing Paul Lalonde
  2025-01-20  2:17 ` B. Atticus Grobe
  2025-01-20  4:36 ` [9front] Truetypefs anti-aliasings ori
@ 2025-01-20  6:30 ` Blue-Maned_Hawk
  2025-01-30  5:32 ` ori
  3 siblings, 0 replies; 5+ messages in thread
From: Blue-Maned_Hawk @ 2025-01-20  6:30 UTC (permalink / raw)
  To: 9front

I can confidently say with complete confidence that i never want 
anything that i use to ever have any amount of antiäliasing 
whatsoëver.  Antiäliasing only ever serves to make everything blurrier 
and induce analog-like uncertainties into a digital world that should be 
free of such horrors.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [9front] Truetypefs anti-aliasing
  2025-01-20  1:40 [9front] Truetypefs anti-aliasing Paul Lalonde
                   ` (2 preceding siblings ...)
  2025-01-20  6:30 ` [9front] Truetypefs anti-aliasing Blue-Maned_Hawk
@ 2025-01-30  5:32 ` ori
  3 siblings, 0 replies; 5+ messages in thread
From: ori @ 2025-01-30  5:32 UTC (permalink / raw)
  To: 9front

Quoth Paul Lalonde <paul.a.lalonde@gmail.com>:
> I posted this earlier on 9fans, but I should do it here:
> I've made a modification to truetypefs to do what ttfrender does: render
> the font at higher resolution and filter down to a good looking 8 bit font.
> 
> This is a significant improvement in the appearance of the fonts from
> truetypefs, as seen in the image below.  Left is the one-bit font, right is
> the filtered font.
> [image: image.png]
> I've attached the change, and I have questions.
> I believe in being opinionated: the 8 bit version is so much better for
> every font I've compared that I don't see any use for the 1 bit versions
> anymore.
> How do other users feel about ditching the 1 bit code path and having only
> the 8 bit code path?  This is the cleanest/smallest change.
> The alternatives would be to have a switch to truetypefs so that it always
> returns either 1 bit or 8 bit fonts; a switch in the fs setup to choose
> based on font size; a way to tell the fs what font depth to return
> (probably a hack like the font size now, very ugly).
> The cost of the filtering is low in compute for smaller point sizes, but
> starts to lag a bit at 30 point or so.  It probably also blurs out very
> small sizes.  I don't know that anyone chooses TrueType fonts for text
> under ~10pt however.
> [image: image.png]
> Thoughts?
> Paul
> 

Applied as a starting point, hoping we get improvements on the algorithm
soon.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2025-01-30  5:34 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-01-20  1:40 [9front] Truetypefs anti-aliasing Paul Lalonde
2025-01-20  2:17 ` B. Atticus Grobe
2025-01-20  4:36 ` [9front] Truetypefs anti-aliasings ori
2025-01-20  6:30 ` [9front] Truetypefs anti-aliasing Blue-Maned_Hawk
2025-01-30  5:32 ` ori

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).