Root/tools/libant/font.c

Source at commit 0f17c404d2bf724b17d8443d6b76701f50be673d created 11 years 6 days ago.
By Werner Almesberger, BOOKSHELF: add data sheets of parts for next Tornado iteration
1/*
2 * tools/libant/font.c - Font operations
3 *
4 * Written 2012 by Werner Almesberger
5 * Copyright 2012 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#include <stdint.h>
15#include <stdlib.h>
16#include <string.h>
17#include <errno.h>
18
19#include "util.h"
20#include "libant.h"
21
22
23static const char charset[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!?$%+-*/=@.";
24
25
26#define CHARS (sizeof(charset)-1)
27
28
29struct sym {
30    int x, y;
31    int w, h;
32};
33
34struct image {
35    int w, h;
36    int span; /* bytes per row */
37    uint8_t *data;
38};
39
40struct font {
41    struct image *img;
42    struct sym sym[CHARS];
43    int max_width;
44};
45
46
47/* ----- XBM image --------------------------------------------------------- */
48
49
50static const char *read_xbm_file(FILE *file, struct image *img)
51{
52    int n;
53    unsigned v;
54    char c;
55    int bytes = 0;
56
57    img->data = NULL;
58
59    n = fscanf(file, "#define %*[^_]_width %d\n", &img->w);
60    if (n < 0)
61        return alloc_sprintf("reading width: %s", strerror(errno));
62    if (n != 1)
63        return alloc_sprintf("width not found (%d)", n);
64
65    n = fscanf(file, "#define %*[^_]_height %d\n", &img->h);
66    if (n < 0)
67        return alloc_sprintf("reading height: %s", strerror(errno));
68    if (n != 1)
69        return alloc_sprintf("height not found");
70
71    n = fscanf(file, "%*[^{]{\n");
72    if (n < 0)
73        return alloc_sprintf("finding data: %s", strerror(errno));
74
75    while (1) {
76        n = fscanf(file, " 0x%x%c", &v, &c);
77        if (n < 0)
78            return alloc_sprintf("reading data: %s",
79                strerror(errno));
80        if (n != 2)
81            return alloc_sprintf("data not found (%d)", n);
82
83        bytes++;
84        img->data = realloc(img->data, bytes);
85        if (!img->data)
86            abort();
87        img->data[bytes-1] = v;
88
89        if (c == ',')
90            continue;
91        if (c == '}')
92            break;
93        return alloc_sprintf("invalid data syntax");
94    }
95    img->span = (img->w+7) >> 3;
96    if (bytes != img->h*img->span)
97        return alloc_sprintf("%d bytes for %dx%d bitmap",
98            bytes, img->h, img->w);
99    return NULL;
100}
101
102
103struct image *load_image_file(FILE *file, const char **error)
104{
105    struct image *img;
106    const char *err;
107
108    img = alloc_type(struct image);
109    err = read_xbm_file(file, img);
110    if (err) {
111        if (error)
112            *error = err;
113        free_image(img);
114        return NULL;
115    }
116    return img;
117}
118
119
120struct image *load_image(const char *name, const char **error)
121{
122    FILE *file;
123    struct image *img;
124
125    file = fopen(name, "r");
126    if (!file) {
127        if (error)
128            *error = alloc_sprintf("%s: %s", name, strerror(errno));
129        return NULL;
130    }
131    img = load_image_file(file, error);
132    fclose(file);
133    return img;
134}
135
136
137void free_image(struct image *img)
138{
139    if (img) {
140        free(img->data);
141        free(img);
142    }
143}
144
145
146/* ----- Font generation --------------------------------------------------- */
147
148
149static void set_block(struct font *font, int *n,
150    int xlast, int x, int y0, int y1)
151{
152    int width = x-xlast-1;
153
154    if (width > font->max_width)
155        font->max_width = width;
156    font->sym[*n].x = xlast+1;
157    font->sym[*n].y = y0;
158    font->sym[*n].w = width;
159    font->sym[*n].h = y1-y0+1;
160    (*n)++;
161}
162
163
164static void analyze_block(struct font *font, int *n, int y0, int y1)
165{
166    const struct image *img = font->img;
167    int x, y, last = -1;
168
169    for (x = 0; x != img->w; x++) {
170        for (y = y0; y <= y1; y++)
171            if (img->data[y*img->span+(x >> 3)] & (1 << (x & 7)))
172                break;
173        if (y <= y1)
174            continue;
175        if (x != last+1)
176            set_block(font, n, last, x, y0, y1);
177        last = x;
178    }
179    if (x != last+1)
180        set_block(font, n, last, x, y0, y1);
181}
182
183
184static const char *analyze_font(struct font *font)
185{
186    const struct image *img = font->img;
187    int x, y, last = -1;
188    int n = 0;
189    
190    for (y = 0; y != img->h; y++) {
191        for (x = 0; x != img->span; x++)
192            if (img->data[y*img->span+x])
193                break;
194        if (x != img->span)
195            continue;
196        if (y != last+1)
197            analyze_block(font, &n, last+1, y-1);
198        last = y;
199    }
200    if (y != last+1)
201        analyze_block(font, &n, last+1, y-1);
202    if (n != CHARS)
203        return alloc_sprintf("found %d instead of %d characters",
204            n, CHARS);
205    return NULL;
206}
207
208
209struct font *make_font(struct image *img, const char **error)
210{
211    struct font *font;
212    const char *err;
213
214    font = calloc(1, sizeof(struct font));
215    if (!font)
216        abort();
217    font->img = img;
218    err = analyze_font(font);
219    if (err) {
220        if (error)
221            *error = err;
222        free_font(font);
223        return NULL;
224    }
225    return font;
226}
227
228
229void free_font(struct font *font)
230{
231    if (font) {
232        free_image(font->img);
233        free(font);
234    }
235}
236
237
238/* ----- Drawing on a canvas ----------------------------------------------- */
239
240
241static void do_draw(uint8_t *canvas, int width, int heigth,
242    const struct image *img, int ox, int oy, int w, int h, int x, int y)
243{
244    int ix, iy, xt;
245
246    for (ix = 0; ix != w; ix++) {
247        if (x+ix < 0 || x+ix >= width)
248            continue;
249        for (iy = 0; iy != h; iy++) {
250            if (y+iy < 0 || y+iy >= heigth)
251                continue;
252            xt = ox+ix;
253            if (img->data[(oy+iy)*img->span+(xt >> 3)] &
254                (1 << (xt & 7))) {
255                xt = x+ix;
256                canvas[((y+iy)*width+xt) >> 3] |= 1 << (xt & 7);
257            }
258        }
259    }
260}
261
262
263int draw_image(void *canvas, int width, int height,
264    const struct image *img, int x, int y)
265{
266    do_draw(canvas, width, height, img, 0, 0, img->w, img->h, x, y);
267    return img->w;
268}
269
270
271int draw_char(void *canvas, int width, int height,
272    const struct font *font, char c, int x, int y)
273{
274    const char *cp;
275    const struct sym *sym;
276
277    if (c == ' ')
278        return font->max_width;
279    cp = strchr(charset, c);
280    if (!cp)
281        return 0;
282    sym = font->sym+(cp-charset);
283
284    do_draw(canvas, width, height,
285        font->img, sym->x, sym->y, sym->w, sym->h, x, y);
286
287    return sym->w;
288}
289
290
291int char_height(const struct font *font, char c)
292{
293    const char *cp;
294    const struct sym *sym;
295
296    cp = strchr(charset, c);
297    if (!cp)
298        return 0;
299    sym = font->sym+(cp-charset);
300    return sym->h;
301}
302

Archive Download this file

Branches:
master
tornado-v1



interactive