bdf2sfd

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

bdf2sfd.c (5971B)


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