bdf2sfd

BDF to SFD converter, allowing to vectorize bitmap fonts
Log | Files | Refs | README | LICENSE

bdf2sfd.c (5925B)


      1 /*
      2  * bdf2sfd 1.1.6
      3  * Copyright (c) 2019-2021, Frederic Cambus
      4  * https://github.com/fcambus/bdf2sfd
      5  *
      6  * Created:      2019-11-21
      7  * Last Updated: 2021-02-28
      8  *
      9  * bdf2sfd is released under the BSD 2-Clause license
     10  * See LICENSE file for details
     11  */
     12 
     13 #include <sys/stat.h>
     14 #include <sys/time.h>
     15 #include <sys/types.h>
     16 #include <err.h>
     17 #include <getopt.h>
     18 #include <inttypes.h>
     19 #include <stdbool.h>
     20 #include <stdlib.h>
     21 #include <stdint.h>
     22 #include <stdio.h>
     23 #include <string.h>
     24 #include <time.h>
     25 
     26 #ifdef HAVE_SECCOMP
     27 #include <sys/prctl.h>
     28 #include <linux/seccomp.h>
     29 #include "seccomp.h"
     30 #endif
     31 
     32 #include "compat.h"
     33 #include "config.h"
     34 #include "header.h"
     35 #include "parse.h"
     36 #include "polygon.h"
     37 
     38 static void
     39 usage()
     40 {
     41 	printf("bdf2sfd [-hv] [-f name] [-p name] font.bdf\n\n"
     42 	    "The options are as follows:\n\n"
     43 	    "	-f name	Specify font name.\n"
     44 	    "	-p name	Specify PostScript font name.\n"
     45 	    "	-h	Display usage.\n"
     46 	    "	-v	Display version.\n");
     47 }
     48 
     49 static void
     50 error(const char *str)
     51 {
     52 	errx(EXIT_FAILURE, "%s", str);
     53 }
     54 
     55 int
     56 main(int argc, char *argv[])
     57 {
     58 	struct timespec begin, current, elapsed;
     59 	struct stat bdf_stat;
     60 
     61 	float x = 0.0, y = 0.0;
     62 	float xlength = 64.0, ylength = 64.0; /* Default for 8x16 fonts */
     63 
     64 	uint64_t glyphs = 0;
     65 	uint32_t height = 0, width = 0;
     66 	uint32_t ascent = 0, descent = 0;
     67 	uint32_t mask = 0;
     68 
     69 	int opt, key, stride;
     70 
     71 	const char *errstr = NULL;
     72 	char *input;
     73 	char *value = NULL;
     74 	char linebuffer[LINE_LENGTH_MAX];
     75 
     76 	bool readglyph = false;
     77 	bool name_allocated = false, psname_allocated = false;
     78 
     79 	FILE *bdf;
     80 
     81 	struct fontinfo font;
     82 	memset(&font, 0, sizeof(struct fontinfo));
     83 
     84 	if (pledge("stdio rpath", NULL) == -1) {
     85 		err(EXIT_FAILURE, "pledge");
     86 	}
     87 
     88 #ifdef HAVE_SECCOMP
     89 	if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
     90 		perror("Can't initialize seccomp");
     91 		return EXIT_FAILURE;
     92 	}
     93 
     94 	if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &bdf2sfd)) {
     95 		perror("Can't load seccomp filter");
     96 		return EXIT_FAILURE;
     97 	}
     98 #endif
     99 
    100 	while ((opt = getopt(argc, argv, "f:p:hv")) != -1) {
    101 		switch (opt) {
    102 		case 'f':
    103 			font.name = optarg;
    104 			break;
    105 
    106 		case 'p':
    107 			font.psname = optarg;
    108 			break;
    109 
    110 		case 'h':
    111 			usage();
    112 			return EXIT_SUCCESS;
    113 
    114 		case 'v':
    115 			printf("%s\n", VERSION);
    116 			return EXIT_SUCCESS;
    117 		}
    118 	}
    119 
    120 	if (optind < argc) {
    121 		input = argv[optind];
    122 	} else {
    123 		usage();
    124 		return EXIT_SUCCESS;
    125 	}
    126 
    127 	/* Starting timer */
    128 	clock_gettime(CLOCK_MONOTONIC, &begin);
    129 
    130 	/* Open BDF file */
    131 	if (!strcmp(input, "-")) {
    132 		/* Read from standard input */
    133 		bdf = stdin;
    134 	} else {
    135 		/* Attempt to read from file */
    136 		if (!(bdf = fopen(input, "r"))) {
    137 			perror("Can't open BDF file");
    138 			return EXIT_FAILURE;
    139 		}
    140 	}
    141 
    142 	/* Get BDF file size */
    143 	if (fstat(fileno(bdf), &bdf_stat)) {
    144 		perror("Can't stat BDF file");
    145 		return EXIT_FAILURE;
    146 	}
    147 
    148 	while (fgets(linebuffer, LINE_LENGTH_MAX, bdf)) {
    149 		if (!*linebuffer)
    150 			continue;
    151 
    152 		key = parseLine(linebuffer);
    153 
    154 		switch(key) {
    155 		case FAMILY_NAME:
    156 		case COPYRIGHT:
    157 		case FONT_ASCENT:
    158 		case FONT_DESCENT:
    159 		case FONT_VERSION:
    160 		case CHARS:
    161 		case STARTCHAR:
    162 		case ENCODING:
    163 			value = strtok(NULL, "\n");
    164 
    165 			if (!value)
    166 				continue;
    167 		}
    168 
    169 		switch(key) {
    170 		case FAMILY_NAME:
    171 			if (!font.name) {
    172 				if ((font.name = strdup(value)) == NULL)
    173 					error("Memory allocation error.");
    174 
    175 				name_allocated = true;
    176 			}
    177 
    178 			if (!font.psname) {
    179 				if ((font.psname = strdup(value)) == NULL)
    180 					error("Memory allocation error.");
    181 
    182 				psname_allocated = true;
    183 			}
    184 
    185 			continue;
    186 
    187 		case COPYRIGHT:
    188 			if ((font.copyright = strdup(value)) == NULL)
    189 				error("Memory allocation error.");
    190 
    191 			continue;
    192 
    193 		case FONTBOUNDINGBOX:
    194 			value = strtok(NULL, " \t");
    195 
    196 			if (value)
    197 				width = strtonum(value, 0, 32, &errstr);
    198 
    199 			if (errstr)
    200 				error("Invalid value for FONTBOUNDINGBOX.");
    201 
    202 			value = strtok(NULL, " \t");
    203 
    204 			if (value)
    205 				height = strtonum(value, 0, 64, &errstr);
    206 
    207 			if (errstr)
    208 				error("Invalid value for FONTBOUNDINGBOX.");
    209 
    210 			if (!width || !height)
    211 				error("Invalid value for FONTBOUNDINGBOX.");
    212 
    213 			xlength = 512.0 / width;
    214 			ylength = 1024.0 / height;
    215 
    216 			stride = (width + 7) / 8;
    217 			mask = 1 << (stride * 8 - 1);
    218 
    219 			continue;
    220 
    221 		case FONT_ASCENT:
    222 			ascent = strtonum(value, 0, 64, &errstr);
    223 
    224 			if (!errstr)
    225 				font.ascent = ascent * ylength;
    226 			else
    227 				error("Invalid value for FONT_ASCENT.");
    228 
    229 			continue;
    230 
    231 		case FONT_DESCENT:
    232 			descent = strtonum(value, 0, 64, &errstr);
    233 
    234 			if (!errstr)
    235 				font.descent = descent * ylength;
    236 			else
    237 				error("Invalid value for FONT_DESCENT.");
    238 
    239 			continue;
    240 
    241 		case FONT_VERSION:
    242 			if ((font.version = strdup(value)) == NULL)
    243 				error("Memory allocation error.");
    244 
    245 			continue;
    246 
    247 		case CHARS:
    248 			font.chars = value;
    249 
    250 			if (font.chars)
    251 				header(stdout, &font);
    252 			else
    253 				error("Invalid value for CHARS.");
    254 
    255 			continue;
    256 
    257 		case STARTCHAR:
    258 			fprintf(stdout, "StartChar: %s", value);
    259 
    260 			continue;
    261 
    262 		case ENCODING:
    263 			fprintf(stdout, "\nEncoding: %s %s %s\n",
    264 			    value, value, value);
    265 
    266 			continue;
    267 
    268 		case BITMAP:
    269 			fprintf(stdout, "Width: 512\n"
    270 					"Flags: HW\n"
    271 					"LayerCount: 2\n"
    272 					"Fore\n"
    273 					"SplineSet\n");
    274 
    275 			y = font.ascent;
    276 			readglyph = true;
    277 			glyphs++;
    278 
    279 			continue;
    280 
    281 		case ENDCHAR:
    282 			fprintf(stdout, "EndSplineSet\n"
    283 					"EndChar\n\n");
    284 
    285 			readglyph = false;
    286 			continue;
    287 		}
    288 
    289 		if (readglyph) {
    290 			uint32_t row = strtoul(linebuffer, NULL, 16);
    291 
    292 			polygon(row, mask, width, x, y, xlength, ylength);
    293 			
    294 			y -= ylength;
    295 		}
    296 	}
    297 
    298 	fprintf(stdout, "EndChars\n"
    299 			"EndSplineFont\n");
    300 
    301 	/* Stopping timer */
    302 	clock_gettime(CLOCK_MONOTONIC, &current);
    303 
    304 	timespecsub(&current, &begin, &elapsed);
    305 
    306 	/* Printing results */
    307 	fprintf(stderr, "Processed %" PRIu64 " glyphs in %f seconds.\n",
    308 	    glyphs, elapsed.tv_sec + elapsed.tv_nsec / 1E9);
    309 
    310 	/* Clean up */
    311 	fclose(bdf);
    312 
    313 	if (name_allocated)
    314 		free(font.name);
    315 
    316 	if (psname_allocated)
    317 		free(font.psname);
    318 
    319 	free(font.copyright);
    320 	free(font.version);
    321 
    322 	return EXIT_SUCCESS;
    323 }