Sigrid Solveig Haflínudóttiradd -d DPI option58437dc11 months agoHistory
389 lines · 9.4 KB · C
RawDownload
#include <stdio.h>#include <stdlib.h>#include <stdint.h>#include <fcntl.h>#include <unistd.h>#include <sys/stat.h>#include <SDL_ttf.h>#include "parg.h"#include "common.h" #if !SDL_TTF_VERSION_ATLEAST(2,0,18)#error SDL2_ttf of version >= 2.0.18 required#else #ifndef MAX#define MAX(a,b) ((a)>(b)?(a):(b))#endif enum {	Substitute = 0xfffd,	Maxsubfwidth = 3000, /* rough */}; static uint8_t pjw[] = {#include "pjw.h"}; static char *opts = "d:hPs:x:H:S:";static SDL_Color white = {255, 255, 255, 255};static SDL_Color black = {0, 0, 0, 255};static char *opath, *prefix;static int ptsz, hint, style; static uint8_t *surf2k8(SDL_Surface *s){	uint8_t *b, *p;	int sz, x, y; 	sz = s->w*s->h;	b = p = malloc(sz);	for(y = 0; y < s->h; y++){		for(x = 0; x < s->w; x++)			*p++ = ((uint8_t*)s->pixels + y*s->pitch)[x*4];	} 	return b;} static intpjwit(int f, char *s, int ssz, int scale){	SDL_Surface *g,  *line;	int dummy, advance, r;	SDL_RWops *ops;	TTF_Font *pf;	Fontchar fc;	uint8_t *b; 	r = 0;	g = NULL;	b = NULL;	line = NULL;	dprintf(f, "0x%X\t0x%X\t%s.%X-%X\n", 0, 0, prefix, 0, 0);	dprintf(f, "0x%X\t0x%X\t%s.%X-%X\n", Substitute, Substitute, prefix, Substitute, Substitute);	if((ops = SDL_RWFromConstMem(pjw, sizeof(pjw))) == NULL){		fprintf(stderr, "pjw: %s\n", SDL_GetError());		return -1;	}	if((pf = TTF_OpenFontRW(ops, 1, ptsz*scale)) == NULL ||	   TTF_SetFontSize(pf, ptsz*scale) != 0 ||	   TTF_GlyphMetrics32(pf, Substitute, &dummy, &dummy, &dummy, &dummy, &advance) != 0 ||	   (g = TTF_RenderGlyph32_Shaded(pf, Substitute, white, black)) == NULL ||	   (line = SDL_CreateRGBSurfaceWithFormat(0, g->w, g->h, 32, SDL_PIXELFORMAT_XRGB8888)) == NULL)		goto err;	SDL_FillRect(line, NULL, SDL_MapRGBA(line->format, 0, 0, 0, 0));	SDL_BlitSurface(g, NULL, line, NULL);	b = surf2k8(line);	if(b == NULL)		goto err; 	snprintf(s, ssz, "%s.%X-%X", opath, 0, 0);	memset(&fc, 0, sizeof(fc));	fc.width = advance;	fc.bottom = line->h;	if(savesubfont(b, line->w, line->h, TTF_FontAscent(pf), 1, &fc, 1, s) != 0)		goto err2;	snprintf(s, ssz, "%s.%X-%X", opath, Substitute, Substitute);	if(savesubfont(b, line->w, line->h, TTF_FontAscent(pf), 1, &fc, 1, s) != 0)		goto err2; 	if(0){err:		fprintf(stderr, "pjw: %s\n", TTF_GetError());err2:		r = -1;	}	if(g != NULL)		SDL_FreeSurface(g);	if(line != NULL)		SDL_FreeSurface(line);	if(pf != NULL)		TTF_CloseFont(pf);	else		SDL_RWclose(ops);	free(b);	return r;} intmain(int argc, char **argv){	int c, optend, nr, i, fdfont, ssz, res, dpi;	int minx, maxx, advance, dummy, w, h, maxh, pjwface, hdr, scale;	struct parg_state ps;	Range *ranges, *rn;	char *ofile, *s;	TTF_Font *f;	uint8_t *b;	Uint32 r; 	if(TTF_Init() != 0){		fprintf(stderr, "ttf init failed: %s\n", TTF_GetError());		return 1;	} 	dpi = -1;	ptsz = 16;	hint = TTF_HINTING_NORMAL;	style = TTF_STYLE_NORMAL;	pjwface = 1;	scale = 1; 	parg_init(&ps);	optend = parg_reorder(argc, argv, opts, NULL);	while((c = parg_getopt(&ps, argc, argv, opts)) >= 0){		switch(c){		case 1:			break;		case 'd':			dpi = atoi(ps.optarg);			break;		case 's':			if((ptsz = atoi(ps.optarg)) < 2){				fprintf(stderr, "invalid point size: %s\n", ps.optarg);				return 1;			}			break;		case 'x':			if((scale = atoi(ps.optarg)) < 1){				fprintf(stderr, "invalid scaling: %s\n", ps.optarg);				return 1;			}			break;		case 'H':			if(strcmp(ps.optarg, "normal") == 0)				hint = TTF_HINTING_NORMAL;			else if(strcmp(ps.optarg, "light") == 0)				hint = TTF_HINTING_LIGHT;			else if(strcmp(ps.optarg, "mono") == 0)				hint = TTF_HINTING_MONO;			else if(strcmp(ps.optarg, "none") == 0)				hint = TTF_HINTING_NONE;			else if(strcmp(ps.optarg, "light_subpixel") == 0)				hint = TTF_HINTING_LIGHT_SUBPIXEL;			else{				fprintf(stderr, "invalid hinting: %s\n", ps.optarg);				return 1;			}			break;		case 'P':			pjwface = 0;			fprintf(stderr, "shame on you!\n");			break;		case 'S':			if(strcmp(ps.optarg, "normal") == 0)				style = TTF_STYLE_NORMAL;			else if(strcmp(ps.optarg, "bold") == 0)				style |= TTF_STYLE_BOLD;			else if(strcmp(ps.optarg, "italic") == 0)				style |= TTF_STYLE_ITALIC;			else if(strcmp(ps.optarg, "underline") == 0)				style |= TTF_STYLE_UNDERLINE;			else if(strcmp(ps.optarg, "strikethrough") == 0)				style |= TTF_STYLE_STRIKETHROUGH;			else{				fprintf(stderr, "invalid style: %s\n", ps.optarg);				return 1;			}			break;		case 'h':usage:			fprintf(stderr, "usage: %s [-d DPI] [-s point_size] [-x scale] [-H hinting] [-S style [-S ...]] [-P] FILE [FILE ...] PATH/PREFIX\n", argv[0]);			fprintf(stderr, " -H: normal (default), none, light, mono, light_subpixel\n");			fprintf(stderr, " -S: normal (default), bold, italic, underline, strikethrough\n");			fprintf(stderr, " -P: I don't want PJW face in my font (shame on you)\n");			return 1;		case '?':			fprintf(stderr, "unknown option -%c\n", ps.optopt);			return 1;		default:			fprintf(stderr, "unhandled option -%c\n", c);			return 1;		}	} 	if(argc-optend < 2)		goto usage; 	opath = argv[argc-1]; 	i = strlen(opath);	s = malloc(ssz = i+64);	snprintf(s, ssz, "%s.font", opath); 	if((prefix = strrchr(s, '/')) == NULL)		prefix = s;	else{		*prefix++ = 0;		mkdir(s, 0755);		prefix[-1] = '/';	} 	res = 0;	if((fdfont = open(s, O_CREAT|O_TRUNC|O_WRONLY|O_CLOEXEC, 0644)) < 0){		prefix = NULL;		perror(s);		goto err;	}	s[i] = 0;	prefix = strdup(prefix);	maxh = 0; 	for(hdr = 0; optend < argc-1; optend++){		ofile = argv[optend]; 		if((f = TTF_OpenFont(ofile, ptsz)) == NULL){			fprintf(stderr, "%s: %s\n", argv[0], TTF_GetError());			goto err;		}		if(dpi > 0)			TTF_SetFontSizeDPI(f, ptsz, dpi, dpi); 		TTF_SetFontStyle(f, style);		TTF_SetFontKerning(f, 0);		TTF_SetFontHinting(f, hint); 		if(!hdr){			h = TTF_FontLineSkip(f);			dprintf(fdfont, "%-4d %d\n", h*scale, TTF_FontAscent(f)*scale);			hdr = 1;		} 		if((ranges = getcharset(ofile, &nr, pjwface)) == NULL)			goto err; 		for(i = 0; i < nr; i++){			rn = ranges+i;			w = 0;			for(r = rn->min; r <= rn->max; r++){				if(TTF_GlyphMetrics32(f, r, &minx, &maxx, &dummy, &dummy, &advance) == 0){					advance = MAX(maxx-minx, advance);					if(w+advance > Maxsubfwidth){						/* subfont too wide - split the range */						ranges = realloc(ranges, (nr+1)*sizeof(Range));						rn = ranges+i;						memmove(rn+1, rn, (nr-i)*sizeof(Range));						rn[0].max = r-1;						rn[1].min = r;						nr++;						break;					}					w += advance;				}			} 			if(w == 0){				/* skip zero-width subfonts altogether */				memmove(rn, rn+1, (nr-i-1)*sizeof(Range));				nr--;				i--;			}		} 		for(i = 0; i < nr; i++){			int ncs, x, y;			SDL_Surface *g, *line;			Fontchar *cs;			SDL_Rect dst; 			rn = ranges+i;			dprintf(fdfont, "0x%X\t0x%X\t%s.%X-%X\n", rn->min, rn->max, prefix, rn->min, rn->max);			w = 0;			for(r = rn->min; r <= rn->max; r++){				if(TTF_GlyphMetrics32(f, r, &minx, &maxx, &dummy, &dummy, &advance) == 0)					w += MAX(maxx-minx, advance);			}			h = TTF_FontLineSkip(f);			line = SDL_CreateRGBSurfaceWithFormat(0, w, h, 32, SDL_PIXELFORMAT_XRGB8888);			SDL_FillRect(line, NULL, SDL_MapRGBA(line->format, 0, 0, 0, 0)); 			memset(&dst, 0, sizeof(dst));			cs = calloc(rn->max - rn->min + 1, sizeof(*cs));			for(r = rn->min, ncs = 0; r <= rn->max; r++, ncs++){				cs[ncs].x = dst.x; 				if(TTF_GlyphMetrics32(f, r, &minx, &maxx, &dummy, &dummy, &advance) != 0){					fprintf(stderr, "%s: rune 0x%x: %s\n", ofile, r, TTF_GetError());					free(cs);					goto err;				}				if((g = TTF_RenderGlyph32_Shaded(f, r, white, black)) == NULL){					/* zero-width chars end up here */					continue;				} 				// this would make sure glyphs always fit, but it also				// makes some monospace fonts not actually have a fixed width				//advance = MAX(g->w, MAX(maxx-minx, advance)); 				if(w < dst.x+advance || h < g->h){					SDL_Surface *bigger;					if(w < dst.x+advance)						w = dst.x+advance;					if(h < g->h)						h = g->h;					bigger = SDL_CreateRGBSurfaceWithFormat(0, w, h, 32, SDL_PIXELFORMAT_XRGB8888);					SDL_FillRect(bigger, NULL, SDL_MapRGBA(bigger->format, 0, 0, 0, 0));					SDL_BlitSurface(line, NULL, bigger, NULL);					SDL_FreeSurface(line);					line = bigger;				} 				for(y = 0; y < g->h; y++){					for(x = 0; x < g->w; x++){						if(((uint8_t*)g->pixels+y*g->pitch)[x*g->format->BytesPerPixel] != 0){							cs[ncs].top = y;							for(y = g->h-1; y >= cs[ncs].top; y--){								for(x = g->w-1; x >= 0; x--){									if(((uint8_t*)g->pixels+y*g->pitch)[x*g->format->BytesPerPixel] != 0){										cs[ncs].bottom = y+1;										goto done;									}								}							}						}					}				}done://				if(r == RUNE)//					fprintf(stderr, "0x%x is %dx%d, top=%d bottom=%d\n", r, g->w, g->h, cs[ncs].top, cs[ncs].bottom);				if(maxh < cs[ncs].bottom)					maxh = cs[ncs].bottom;				SDL_BlitSurface(g, NULL, line, &dst);				cs[ncs].width = advance;				dst.x += advance;				SDL_FreeSurface(g);			}			snprintf(s, ssz, "%s.%X-%X", opath, rn->min, rn->max);			b = surf2k8(line);			if(savesubfont(b, line->w, line->h, TTF_FontAscent(f), scale, cs, ncs, s) != 0)				goto err;			free(b);			free(cs);			SDL_FreeSurface(line);		} 		TTF_CloseFont(f);		free(ranges);	} 	if(pjwface)		pjwit(fdfont, s, ssz, scale); 	/* actual height of the font might be slightly different, so rewrite it */	lseek(fdfont, 0, 0);	dprintf(fdfont, "%-4d", maxh*scale);	close(fdfont); 	if(0){err:		res = 1;	}	free(s);	free(prefix); 	return res;}#endif

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