ref: d80042223e0f2b2bdcd6342fbf1d76e36afcf9e7
dir: /test.h/
#include <ctype.h>
static void
printusage(Otfile *f)
{
f->print(f->aux, "usage: %s [-i GLYPH_ID | -r RUNE] [-p PPEM [-g PIXELS] [-m ... -[-H GLYPH_ID]]] font.otf\n", argv0);
f->print(f->aux, " -i: operate on a single glyph by its id\n");
f->print(f->aux, " -r: operate on a single glyph by its rune\n");
f->print(f->aux, " -p: draw (of size in pixels per em) and write the image to stdout\n");
f->print(f->aux, " -g: gap (in pixels) to add to every border of a glyph\n");
f->print(f->aux, " -m: print out glyph ids or render them all as a map (with -p)\n");
f->print(f->aux, " -R: ignore glyphs that do not represent valid runes\n");
f->print(f->aux, " -H: highlight a specific glyph in the map by its ID\n");
f->print(f->aux, "Specifying -m more than once adds guide lines\n");
f->print(f->aux, "Specifying -m more than twice makes empty pixels filled out\n");
}
static int gap, gind = -1, map, highlight = -1, runesonly;
static double ppem;
static Rune rune = NoRune;
static int
dumpmap(Otfile *f, GlyfImage *im, int n)
{
int x, y, i, j, t, maxh, prebase, postbase, d, border;
int gap, total, mid, npix, bw, bh, lines, fill;
u8int *b;
total = 0;
maxh = 0;
gap = 1;
lines = map > 1;
fill = map > 2;
for(i = 0; i < n; i++){
if(im[i].b == nil)
continue;
if(maxh < im[i].h)
maxh = im[i].h;
total += im[i].w;
}
mid = total / n;
npix = (mid+gap)*(maxh+gap)*n;
bh = sqrt(npix);
bw = npix/bh;
npix *= 2;
bh *= 2;
npix += bw*gap;
if((b = malloc(npix*3)) == nil)
return -1;
memset(b, 0xff, npix*3);
y = gap;
for(i = 0; i < n;){
prebase = postbase = 0;
for(x = 0, j = i; j < n; j++){
if(im[j].b == nil)
continue;
x += im[j].w + gap;
if(x > bw)
break;
if(prebase < im[j].h+im[j].baseline)
prebase = im[j].h+im[j].baseline;
if(im[j].baseline < 0 && postbase < -im[j].baseline)
postbase = -im[j].baseline;
}
maxh = prebase + postbase;
if(j == i || y+maxh > bh)
break;
for(x = 0; i < j; i++){
if(im[i].b == nil)
continue;
u8int *lt = b + ((y + prebase - (im[i].h+im[i].baseline))*bw + x)*3;
x += im[i].w + gap;
for(d = 0; d < im[i].h; d++, lt += bw*3){
for(t = 0; t < im[i].w; t++){
u8int r, g, b;
r = g = b = im[i].b[d*im[i].w + t];
border = d == 0 || t == 0 || t == im[i].w-1 || d == im[i].h-1;
if((lines || highlight == i) && g == 0xff && (d == im[i].h+im[i].baseline)){
g = 0;
b = 0;
}else if((lines || highlight == i) && g == 0xff && (fill || border)){
if(fill && !border){
r = 0xff;
g = 0x80;
b = 0xff;
}else if(border){
r = 0;
b = 0;
}
}
if(r != 0xff || g != 0xff || b != 0xff){
lt[t*3+0] = b;
lt[t*3+1] = g;
lt[t*3+2] = r;
}
}
}
}
y += maxh + gap;
}
f->print(f->aux, "%11s %11d %11d %11d %11d ", "r8g8b8", 0, 0, bw, y);
f->write(f->aux, b, bw*y*3);
free(b);
return 0;
}
static int
process(Otfile *in, Otfile *out)
{
GlyfImage *im;
int i, n;
Glyf *g;
Otf *o;
if((o = otfopen(in)) == nil)
return -1;
n = otfglyfnum(o);
if(rune != NoRune){
if((gind = otfrune2glyph(o, rune)) < 0){
werrstr("no such rune->glyph mapping\n");
return -1;
}
}else if(gind >= 0 && runesonly && otfglyph2rune(o, gind) == NoRune){
werrstr("no such glyph->rune mapping\n");
return -1;
}
if(gind >= n){
werrstr("out of range (max %d)", n-1);
goto glypherr;
}
if(map && gind < 0){
im = ppem > 0 ? calloc(n, sizeof(*im)) : nil;
for(i = 0; i < n; i++){
if(runesonly && otfglyph2rune(o, i) == NoRune)
continue;
if((g = otfglyf(o, i)) == nil){
gind = i;
glypherr:
werrstr("glyph %d: %r", gind);
return -1;
}
if(ppem > 0 && g->numberOfContours != 0){
if(otfdrawglyf(o, g, ppem, gap, im+i) != 0)
goto glypherr;
}else if(ppem <= 0){
out->print(out->aux, "%d (%s):\n", i,
g->simple ? "simple" : (g->component ? "component" : "empty"));
print_Glyf(out, indentΔ, o, g);
}
free(g);
}
if(ppem > 0){
if(out->write != otfdiscard && dumpmap(out, im, n) != 0)
return -1;
for(i = 0; i < n; i++)
free(im[i].b);
free(im);
}
}else if(gind < 0){
otfprint(o, out, indentΔ);
}else{
if((g = otfglyf(o, gind)) == nil){
goto glypherr;
}else if(ppem > 0){
GlyfImage im;
if(otfdrawglyf(o, g, ppem, gap, &im) != 0)
goto glypherr;
if(out->write != otfdiscard && dumpmap(out, &im, 1) != 0)
return -1;
free(im.b);
}else{
out->print(out->aux, "\n%d:\n", gind);
print_Glyf(out, indentΔ, o, g);
}
}
otfclose(o);
return 0;
}
#define parseoptions() \
ARGBEGIN{ \
case 'g': \
gap = strtol(EARGF(usage(&out)), nil, 0); \
break; \
case 'H': \
highlight = strtol(EARGF(usage(&out)), nil, 0); \
break; \
case 'i': \
if(rune != NoRune){ \
errboth: \
out.print(out.aux, "can't specify both rune and glyph\n"); \
usage(&out); \
} \
gind = strtol(EARGF(usage(&out)), nil, 0); \
break; \
case 'm': \
map++; \
break; \
case 'p': \
ppem = strtod(EARGF(usage(&out)), nil); \
break; \
case 'r': { \
char *s = EARGF(usage(&out)); \
if(gind >= 0) \
goto errboth; \
if(isdigit(*s) && strlen(s) > 1) \
rune = strtol(s, nil, 0); \
else if(chartorune(&rune, s) == 1 && rune == Runeerror){ \
out.print(out.aux, "invalid rune\n"); \
usage(&out); \
} \
} break; \
case 'R': \
runesonly++; \
break; \
default: \
usage(&out); \
}ARGEND \
if(argc != 1) \
usage(&out);