bdf2sfd

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

bdf2sfd.c (5848B)


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