libcaca  0.99.beta19
About: libcaca is a graphics library that outputs text instead of pixels, so that it can work on older video cards or text terminals (something like an advanced AAlib library).
  Fossies Dox: libcaca-0.99.beta19.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

font.c
Go to the documentation of this file.
1 /*
2  * libcaca Colour ASCII-Art library
3  * Copyright (c) 2002-2012 Sam Hocevar <sam@hocevar.net>
4  * All Rights Reserved
5  *
6  * This library is free software. It comes without any warranty, to
7  * the extent permitted by applicable law. You can redistribute it
8  * and/or modify it under the terms of the Do What the Fuck You Want
9  * to Public License, Version 2, as published by Sam Hocevar. See
10  * http://www.wtfpl.net/ for more details.
11  */
12 
13 /*
14  * This file contains font handling functions.
15  */
16 
17 #include "config.h"
18 
19 #if !defined(__KERNEL__)
20 # if defined(HAVE_ENDIAN_H)
21 # include <endian.h>
22 # endif
23 # include <stdio.h>
24 # include <stdlib.h>
25 # include <string.h>
26 #endif
27 
28 #include "caca.h"
29 #include "caca_internals.h"
30 
31 /* Internal fonts */
32 #include "mono9.data"
33 #include "monobold12.data"
34 
35 /* Helper structures for font loading */
36 #if !defined(_DOXYGEN_SKIP_ME)
38 {
40  uint16_t version, blocks;
41  uint32_t glyphs;
43 };
44 
45 struct block_info
46 {
47  uint32_t start, stop, index;
48 };
49 
50 struct glyph_info
51 {
52  uint16_t width, height;
53  uint32_t data_offset;
54 };
55 
56 struct caca_font
57 {
59 
61  uint32_t *user_block_list;
63  uint8_t *font_data;
64 
65  uint8_t *private;
66 };
67 #endif
68 
69 #define DECLARE_UNPACKGLYPH(bpp) \
70  static inline void \
71  unpack_glyph ## bpp(uint8_t *glyph, uint8_t *packed_data, int n) \
72 { \
73  int i; \
74  \
75  for(i = 0; i < n; i++) \
76  { \
77  uint8_t pixel = packed_data[i / (8 / bpp)]; \
78  pixel >>= bpp * ((8 / bpp) - 1 - (i % (8 / bpp))); \
79  pixel %= (1 << bpp); \
80  pixel *= 0xff / ((1 << bpp) - 1); \
81  *glyph++ = pixel; \
82  } \
83 }
84 
88 
111 caca_font_t *caca_load_font(void const *data, size_t size)
112 {
113  caca_font_t *f;
114  int i;
115 
116  if(size == 0)
117  {
118  if(!strcasecmp(data, "Monospace 9"))
119  return caca_load_font(mono9_data, mono9_size);
120  if(!strcasecmp(data, "Monospace Bold 12"))
121  return caca_load_font(monobold12_data, monobold12_size);
122 
123  seterrno(ENOENT);
124  return NULL;
125  }
126 
127  if(size < sizeof(struct font_header))
128  {
129  debug("font error: data size %i < header size %i",
130  size, (int)sizeof(struct font_header));
131  seterrno(EINVAL);
132  return NULL;
133  }
134 
135  f = malloc(sizeof(caca_font_t));
136  if(!f)
137  {
138  seterrno(ENOMEM);
139  return NULL;
140  }
141 
142  f->private = (void *)(uintptr_t)data;
143 
144  memcpy(&f->header, f->private + 4, sizeof(struct font_header));
148  f->header.blocks = hton16(f->header.blocks);
149  f->header.glyphs = hton32(f->header.glyphs);
150  f->header.bpp = hton16(f->header.bpp);
151  f->header.width = hton16(f->header.width);
152  f->header.height = hton16(f->header.height);
155  f->header.flags = hton16(f->header.flags);
156 
157  if(size != 4 + f->header.control_size + f->header.data_size
158  || (f->header.bpp != 8 && f->header.bpp != 4 &&
159  f->header.bpp != 2 && f->header.bpp != 1)
160  || (f->header.flags & 1) == 0)
161  {
162 #if defined DEBUG
163  if(size != 4 + f->header.control_size + f->header.data_size)
164  debug("font error: data size %i < expected size %i",
165  size, 4 + f->header.control_size + f->header.data_size);
166  else if(f->header.bpp != 8 && f->header.bpp != 4 &&
167  f->header.bpp != 2 && f->header.bpp != 1)
168  debug("font error: invalid bpp %i", f->header.bpp);
169  else if((f->header.flags & 1) == 0)
170  debug("font error: invalid flags %.04x", f->header.flags);
171 #endif
172  free(f);
173  seterrno(EINVAL);
174  return NULL;
175  }
176 
177  f->block_list = malloc(f->header.blocks * sizeof(struct block_info));
178  if(!f->block_list)
179  {
180  free(f);
181  seterrno(ENOMEM);
182  return NULL;
183  }
184 
185  f->user_block_list = malloc((f->header.blocks + 1)
186  * 2 * sizeof(uint32_t));
187  if(!f->user_block_list)
188  {
189  free(f->block_list);
190  free(f);
191  seterrno(ENOMEM);
192  return NULL;
193  }
194 
195  memcpy(f->block_list,
196  f->private + 4 + sizeof(struct font_header),
197  f->header.blocks * sizeof(struct block_info));
198  for(i = 0; i < f->header.blocks; i++)
199  {
200  f->block_list[i].start = hton32(f->block_list[i].start);
201  f->block_list[i].stop = hton32(f->block_list[i].stop);
202  f->block_list[i].index = hton32(f->block_list[i].index);
203 
204  if(f->block_list[i].start > f->block_list[i].stop
205  || (i > 0 && f->block_list[i].start < f->block_list[i - 1].stop)
206  || f->block_list[i].index >= f->header.glyphs)
207  {
208 #if defined DEBUG
209  if(f->block_list[i].start > f->block_list[i].stop)
210  debug("font error: block %i has start %i > stop %i",
211  i, f->block_list[i].start, f->block_list[i].stop);
212  else if(i > 0 && f->block_list[i].start < f->block_list[i - 1].stop)
213  debug("font error: block %i has start %i < previous stop %i",
214  f->block_list[i].start, f->block_list[i - 1].stop);
215  else if(f->block_list[i].index >= f->header.glyphs)
216  debug("font error: block %i has index >= glyph count %i",
217  f->block_list[i].index, f->header.glyphs);
218 #endif
219  free(f->user_block_list);
220  free(f->block_list);
221  free(f);
222  seterrno(EINVAL);
223  return NULL;
224  }
225 
226  f->user_block_list[i * 2] = f->block_list[i].start;
227  f->user_block_list[i * 2 + 1] = f->block_list[i].stop;
228  }
229 
230  f->user_block_list[i * 2] = 0;
231  f->user_block_list[i * 2 + 1] = 0;
232 
233  f->glyph_list = malloc(f->header.glyphs * sizeof(struct glyph_info));
234  if(!f->glyph_list)
235  {
236  free(f->user_block_list);
237  free(f->block_list);
238  free(f);
239  seterrno(ENOMEM);
240  return NULL;
241  }
242 
243  memcpy(f->glyph_list,
244  f->private + 4 + sizeof(struct font_header)
245  + f->header.blocks * sizeof(struct block_info),
246  f->header.glyphs * sizeof(struct glyph_info));
247  for(i = 0; i < (int)f->header.glyphs; i++)
248  {
249  f->glyph_list[i].width = hton16(f->glyph_list[i].width);
250  f->glyph_list[i].height = hton16(f->glyph_list[i].height);
252 
253  if(f->glyph_list[i].data_offset >= f->header.data_size
254  || f->glyph_list[i].data_offset
255  + (f->glyph_list[i].width * f->glyph_list[i].height *
256  f->header.bpp + 7) / 8 > f->header.data_size
257  || f->glyph_list[i].width > f->header.maxwidth
258  || f->glyph_list[i].height > f->header.maxheight)
259  {
260 #if defined DEBUG
261  if(f->glyph_list[i].data_offset >= f->header.data_size)
262  debug("font error: glyph %i has data start %i > "
263  "data end %i",
265  else if(f->glyph_list[i].data_offset
266  + (f->glyph_list[i].width * f->glyph_list[i].height *
267  f->header.bpp + 7) / 8 > f->header.data_size)
268  debug("font error: glyph %i has data end %i > "
269  "data end %i", f->glyph_list[i].data_offset
270  + (f->glyph_list[i].width * f->glyph_list[i].height *
271  f->header.bpp + 7) / 8, f->header.data_size);
272  else if(f->glyph_list[i].width > f->header.maxwidth)
273  debug("font error: glyph %i has width %i > max width %i",
274  f->glyph_list[i].width, f->header.maxwidth);
275  else if(f->glyph_list[i].height > f->header.maxheight)
276  debug("font error: glyph %i has height %i > max height %i",
277  f->glyph_list[i].height, f->header.maxheight);
278 #endif
279  free(f->glyph_list);
280  free(f->user_block_list);
281  free(f->block_list);
282  free(f);
283  seterrno(EINVAL);
284  return NULL;
285  }
286  }
287 
288  f->font_data = f->private + 4 + f->header.control_size;
289 
290  return f;
291 }
292 
302 char const * const * caca_get_font_list(void)
303 {
304  static char const * const list[] =
305  {
306  "Monospace 9",
307  "Monospace Bold 12",
308  NULL
309  };
310 
311  return list;
312 }
313 
325 {
326  return f->header.width;
327 }
328 
340 {
341  return f->header.height;
342 }
343 
364 uint32_t const *caca_get_font_blocks(caca_font_t const *f)
365 {
366  return (uint32_t const *)f->user_block_list;
367 }
368 
382 {
383  free(f->glyph_list);
384  free(f->user_block_list);
385  free(f->block_list);
386  free(f);
387 
388  return 0;
389 }
390 
416  void *buf, int width, int height, int pitch)
417 {
418  uint8_t *glyph = NULL;
419  int x, y, xmax, ymax;
420 
421  if(width < 0 || height < 0 || pitch < 0)
422  {
423  seterrno(EINVAL);
424  return -1;
425  }
426 
427  if(f->header.bpp != 8)
428  glyph = malloc(f->header.width * 2 * f->header.height);
429 
430  if(width < cv->width * f->header.width)
431  xmax = width / f->header.width;
432  else
433  xmax = cv->width;
434 
435  if(height < cv->height * f->header.height)
436  ymax = height / f->header.height;
437  else
438  ymax = cv->height;
439 
440  for(y = 0; y < ymax; y++)
441  {
442  for(x = 0; x < xmax; x++)
443  {
444  uint8_t argb[8];
445  int starty = y * f->header.height;
446  int startx = x * f->header.width;
447  uint32_t ch = cv->chars[y * cv->width + x];
448  uint32_t attr = cv->attrs[y * cv->width + x];
449  int b, i, j;
450  struct glyph_info *g;
451 
452  /* Find the Unicode block where our glyph lies */
453  for(b = 0; b < f->header.blocks; b++)
454  {
455  if(ch < f->block_list[b].start)
456  {
457  b = f->header.blocks;
458  break;
459  }
460 
461  if(ch < f->block_list[b].stop)
462  break;
463  }
464 
465  /* Glyph not in font? Skip it. */
466  if(b == f->header.blocks)
467  continue;
468 
469  g = &f->glyph_list[f->block_list[b].index
470  + ch - f->block_list[b].start];
471 
472  caca_attr_to_argb64(attr, argb);
473 
474  /* Step 1: unpack glyph */
475  switch(f->header.bpp)
476  {
477  case 8:
478  glyph = f->font_data + g->data_offset;
479  break;
480  case 4:
481  unpack_glyph4(glyph, f->font_data + g->data_offset,
482  g->width * g->height);
483  break;
484  case 2:
485  unpack_glyph2(glyph, f->font_data + g->data_offset,
486  g->width * g->height);
487  break;
488  case 1:
489  unpack_glyph1(glyph, f->font_data + g->data_offset,
490  g->width * g->height);
491  break;
492  }
493 
494  /* Step 2: render glyph using colour attribute */
495  for(j = 0; j < g->height; j++)
496  {
497  uint8_t *line = buf;
498  line += (starty + j) * pitch + 4 * startx;
499 
500  for(i = 0; i < g->width; i++)
501  {
502  uint8_t *pixel = line + 4 * i;
503  uint32_t p, q, t;
504 
505  p = glyph[j * g->width + i];
506  q = 0xff - p;
507 
508  for(t = 0; t < 4; t++)
509  pixel[t] = (((q * argb[t]) + (p * argb[4 + t])) / 0xf);
510  }
511  }
512  }
513  }
514 
515  if(f->header.bpp != 8)
516  free(glyph);
517 
518  return 0;
519 }
520 
521 /*
522  * XXX: The following functions are aliases.
523  */
524 
525 cucul_font_t *cucul_load_font(void const *, size_t) CACA_ALIAS(caca_load_font);
526 char const * const * cucul_get_font_list(void) CACA_ALIAS(caca_get_font_list);
530 uint32_t const *cucul_get_font_blocks(cucul_font_t const *)
532 int cucul_render_canvas(cucul_canvas_t const *, cucul_font_t const *,
533  void *, int, int, int) CACA_ALIAS(caca_render_canvas);
535 
caca_get_font_height
int caca_get_font_height(caca_font_t const *f)
Get a font's standard glyph height.
Definition: font.c:339
caca_font::font_data
uint8_t * font_data
Definition: font.c:63
CACA_ALIAS
#define CACA_ALIAS(x)
Definition: caca.h:689
cucul_free_font
#define cucul_free_font
Definition: caca.h:806
cucul_get_font_width
#define cucul_get_font_width
Definition: caca.h:802
y
static int y
Definition: cacadraw.c:27
g
int g
Definition: cacaview.c:60
caca_render_canvas
int caca_render_canvas(caca_canvas_t const *cv, caca_font_t const *f, void *buf, int width, int height, int pitch)
Render the canvas onto an image buffer.
Definition: font.c:415
font_header::glyphs
uint32_t glyphs
Definition: font.c:41
unpack_glyph4
static void unpack_glyph4(uint8_t *glyph, uint8_t *packed_data, int n)
Definition: font.c:85
block_info::index
uint32_t index
Definition: font.c:47
caca_font::block_list
struct block_info * block_list
Definition: font.c:60
caca_font::header
struct font_header header
Definition: font.c:58
hton16
static uint16_t hton16(uint16_t x)
Definition: caca_stubs.h:46
font_header::data_size
uint32_t data_size
Definition: font.c:39
caca_get_font_list
const char *const * caca_get_font_list(void)
Get available builtin fonts.
Definition: font.c:302
caca_canvas::attrs
uint32_t * attrs
Definition: caca_internals.h:73
glyph_info::height
uint16_t height
Definition: font.c:52
caca_get_font_width
int caca_get_font_width(caca_font_t const *f)
Get a font's standard glyph width.
Definition: font.c:324
caca_attr_to_argb64
void caca_attr_to_argb64(uint32_t attr, uint8_t argb[8])
Get 64-bit ARGB information from attribute.
Definition: attr.c:433
cucul_get_font_list
#define cucul_get_font_list
Definition: caca.h:801
glyph_info::width
uint16_t width
Definition: font.c:52
strcasecmp
#define strcasecmp
Definition: config.h:95
caca_canvas::chars
uint32_t * chars
Definition: caca_internals.h:72
caca_font::glyph_list
struct glyph_info * glyph_list
Definition: font.c:62
seterrno
#define seterrno(x)
Definition: caca_stubs.h:27
cucul_get_font_blocks
#define cucul_get_font_blocks
Definition: caca.h:804
caca_free_font
int caca_free_font(caca_font_t *f)
Free a font structure.
Definition: font.c:381
DECLARE_UNPACKGLYPH
#define DECLARE_UNPACKGLYPH(bpp)
Definition: font.c:69
cucul_canvas_t
#define cucul_canvas_t
Definition: caca.h:763
glyph
Definition: makefont.c:69
font_header::maxheight
uint16_t maxheight
Definition: font.c:42
cv
caca_canvas_t * cv
Definition: cacaview.c:45
block_info::stop
uint32_t stop
Definition: font.c:47
font_header::width
uint16_t width
Definition: font.c:42
caca_font::private
uint8_t * private
Definition: font.c:65
unpack_glyph2
static void unpack_glyph2(uint8_t *glyph, uint8_t *packed_data, int n)
Definition: font.c:86
block_info::start
uint32_t start
Definition: font.c:47
font_header::blocks
uint16_t blocks
Definition: font.c:40
caca_internals.h
line
Definition: line.c:28
caca_font::user_block_list
uint32_t * user_block_list
Definition: font.c:61
font_header::version
uint16_t version
Definition: font.c:40
font_header
Definition: font.c:37
hton32
static uint32_t hton32(uint32_t x)
Definition: caca_stubs.h:60
caca_canvas::width
int width
Definition: caca_internals.h:71
caca_get_font_blocks
const uint32_t * caca_get_font_blocks(caca_font_t const *f)
Get a font's list of supported glyphs.
Definition: font.c:364
caca_font
Definition: font.c:56
caca.h
The libcaca public header.
font_header::flags
uint16_t flags
Definition: font.c:42
glyph_info::data_offset
uint32_t data_offset
Definition: font.c:53
font_header::control_size
uint32_t control_size
Definition: font.c:39
config.h
caca_load_font
caca_font_t * caca_load_font(void const *data, size_t size)
Load a font from memory for future use.
Definition: font.c:111
cucul_render_canvas
#define cucul_render_canvas
Definition: caca.h:805
glyph_info
Definition: font.c:50
font_header::height
uint16_t height
Definition: font.c:42
caca_canvas::height
int height
Definition: caca_internals.h:71
debug
#define debug(format,...)
Definition: caca_debug.h:36
cucul_get_font_height
#define cucul_get_font_height
Definition: caca.h:803
unpack_glyph1
static void unpack_glyph1(uint8_t *glyph, uint8_t *packed_data, int n)
Definition: font.c:87
font_header::bpp
uint16_t bpp
Definition: font.c:42
font_header::maxwidth
uint16_t maxwidth
Definition: font.c:42
cucul_font_t
#define cucul_font_t
Definition: caca.h:765
caca_canvas
Definition: caca_internals.h:47
block_info
Definition: font.c:45
x
static int x
Definition: cacadraw.c:27
cucul_load_font
#define cucul_load_font
Definition: caca.h:800