From 3b63c5a73fb86d17bede0eaa87130b2446c41ef9 Mon Sep 17 00:00:00 2001 From: aiju Date: Sat, 9 Jun 2018 14:34:44 +0000 Subject: [PATCH] add ttfrender(1) --- sys/src/cmd/ttfrender.c | 173 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 sys/src/cmd/ttfrender.c diff --git a/sys/src/cmd/ttfrender.c b/sys/src/cmd/ttfrender.c new file mode 100644 index 000000000..d4892f897 --- /dev/null +++ b/sys/src/cmd/ttfrender.c @@ -0,0 +1,173 @@ +#include +#include +#include +#include +#include +#include + +void +elidenl(char **sp, int *np) +{ + char *s, *e, *t; + int nl; + + s = t = *sp; + e = *sp + *np; + for(; s < e; s++){ + if(isspace(*s)){ + nl = 0; + do + nl += *s == '\n'; + while(++s < e && isspace(*s)); + if(nl <= 1) + *t++ = ' '; + else while(nl-- > 0) + *t++ = '\n'; + if(s == e) break; + } + *t++ = *s; + } +} + +int +readtext(char *fn, char **sp, int newline) +{ + int fd, n, a, rc; + char *s; + enum {B = 4096}; + + fd = open(fn, OREAD); + if(fd < 0) sysfatal("open: %r"); + s = nil; + n = 0; + a = 0; + for(;;){ + if(n + B > a) + s = realloc(s, a += B); + if(s == nil) sysfatal("realloc: %r"); + rc = read(fd, &s[n], B); + if(rc < 0) sysfatal("read: %r"); + if(rc == 0) break; + n += rc; + } + if(newline) + elidenl(&s, &n); + s = realloc(s, n); + if(s == nil) sysfatal("realloc: %r"); + *sp = s; + return n; +} + +void +usage(void) +{ + fprint(2, "usage: %s [ -lrjn ] [ -s scale ] [ -w width ] [ -h height ] [ -p ppem ] font [ text ]\n", argv0); + exits("usage"); +} + +int +number(char *s) +{ + char *p; + int n; + + n = strtol(s, &p, 0); + if(p == s || *p != 0 || n <= 0) + usage(); + return n; +} + +TTBitmap * +scaledown(TTBitmap *b, int scale) +{ + TTBitmap *a; + int i, j; + + a = ttfnewbitmap(b->width / scale * 8, b->height / scale); + 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; +} + +void +cropwrite(TTBitmap *b) +{ + int l, r, u, d, i; + + l = 0; + r = b->stride; + u = 0; + d = b->height; + for(; l < r; l++) + for(i = u; i < d; i++) + if(b->bit[i * b->stride + l] != 0xff) + goto right; +right: + for(; l < r; r--) + for(i = u; i < d; i++) + if(b->bit[i * b->stride + r - 1] != 0xff) + goto up; +up: + for(; u < d; u++) + for(i = l; i < r; i++) + if(b->bit[u * b->stride + i] != 0xff) + goto down; +down: + for(; u < d; d--) + for(i = l; i < r; i++) + if(b->bit[(d - 1) * b->stride + i] != 0xff) + goto out; +out: + print("%11s %11d %11d %11d %11d ", "k8", 0, 0, r - l, d - u); + for(i = u; i < d; i++) + write(1, b->bit + i * b->stride + l, r - l); + +} + +void +main(int argc, char **argv) +{ + static int flags, scale, width, height, ppem, newline, crop; + char *font, *txtfn, *txt; + int txtn; + TTFont *f; + TTBitmap *b; + TTBitmap *d; + + width = 640; + height = 480; + ppem = 18; + scale = 1; + ARGBEGIN { + case 'l': break; + case 'r': flags |= TTFRALIGN; break; + case 'c': flags |= TTFCENTER; break; + case 'j': flags |= TTFJUSTIFY; break; + case 'p': ppem = number(EARGF(usage())); break; + case 's': scale = number(EARGF(usage())); break; + case 'w': width = number(EARGF(usage())); break; + case 'h': height = number(EARGF(usage())); break; + case 'n': newline++; break; + case 'C': crop++; break; + } ARGEND; + if((uint)(argc - 1) > 1) usage(); + font = argv[0]; + txtfn = argc > 1 ? argv[1] : "/fd/0"; + txtn = readtext(txtfn, &txt, newline); + f = ttfopen(font, ppem * scale, 0); + if(f == nil) sysfatal("ttfopen: %r"); + b = ttfrender(f, txt, txt + txtn, width * scale, height * scale, flags, nil); + if(b == nil) sysfatal("ttfrender: %r"); + d = scaledown(b, scale); + if(crop) cropwrite(d); + else{ + print("%11s %11d %11d %11d %11d ", "k8", 0, 0, d->width/8, d->height); + write(1, d->bit, d->stride * d->height); + } +}