diff options
Diffstat (limited to 'third_party/spiro/font')
-rw-r--r-- | third_party/spiro/font/Makefile | 3 | ||||
-rw-r--r-- | third_party/spiro/font/blend.c | 372 | ||||
-rw-r--r-- | third_party/spiro/font/cut.py | 52 | ||||
-rw-r--r-- | third_party/spiro/font/mkblends.py | 16 | ||||
-rw-r--r-- | third_party/spiro/font/replace_class.py | 14 | ||||
-rw-r--r-- | third_party/spiro/font/segment.c | 194 |
6 files changed, 651 insertions, 0 deletions
diff --git a/third_party/spiro/font/Makefile b/third_party/spiro/font/Makefile new file mode 100644 index 0000000..f6096a6 --- /dev/null +++ b/third_party/spiro/font/Makefile @@ -0,0 +1,3 @@ +CFLAGS = -Wall -O2 -g +LDLIBS = -lm +all: blend segment diff --git a/third_party/spiro/font/blend.c b/third_party/spiro/font/blend.c new file mode 100644 index 0000000..87a540f --- /dev/null +++ b/third_party/spiro/font/blend.c @@ -0,0 +1,372 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +typedef struct { + const char *fn; + int xs; + int ys; + unsigned char *buf; +} pgm; + +typedef struct { + int xs; + int ys; + int *sum; + int *count; +} blendbuf; + +static void +die (char *why) +{ + fprintf (stderr, "%s\n", why); + exit (1); +} + +#define MAX_SIZE 65536 + +pgm *load_pgm(const char *fn) +{ + FILE *fi = fopen(fn, "rb"); + pgm *result; + char buf[256]; + int xs, ys; + int depth; + + if (fi == NULL) + return NULL; + + fgets (buf, sizeof(buf), fi); + if (buf[0] != 'P' || buf[1] != '5') + die ("Need pgmraw image on input"); + + xs = ys = 0; + do + fgets (buf, sizeof(buf), fi); + while (buf[0] == '#'); + sscanf (buf, "%d %d", &xs, &ys); + if (xs <= 0 || ys <= 0 || xs > MAX_SIZE || ys > MAX_SIZE) + die ("Input image size out of range"); + + do + fgets (buf, sizeof(buf), fi); + while (buf[0] == '#'); + sscanf (buf, "%d", &depth); + if (depth != 255) + die ("Only works with depth=255 images"); + + result = (pgm *)malloc(sizeof(pgm)); + + result->fn = fn; + result->xs = xs; + result->ys = ys; + result->buf = (unsigned char *)malloc(xs * ys); + + fread(result->buf, 1, xs * ys, fi); + fprintf(stderr, "loaded file %s %dx%d\n", fn, xs, ys); + fclose(fi); + return result; +} + +int +align_pgms(const pgm *p1, const pgm *p2, int *px, int *py) +{ + int xo, yo; + int xa, ya; + int best = 0x7fffffff; + + xa = (p1->xs < p2->xs ? p1->xs : p2->xs) - 20; + ya = (p1->ys < p2->ys ? p1->ys : p2->ys) - 20; + + for (yo = -10; yo <= 10; yo++) + for (xo = -10; xo <= 10; xo++) { + int sum = 0; + int i, j; + + for (j = 0; j < ya; j++) + for (i = 0; i < xa; i++) { + int g1 = p1->buf[(j + 10) * p1->xs + i + 10]; + int g2 = p2->buf[(j + 10 - yo) * p2->xs + i - xo + 10]; + sum += (g1 - g2) * (g1 - g2); + } + if (sum < best) { + best = sum; + *px = xo; + *py = yo; + } + } + return best; +} + +blendbuf * +new_blendbuf(int xs, int ys) +{ + blendbuf *result = (blendbuf *)malloc(sizeof(blendbuf)); + int i; + + result->xs = xs; + result->ys = ys; + result->sum = (int *)malloc(sizeof(int) * xs * ys); + result->count = (int *)malloc(sizeof(int) * xs * ys); + for (i = 0; i < xs * ys; i++) { + result->sum[i] = 0; + result->count[i] = 0; + } + + return result; +} + +void +add_pgm(blendbuf *bb, pgm *p, int xo, int yo) +{ + int i, j; + + for (j = 0; j < p->ys; j++) { + if (j + yo >= 0 && j + yo < bb->ys) { + for (i = 0; i < p->xs; i++) { + if (i + xo >= 0 && i + xo < bb->xs) { + int ix = (j + yo) * bb->xs + i + xo; + bb->sum[ix] += p->buf[j * p->xs + i]; + bb->count[ix]++; + } + } + } + } +} + +pgm * +pgm_from_blendbuf(blendbuf *bb) +{ + int xs = bb->xs; + int ys = bb->ys; + pgm *result = (pgm *)malloc(sizeof(pgm)); + int i, j; + + result->xs = xs; + result->ys = ys; + result->buf = (unsigned char *)malloc(xs * ys); + + for (j = 0; j < ys; j++) { + for (i = 0; i < xs; i++) { + int ix = j * xs + i; + unsigned char g; + if (bb->count[ix]) + g = (bb->sum[ix] + (bb->count[ix] >> 1)) / bb->count[ix]; + else + g = 255; + result->buf[ix] = g; + } + } + return result; +} + +pgm * +pgm_from_blendbuf_enhanced(blendbuf *bb, double sharp, double gamma) +{ + int xs = bb->xs; + int ys = bb->ys; + pgm *result = (pgm *)malloc(sizeof(pgm)); + int i, j; + double ming = 255, maxg = 0; + double *tmpbuf; + + result->xs = xs; + result->ys = ys; + result->buf = (unsigned char *)malloc(xs * ys); + + tmpbuf = (double *)malloc(xs * ys * sizeof(double)); + + for (j = 0; j < ys; j++) { + for (i = 0; i < xs; i++) { + int ix = j * xs + i; + double g; + if (bb->count[ix]) { + g = ((double)bb->sum[ix]) / bb->count[ix]; + if (g < ming) ming = g; + if (g > maxg) maxg = g; + } else + g = 255.0; + tmpbuf[ix] = g; + } + } + for (j = 0; j < ys; j++) { + for (i = 0; i < xs; i++) { + int ix = j * xs + i; + double g; + if (bb->count[ix]) { + int u, v; + int cnt = 0; + double sum = 0; + + for (v = -1; v <= 1; v++) { + for (u = -1; u <= 1; u++) { + if (i + u >= 0 && i + u < xs && + j + v >= 0 && j + v < ys && + bb->count[(j + v) * xs + i + u]) { + sum += tmpbuf[(j + v) * xs + i + u]; + cnt += 1; + } + } + } + + g = (1 + sharp) * tmpbuf[ix] - sharp * sum / cnt; + g = (g - ming) / (maxg - ming); + if (g < 0) g = 0; + if (g > 1) g = 1; + g = pow(g, gamma); + } else + g = 1; + result->buf[ix] = (int)(255 * g + 0.5); + } + } + free(tmpbuf); + return result; +} + +void +print_pgm(pgm *p, FILE *f) +{ + fprintf(f, "P5\n%d %d\n255\n", p->xs, p->ys); + fwrite(p->buf, 1, p->xs * p->ys, f); +} + +void +threshold(pgm *p) +{ + int i; + + for (i = 0; i < p->xs * p->ys; i++) + p->buf[i] = p->buf[i] > 128 ? 1 : 0; +} + +int +classify(pgm **pgmlist, int n_pgm) +{ + int *class = (int *)malloc(sizeof(int) * n_pgm); + int n_class = 0; + int i, j; + int tshift = 4; + + for (i = 0; i < n_pgm; i++) + class[i] = -1; + + for (i = 0; i < n_pgm; i++) { + pgm *pi = pgmlist[i]; + + if (class[i] == -1) { + class[i] = n_class++; + for (j = i + 1; j < n_pgm; j++) { + pgm *pj = pgmlist[j]; + int xo, yo; + int score; + + if (abs(pi->xs - pj->xs) < 10 && + abs(pi->ys - pj->ys) < 10) { + score = align_pgms(pi, pj, &xo, &yo); + if (score < ((pi->xs - 20) * (pi->ys - 20)) >> tshift) { + class[j] = class[i]; + } + } + } + } + printf("%s: class%d\n", pi->fn, class[i]); + fflush(stdout); + } + free(class); + return 0; +} + + +static int +intcompar(const void *a, const void *b) { + return *((int *)a) - *((int *)b); +} + +int +do_blend(pgm **pgmlist, int n_pgm, int n_passes, float thresh) +{ + blendbuf *bb; + int pass; + int i; + pgm *base = pgmlist[0]; + int *scores, *scores2, *xos, *yos; + + scores = (int *)malloc(n_pgm * sizeof(int)); + scores2 = (int *)malloc(n_pgm * sizeof(int)); + xos = (int *)malloc(n_pgm * sizeof(int)); + yos = (int *)malloc(n_pgm * sizeof(int)); + + for (pass = 0; pass < n_passes; pass++) { + int scorethresh; + + bb = new_blendbuf(base->xs, base->ys); + for (i = 0; i < n_pgm; i++) { + int xo, yo; + int score = align_pgms(base, pgmlist[i], &xo, &yo); + fprintf(stderr, "%s: score = %d, offset = %d, %d\n", + pgmlist[i]->fn, score, xo, yo); + scores[i] = score; + xos[i] = xo; + yos[i] = yo; + } + + if (pass == 0) { + scorethresh = 0x7fffffff; + } else { + memcpy(scores2, scores, n_pgm * sizeof(int)); + qsort(scores2, n_pgm, sizeof(int), intcompar); + scorethresh = scores2[(int)(thresh * n_pgm)]; + } + + for (i = 0; i < n_pgm; i++) { + if (pass > 0) + fprintf(stderr, "%s: score = %d %s\n", + pgmlist[i]->fn, scores[i], + scores[i] <= scorethresh ? "ok" : "-"); + if (scores[i] <= scorethresh) + add_pgm(bb, pgmlist[i], xos[i], yos[i]); + } + + if (pass == n_passes - 1) + base = pgm_from_blendbuf_enhanced(bb, 5, 0.5); + else + base = pgm_from_blendbuf(bb); + if (pass != n_passes - 1) + fprintf(stderr, "\n"); + } + + free(scores); + free(xos); + free(yos); + print_pgm(base, stdout); + return 0; +} + +int +main(int argc, char **argv) +{ + int i; + int n_pgm = 0; + pgm **pgmlist = (pgm **)malloc(sizeof(pgm *) * argc - 1); + int do_class = 0; + int n_pass = 2; + float thresh = 0.90; + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-c")) + do_class = 1; + else + pgmlist[n_pgm++] = load_pgm(argv[i]); + } + + if (do_class) { + for (i = 0; i < n_pgm; i++) + threshold(pgmlist[i]); + return classify(pgmlist, n_pgm); + } else { + return do_blend(pgmlist, n_pgm, n_pass, thresh); + } + + return 0; +} diff --git a/third_party/spiro/font/cut.py b/third_party/spiro/font/cut.py new file mode 100644 index 0000000..541efa8 --- /dev/null +++ b/third_party/spiro/font/cut.py @@ -0,0 +1,52 @@ +import sys + +athresh = 100 +border = 20 + +segf = sys.argv[1] +if len(sys.argv) > 2: + pref = sys.argv[2] +else: + pref = '/tmp/cut' +rects = [] +starts = {} +for l in file(segf).xreadlines(): + ls = l.split() + if len(ls) == 6 and ls[-1] == 'rect': + r = map(int, ls[:4]) + area = (r[2] - r[0]) * (r[3] - r[1]) + if area > athresh: + rpad = [r[0] - border, r[1] - border, r[2] + border, r[3] + border] + if not starts.has_key(rpad[1]): + starts[rpad[1]] = [] + starts[rpad[1]].append(len(rects)) + rects.append(rpad) +inf = sys.stdin +l = inf.readline() +if l != 'P5\n': + raise 'expected pgm file' +while 1: + l = inf.readline() + if l[0] != '#': break +x, y = map(int, l.split()) +l = inf.readline() + +active = {} +for j in range(y): + if starts.has_key(j): + for ix in starts[j]: + r = rects[ix] + ofn = pref + '%04d.pgm' % ix + of = file(ofn, 'w') + active[ix] = of + print >> of, 'P5' + print >> of, r[2] - r[0], r[3] - r[1] + print >> of, '255' + buf = inf.read(x) + for ix, of in active.items(): + r = rects[ix] + of.write(buf[r[0]:r[2]]) + if j == r[3] - 1: + of.close() + del active[ix] + diff --git a/third_party/spiro/font/mkblends.py b/third_party/spiro/font/mkblends.py new file mode 100644 index 0000000..09fe882 --- /dev/null +++ b/third_party/spiro/font/mkblends.py @@ -0,0 +1,16 @@ +import os, sys + +glyphmap = {} +for ln in file(sys.argv[1]).xreadlines(): + fnglyph = ln.strip().split(': ') + if len(fnglyph) == 2: + fn, name = fnglyph + pgmf = fn[:-4] + '.pgm' + if not glyphmap.has_key(name): + glyphmap[name] = [] + glyphmap[name].append(pgmf) +for name in glyphmap.iterkeys(): + cmd = '~/garden/font/blend ' + ' '.join(glyphmap[name]) + ' | pnmtopng > ' + name + '.png' + print cmd + os.system(cmd) + diff --git a/third_party/spiro/font/replace_class.py b/third_party/spiro/font/replace_class.py new file mode 100644 index 0000000..9a1da51 --- /dev/null +++ b/third_party/spiro/font/replace_class.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python + +import sys +srfile = file(sys.argv[1]) +table = {} +for line in srfile.xreadlines(): + clas, repl = line.split() + if repl[-1] not in '-?': + table['class' + clas] = repl + +for line in sys.stdin.xreadlines(): + fn, clas = line.split() + if table.has_key(clas): + print fn, table[clas] diff --git a/third_party/spiro/font/segment.c b/third_party/spiro/font/segment.c new file mode 100644 index 0000000..8eb6b06 --- /dev/null +++ b/third_party/spiro/font/segment.c @@ -0,0 +1,194 @@ +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +typedef struct { + int x0; + int x1; + int y0; + int y1; + double xmom; + double ymom; + int area; +} seg; + +typedef struct { + int x0; + int x1; +} run; + +void +find_runs(run *result, const unsigned char *buf, unsigned char thresh, int xs) +{ + int x; + int j = 0; + + for (x = 0; x < xs;) { + int x0, x1; + for (x0 = x; x0 < xs; x0++) + if (buf[x0] < thresh) + break; + if (x0 == xs) + break; + for (x1 = x0 + 1; x1 < xs; x1++) + if (buf[x1] >= thresh) + break; + result[j].x0 = x0; + result[j].x1 = x1; + j++; + x = x1 + 1; + } + result[j].x0 = 0; + result[j].x1 = 0; +} + +void +print_rect(const seg *r) +{ + printf("%d %d %d %d %g rect\n", r->x0, r->y0, r->x1, r->y1, + r->area / (1.0 * (r->x1 - r->x0) * (r->y1 - r->y0))); + printf("%g %g ci\n", r->xmom / r->area, r->ymom / r->area); +} + +void +merge_runs(seg *buf, const run *new_runs, int y) +{ + int bi, ni; + int bs; + int bi0; + int flag; + + for (bs = 0; buf[bs].x1; bs++); + + bi = 0; + flag = 1; + for (ni = 0; new_runs[ni].x1; ni++) { + int run_len = new_runs[ni].x1 - new_runs[ni].x0; + + bi0 = bi; + for (; bi < bs && buf[bi].x1 <= new_runs[ni].x0; bi++) { + if (flag) { + buf[bi].y1 = y; + print_rect(&buf[bi]); + } else { + bi0 = bi + 1; + flag = 1; + } + } + if (bi > bi0) { + memmove(&buf[bi0], &buf[bi], (bs - bi) * sizeof(seg)); + bs += bi0 - bi; + } + bi = bi0; + if (bi < bs && buf[bi].x0 < new_runs[ni].x1) { + double xmom = buf[bi].xmom; + double ymom = buf[bi].ymom; + int area = buf[bi].area; + int y0 = buf[bi].y0; + + for (bi = bi + 1; bi < bs && buf[bi].x0 < new_runs[ni].x1; bi++) { + y0 = MIN(y0, buf[bi].y0); + xmom += buf[bi].xmom; + ymom += buf[bi].ymom; + area += buf[bi].area; + } + buf[bi0].x0 = MIN(buf[bi0].x0, new_runs[ni].x0); + buf[bi0].x1 = MAX(buf[bi - 1].x1, new_runs[ni].x1); + buf[bi0].y0 = y0; + buf[bi0].xmom = xmom + run_len * .5 * (new_runs[ni].x0 + new_runs[ni].x1); + buf[bi0].ymom = ymom + run_len * y; + buf[bi0].area = area + run_len; + if (bi > bi0 + 1) { + memmove(&buf[bi0 + 1], &buf[bi], (bs - bi) * sizeof(seg)); + bs += bi0 + 1 - bi; + } + bi = bi0; + flag = 0; + } else { + memmove(&buf[bi + 1], &buf[bi], (bs - bi) * sizeof(seg)); + bs++; + buf[bi].x0 = new_runs[ni].x0; + buf[bi].x1 = new_runs[ni].x1; + buf[bi].y0 = y; + buf[bi].xmom = run_len * .5 * (new_runs[ni].x0 + new_runs[ni].x1); + buf[bi].ymom = run_len * y; + buf[bi].area = run_len; + bi++; + flag = 1; + } + } + bi0 = bi; + for (; bi < bs; bi++) { + if (flag) { + buf[bi].y1 = y; + print_rect(&buf[bi]); + } else { + bi0 = bi + 1; + flag = 1; + } + } + buf[bi0].x0 = 0; + buf[bi0].x1 = 0; +} + +static void +die (char *why) +{ + fprintf (stderr, "%s\n", why); + exit (1); +} + +#define MAX_SIZE 65536 + +int +main (int argc, char **argv) +{ + FILE *fi = stdin; + FILE *fo = stdout; + char buf[256]; + int xs, ys; + int depth; + unsigned char *imgbuf; + seg *segs; + run *runs; + int y; + + fgets (buf, sizeof(buf), fi); + if (buf[0] != 'P' || buf[1] != '5') + die ("Need pgmraw image on input"); + + xs = ys = 0; + do + fgets (buf, sizeof(buf), fi); + while (buf[0] == '#'); + sscanf (buf, "%d %d", &xs, &ys); + if (xs <= 0 || ys <= 0 || xs > MAX_SIZE || ys > MAX_SIZE) + die ("Input image size out of range"); + + do + fgets (buf, sizeof(buf), fi); + while (buf[0] == '#'); + sscanf (buf, "%d", &depth); + if (depth != 255) + die ("Only works with depth=255 images"); + + runs = (run *)malloc(((xs + 3) >> 1) * sizeof(run)); + segs = (seg *)malloc(((xs + 3) >> 1) * sizeof(seg)); + imgbuf = (unsigned char *)malloc (xs); + segs[0].x0 = 0; + segs[0].x1 = 0; + for (y = 0; y < ys; y++) { + fread (imgbuf, 1, xs, fi); + find_runs(runs, imgbuf, 160, xs); + merge_runs(segs, runs, y); + } + + free(imgbuf); + free(runs); + free(segs); + + return 0; +} |