diff options
author | Roozbeh Pournader <roozbeh@google.com> | 2014-07-26 11:20:29 -0700 |
---|---|---|
committer | Roozbeh Pournader <roozbeh@google.com> | 2014-07-26 11:20:29 -0700 |
commit | 0f1bd27678fb542f8601bbaf493baa1c22732fe2 (patch) | |
tree | 78ecb8f8082fb1b3ae24720549578b9272f36f0c /third_party/spiro/font/blend.c | |
parent | 5a480b939b43dec473550292501a88518fe1208c (diff) |
Add Spiro version 0.01.
Diffstat (limited to 'third_party/spiro/font/blend.c')
-rw-r--r-- | third_party/spiro/font/blend.c | 372 |
1 files changed, 372 insertions, 0 deletions
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; +} |