| /**************************************************************************** |
| * tools/bdf-converter.c |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| * |
| ****************************************************************************/ |
| |
| /* Based one the "Glyph Bitmap Distribution Format (BDF) Specification", |
| * Version 2.2, by Adobe Systems Incorporated. |
| */ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <stdbool.h> |
| #include <string.h> |
| #include <ctype.h> |
| |
| /**************************************************************************** |
| * Pre-processor Definitions |
| ****************************************************************************/ |
| |
| #if 0 |
| # define VERBOSE |
| # define DBG |
| #endif |
| |
| /* BDF Specification Version 2.2: |
| * This version lifts the restriction on line length. In this version, |
| * the new maximum length of a value of the type string is 65535 characters, |
| * and hence lines may now be at least this long. |
| */ |
| |
| #define BDF_MAX_LINE_LENGTH 65535 |
| |
| /* Ranges of 7-bit and 8-bit fonts */ |
| |
| #define NXFONT_MIN7BIT 33 |
| #define NXFONT_MAX7BIT 126 |
| |
| #define NXFONT_MIN8BIT 161 |
| #define NXFONT_MAX8BIT 255 |
| |
| /**************************************************************************** |
| * Private Types |
| ****************************************************************************/ |
| |
| /* This structure holds information about a glyph */ |
| |
| typedef struct glyphinfo_s |
| { |
| char *name; /* Name for they glyph */ |
| int encoding; /* The Adobe Standard Encoding value */ |
| int dw_x0; /* Width in x of the vector indicating |
| * the position of the next glyph's origin |
| * relative to the origin of this glyph */ |
| int dw_y0; /* Width in y of the vector indicating |
| * the position of the next glyph's origin |
| * relative to the origin of this glyph */ |
| int bb_w; /* The width of the black pixels in x */ |
| int bb_h; /* The height of the black pixels in y */ |
| int bb_x_off; /* X displacement of the lower left corner |
| * of the bitmap from origin 0 */ |
| int bb_y_off; /* Y displacement of the lower left corner |
| * of the bitmap from origin 0 */ |
| uint64_t *bitmap; /* Hexadecimal data for the character bitmap */ |
| } glyphinfo_t; |
| |
| /* This structures provides the metrics for one glyph */ |
| |
| typedef struct nx_fontmetric_s |
| { |
| uint32_t stride : 3; /* Width of one font row in bytes */ |
| uint32_t width : 6; /* Width of the font in bits */ |
| uint32_t height : 6; /* Height of the font in rows */ |
| uint32_t xoffset : 6; /* Top, left-hand corner X-offset in pixels */ |
| uint32_t yoffset : 6; /* Top, left-hand corner y-offset in pixels */ |
| uint32_t unused : 5; |
| } nx_fontmetric_t; |
| |
| /**************************************************************************** |
| * Private Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: my_strtok_r |
| * |
| * Description: |
| * MinGW does not seem to provide strtok_r |
| * |
| ****************************************************************************/ |
| |
| #ifndef HAVE_STRTOK_R |
| static char *my_strtok_r(char *str, const char *delim, char **saveptr) |
| { |
| char *pbegin; |
| char *pend = NULL; |
| |
| /* Decide if we are starting a new string or continuing from |
| * the point we left off. |
| */ |
| |
| if (str) |
| { |
| pbegin = str; |
| } |
| else if (saveptr && *saveptr) |
| { |
| pbegin = *saveptr; |
| } |
| else |
| { |
| return NULL; |
| } |
| |
| /* Find the beginning of the next token */ |
| |
| for (; |
| *pbegin && strchr(delim, *pbegin) != NULL; |
| pbegin++); |
| |
| /* If we are at the end of the string with nothing |
| * but delimiters found, then return NULL. |
| */ |
| |
| if (!*pbegin) |
| { |
| return NULL; |
| } |
| |
| /* Find the end of the token */ |
| |
| for (pend = pbegin + 1; |
| *pend && strchr(delim, *pend) == NULL; |
| pend++); |
| |
| /* pend either points to the end of the string or to |
| * the first delimiter after the string. |
| */ |
| |
| if (*pend) |
| { |
| /* Turn the delimiter into a null terminator */ |
| |
| *pend++ = '\0'; |
| } |
| |
| /* Save the pointer where we left off and return the |
| * beginning of the token. |
| */ |
| |
| if (saveptr) |
| { |
| *saveptr = pend; |
| } |
| |
| return pbegin; |
| } |
| |
| #undef strtok_r |
| #define strtok_r my_strtok_r |
| #endif |
| |
| /**************************************************************************** |
| * Name: trimline |
| * |
| * Description: |
| * Trims the line removing space characters at the front and at the end |
| * of the line. |
| * |
| * Input Parameters: |
| * line - The line to trim |
| * |
| ****************************************************************************/ |
| |
| static void trimline(char *line) |
| { |
| char *str; |
| str = line; |
| char *strend; |
| for (strend = str + strlen(str) - 1; |
| strend >= str && isspace((int)(*strend)); |
| strend--); |
| *(strend + 1) = 0; |
| } |
| |
| /**************************************************************************** |
| * Name: bdf_parseIntLine |
| * |
| * Description: |
| * Parses a line containing a BDF property followed by integers. It will |
| * ignore the first token that corresponds to the property name. |
| * |
| * Input Parameters: |
| * line - A line with a BDF property followed by integers, i.e.: |
| * "FONTBOUNDINGBOX 8 13 0 -2" |
| * count - How many integers are specified by the BDF property. In the |
| * example above, count = 4. |
| * info - A pointer to memory provided by the caller in which to |
| * return the array of integers. For the example above: |
| * info[0] = 8 |
| * info[1] = 13 |
| * info[2] = 0 |
| * info[3] = -2 |
| * |
| ****************************************************************************/ |
| |
| static void bdf_parseintline(char *line, unsigned int count, int *info) |
| { |
| char *str; |
| char *token; |
| char *saveptr1; |
| str = line; |
| |
| /* Ignore the key */ |
| |
| token = (char *)strtok_r(str, " ", &saveptr1); |
| |
| while ((token = (char *)strtok_r(NULL, " ", &saveptr1)) && count--) |
| { |
| *(info++) = atoi(token); |
| } |
| } |
| |
| /**************************************************************************** |
| * Name: bdf_printglyphinfo |
| * |
| * Description: |
| * Prints the information available for a glyph. |
| * |
| * Input Parameters: |
| * ginfo - A glyphinfo_t struct with the glyph's information. |
| * |
| ****************************************************************************/ |
| |
| #ifdef DBG |
| static void bdf_printglyphinfo(const glyphinfo_t *ginfo) |
| { |
| printf("NAME = %s\n", ginfo->name); |
| printf("ENCODING = %d\n", ginfo->encoding); |
| printf("DW_X0 = %d\n", ginfo->dw_x0); |
| printf("DW_Y0 = %d\n", ginfo->dw_y0); |
| printf("BB_W = %d\n", ginfo->bb_w); |
| printf("BB_H = %d\n", ginfo->bb_h); |
| printf("BB_X_OFF = %d\n", ginfo->bb_x_off); |
| printf("BB_Y_OFF = %d\n", ginfo->bb_y_off); |
| int i; |
| for (i = 0; i < ginfo->bb_h; i++) |
| { |
| printf("BITMAP[%d] = %x\n", i, ginfo->bitmap[i]); |
| } |
| } |
| #endif /* DBG */ |
| |
| /**************************************************************************** |
| * Name: bdf_printnxmetricinfo |
| * |
| * Description: |
| * Prints the information available for a glyph's metric in the NX |
| * graphics system. |
| * |
| * Input Parameters: |
| * info - A nx_fontmetric_t struct with the glyph's information. |
| * |
| ****************************************************************************/ |
| |
| #ifdef DBG |
| static void bdf_printnxmetricinfo(const nx_fontmetric_t *info) |
| { |
| printf("STRIDE = %d\n", info->stride); |
| printf("WIDTH = %d\n", info->width); |
| printf("HEIGHT = %d\n", info->height); |
| printf("XOFFSET = %d\n", info->xoffset); |
| printf("YOFFSET = %d\n", info->yoffset); |
| } |
| #endif /* DBG */ |
| |
| /**************************************************************************** |
| * Name: bdf_getglyphinfo |
| * |
| * Description: |
| * Obtains the information for an individual glyph. The BDF properties |
| * taken into account are: |
| * - ENCODING |
| * - DWIDTH |
| * - BBX |
| * BDF properties ignored: |
| * - SWIDTH |
| * - SWIDTH1 |
| * - DWIDTH1 |
| * - VVECTOR |
| * |
| * Input Parameters: |
| * file - The input file stream pointing to the first line of the |
| * glyph's information (right after STARTCHAR). |
| * ginfo - A glyphinfo_t struct to fill with the glyph's information. |
| * |
| ****************************************************************************/ |
| |
| static void bdf_getglyphinfo(FILE *file, glyphinfo_t *ginfo) |
| { |
| char line[BDF_MAX_LINE_LENGTH]; |
| char linecopy[BDF_MAX_LINE_LENGTH]; |
| char *str; |
| char *token; |
| char *saveptr1; |
| bool done; |
| |
| done = false; |
| |
| while (fgets(line, BDF_MAX_LINE_LENGTH, file) != NULL && !done) |
| { |
| trimline(line); |
| strcpy(linecopy, line); |
| str = line; |
| |
| while ((token = (char *)strtok_r(str, " ", &saveptr1))) |
| { |
| /* ENCODING information */ |
| |
| if (strcmp(token, "ENCODING") == 0) |
| { |
| token = (char *)strtok_r(NULL, " ", &saveptr1); |
| ginfo->encoding = atoi(token); |
| } |
| |
| /* DWIDTH information */ |
| |
| if (strcmp(token, "DWIDTH") == 0) |
| { |
| token = (char *)strtok_r(NULL, " ", &saveptr1); |
| ginfo->dw_x0 = atoi(token); |
| token = (char *)strtok_r(NULL, " ", &saveptr1); |
| ginfo->dw_y0 = atoi(token); |
| } |
| |
| /* BBX information */ |
| |
| else if (strcmp(token, "BBX") == 0) |
| { |
| int bbxinfo[4]; |
| bdf_parseintline(linecopy, 4, bbxinfo); |
| ginfo->bb_w = bbxinfo[0]; |
| ginfo->bb_h = bbxinfo[1]; |
| ginfo->bb_x_off = bbxinfo[2]; |
| ginfo->bb_y_off = bbxinfo[3]; |
| |
| /* This is the last BDF property of interest */ |
| |
| done = true; |
| } |
| |
| str = NULL; |
| } |
| } |
| } |
| |
| /**************************************************************************** |
| * Name: bdf_getglyphbitmap |
| * |
| * Description: |
| * Obtains the character bitmap information for an individual glyph. |
| * |
| * Input Parameters: |
| * file - The input file stream pointing to the first line of the |
| * glyph's bitmap (right after BITMAP). |
| * ginfo - A glyphinfo_t struct to fill with the glyph's bitmap. |
| * |
| ****************************************************************************/ |
| |
| static void bdf_getglyphbitmap(FILE *file, glyphinfo_t *ginfo) |
| { |
| char line[BDF_MAX_LINE_LENGTH]; |
| uint64_t *bitmap; |
| int readingbitmap; |
| |
| bitmap = ginfo->bitmap; |
| readingbitmap = ginfo->bb_h; |
| |
| while (readingbitmap > 0) |
| { |
| if (fgets(line, BDF_MAX_LINE_LENGTH, file) != NULL) |
| { |
| trimline(line); |
| |
| if (strcmp(line, "ENDCHAR") == 0) |
| { |
| readingbitmap = 0; |
| } |
| else |
| { |
| char *endptr; |
| *bitmap = strtoul(line, &endptr, 16); |
| bitmap++; |
| readingbitmap--; |
| } |
| } |
| else |
| { |
| /* error condition */ |
| |
| readingbitmap = 0; |
| } |
| } |
| } |
| |
| /**************************************************************************** |
| * Name: bdf_getstride |
| * |
| * Description: |
| * Obtains the stride for an individual glyph. The stride is the width |
| * of one glyph's bitmap row in bytes. |
| * |
| * Input Parameters: |
| * ginfo - A glyphinfo_t struct with the glyph's information. |
| * stride - A pointer to memory provided by the caller in which to |
| * return the stride. |
| * |
| ****************************************************************************/ |
| |
| static void bdf_getstride(glyphinfo_t *ginfo, uint32_t *stride) |
| { |
| *stride = (ginfo->bb_w % 8 == 0) ? ginfo->bb_w / 8 : ginfo->bb_w / 8 + 1; |
| } |
| |
| /**************************************************************************** |
| * Name: bdf_printoutput |
| * |
| * Description: |
| * Prints to the output stream the information of an individual glyph in |
| * the NuttX font format. |
| * |
| * Input Parameters: |
| * out - The output stream. |
| * ginfo - A glyphinfo_t struct with the glyph's information. |
| * nxmetric - A nx_fontmetric_t struct with the glyph's information. |
| * |
| ****************************************************************************/ |
| |
| static void bdf_printoutput(FILE *out, |
| glyphinfo_t *ginfo, |
| nx_fontmetric_t *nxmetric) |
| { |
| int i; |
| int j; |
| |
| /* Only interested in the 7 and 8 bit ranges */ |
| |
| if ((ginfo->encoding >= NXFONT_MIN7BIT && |
| ginfo->encoding <= NXFONT_MAX7BIT) || |
| (ginfo->encoding >= NXFONT_MIN8BIT && |
| ginfo->encoding <= NXFONT_MAX8BIT)) |
| { |
| /* Glyph general info */ |
| |
| if (ginfo->bb_x_off < 0) |
| { |
| fprintf(out, |
| "/* %s (%d) -- NOTE: Xoffset should be %d, not 0. */\n", |
| ginfo->name, |
| ginfo->encoding, |
| ginfo->bb_x_off); |
| } |
| else |
| { |
| fprintf(out, "/* %s (%d) */\n", ginfo->name, ginfo->encoding); |
| } |
| |
| /* Glyph metrics */ |
| |
| fprintf(out, |
| "#define NXFONT_METRICS_%d {%d, %d, %d, %d, %d, 0}\n", |
| ginfo->encoding, |
| nxmetric->stride, |
| nxmetric->width, |
| nxmetric->height, |
| nxmetric->xoffset, |
| nxmetric->yoffset); |
| |
| /* Glyph bitmap */ |
| |
| fprintf(out, "#define NXFONT_BITMAP_%d {", ginfo->encoding); |
| |
| for (i = 0; i < ginfo->bb_h - 1; i++) |
| { |
| for (j = 1; j <= nxmetric->stride; j++) |
| { |
| int nxbyteoffset; |
| uint8_t nxbyte = 0; |
| uint64_t tempbitmap = ginfo->bitmap[i]; |
| |
| /* Get the next byte */ |
| |
| nxbyteoffset = (nxmetric->stride - j) * 8; |
| nxbyte = (uint8_t)(tempbitmap >> nxbyteoffset); |
| fprintf(out, "0x%x, ", nxbyte); |
| } |
| } |
| |
| /* Different behavior for the last bitmap */ |
| |
| for (j = 1; j <= nxmetric->stride; j++) |
| { |
| int nxbyteoffset; |
| uint8_t nxbyte = 0; |
| uint64_t tempbitmap = ginfo->bitmap[i]; |
| |
| /* Get the next byte */ |
| |
| nxbyteoffset = (nxmetric->stride - j) * 8; |
| nxbyte = (uint8_t)(tempbitmap >> nxbyteoffset); |
| |
| if (j == nxmetric->stride) |
| { |
| fprintf(out, "0x%x}\n", nxbyte); |
| } |
| else |
| { |
| fprintf(out, "0x%x, ", nxbyte); |
| } |
| } |
| |
| fprintf(out, "\n"); |
| } |
| } |
| |
| /**************************************************************************** |
| * Main |
| ****************************************************************************/ |
| |
| int main(int argc, char **argv) |
| { |
| FILE *file, *out; |
| char line[BDF_MAX_LINE_LENGTH]; |
| char linecopy[BDF_MAX_LINE_LENGTH]; |
| char *str; |
| char *token; |
| char *saveptr1; |
| char *input; |
| char *output; |
| |
| /* FONTBOUNDINGBOX properties */ |
| |
| int fbb_x = 0; |
| int fbb_y = 0; |
| int fbb_y_off = 0; |
| |
| /* int fbb_x_off = 0; */ |
| |
| /* Input BDF file */ |
| |
| input = argv[1]; |
| |
| if (input == NULL) |
| { |
| printf("%s: no input file\n", argv[0]); |
| exit(0); |
| } |
| |
| file = fopen(input, "r"); |
| |
| if (file == NULL) |
| { |
| printf("%s: error opening file %s\n", argv[0], input); |
| exit(0); |
| } |
| else |
| { |
| #ifdef VERBOSE |
| printf("Opening \"%s\"\n", input); |
| #endif /* VERBOSE */ |
| } |
| |
| /* Output file */ |
| |
| if (argv[2]) |
| { |
| output = argv[2]; |
| } |
| else |
| { |
| output = "nxfonts_myfont.h"; |
| } |
| |
| out = fopen(output, "w"); |
| |
| if (out == NULL) |
| { |
| printf("%s: error opening file %s\n", argv[0], output); |
| fclose(file); |
| exit(0); |
| } |
| else |
| { |
| while (fgets(line, BDF_MAX_LINE_LENGTH, file) != NULL) |
| { |
| #ifdef DBG |
| printf("--\n"); |
| #endif /* DBG */ |
| |
| /* Save a copy of the line */ |
| |
| strcpy(linecopy, line); |
| |
| /* Clean it */ |
| |
| trimline(line); |
| str = line; |
| |
| while ((token = (char *)strtok_r(str, " ", &saveptr1))) |
| { |
| /* FONTBOUNDINGBOX - Global font information */ |
| |
| if (strcmp(token, "FONTBOUNDINGBOX") == 0) |
| { |
| int fbbinfo[4]; |
| bdf_parseintline(linecopy, 4, fbbinfo); |
| fbb_x = fbbinfo[0]; |
| fbb_y = fbbinfo[1]; |
| |
| /* fbb_x_off = fbbinfo[2]; */ |
| |
| fbb_y_off = fbbinfo[3]; |
| |
| /* Print FONTBOUNDINGBOX information */ |
| |
| fprintf(out, "/* Maximum height and width of any"); |
| fprintf(out, " glyph in the set */\n\n"); |
| fprintf(out, "#define NXFONT_MAXHEIGHT %d\n", fbb_y); |
| fprintf(out, "#define NXFONT_MAXWIDTH %d\n\n", fbb_x); |
| } |
| |
| /* STARTCHAR - Individual glyph information */ |
| |
| if (strcmp(token, "STARTCHAR") == 0) |
| { |
| glyphinfo_t ginfo; |
| |
| /* Glyph name */ |
| |
| ginfo.name = (char *)strtok_r(NULL, " ", &saveptr1); |
| |
| #ifdef VERBOSE |
| printf("Processing glyph: %s\n", ginfo.name); |
| #endif /* VERBOSE */ |
| |
| /* Glyph information: |
| * ENCODING |
| * DWIDTH |
| * BBX |
| */ |
| |
| ginfo.encoding = 0; |
| ginfo.dw_x0 = 0; |
| ginfo.dw_y0 = 0; |
| ginfo.bb_w = 0; |
| ginfo.bb_h = 0; |
| ginfo.bb_x_off = 0; |
| ginfo.bb_y_off = 0; |
| bdf_getglyphinfo(file, &ginfo); |
| |
| /* Glyph bitmap */ |
| |
| ginfo.bitmap = malloc(sizeof(uint64_t) * ginfo.bb_h); |
| bdf_getglyphbitmap(file, &ginfo); |
| |
| #ifdef DBG |
| bdf_printglyphinfo(&ginfo); |
| #endif /* DBG */ |
| |
| /* Convert to nxfonts */ |
| |
| nx_fontmetric_t nxmetric; |
| uint32_t stride; |
| bdf_getstride(&ginfo, &stride); |
| nxmetric.stride = stride; |
| nxmetric.width = ginfo.bb_w; |
| nxmetric.height = ginfo.bb_h; |
| |
| /* The NuttX font format does not support |
| * negative X offsets. |
| */ |
| |
| if (ginfo.bb_x_off < 0) |
| { |
| nxmetric.xoffset = 0; |
| printf("%s: ignoring negative x offset for " |
| "glyph '%s' (%d)\n", |
| argv[0], |
| ginfo.name, |
| ginfo.encoding); |
| } |
| else |
| { |
| nxmetric.xoffset = ginfo.bb_x_off; |
| } |
| |
| nxmetric.yoffset = fbb_y + fbb_y_off - |
| ginfo.bb_y_off - ginfo.bb_h; |
| |
| #ifdef DBG |
| bdf_printnxmetricinfo(&nxmetric); |
| #endif /* DBG */ |
| |
| /* The space (32) character is treated differently */ |
| |
| if (ginfo.encoding == 32) |
| { |
| fprintf(out, "/* The width of a space */\n\n"); |
| fprintf(out, "#define NXFONT_SPACEWIDTH %d\n\n", |
| ginfo.dw_x0); |
| } |
| else |
| { |
| bdf_printoutput(out, &ginfo, &nxmetric); |
| } |
| |
| /* Free memory */ |
| |
| free(ginfo.bitmap); |
| } |
| |
| str = NULL; |
| } |
| } |
| |
| fclose(file); |
| fclose(out); |
| |
| /* The End */ |
| |
| printf("Generated \"%s\"\n", output); |
| } |
| |
| return EXIT_SUCCESS; |
| } |