source: libcaca/trunk/cucul/font.c @ 777

Last change on this file since 777 was 777, checked in by Sam Hocevar, 15 years ago
  • Replaced "struct cucul_*" and "struct caca_*" types with opaque typedefs such as cucul_dither_t instead of struct cucul_dither.
  • Made cucul_buffer_t an opaque structure and implemented the two getters cucul_get_buffer_data() and cucul_get_buffer_size().
  • Documented all missing functions and function parameters.
  • Property svn:keywords set to Id
File size: 12.8 KB
Line 
1/*
2 *  libcucul      Canvas for ultrafast compositing of Unicode letters
3 *  Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  $Id: font.c 777 2006-04-16 18:28:47Z sam $
7 *
8 *  This library is free software; you can redistribute it and/or
9 *  modify it under the terms of the Do What The Fuck You Want To
10 *  Public License, Version 2, as published by Sam Hocevar. See
11 *  http://sam.zoy.org/wtfpl/COPYING for more details.
12 */
13
14/*
15 *  This file contains font handling functions.
16 */
17
18#include "config.h"
19
20#if !defined(USE_WIN32)
21#if !defined(__KERNEL__)
22#   if defined(HAVE_ENDIAN_H)
23#       include <endian.h>
24#   endif
25#   include <stdio.h>
26#   include <stdlib.h>
27#   include <string.h>
28#   include <arpa/inet.h>
29#endif
30
31#include "cucul.h"
32#include "cucul_internals.h"
33
34/* Internal fonts */
35#include "font_mono9.h"
36#include "font_monobold12.h"
37
38/* Helper structures for font loading */
39#if !defined(_DOXYGEN_SKIP_ME)
40struct font_header
41{
42    uint32_t control_size, data_size;
43    uint16_t version, blocks;
44    uint32_t glyphs;
45    uint16_t bpp, width, height, flags;
46};
47
48struct block_info
49{
50    uint32_t start, stop, index;
51};
52
53struct glyph_info
54{
55    uint16_t width, height;
56    uint32_t data_offset;
57};
58
59struct cucul_font
60{
61    struct font_header header;
62
63    struct block_info *block_list;
64    struct glyph_info *glyph_list;
65    uint8_t *font_data;
66
67    uint8_t *private;
68};
69#endif
70
71#define DECLARE_UNPACKGLYPH(bpp) \
72    static inline void \
73      unpack_glyph ## bpp(uint8_t *glyph, uint8_t *packed_data, \
74                          unsigned int n) \
75{ \
76    unsigned int i; \
77    \
78    for(i = 0; i < n; i++) \
79    { \
80        uint8_t pixel = packed_data[i / (8 / bpp)]; \
81        pixel >>= bpp * ((8 / bpp) - 1 - (i % (8 / bpp))); \
82        pixel %= (1 << bpp); \
83        pixel *= 0xff / ((1 << bpp) - 1); \
84        *glyph++ = pixel; \
85    } \
86}
87
88DECLARE_UNPACKGLYPH(4)
89DECLARE_UNPACKGLYPH(2)
90DECLARE_UNPACKGLYPH(1)
91
92/** \brief Load a font from memory for future use.
93 *
94 *  This function loads a font and returns a handle to its internal
95 *  structure. The handle can then be used with \e cucul_render_canvas()
96 *  for bitmap output.
97 *
98 *  Internal fonts can also be loaded: if \e size is set to 0, \e data must
99 *  be a string containing the internal font name.
100 *
101 *  If \e size is non-zero, the \e size bytes of memory at address \e data
102 *  are loaded as a font. This memory are must not be freed by the calling
103 *  program until the font handle has been freed with \e cucul_free_font().
104 *
105 *  \param data The memory area containing the font or its name.
106 *  \param size The size of the memory area, or 0 if the font name is given.
107 *  \return A font handle or NULL in case of error.
108 */
109cucul_font_t *cucul_load_font(void const *data, unsigned int size)
110{
111    cucul_font_t *f;
112    unsigned int i;
113
114    if(size == 0)
115    {
116        if(!strcasecmp(data, "Monospace 9"))
117            return cucul_load_font(mono9_data, mono9_size);
118        if(!strcasecmp(data, "Monospace Bold 12"))
119            return cucul_load_font(monobold12_data, monobold12_size);
120
121        return NULL;
122    }
123
124    if(size < sizeof(struct font_header))
125        return NULL;
126
127    f = malloc(sizeof(cucul_font_t));
128    f->private = (void *)(uintptr_t)data;
129
130    memcpy(&f->header, f->private + 8, sizeof(struct font_header));
131    f->header.control_size = htonl(f->header.control_size);
132    f->header.data_size = htonl(f->header.data_size);
133    f->header.version = htons(f->header.version);
134    f->header.blocks = htons(f->header.blocks);
135    f->header.glyphs = htonl(f->header.glyphs);
136    f->header.bpp = htons(f->header.bpp);
137    f->header.width = htons(f->header.width);
138    f->header.height = htons(f->header.height);
139    f->header.flags = htons(f->header.flags);
140
141    if(size != 8 + f->header.control_size + f->header.data_size
142        || (f->header.bpp != 8 && f->header.bpp != 4 &&
143            f->header.bpp != 2 && f->header.bpp != 1)
144        || (f->header.flags & 1) == 0)
145    {
146        free(f);
147        return NULL;
148    }
149
150    f->block_list = malloc(f->header.blocks * sizeof(struct block_info));
151    memcpy(f->block_list,
152           f->private + 8 + sizeof(struct font_header),
153           f->header.blocks * sizeof(struct block_info));
154    for(i = 0; i < f->header.blocks; i++)
155    {
156        f->block_list[i].start = htonl(f->block_list[i].start);
157        f->block_list[i].stop = htonl(f->block_list[i].stop);
158        f->block_list[i].index = htonl(f->block_list[i].index);
159
160        if(f->block_list[i].start > f->block_list[i].stop
161            || (i > 0 && f->block_list[i].start < f->block_list[i - 1].stop)
162            || f->block_list[i].index >= f->header.glyphs)
163        {
164            free(f->block_list);
165            free(f);
166            return NULL;
167        }
168    }
169
170    f->glyph_list = malloc(f->header.glyphs * sizeof(struct glyph_info));
171    memcpy(f->glyph_list,
172           f->private + 8 + sizeof(struct font_header)
173                + f->header.blocks * sizeof(struct block_info),
174           f->header.glyphs * sizeof(struct glyph_info));
175    for(i = 0; i < f->header.glyphs; i++)
176    {
177        f->glyph_list[i].width = htons(f->glyph_list[i].width);
178        f->glyph_list[i].height = htons(f->glyph_list[i].height);
179        f->glyph_list[i].data_offset = htonl(f->glyph_list[i].data_offset);
180
181        if(f->glyph_list[i].data_offset >= f->header.data_size
182            || f->glyph_list[i].data_offset
183                + f->glyph_list[i].width * f->glyph_list[i].height *
184                  f->header.bpp / 8 >= f->header.data_size)
185        {
186            free(f->glyph_list);
187            free(f->block_list);
188            free(f);
189            return NULL;
190        }
191    }
192
193    f->font_data = f->private + 8 + f->header.control_size;
194
195    return f;
196}
197
198/** \brief Get available builtin fonts
199 *
200 *  Return a list of available builtin fonts. The list is a NULL-terminated
201 *  array of strings.
202 *
203 *  \return An array of strings.
204 */
205char const * const * cucul_get_font_list(void)
206{
207    static char const * const list[] =
208    {
209        "Monospace 9",
210        "Monospace Bold 12",
211        NULL
212    };
213
214    return list;
215}
216
217/** \brief Get a font's maximum glyph width.
218 *
219 *  This function returns the maximum value for the current font's glyphs
220 *
221 *  \param f The font, as returned by \e cucul_load_font()
222 *  \return The maximum glyph width.
223 */
224unsigned int cucul_get_font_width(cucul_font_t *f)
225{
226    return f->header.width;
227}
228
229/** \brief Get a font's maximum glyph height.
230 *
231 *  This function returns the maximum value for the current font's glyphs
232 *
233 *  \param f The font, as returned by \e cucul_load_font()
234 *  \return The maximum glyph height.
235 */
236unsigned int cucul_get_font_height(cucul_font_t *f)
237{
238    return f->header.height;
239}
240
241/** \brief Free a font structure.
242 *
243 *  This function frees all data allocated by \e cucul_load_font(). The
244 *  font structure is no longer usable by other libcucul functions. Once
245 *  this function has returned, the memory area that was given to
246 *  \e cucul_load_font() can be freed.
247 *
248 *  \param f The font, as returned by \e cucul_load_font()
249 */
250void cucul_free_font(cucul_font_t *f)
251{
252    free(f->glyph_list);
253    free(f->block_list);
254    free(f);
255}
256
257/** \brief Render the canvas onto an image buffer.
258 *
259 *  This function renders the given canvas on an image buffer using a specific
260 *  font. The pixel format is fixed (32-bit ARGB, 8 bits for each component).
261 *
262 *  The required image width can be computed using \e cucul_get_width(qq) and
263 *  \e cucul_get_font_width(f). The required height can be computed using
264 *  \e cucul_get_height(qq) and \e cucul_get_font_height(f).
265 *
266 *  Glyphs that do not fit in the image buffer are currently not rendered at
267 *  all. They may be cropped instead in future versions.
268 *
269 *  \param qq The canvas to render
270 *  \param f The font, as returned by \e cucul_load_font()
271 *  \param buf The image buffer
272 *  \param width The width (in pixels) of the image buffer
273 *  \param height The height (in pixels) of the image buffer
274 *  \param pitch The pitch (in bytes) of an image buffer line.
275 */
276void cucul_render_canvas(cucul_t *qq, cucul_font_t *f,
277                         unsigned char *buf, unsigned int width,
278                         unsigned int height, unsigned int pitch)
279{
280    uint8_t *glyph = NULL;
281    unsigned int x, y, xmax, ymax;
282
283    if(f->header.bpp != 8)
284        glyph = malloc(f->header.width * f->header.height);
285
286    if(width < qq->width * f->header.width)
287        xmax = width / f->header.width;
288    else
289        xmax = qq->width;
290
291    if(height < qq->height * f->header.height)
292        ymax = height / f->header.height;
293    else
294        ymax = qq->height;
295
296    for(y = 0; y < ymax; y++)
297    {
298        for(x = 0; x < xmax; x++)
299        {
300            uint8_t argb[8];
301            unsigned int starty = y * f->header.height;
302            unsigned int startx = x * f->header.width;
303            uint32_t ch = qq->chars[y * qq->width + x];
304            uint32_t attr = qq->attr[y * qq->width + x];
305            unsigned int b, i, j;
306            struct glyph_info *g;
307
308            /* Find the Unicode block where our glyph lies */
309            for(b = 0; b < f->header.blocks; b++)
310            {
311                if(ch < f->block_list[b].start)
312                {
313                    b = f->header.blocks;
314                    break;
315                }
316
317                if(ch < f->block_list[b].stop)
318                    break;
319            }
320
321            /* Glyph not in font? Skip it. */
322            if(b == f->header.blocks)
323                continue;
324
325            g = &f->glyph_list[f->block_list[b].index
326                                + ch - f->block_list[b].start];
327
328            _cucul_argb32_to_argb4(attr, argb);
329
330            /* Step 1: unpack glyph */
331            switch(f->header.bpp)
332            {
333            case 8:
334                glyph = f->font_data + g->data_offset;
335                break;
336            case 4:
337                unpack_glyph4(glyph, f->font_data + g->data_offset,
338                              g->width * g->height);
339                break;
340            case 2:
341                unpack_glyph2(glyph, f->font_data + g->data_offset,
342                              g->width * g->height);
343                break;
344            case 1:
345                unpack_glyph1(glyph, f->font_data + g->data_offset,
346                              g->width * g->height);
347                break;
348            }
349
350            /* Step 2: render glyph using colour attribute */
351            for(j = 0; j < g->height; j++)
352            {
353                uint8_t *line = buf + (starty + j) * pitch + 4 * startx;
354
355                for(i = 0; i < g->width; i++)
356                {
357                    uint8_t *pixel = line + 4 * i;
358                    uint32_t p, q, t;
359
360                    p = glyph[j * g->width + i];
361                    q = 0xff - p;
362
363                    for(t = 0; t < 4; t++)
364                       pixel[t] = (((q * argb[t]) + (p * argb[4 + t])) / 0xf);
365                }
366            }
367        }
368    }
369
370    if(f->header.bpp != 8)
371        free(glyph);
372}
373
374/*
375 * The libcaca font format, version 1
376 * ----------------------------------
377 *
378 * All types are big endian.
379 *
380 * struct
381 * {
382 *    uint8_t caca_header[4];    // "CACA"
383 *    uint8_t caca_file_type[4]; // "FONT"
384 *
385 * font_header:
386 *    uint32_t control_size;     // Control size (font_data - font_header)
387 *    uint32_t data_size;        // Data size (EOF - font_data)
388 *
389 *    uint16_t version;          // Font format version
390 *                               //  bit 0: set to 1 if font is compatible
391 *                               //         with version 1 of the format
392 *                               //  bits 1-15: unused yet, must be 0
393 *
394 *    uint16_t blocks;           // Number of blocks in the font
395 *    uint32_t glyphs;           // Total number of glyphs in the font
396 *
397 *    uint16_t bpp;              // Bits per pixel for glyph data (valid
398 *                               // Values are 1, 2, 4 and 8)
399 *    uint16_t width;            // Maximum glyph width
400 *    uint16_t height;           // Maximum glyph height
401 *
402 *    uint16_t flags;            // Feature flags
403 *                               //  bit 0: set to 1 if font is fixed width
404 *                               //  bits 1-15: unused yet, must be 0
405 *
406 * block_info:
407 *    struct
408 *    {
409 *       uint32_t start;         // Unicode index of the first glyph
410 *       uint32_t stop;          // Unicode index of the last glyph + 1
411 *       uint32_t index;         // Glyph info index of the first glyph
412 *    }
413 *    block_list[blocks];
414 *
415 * glyph_info:
416 *    struct
417 *    {
418 *       uint16_t width;         // Glyph width in pixels
419 *       uint16_t height;        // Glyph height in pixels
420 *       uint32_t data_offset;   // Offset (starting from data) to the data
421 *                               // for the first character
422 *    }
423 *    glyph_list[glyphs];
424 *
425 * extension_1:
426 * extension_2:
427 *    ...
428 * extension_N:
429 *    ...                        // reserved for future use
430 *
431 * font_data:
432 *    uint8_t data[data_size];   // glyph data
433 * };
434 */
435
436#endif
Note: See TracBrowser for help on using the repository browser.