285 lines · 6.9 KB · C
RawDownload
#include <ctype.h> static voidprintusage(Otfile *f){	f->print(f->aux, "usage: %s [-i GLYPH_ID | -r RUNE] [-p PPEM [-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, " -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, " -x: horizontal ppem\n");	f->print(f->aux, " -y: vertical ppem\n");	f->print(f->aux, " -s: use subpixel rendering if applicable (rgb, bgr, rgbv, bgrv)\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 u8int deffir[] = {8, 77, 86, 77, 8};static RasterOpts ropts;static SubPx subpx = {	.fir = {		.c = deffir,		.nc = nelem(deffir),	},	.lcdorder = LCD_ORDER_RGB,	.lcdvert = 0,};static int gind = -1, map, highlight = -1, runesonly;static Rune rune = NoRune;static char *gtypes[] = {	[GLYPH_EMPTY] = "empty",	[GLYPH_BITMAP] = "bitmap",	[GLYPH_SIMPLE] = "simple",	[GLYPH_COMPONENT] = "component",}; static intdumpmap(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; 	gap = 1;	total = 0;	maxh = 0;	lines = map > 1;	fill = map > 2;	if(n == 1){		maxh = im[0]->h;		if(im[0]->baseline)			maxh += im[0]->baseline;		bw = 2*gap + im[0]->w;		bh = 2*gap + maxh*2;		npix = bw * bh;	}else{		for(i = 0; i < n; i++){			if(im[i] == 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 = gap, j = i; j < n; j++){			if(im[j] == 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] == 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;					u32int rgb;					if(im[i]->fmt == GLYF_FMT_RGB_24){						r = im[i]->b[(d*im[i]->w + t)*3 + 0];						g = im[i]->b[(d*im[i]->w + t)*3 + 1];						b = im[i]->b[(d*im[i]->w + t)*3 + 2];					}else{						r = g = b = im[i]->b[d*im[i]->w + t];					}					rgb = r<<16 | g<<8 | b;					border = d == 0 || t == 0 || t == im[i]->w-1 || d == im[i]->h-1;					if((lines || highlight == i) && rgb == 0 && (d == im[i]->h+im[i]->baseline)){						r = 0xff;						g = 0;						b = 0;					}else if((lines || highlight == i) && rgb == 0 && (fill || border)){						if(fill && !border){							r = 0xff;							g = 0x80;							b = 0xff;						}else if(border){							r = 0;							g = 0xff;							b = 0;						}					}else{						r = 0xff - r;						g = 0xff - g;						b = 0xff - b;					}					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 intprocess(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 = ropts.ppemX > 0 ? calloc(n, sizeof(*im)) : nil;		for(i = 0; i < n; i++){			if(runesonly && otfglyph2rune(o, i) == NoRune)				continue;			if((g = otfglyf(o, i, &ropts)) == nil){				gind = i;glypherr:				werrstr("glyph %d: %r", gind);				return -1;			}			if(ropts.ppemX > 0 && g->type != GLYPH_EMPTY){				if((im[i] = otfdrawglyf(o, g, &ropts)) == nil){					werrstr("draw: %r");					gind = i;					goto glypherr;				}			}else if(ropts.ppemX <= 0){				out->print(out->aux, "%d (%s):\n", i, gtypes[g->type]);				print_Glyf(out, indentΔ, o, g);			}			free(g);		}		if(ropts.ppemX > 0){			if(out->write != otfdiscard && dumpmap(out, im, n) != 0)				return -1;			for(i = 0; i < n; i++)				free(im[i]);			free(im);		}	}else if(gind < 0){		otfprint(o, out, indentΔ);	}else{		if((g = otfglyf(o, gind, &ropts)) == nil){			goto glypherr;		}else if(ropts.ppemX > 0){			GlyfImage *im;			if((im = otfdrawglyf(o, g, &ropts)) == nil){				werrstr("draw: %r");				goto glypherr;			}			if(out->write != otfdiscard && dumpmap(out, &im, 1) != 0)				return -1;			free(im);		}else{			out->print(out->aux, "\n%d:\n", gind);			print_Glyf(out, indentΔ, o, g);		}	}	otfclose(o);	return 0;} #define parseoptions() \	ARGBEGIN{ \	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': \		ropts.ppemX = ropts.ppemY = 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; \	case 's': { \		char *s = EARGF(usage(&out)); \		if(strcmp(s, "bgr") == 0) \			subpx.lcdorder = LCD_ORDER_BGR; \		else if(strcmp(s, "rgbv") == 0) \			subpx.lcdvert = 1; \		else if(strcmp(s, "bgrv") == 0){ \			subpx.lcdorder = LCD_ORDER_BGR; \			subpx.lcdvert = 1; \		}else if(strcmp(s, "rgb") != 0){ \			out.print(out.aux, "invalid subpixel configuration: %s\n", s); \			usage(&out); \		} \		ropts.subpx = &subpx; \		} break; \	case 'x': \		ropts.ppemX = strtod(EARGF(usage(&out)), nil); \		break; \	case 'y': \		ropts.ppemY = strtod(EARGF(usage(&out)), nil); \		break; \	default: \		usage(&out); \	}ARGEND \	if(argc != 1) \		usage(&out); \	if(ropts.ppemX == 0 && ropts.ppemY != 0) \		ropts.ppemX = ropts.ppemY; \	if(ropts.ppemY == 0 && ropts.ppemX != 0) \		ropts.ppemY = ropts.ppemX;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t