summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2011-03-05 18:36:51 +0000
committerThomas Martitz <kugel@rockbox.org>2011-03-05 18:36:51 +0000
commit9edd6d4ee912273690b2600e8c52183dfa058eb9 (patch)
treecf6b0723f42c090022b94b38b3c4d856e9378d40
parent396ddd9fd79e458d1107f4065ce072eef99b6bce (diff)
downloadrockbox-9edd6d4ee912273690b2600e8c52183dfa058eb9.tar.gz
rockbox-9edd6d4ee912273690b2600e8c52183dfa058eb9.zip
Anti-Aliased Fonts support.
This enables Rockbox to render anti-aliased fonts using an alpha blending method. The input font bitmaps are 4bit, i.e. 4x larger, but the metadata size stays the same. A tool, convttf, for converting ttf fonts directly to the Rockbox fnt format is provided. It has a useful help output, but the parameter that works best is -c1 or -c2 (2 for larger font sizes). Flyspray: FS#8961 Author: Initial work by Jonas Hurrelmann, further work by Fred Bauer, Andrew Mahone, Teruaki Kawashima and myself. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29523 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/plugins/mpegplayer/mpegplayer.c174
-rw-r--r--apps/plugins/rockpaint.c182
-rw-r--r--firmware/drivers/lcd-16bit.c252
-rw-r--r--firmware/drivers/lcd-bitmap-common.c10
-rw-r--r--firmware/export/font.h3
-rw-r--r--firmware/font.c31
-rw-r--r--tools/Makefile9
-rw-r--r--tools/convbdf.c15
-rw-r--r--tools/convttf.c1283
-rw-r--r--tools/root.make2
-rw-r--r--tools/tools.make5
11 files changed, 1939 insertions, 27 deletions
diff --git a/apps/plugins/mpegplayer/mpegplayer.c b/apps/plugins/mpegplayer/mpegplayer.c
index 2361ba0fbd..22136d8393 100644
--- a/apps/plugins/mpegplayer/mpegplayer.c
+++ b/apps/plugins/mpegplayer/mpegplayer.c
@@ -663,6 +663,172 @@ static void draw_oriented_mono_bitmap_part(const unsigned char *src,
while (src < src_end);
}
+/* draw alpha bitmap for anti-alias font */
+#define ALPHA_COLOR_FONT_DEPTH 2
+#define ALPHA_COLOR_LOOKUP_SHIFT (1 << ALPHA_COLOR_FONT_DEPTH)
+#define ALPHA_COLOR_LOOKUP_SIZE ((1 << ALPHA_COLOR_LOOKUP_SHIFT) - 1)
+#define ALPHA_COLOR_PIXEL_PER_BYTE (8 >> ALPHA_COLOR_FONT_DEPTH)
+#define ALPHA_COLOR_PIXEL_PER_WORD (32 >> ALPHA_COLOR_FONT_DEPTH)
+#ifdef CPU_ARM
+#define BLEND_INIT do {} while (0)
+#define BLEND_START(acc, color, alpha) \
+ asm volatile("mul %0, %1, %2" : "=&r" (acc) : "r" (color), "r" (alpha))
+#define BLEND_CONT(acc, color, alpha) \
+ asm volatile("mla %0, %1, %2, %0" : "+&r" (acc) : "r" (color), "r" (alpha))
+#define BLEND_OUT(acc) do {} while (0)
+#elif defined(CPU_COLDFIRE)
+#define ALPHA_BITMAP_READ_WORDS
+#define BLEND_INIT coldfire_set_macsr(EMAC_UNSIGNED)
+#define BLEND_START(acc, color, alpha) \
+ asm volatile("mac.l %0, %1, %%acc0" :: "%d" (color), "d" (alpha))
+#define BLEND_CONT BLEND_START
+#define BLEND_OUT(acc) asm volatile("movclr.l %%acc0, %0" : "=d" (acc))
+#else
+#define BLEND_INIT do {} while (0)
+#define BLEND_START(acc, color, alpha) ((acc) = (color) * (alpha))
+#define BLEND_CONT(acc, color, alpha) ((acc) += (color) * (alpha))
+#define BLEND_OUT(acc) do {} while (0)
+#endif
+
+/* Blend the given two colors */
+static inline unsigned blend_two_colors(unsigned c1, unsigned c2, unsigned a)
+{
+ a += a >> (ALPHA_COLOR_LOOKUP_SHIFT - 1);
+#if (LCD_PIXELFORMAT == RGB565SWAPPED)
+ c1 = swap16(c1);
+ c2 = swap16(c2);
+#endif
+ unsigned c1l = (c1 | (c1 << 16)) & 0x07e0f81f;
+ unsigned c2l = (c2 | (c2 << 16)) & 0x07e0f81f;
+ unsigned p;
+ BLEND_START(p, c1l, a);
+ BLEND_CONT(p, c2l, ALPHA_COLOR_LOOKUP_SIZE + 1 - a);
+ BLEND_OUT(p);
+ p = (p >> ALPHA_COLOR_LOOKUP_SHIFT) & 0x07e0f81f;
+ p |= (p >> 16);
+#if (LCD_PIXELFORMAT == RGB565SWAPPED)
+ return swap16(p);
+#else
+ return p;
+#endif
+}
+
+static void draw_oriented_alpha_bitmap_part(const unsigned char *src,
+ int src_x, int src_y,
+ int stride, int x, int y,
+ int width, int height)
+{
+ fb_data *dst, *dst_start;
+ unsigned fg_pattern, bg_pattern;
+
+ if (x + width > SCREEN_WIDTH)
+ width = SCREEN_WIDTH - x; /* Clip right */
+ if (x < 0)
+ width += x, x = 0; /* Clip left */
+ if (width <= 0)
+ return; /* nothing left to do */
+
+ if (y + height > SCREEN_HEIGHT)
+ height = SCREEN_HEIGHT - y; /* Clip bottom */
+ if (y < 0)
+ height += y, y = 0; /* Clip top */
+ if (height <= 0)
+ return; /* nothing left to do */
+
+ /* initialize blending */
+ BLEND_INIT;
+
+ fg_pattern = rb->lcd_get_foreground();
+ bg_pattern = rb->lcd_get_background();
+
+ dst_start = rb->lcd_framebuffer + (LCD_WIDTH - y - 1) + x*LCD_WIDTH;
+ int col, row = height;
+ unsigned data, pixels;
+ unsigned skip_end = (stride - width);
+ unsigned skip_start = src_y * stride + src_x;
+
+#ifdef ALPHA_BITMAP_READ_WORDS
+ uint32_t *src_w = (uint32_t *)((uintptr_t)src & ~3);
+ skip_start += ALPHA_COLOR_PIXEL_PER_BYTE * ((uintptr_t)src & 3);
+ src_w += skip_start / ALPHA_COLOR_PIXEL_PER_WORD;
+ data = letoh32(*src_w++);
+#else
+ src += skip_start / ALPHA_COLOR_PIXEL_PER_BYTE;
+ data = *src;
+#endif
+ pixels = skip_start % ALPHA_COLOR_PIXEL_PER_WORD;
+ data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT;
+#ifdef ALPHA_BITMAP_READ_WORDS
+ pixels = 8 - pixels;
+#endif
+
+ do
+ {
+ col = width;
+ dst = dst_start--;
+#ifdef ALPHA_BITMAP_READ_WORDS
+#define UPDATE_SRC_ALPHA do { \
+ if (--pixels) \
+ data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
+ else \
+ { \
+ data = letoh32(*src_w++); \
+ pixels = ALPHA_COLOR_PIXEL_PER_WORD; \
+ } \
+ } while (0)
+#elif ALPHA_COLOR_PIXEL_PER_BYTE == 2
+#define UPDATE_SRC_ALPHA do { \
+ if (pixels ^= 1) \
+ data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
+ else \
+ data = *(++src); \
+ } while (0)
+#else
+#define UPDATE_SRC_ALPHA do { \
+ if (pixels = (++pixels % ALPHA_COLOR_PIXEL_PER_BYTE)) \
+ data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
+ else \
+ data = *(++src); \
+ } while (0)
+#endif
+ do
+ {
+ *dst=blend_two_colors(*dst, fg_pattern,
+ data & ALPHA_COLOR_LOOKUP_SIZE );
+ dst += LCD_WIDTH;
+ UPDATE_SRC_ALPHA;
+ }
+ while (--col);
+#ifdef ALPHA_BITMAP_READ_WORDS
+ if (skip_end < pixels)
+ {
+ pixels -= skip_end;
+ data >>= skip_end * ALPHA_COLOR_LOOKUP_SHIFT;
+ } else {
+ pixels = skip_end - pixels;
+ src_w += pixels / ALPHA_COLOR_PIXEL_PER_WORD;
+ pixels %= ALPHA_COLOR_PIXEL_PER_WORD;
+ data = letoh32(*src_w++);
+ data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT;
+ pixels = 8 - pixels;
+ }
+#else
+ if (skip_end)
+ {
+ pixels += skip_end;
+ if (pixels >= ALPHA_COLOR_PIXEL_PER_BYTE)
+ {
+ src += pixels / ALPHA_COLOR_PIXEL_PER_BYTE;
+ pixels %= ALPHA_COLOR_PIXEL_PER_BYTE;
+ data = *src;
+ data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT;
+ } else
+ data >>= skip_end * ALPHA_COLOR_LOOKUP_SHIFT;
+ }
+#endif
+ } while (--row);
+}
+
static void draw_putsxy_oriented(int x, int y, const char *str)
{
unsigned short ch;
@@ -690,8 +856,12 @@ static void draw_putsxy_oriented(int x, int y, const char *str)
bits = rb->font_get_bits(pf, ch);
- draw_oriented_mono_bitmap_part(bits, ofs, 0, width, x, y,
- width - ofs, pf->height);
+ if (pf->depth)
+ draw_oriented_alpha_bitmap_part(bits, ofs, 0, width, x, y,
+ width - ofs, pf->height);
+ else
+ draw_oriented_mono_bitmap_part(bits, ofs, 0, width, x, y,
+ width - ofs, pf->height);
x += width - ofs;
ofs = 0;
diff --git a/apps/plugins/rockpaint.c b/apps/plugins/rockpaint.c
index 0acbe41aaf..1fef0e9f5f 100644
--- a/apps/plugins/rockpaint.c
+++ b/apps/plugins/rockpaint.c
@@ -562,6 +562,180 @@ static void buffer_mono_bitmap_part(
} while( src < src_end );
}
+/* draw alpha bitmap for anti-alias font */
+#define ALPHA_COLOR_FONT_DEPTH 2
+#define ALPHA_COLOR_LOOKUP_SHIFT (1 << ALPHA_COLOR_FONT_DEPTH)
+#define ALPHA_COLOR_LOOKUP_SIZE ((1 << ALPHA_COLOR_LOOKUP_SHIFT) - 1)
+#define ALPHA_COLOR_PIXEL_PER_BYTE (8 >> ALPHA_COLOR_FONT_DEPTH)
+#define ALPHA_COLOR_PIXEL_PER_WORD (32 >> ALPHA_COLOR_FONT_DEPTH)
+#ifdef CPU_ARM
+#define BLEND_INIT do {} while (0)
+#define BLEND_START(acc, color, alpha) \
+ asm volatile("mul %0, %1, %2" : "=&r" (acc) : "r" (color), "r" (alpha))
+#define BLEND_CONT(acc, color, alpha) \
+ asm volatile("mla %0, %1, %2, %0" : "+&r" (acc) : "r" (color), "r" (alpha))
+#define BLEND_OUT(acc) do {} while (0)
+#elif defined(CPU_COLDFIRE)
+#define ALPHA_BITMAP_READ_WORDS
+#define BLEND_INIT coldfire_set_macsr(EMAC_UNSIGNED)
+#define BLEND_START(acc, color, alpha) \
+ asm volatile("mac.l %0, %1, %%acc0" :: "%d" (color), "d" (alpha))
+#define BLEND_CONT BLEND_START
+#define BLEND_OUT(acc) asm volatile("movclr.l %%acc0, %0" : "=d" (acc))
+#else
+#define BLEND_INIT do {} while (0)
+#define BLEND_START(acc, color, alpha) ((acc) = (color) * (alpha))
+#define BLEND_CONT(acc, color, alpha) ((acc) += (color) * (alpha))
+#define BLEND_OUT(acc) do {} while (0)
+#endif
+
+/* Blend the given two colors */
+static inline unsigned blend_two_colors(unsigned c1, unsigned c2, unsigned a)
+{
+ a += a >> (ALPHA_COLOR_LOOKUP_SHIFT - 1);
+#if (LCD_PIXELFORMAT == RGB565SWAPPED)
+ c1 = swap16(c1);
+ c2 = swap16(c2);
+#endif
+ unsigned c1l = (c1 | (c1 << 16)) & 0x07e0f81f;
+ unsigned c2l = (c2 | (c2 << 16)) & 0x07e0f81f;
+ unsigned p;
+ BLEND_START(p, c1l, a);
+ BLEND_CONT(p, c2l, ALPHA_COLOR_LOOKUP_SIZE + 1 - a);
+ BLEND_OUT(p);
+ p = (p >> ALPHA_COLOR_LOOKUP_SHIFT) & 0x07e0f81f;
+ p |= (p >> 16);
+#if (LCD_PIXELFORMAT == RGB565SWAPPED)
+ return swap16(p);
+#else
+ return p;
+#endif
+}
+
+static void buffer_alpha_bitmap_part(
+ fb_data *buf, int buf_width, int buf_height,
+ const unsigned char *src, int src_x, int src_y,
+ int stride, int x, int y, int width, int height )
+{
+ fb_data *dst;
+ unsigned fg_pattern = rb->lcd_get_foreground();
+
+ /* nothing to draw? */
+ if ((width <= 0) || (height <= 0) || (x >= buf_width) ||
+ (y >= buf_height) || (x + width <= 0) || (y + height <= 0))
+ return;
+
+ /* initialize blending */
+ BLEND_INIT;
+
+ /* clipping */
+ if (x < 0)
+ {
+ width += x;
+ src_x -= x;
+ x = 0;
+ }
+ if (y < 0)
+ {
+ height += y;
+ src_y -= y;
+ y = 0;
+ }
+ if (x + width > buf_width)
+ width = buf_width - x;
+ if (y + height > buf_height)
+ height = buf_height - y;
+
+ dst = buf + y*buf_width + x;
+
+ int col, row = height;
+ unsigned data, pixels;
+ unsigned skip_end = (stride - width);
+ unsigned skip_start = src_y * stride + src_x;
+
+#ifdef ALPHA_BITMAP_READ_WORDS
+ uint32_t *src_w = (uint32_t *)((uintptr_t)src & ~3);
+ skip_start += ALPHA_COLOR_PIXEL_PER_BYTE * ((uintptr_t)src & 3);
+ src_w += skip_start / ALPHA_COLOR_PIXEL_PER_WORD;
+ data = letoh32(*src_w++);
+#else
+ src += skip_start / ALPHA_COLOR_PIXEL_PER_BYTE;
+ data = *src;
+#endif
+ pixels = skip_start % ALPHA_COLOR_PIXEL_PER_WORD;
+ data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT;
+#ifdef ALPHA_BITMAP_READ_WORDS
+ pixels = 8 - pixels;
+#endif
+
+ do
+ {
+ col = width;
+#ifdef ALPHA_BITMAP_READ_WORDS
+#define UPDATE_SRC_ALPHA do { \
+ if (--pixels) \
+ data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
+ else \
+ { \
+ data = letoh32(*src_w++); \
+ pixels = ALPHA_COLOR_PIXEL_PER_WORD; \
+ } \
+ } while (0)
+#elif ALPHA_COLOR_PIXEL_PER_BYTE == 2
+#define UPDATE_SRC_ALPHA do { \
+ if (pixels ^= 1) \
+ data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
+ else \
+ data = *(++src); \
+ } while (0)
+#else
+#define UPDATE_SRC_ALPHA do { \
+ if (pixels = (++pixels % ALPHA_COLOR_PIXEL_PER_BYTE)) \
+ data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
+ else \
+ data = *(++src); \
+ } while (0)
+#endif
+
+ do
+ {
+ *dst=blend_two_colors(*dst, fg_pattern,
+ data & ALPHA_COLOR_LOOKUP_SIZE );
+ dst++;
+ UPDATE_SRC_ALPHA;
+ }
+ while (--col);
+#ifdef ALPHA_BITMAP_READ_WORDS
+ if (skip_end < pixels)
+ {
+ pixels -= skip_end;
+ data >>= skip_end * ALPHA_COLOR_LOOKUP_SHIFT;
+ } else {
+ pixels = skip_end - pixels;
+ src_w += pixels / ALPHA_COLOR_PIXEL_PER_WORD;
+ pixels %= ALPHA_COLOR_PIXEL_PER_WORD;
+ data = letoh32(*src_w++);
+ data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT;
+ pixels = 8 - pixels;
+ }
+#else
+ if (skip_end)
+ {
+ pixels += skip_end;
+ if (pixels >= ALPHA_COLOR_PIXEL_PER_BYTE)
+ {
+ src += pixels / ALPHA_COLOR_PIXEL_PER_BYTE;
+ pixels %= ALPHA_COLOR_PIXEL_PER_BYTE;
+ data = *src;
+ data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT;
+ } else
+ data >>= skip_end * ALPHA_COLOR_LOOKUP_SHIFT;
+ }
+#endif
+ dst += LCD_WIDTH - width;
+ } while (--row);
+}
+
static void buffer_putsxyofs( fb_data *buf, int buf_width, int buf_height,
int x, int y, int ofs, const unsigned char *str )
{
@@ -589,8 +763,12 @@ static void buffer_putsxyofs( fb_data *buf, int buf_width, int buf_height,
bits = rb->font_get_bits( pf, ch );
- buffer_mono_bitmap_part( buf, buf_width, buf_height, bits, ofs, 0,
- width, x, y, width - ofs, pf->height);
+ if (pf->depth)
+ buffer_alpha_bitmap_part( buf, buf_width, buf_height, bits, ofs, 0,
+ width, x, y, width - ofs, pf->height);
+ else
+ buffer_mono_bitmap_part( buf, buf_width, buf_height, bits, ofs, 0,
+ width, x, y, width - ofs, pf->height);
x += width - ofs;
ofs = 0;
diff --git a/firmware/drivers/lcd-16bit.c b/firmware/drivers/lcd-16bit.c
index be4f21f412..a2eb3e630c 100644
--- a/firmware/drivers/lcd-16bit.c
+++ b/firmware/drivers/lcd-16bit.c
@@ -901,6 +901,258 @@ void lcd_mono_bitmap(const unsigned char *src, int x, int y, int width, int heig
lcd_mono_bitmap_part(src, 0, 0, width, x, y, width, height);
}
+/* draw alpha bitmap for anti-alias font */
+#define ALPHA_COLOR_FONT_DEPTH 2
+#define ALPHA_COLOR_LOOKUP_SHIFT (1 << ALPHA_COLOR_FONT_DEPTH)
+#define ALPHA_COLOR_LOOKUP_SIZE ((1 << ALPHA_COLOR_LOOKUP_SHIFT) - 1)
+#define ALPHA_COLOR_PIXEL_PER_BYTE (8 >> ALPHA_COLOR_FONT_DEPTH)
+#define ALPHA_COLOR_PIXEL_PER_WORD (32 >> ALPHA_COLOR_FONT_DEPTH)
+#ifdef CPU_ARM
+#define BLEND_INIT do {} while (0)
+#define BLEND_START(acc, color, alpha) \
+ asm volatile("mul %0, %1, %2" : "=&r" (acc) : "r" (color), "r" (alpha))
+#define BLEND_CONT(acc, color, alpha) \
+ asm volatile("mla %0, %1, %2, %0" : "+&r" (acc) : "r" (color), "r" (alpha))
+#define BLEND_OUT(acc) do {} while (0)
+#elif defined(CPU_COLDFIRE)
+#define ALPHA_BITMAP_READ_WORDS
+#define BLEND_INIT coldfire_set_macsr(EMAC_UNSIGNED)
+#define BLEND_START(acc, color, alpha) \
+ asm volatile("mac.l %0, %1, %%acc0" :: "%d" (color), "d" (alpha))
+#define BLEND_CONT BLEND_START
+#define BLEND_OUT(acc) asm volatile("movclr.l %%acc0, %0" : "=d" (acc))
+#else
+#define BLEND_INIT do {} while (0)
+#define BLEND_START(acc, color, alpha) ((acc) = (color) * (alpha))
+#define BLEND_CONT(acc, color, alpha) ((acc) += (color) * (alpha))
+#define BLEND_OUT(acc) do {} while (0)
+#endif
+
+/* Blend the given two colors */
+static inline unsigned blend_two_colors(unsigned c1, unsigned c2, unsigned a)
+{
+ a += a >> (ALPHA_COLOR_LOOKUP_SHIFT - 1);
+#if (LCD_PIXELFORMAT == RGB565SWAPPED)
+ c1 = swap16(c1);
+ c2 = swap16(c2);
+#endif
+ unsigned c1l = (c1 | (c1 << 16)) & 0x07e0f81f;
+ unsigned c2l = (c2 | (c2 << 16)) & 0x07e0f81f;
+ unsigned p;
+ BLEND_START(p, c1l, a);
+ BLEND_CONT(p, c2l, ALPHA_COLOR_LOOKUP_SIZE + 1 - a);
+ BLEND_OUT(p);
+ p = (p >> ALPHA_COLOR_LOOKUP_SHIFT) & 0x07e0f81f;
+ p |= (p >> 16);
+#if (LCD_PIXELFORMAT == RGB565SWAPPED)
+ return swap16(p);
+#else
+ return p;
+#endif
+}
+
+/* Blend the given color with the value from the alpha_color_lookup table */
+static inline unsigned blend_color(unsigned c, unsigned a)
+{
+ return blend_two_colors(c, current_vp->fg_pattern, a);
+}
+
+void ICODE_ATTR lcd_alpha_bitmap_part(const unsigned char *src, int src_x,
+ int src_y, int stride, int x, int y,
+ int width, int height)
+{
+ fb_data *dst, *backdrop;
+ unsigned dmask = 0x00000000;
+ int drmode = current_vp->drawmode;
+ /* nothing to draw? */
+ if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
+ (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
+ return;
+ /* initialize blending */
+ BLEND_INIT;
+
+ /* clipping */
+ if (x < 0)
+ {
+ width += x;
+ src_x -= x;
+ x = 0;
+ }
+ if (y < 0)
+ {
+ height += y;
+ src_y -= y;
+ y = 0;
+ }
+ if (x + width > current_vp->width)
+ width = current_vp->width - x;
+ if (y + height > current_vp->height)
+ height = current_vp->height - y;
+
+ if (drmode & DRMODE_INVERSEVID)
+ {
+ dmask = 0xffffffff;
+ drmode &= DRMODE_SOLID; /* mask out inversevid */
+ }
+ if (drmode == DRMODE_BG)
+ {
+ dmask = ~dmask;
+ }
+
+ dst = LCDADDR(current_vp->x + x, current_vp->y + y);
+
+ int col, row = height;
+ unsigned data, pixels;
+ unsigned skip_end = (stride - width);
+ unsigned skip_start = src_y * stride + src_x;
+
+#ifdef ALPHA_BITMAP_READ_WORDS
+ uint32_t *src_w = (uint32_t *)((uintptr_t)src & ~3);
+ skip_start += ALPHA_COLOR_PIXEL_PER_BYTE * ((uintptr_t)src & 3);
+ src_w += skip_start / ALPHA_COLOR_PIXEL_PER_WORD;
+ data = letoh32(*src_w++) ^ dmask;
+ pixels = skip_start % ALPHA_COLOR_PIXEL_PER_WORD;
+#else
+ src += skip_start / ALPHA_COLOR_PIXEL_PER_BYTE;
+ data = *src ^ dmask;
+ pixels = skip_start % ALPHA_COLOR_PIXEL_PER_BYTE;
+#endif
+ data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT;
+#ifdef ALPHA_BITMAP_READ_WORDS
+ pixels = 8 - pixels;
+#endif
+
+ do
+ {
+ col = width;
+#ifdef ALPHA_BITMAP_READ_WORDS
+#define UPDATE_SRC_ALPHA do { \
+ if (--pixels) \
+ data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
+ else \
+ { \
+ data = letoh32(*src_w++) ^ dmask; \
+ pixels = ALPHA_COLOR_PIXEL_PER_WORD; \
+ } \
+ } while (0)
+#elif ALPHA_COLOR_PIXEL_PER_BYTE == 2
+#define UPDATE_SRC_ALPHA do { \
+ if (pixels ^= 1) \
+ data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
+ else \
+ data = *(++src) ^ dmask; \
+ } while (0)
+#else
+#define UPDATE_SRC_ALPHA do { \
+ if (pixels = (++pixels % ALPHA_COLOR_PIXEL_PER_BYTE)) \
+ data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
+ else \
+ data = *(++src) ^ dmask; \
+ } while (0)
+#endif
+ /* we don't want to have this in our inner
+ * loop and the codesize increase is minimal */
+ switch (drmode)
+ {
+ case DRMODE_COMPLEMENT:
+ do
+ {
+ *dst=blend_two_colors(*dst, ~(*dst),
+ data & ALPHA_COLOR_LOOKUP_SIZE );
+ dst++;
+ UPDATE_SRC_ALPHA;
+ }
+ while (--col);
+ break;
+ case DRMODE_BG:
+ if(lcd_backdrop)
+ {
+ backdrop = (fb_data *)((long)dst+lcd_backdrop_offset);
+ do
+ {
+ *dst=blend_two_colors(*dst, *(backdrop++),
+ data & ALPHA_COLOR_LOOKUP_SIZE );
+ dst++;
+ UPDATE_SRC_ALPHA;
+ }
+ while (--col);
+ }
+ else
+ {
+ do
+ {
+ *dst=blend_two_colors(*dst, current_vp->bg_pattern,
+ data & ALPHA_COLOR_LOOKUP_SIZE );
+ dst++;
+ UPDATE_SRC_ALPHA;
+ }
+ while (--col);
+ }
+ break;
+ case DRMODE_FG:
+ do
+ {
+ *dst=blend_color(*dst, data & ALPHA_COLOR_LOOKUP_SIZE );
+ dst++;
+ UPDATE_SRC_ALPHA;
+ }
+ while (--col);
+ break;
+ case DRMODE_SOLID:
+ if(lcd_backdrop)
+ {
+ backdrop = (fb_data *)((long)dst+lcd_backdrop_offset);
+ do
+ {
+ *(dst++)=blend_color(*(backdrop++),
+ data & ALPHA_COLOR_LOOKUP_SIZE );
+ UPDATE_SRC_ALPHA;
+ }
+ while (--col);
+ }
+ else
+ {
+ do
+ {
+ *(dst++)=blend_color(current_vp->bg_pattern,
+ data & ALPHA_COLOR_LOOKUP_SIZE );
+ UPDATE_SRC_ALPHA;
+ }
+ while (--col);
+ }
+ break;
+ }
+#ifdef ALPHA_BITMAP_READ_WORDS
+ if (skip_end < pixels)
+ {
+ pixels -= skip_end;
+ data >>= skip_end * ALPHA_COLOR_LOOKUP_SHIFT;
+ } else {
+ pixels = skip_end - pixels;
+ src_w += pixels / ALPHA_COLOR_PIXEL_PER_WORD;
+ pixels %= ALPHA_COLOR_PIXEL_PER_WORD;
+ data = letoh32(*src_w++) ^ dmask;
+ data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT;
+ pixels = 8 - pixels;
+ }
+#else
+ if (skip_end)
+ {
+ pixels += skip_end;
+ if (pixels >= ALPHA_COLOR_PIXEL_PER_BYTE)
+ {
+ src += pixels / ALPHA_COLOR_PIXEL_PER_BYTE;
+ pixels %= ALPHA_COLOR_PIXEL_PER_BYTE;
+ data = *src ^ dmask;
+ data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT;
+ } else
+ data >>= skip_end * ALPHA_COLOR_LOOKUP_SHIFT;
+ }
+#endif
+ dst += LCD_WIDTH - width;
+ } while (--row);
+}
+
/* Draw a partial native bitmap */
void ICODE_ATTR lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
int stride, int x, int y, int width,
diff --git a/firmware/drivers/lcd-bitmap-common.c b/firmware/drivers/lcd-bitmap-common.c
index 364fb3c527..fc84fdd6a1 100644
--- a/firmware/drivers/lcd-bitmap-common.c
+++ b/firmware/drivers/lcd-bitmap-common.c
@@ -203,9 +203,15 @@ static void LCDFN(putsxyofs)(int x, int y, int ofs, const unsigned char *str)
}
bits = font_get_bits(pf, *ucs);
- LCDFN(mono_bitmap_part)(bits, ofs, 0, width, x + base_ofs, y,
- width - ofs, pf->height);
+#if defined(MAIN_LCD) && defined(HAVE_LCD_COLOR)
+ if (pf->depth)
+ lcd_alpha_bitmap_part(bits, ofs, 0, width, x + base_ofs, y,
+ width - ofs, pf->height);
+ else
+#endif
+ LCDFN(mono_bitmap_part)(bits, ofs, 0, width, x + base_ofs,
+ y, width - ofs, pf->height);
if (is_diac)
{
current_vp->drawmode = drawmode;
diff --git a/firmware/export/font.h b/firmware/export/font.h
index 0a75768fa5..a85f95e6ae 100644
--- a/firmware/export/font.h
+++ b/firmware/export/font.h
@@ -68,7 +68,7 @@ enum {
* USHORT maxwidth 2 font max width in pixels
* USHORT height 2 font height in pixels
* USHORT ascent 2 font ascent (baseline) in pixels
- * USHORT pad 2 unused, pad to 32-bit boundary
+ * USHORT depth 2 depth of the font, 0=1bit and 1=4bit
* ULONG firstchar 4 first character code in font
* ULONG defaultchar 4 default character code in font
* ULONG size 4 # characters in font
@@ -92,6 +92,7 @@ struct font {
int ascent; /* ascent (baseline) height*/
int firstchar; /* first character in bitmap*/
int size; /* font size in glyphs*/
+ int depth; /* depth of the font, 0=1bit and 1=4bit */
const unsigned char *bits; /* 8-bit column bitmap data*/
const void *offset; /* offsets into bitmap data,
uint16_t if bits_size < 0xFFDB else uint32_t*/
diff --git a/firmware/font.c b/firmware/font.c
index 45ddef3afe..0f9f453ae2 100644
--- a/firmware/font.c
+++ b/firmware/font.c
@@ -89,7 +89,7 @@ static struct font* sysfonts[MAXFONTS] = { &sysfont, &font_ui, NULL};
/* Font cache structures */
-static void cache_create(struct font* pf, int maxwidth, int height);
+static void cache_create(struct font* pf);
static void glyph_cache_load(struct font* pf);
/* End Font cache structures */
@@ -132,6 +132,13 @@ static int32_t readlong(struct font *pf)
return l;
}
+static int glyph_bytes( struct font *pf, int width )
+{
+ return pf->depth ?
+ (pf->height * width + 1) / 2:
+ width * ((pf->height + 7) / 8);
+}
+
void font_reset(struct font *pf)
{
unsigned char* buffer = NULL;
@@ -168,7 +175,7 @@ static struct font* font_load_header(struct font *pf)
pf->maxwidth = readshort(pf);
pf->height = readshort(pf);
pf->ascent = readshort(pf);
- pf->buffer_position += 2; /* Skip padding */
+ pf->depth = readshort(pf);
pf->firstchar = readlong(pf);
pf->defaultchar = readlong(pf);
pf->size = readlong(pf);
@@ -308,7 +315,7 @@ static struct font* font_load_cached(struct font* pf)
pf->buffer_position = oldfileptr;
/* Create the cache */
- cache_create(pf, pf->maxwidth, pf->height);
+ cache_create(pf);
return pf;
}
@@ -436,7 +443,8 @@ int font_load(struct font* pf, const char *path)
{
/* currently, font loading replaces earlier font allocation*/
buffer = (unsigned char *)(((intptr_t)main_buf + 3) & ~3);
- buffer_size = MAX_FONT_SIZE;
+ /* make sure above doesn't exceed */
+ buffer_size = MAX_FONT_SIZE-3;
}
else
{
@@ -516,24 +524,23 @@ load_cache_entry(struct font_cache_entry* p, void* callback_data)
}
else
{
- bitmap_offset = ((pf->height + 7) / 8) * p->width * char_code;
+ bitmap_offset = char_code * glyph_bytes(pf, p->width);
}
int32_t file_offset = FONT_HEADER_SIZE + bitmap_offset;
lseek(pf->fd, file_offset, SEEK_SET);
-
- int src_bytes = p->width * ((pf->height + 7) / 8);
+ int src_bytes = glyph_bytes(pf, p->width);
read(pf->fd, p->bitmap, src_bytes);
}
/*
* Converts cbuf into a font cache
*/
-static void cache_create(struct font* pf, int maxwidth, int height)
+static void cache_create(struct font* pf)
{
/* maximum size of rotated bitmap */
- int bitmap_size = maxwidth * ((height + 7) / 8);
-
+ int bitmap_size = glyph_bytes( pf, pf->maxwidth);
+
/* Initialise cache */
font_cache_create(&pf->cache, pf->buffer_start, pf->buffer_size, bitmap_size);
}
@@ -578,7 +585,7 @@ const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
bits += ((uint32_t*)(pf->offset))[char_code];
}
else
- bits += ((pf->height + 7) / 8) * pf->maxwidth * char_code;
+ bits += char_code * glyph_bytes(pf, pf->maxwidth);
}
return bits;
@@ -655,7 +662,7 @@ int font_glyphs_to_bufsize(const char *path, int glyphs)
bufsize = LRU_SLOT_OVERHEAD + sizeof(struct font_cache_entry) +
sizeof( unsigned short);
- bufsize += f.maxwidth * ((f.height + 7) / 8);
+ bufsize += glyph_bytes(&f, f.maxwidth);
bufsize *= glyphs;
if ( bufsize < FONT_HEADER_SIZE )
bufsize = FONT_HEADER_SIZE;
diff --git a/tools/Makefile b/tools/Makefile
index 0a69dde5da..c33d152c41 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -13,10 +13,10 @@ LDFLAGS := -g
CLEANALL := scramble descramble iriver sh2d bmp2rb rdf2binary convbdf \
generate_rocklatin mkboot ipod_fw codepages uclpack mi4 gigabeat lngdump \
- telechips gigabeats creative hmac-sha1 rbspeexenc mkzenboot mk500boot
+ telechips gigabeats creative hmac-sha1 rbspeexenc mkzenboot mk500boot convttf
all: scramble descramble sh2d rdf2binary mkboot mkzenboot convbdf codepages \
- uclpack rbspeexenc voicefont mk500boot
+ uclpack rbspeexenc voicefont mk500boot convttf
scramble: scramble.o iriver.o mi4.o gigabeat.o gigabeats.o telechips.o \
iaudio_bl_flash.o creative.o hmac-sha1.o
@@ -97,6 +97,11 @@ voicefont: voicefont.c
usb_benchmark: usb_benchmark.c
$(SILENT)$(CC) $(CFLAGS) -lusb $+ -o $@
+convttf: convttf.c
+ $(call PRINTS,CC $(@F))
+ $(SILENT)$(CC) $(CFLAGS) -lm -std=c99 -O2 -Wall -g $+ -o $@ \
+ `freetype-config --libs` `freetype-config --cflags`
+
clean:
@echo "Cleaning tools"
$(SILENT)rm -f $(CLEANALL) $(shell for f in $(CLEANALL) ; do \
diff --git a/tools/convbdf.c b/tools/convbdf.c
index 5a563220fd..671312e66b 100644
--- a/tools/convbdf.c
+++ b/tools/convbdf.c
@@ -46,6 +46,7 @@ struct font {
int ascent; /* ascent (baseline) height */
int firstchar; /* first character in bitmap */
int size; /* font size in glyphs ('holes' included) */
+ int depth; /* depth of the font, 0=1bit 1=4bit */
bitmap_t* bits; /* 16-bit right-padded bitmap data */
int* offset; /* offsets into bitmap data */
unsigned char* width; /* character widths or NULL if fixed */
@@ -1220,6 +1221,7 @@ int gen_c_source(struct font* pf, char *path)
" size: %d\n"
" ascent: %d\n"
" descent: %d\n"
+ " depth: %d\n"
" first char: %d (0x%02x)\n"
" last char: %d (0x%02x)\n"
" default char: %d (0x%02x)\n"
@@ -1245,7 +1247,7 @@ int gen_c_source(struct font* pf, char *path)
pf->facename? pf->facename: "",
pf->maxwidth, pf->height,
pf->size,
- pf->ascent, pf->descent,
+ pf->ascent, pf->descent, pf->depth,
pf->firstchar, pf->firstchar,
pf->firstchar+pf->size-1, pf->firstchar+pf->size-1,
pf->defaultchar, pf->defaultchar,
@@ -1392,6 +1394,7 @@ int gen_c_source(struct font* pf, char *path)
" %d, /* ascent */\n"
" %d, /* firstchar */\n"
" %d, /* size */\n"
+ " %d, /* depth */\n"
" _font_bits, /* bits */\n"
" %s /* offset */\n"
" %s\n"
@@ -1411,7 +1414,7 @@ int gen_c_source(struct font* pf, char *path)
pf->maxwidth, pf->height,
pf->ascent,
pf->firstchar,
- pf->size,
+ pf->size, 0,
obuf,
buf,
pf->defaultchar,
@@ -1436,7 +1439,8 @@ int gen_h_header(struct font* pf, char *path)
"#define SYSFONT_WIDTH %d\n"
"#define SYSFONT_HEIGHT %d\n"
"#define SYSFONT_SIZE %d\n"
- "#define SYSFONT_ASCENT %d\n";
+ "#define SYSFONT_ASCENT %d\n"
+ "#define SYSFONT_DEPTH %d\n";
char *hdr2 =
"#define SYSFONT_DESCENT %d\n"
"#define SYSFONT_FIRST_CHAR %d\n"
@@ -1463,7 +1467,8 @@ int gen_h_header(struct font* pf, char *path)
pf->maxwidth,
pf->height,
pf->size,
- pf->ascent);
+ pf->ascent,
+ pf->depth);
fprintf(ofp, hdr2,
pf->descent,
@@ -1546,7 +1551,7 @@ int gen_fnt_file(struct font* pf, char *path)
writeshort(ofp, pf->maxwidth);
writeshort(ofp, pf->height);
writeshort(ofp, pf->ascent);
- writeshort(ofp, 0);
+ writeshort(ofp, 0); /* depth = 0 for bdffonts */
writeint(ofp, pf->firstchar);
writeint(ofp, pf->defaultchar);
writeint(ofp, pf->size);
diff --git a/tools/convttf.c b/tools/convttf.c
new file mode 100644
index 0000000000..ca9e4fbb4d
--- /dev/null
+++ b/tools/convttf.c
@@ -0,0 +1,1283 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2007 Jonas Hurrelmann
+ *
+ * A command-line tool to convert ttf file to bitmap fonts
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+
+#include <stdbool.h>
+#include <stdio.h>
+#ifdef WIN32
+#include <windows.h>
+#else
+#include <stdlib.h>
+#include <unistd.h>
+#endif
+#include FT_SFNT_NAMES_H
+#include FT_TRUETYPE_TABLES_H
+
+#include <string.h>
+/*
+ * Set the default values used to generate a BDF font.
+ */
+#ifndef DEFAULT_PLATFORM_ID
+#define DEFAULT_PLATFORM_ID 3
+#endif
+
+#ifndef DEFAULT_ENCODING_ID
+#define DEFAULT_ENCODING_ID 1
+#endif
+
+#define ABS(x) (((x) < 0) ? -(x) : (x))
+
+#define VERSION "RB12"
+/*
+ * nameID macros for getting strings from the OT font.
+ */
+enum {
+ BDFOTF_COPYRIGHT_STRING = 0,
+ BDFOTF_FAMILY_STRING,
+ BDFOTF_SUBFAMILY_STRING,
+ BDFOTF_UNIQUEID_STRING,
+ BDFOTF_FULLNAME_STRING,
+ BDFOTF_VENDOR_STRING,
+ BDFOTF_POSTSCRIPT_STRING,
+ BDFOTF_TRADEMARK_STRING,
+};
+/*
+ * String names for the string indexes. Used for error messages.
+ */
+static char *string_names[] = {
+ "\"Copyright\"",
+ "\"Family\"",
+ "\"SubFamily\"",
+ "\"Unique ID\"",
+ "\"Full Name\"",
+ "\"Vendor\"",
+ "\"Postscript Name\"",
+ "\"Trademark\""
+};
+
+
+/*
+ * The default platform and encoding ID's.
+ */
+static int pid = DEFAULT_PLATFORM_ID;
+static int eid = DEFAULT_ENCODING_ID;
+
+
+/*
+ * A flag indicating if a CMap was found or not.
+ */
+static FT_UShort nocmap;
+
+int pct = 0; /* display ttc table if it is not zero. */
+unsigned long max_char = 65535;
+int pixel_size = 15;
+unsigned long start_char = 0;
+unsigned long limit_char;
+unsigned long firstchar = 0;
+unsigned long lastchar;
+FT_Long ttc_index = -1;
+int flg_all_ttc = 0;
+short antialias = 1; /* smooth fonts with gray levels */
+int oflag = 0;
+char outfile[1024];
+float between_chr = 0.0f;
+float between_row = 0.0f;
+int hv_resolution = 60;
+int dump_glyphs = 0;
+int trimming = 0;
+int trim_dp = 0; /* trim descent percent */
+int trim_da = 0; /* trim descnet actual */
+int trim_ap = 0; /* trim ascent precent */
+int trim_aa = 0; /* trim ascent actual */
+
+struct font_header_struct {
+ char header[4]; /* magic number and version bytes */
+ unsigned short maxwidth; /* max width in pixels */
+ unsigned short height; /* height in pixels */
+ unsigned short ascent; /* ascent (baseline) height */
+ unsigned short depth; /* depth 0=1-bit, 1=4-bit */
+ unsigned long firstchar; /* first character in font */
+ unsigned long defaultchar; /* default character in font */
+ unsigned long size; /* # characters in font */
+ unsigned long nbits; /* # bytes imagebits data in file */ /* = bits_size */
+
+ FT_Long noffset; /* # longs offset data in file */
+ FT_Long nwidth; /* # bytes width data in file */
+};
+
+struct font_struct {
+ struct font_header_struct header;
+ unsigned char *chars_data;
+ unsigned short *offset;
+ FT_Long *offset_long;
+ unsigned char *width;
+};
+
+struct ttc_table{
+ FT_Long ttc_count;
+ char **ttf_name;
+};
+
+/* exit the program with given message */
+static void
+panic( const char* message)
+{
+ fprintf( stderr, "%s\n", message );
+ exit( 1 );
+}
+
+static void
+arg_panic( const char* message, const char* arg )
+{
+ fprintf( stderr, "%s: %s\n", message, arg );
+ exit( 1 );
+}
+
+static int writebyte(FILE *fp, unsigned char c)
+{
+ return putc(c, fp) != EOF;
+}
+
+static int writeshort(FILE *fp, unsigned short s)
+{
+ putc(s, fp);
+ return putc(s>>8, fp) != EOF;
+}
+
+static int writeint(FILE *fp, unsigned int l)
+{
+ putc(l, fp);
+ putc(l>>8, fp);
+ putc(l>>16, fp);
+ return putc(l>>24, fp) != EOF;
+}
+
+static int writestr(FILE *fp, char *str, int count)
+{
+ return (int)fwrite(str, 1, count, fp) == count;
+}
+
+/* print usage information */
+void usage(void)
+{
+ char help[] = {
+ "Usage: convttf [options] [input-files]\n"
+ " convttf [options] [-o output-file] [single-input-file]\n\n"
+ " Default output-file : <font-size>-<basename>.fnt.\n"
+ " When '-ta' or '-tc' is specified in command line,\n "
+ " default output-file is: \n"
+ " <font-size>-<internal postscript-name of input-file>.fnt.\n"
+ "Options:\n"
+ " -s N Start output at character encodings >= N\n"
+ " -l N Limit output to character encodings <= N\n"
+ " -p N Font size N in pixel (default N=15)\n"
+ " -c N Character separation in pixel.Insert space between lines.\n"
+ " -x Trim glyphs horizontally of nearly empty space\n"
+ " (to improve spacing on V's W's, etc.)\n"
+ " -X Set the horizontal and vertical resolution (default: 60)\n"
+ " -TA N Trim vertical ascent (N percent)\n"
+ " -TD N Trim vertical descent (N percent)\n"
+ " -Ta N Trim vertical ascent (N pixels)\n"
+ " -Td N Trim vertical descent (N pixels)\n"
+ " -r N Row separation in pixel.Insert space between characters\n"
+ " -d Debug: print converted glyph images\n"
+ " -tt Display the True Type Collection tables available in the font\n"
+ " -t N Index of true type collection. It must be start from 0.(default N=0).\n"
+ " -ta Convert all fonts in ttc (ignores outfile option)\n"
+ };
+ fprintf(stderr, "%s", help);
+ exit( 1 );
+}
+
+/* remove directory prefix and file suffix from full path*/
+char *basename(char *path)
+{
+ char *p, *b;
+ static char base[256];
+
+ /* remove prepended path and extension*/
+ b = path;
+ for (p=path; *p; ++p) {
+ if (*p == '/')
+ b = p + 1;
+ }
+ strcpy(base, b);
+ for (p=base; *p; ++p) {
+ if (*p == '.') {
+ *p = 0;
+ break;
+ }
+ }
+ return base;
+}
+
+
+void setcharmap(FT_Face face)
+{
+ FT_Long i;
+
+ /*
+ * Get the requested cmap.
+ */
+ for (i = 0; i < face->num_charmaps; i++) {
+ if (face->charmaps[i]->platform_id == pid &&
+ face->charmaps[i]->encoding_id == eid)
+ break;
+ }
+
+ if (i == face->num_charmaps && pid == 3 && eid == 1) {
+ /*
+ * Make a special case when this fails with pid == 3 and eid == 1.
+ * Change to eid == 0 and try again. This captures the two possible
+ * cases for MS fonts. Some other method should be used to cycle
+ * through all the alternatives later.
+ */
+ for (i = 0; i < face->num_charmaps; i++) {
+ if (face->charmaps[i]->platform_id == pid &&
+ face->charmaps[i]->encoding_id == 0)
+ break;
+ }
+ if (i < face->num_charmaps) {
+ pid = 3;
+ eid = 1;
+ FT_Set_Charmap(face, face->charmaps[i]);
+ } else {
+ /*
+ * No CMAP was found.
+ */
+ nocmap = 1;
+ pid = eid = -1;
+ }
+ } else {
+ FT_Set_Charmap(face, face->charmaps[i]);
+ nocmap = 0;
+ }
+
+}
+
+/*
+ * quote in otf2bdf.
+ * A generic routine to get a name from the OT name table. This routine
+ * always looks for English language names and checks three possibilities:
+ * 1. English names with the MS Unicode encoding ID.
+ * 2. English names with the MS unknown encoding ID.
+ * 3. English names with the Apple Unicode encoding ID.
+ *
+ * The particular name ID mut be provided (e.g. nameID = 0 for copyright
+ * string, nameID = 6 for Postscript name, nameID = 1 for typeface name.
+ *
+ * If the `dash_to_space' flag is non-zero, all dashes (-) in the name will be
+ * replaced with the character passed.
+ *
+ * Returns the number of bytes added.
+ */
+static int
+otf_get_english_string(FT_Face face, int nameID, int dash_to_space,
+ char *name, int name_size)
+{
+
+ int j, encid;
+ FT_UInt i, nrec;
+ FT_SfntName sfntName;
+ unsigned char *s;
+ unsigned short slen;
+
+ nrec = FT_Get_Sfnt_Name_Count(face);
+
+ for (encid = 1, j = 0; j < 2; j++, encid--) {
+ /*
+ * Locate one of the MS English font names.
+ */
+ for (i = 0; i < nrec; i++) {
+ FT_Get_Sfnt_Name(face, i, &sfntName);
+ if (sfntName.platform_id == 3 &&
+ sfntName.encoding_id == encid &&
+ sfntName.name_id == nameID &&
+ (sfntName.language_id == 0x0409 ||
+ sfntName.language_id == 0x0809 ||
+ sfntName.language_id == 0x0c09 ||
+ sfntName.language_id == 0x1009 ||
+ sfntName.language_id == 0x1409 ||
+ sfntName.language_id == 0x1809)) {
+ s = sfntName.string;
+ slen = sfntName.string_len;
+ break;
+ }
+ }
+
+ if (i < nrec) {
+ if (slen >> 1 >= name_size) {
+ fprintf(stderr, "warning: %s string longer than buffer."
+ "Truncating to %d bytes.\n", string_names[nameID], name_size);
+ slen = name_size << 1;
+ }
+
+ /*
+ * Found one of the MS English font names. The name is by
+ * definition encoded in Unicode, so copy every second byte into
+ * the `name' parameter, assuming there is enough space.
+ */
+ for (i = 1; i < slen; i += 2) {
+ if (dash_to_space)
+ *name++ = (s[i] != '-') ? s[i] : ' ';
+ else if (s[i] == '\r' || s[i] == '\n') {
+ if (s[i] == '\r' && i + 2 < slen && s[i + 2] == '\n')
+ i += 2;
+ *name++ = ' ';
+ *name++ = ' ';
+ } else
+ *name++ = s[i];
+ }
+ *name = 0;
+ return (slen >> 1);
+ }
+ }
+
+ /*
+ * No MS English name found, attempt to find an Apple Unicode English
+ * name.
+ */
+ for (i = 0; i < nrec; i++) {
+ FT_Get_Sfnt_Name(face, i, &sfntName);
+ if (sfntName.platform_id == 0 && sfntName.language_id == 0 &&
+ sfntName.name_id == nameID) {
+ s = sfntName.string;
+ slen = sfntName.string_len;
+ break;
+ }
+ }
+
+ if (i < nrec) {
+ if (slen >> 1 >= name_size) {
+ fprintf(stderr, "warning: %s string longer than buffer."
+ "Truncating to %d bytes.\n", string_names[nameID], name_size);
+ slen = name_size << 1;
+ }
+
+ /*
+ * Found the Apple Unicode English name. The name is by definition
+ * encoded in Unicode, so copy every second byte into the `name'
+ * parameter, assuming there is enough space.
+ */
+ for (i = 1; i < slen; i += 2) {
+ if (dash_to_space)
+ *name++ = (s[i] != '-') ? s[i] : ' ';
+ else if (s[i] == '\r' || s[i] == '\n') {
+ if (s[i] == '\r' && i + 2 < slen && s[i + 2] == '\n')
+ i += 2;
+ *name++ = ' ';
+ *name++ = ' ';
+ } else
+ *name++ = s[i];
+ }
+ *name = 0;
+ return (slen >> 1);
+ }
+
+ return 0;
+}
+
+
+int get_ttc_table(char *path, struct ttc_table *ttcname )
+{
+
+
+ FT_Error error;
+ FT_Library library;
+ FT_Face face;
+ FT_Long i;
+ char xlfd[BUFSIZ];
+
+ /* init number of ttf in ttc */
+ ttcname->ttc_count = 0;
+
+ /* Initialize engine */
+ if ( ( error = FT_Init_FreeType( &library ) ) != 0 )
+ {
+ panic( "Error while initializing engine" );
+ return error;
+ }
+
+
+ /* Load face */
+ error = FT_New_Face( library, path, (FT_Long) 0, &face );
+ if ( error )
+ {
+ arg_panic( "Could not find/open font", path );
+ return error;
+ }
+
+ ttcname->ttc_count = face->num_faces;
+ ttcname->ttf_name = malloc( sizeof(char*) * ttcname->ttc_count);
+
+ for(i = 0; i < ttcname->ttc_count; i++)
+ {
+ error = FT_New_Face( library, path, i, &face );
+ if ( error == FT_Err_Cannot_Open_Stream )
+ arg_panic( "Could not find/open font", path );
+ otf_get_english_string(face, BDFOTF_POSTSCRIPT_STRING, 0, xlfd,
+ sizeof(xlfd));
+ ttcname->ttf_name[i] = malloc(sizeof(char) * (strlen(xlfd) + 1 ));
+ strcpy(ttcname->ttf_name[i], xlfd);
+ }
+ return 0;
+}
+
+void print_ttc_table(char* path)
+{
+ struct ttc_table ttcname;
+ FT_Long i;
+
+ get_ttc_table(path, &ttcname);
+ printf("ttc header count = %ld \n\n", ttcname.ttc_count);
+ printf("Encoding tables available in the true type collection\n\n");
+ printf("INDEX\tPOSTSCRIPT NAME\n");
+ printf("-----------------------------------------------------\n");
+ for(i = 0; i < ttcname.ttc_count; i++)
+ {
+ printf("%ld\t%s\n", i, ttcname.ttf_name[i]);
+ }
+ for(i = 0; i < ttcname.ttc_count; i++)
+ {
+ free(ttcname.ttf_name[i]);
+ }
+ printf("\n\n");
+ free(ttcname.ttf_name);
+
+ return;
+}
+
+FT_Long getcharindex(FT_Face face, FT_Long code)
+{
+ FT_Long idx;
+ if (nocmap) {
+ if (code >= face->num_glyphs)
+ idx = 0;
+ else
+ idx = code;
+ } else
+ idx = FT_Get_Char_Index( face, code);
+
+ if ( idx <= 0 || idx > face->num_glyphs)
+ return 0;
+ else
+ return idx;
+}
+
+void print_raw_glyph( FT_Face face)
+{
+ int pixel,row,col,width;
+ width = face->glyph->metrics.width >> 6;
+
+ printf("\n---Raw-Glyph---\n");
+ for(row=0; row < face->glyph->metrics.height >> 6; row++)
+ {
+ printf("_");
+ for(col=0; col < width; col++)
+ {
+ pixel = *(face->glyph->bitmap.buffer+width*row+col)/26;
+ if ( pixel ) printf("%d",pixel); else printf(" ");
+ }
+ printf("_\n");
+ }
+ printf("----End-----\n");
+}
+
+int glyph_width( FT_Face face)
+{
+ int pitch, h_adv, width;
+ unsigned spacing = (unsigned)(between_chr * (1<<6));/* convert to fixed point */
+
+ pitch = ABS(face->glyph->bitmap.pitch);
+ h_adv = face->glyph->metrics.horiAdvance >> 6;
+ width = (face->glyph->metrics.width + spacing) >> 6;
+
+ if(pitch == 0) pitch = h_adv;
+ if(width < pitch) width = pitch;
+ if(width == 0) return 0;
+
+ return width;
+}
+
+
+void trim_glyph( FT_GlyphSlot glyph, int *empty_first_col,
+ int *empty_last_col, int *width )
+{
+ int row;
+ int stride = glyph->bitmap.pitch;
+ int end = stride-1;
+ int trim_left = 2, trim_right = 2;
+
+ const unsigned char limit = 64u;
+ const unsigned char *image = glyph->bitmap.buffer;
+
+ if (*width < 2)
+ return; /* nothing to do? */
+
+ for(row=0; row< glyph->metrics.height >> 6; row++)
+ {
+ const unsigned char *column = image+row*stride;
+ if (*column++ < limit && trim_left)
+ {
+ if (*column >= limit/2)
+ trim_left = 1;
+ }
+ else
+ trim_left = 0;
+
+ column = image+row*stride+end;
+ if (*column-- < limit && trim_right)
+ {
+ if (*column >= limit/2)
+ trim_right = 1;
+ }
+ else
+ trim_right = 0;
+ }
+
+
+ (*width) -= trim_left + trim_right;
+ if (*width < 0) *width = 0;
+
+ *empty_first_col = trim_left;
+ *empty_last_col = trim_right;
+}
+
+void convttf(char* path, char* destfile, FT_Long face_index)
+{
+ FT_Error error;
+ FT_Library library;
+ FT_Face face;
+ int w,h;
+ int row,col;
+ int empty_first_col, empty_last_col;
+ FT_Long charindex;
+ FT_Long index = 0;
+ FT_Long code;
+
+ int depth = 2;
+ unsigned char bit_shift = 1 << depth;
+ unsigned char pixel_per_byte = CHAR_BIT / bit_shift;
+
+ /* Initialize engine */
+ if ( ( error = FT_Init_FreeType( &library ) ) != 0 )
+ panic( "Error while initializing engine" );
+
+ /* Load face */
+ error = FT_New_Face( library, path, (FT_Long) face_index, &face );
+ if ( error == FT_Err_Cannot_Open_Stream )
+ arg_panic( "Could not find/open font\n", path );
+ else if ( error )
+ arg_panic( "Error while opening font\n", path );
+
+
+ setcharmap( face );
+ /* Set font header data */
+ struct font_struct export_font;
+ export_font.header.header[0] = 'R';
+ export_font.header.header[1] = 'B';
+ export_font.header.header[2] = '1';
+ export_font.header.header[3] = '2';
+ //export_font.header.height = 0;
+ //export_font.header.ascent = 0;
+
+ float extra_space = (float)(between_row-trim_aa-trim_da);
+ FT_Set_Char_Size( face, 0, pixel_size << 6, hv_resolution, hv_resolution );
+ export_font.header.ascent =
+ ((face->size->metrics.ascender*(100-trim_ap)/100) >> 6) - trim_aa;
+
+ export_font.header.height =
+ (((face->size->metrics.ascender*(100-trim_ap)/100) -
+ (face->size->metrics.descender*(100-trim_dp)/100)) >> 6) + extra_space;
+
+ printf("\n");
+ printf("Please wait, converting %s:\n", path);
+
+ /* "face->num_glyphs" is NG.; */
+ if ( limit_char == 0 ) limit_char = max_char;
+ if ( limit_char > max_char ) limit_char = max_char;
+
+ FT_Long char_count = 0;
+
+
+
+ export_font.header.maxwidth = 1;
+ export_font.header.depth = 1;
+ firstchar = limit_char;
+ lastchar = start_char;
+
+ /* calculate memory usage */
+ for(code = start_char; code <= limit_char ; code++ )
+ {
+ charindex = getcharindex( face, code);
+ if ( !(charindex) ) continue;
+ error = FT_Load_Glyph( face, charindex,
+ (FT_LOAD_RENDER | FT_LOAD_NO_BITMAP) );
+ if ( error ) continue;
+
+ w = glyph_width( face );
+ if (w == 0) continue;
+ empty_first_col = empty_last_col = 0;
+ if(trimming)
+ trim_glyph( face->glyph, &empty_first_col, &empty_last_col, &w);
+
+ if (export_font.header.maxwidth < w)
+ export_font.header.maxwidth = w;
+
+
+ char_count++;
+ index += (w*export_font.header.height + pixel_per_byte - 1)/pixel_per_byte;
+
+ if (code >= lastchar)
+ lastchar = code;
+
+ if (code <= firstchar)
+ firstchar = code;
+ }
+ export_font.header.defaultchar = firstchar;
+ export_font.header.firstchar = firstchar;
+ export_font.header.size = lastchar - firstchar + 1;
+ export_font.header.nbits = index;
+ export_font.header.noffset = export_font.header.size;
+ export_font.header.nwidth = export_font.header.size;
+
+ /* check if we need to use long offsets */
+ char use_long_offset = (export_font.header.nbits >= 0xFFDB );
+
+ /* allocate memory */
+ export_font.offset = NULL;
+ export_font.offset_long = NULL;
+ if (use_long_offset)
+ export_font.offset_long =
+ malloc( sizeof(FT_Long)* export_font.header.noffset );
+ else
+ export_font.offset =
+ malloc( sizeof(unsigned short)* export_font.header.noffset );
+
+ export_font.width =
+ malloc( sizeof(unsigned char) * export_font.header.nwidth );
+ export_font.chars_data =
+ malloc( sizeof(unsigned char) * export_font.header.nbits );
+
+ /* for now we use the full height for each character */
+ h = export_font.header.height;
+
+ index = 0;
+ int done = 0;
+ char char_name[1024];
+ int converted_char_count = 0;
+ int failed_char_count = 0;
+
+ for( code = firstchar; code <= lastchar; code++ )
+ {
+ /* Get gylph index from the char and render it */
+ charindex = getcharindex( face, code);
+ if ( !charindex )
+ {
+ if ( use_long_offset )
+ export_font.offset_long[code - firstchar] = export_font.offset_long[0];
+ else
+ export_font.offset[code - firstchar] = export_font.offset[0];
+ export_font.width[code - firstchar] = export_font.width[0];
+ continue;
+ }
+
+ error = FT_Load_Glyph( face, charindex ,
+ (FT_LOAD_RENDER | FT_LOAD_NO_BITMAP) );
+ if ( error ) {
+ continue;
+ }
+ if FT_HAS_GLYPH_NAMES( face )
+ FT_Get_Glyph_Name( face, charindex, char_name, 16);
+ else
+ char_name[0] = '\0';
+
+ FT_GlyphSlot slot = face->glyph;
+ FT_Bitmap* source = &slot->bitmap;
+ //print_raw_glyph( face );
+ w = glyph_width( face );
+ if (w == 0) continue;
+ empty_first_col = empty_last_col = 0;
+
+ if(trimming)
+ trim_glyph( face->glyph, &empty_first_col, &empty_last_col, &w );
+
+ if ( use_long_offset )
+ export_font.offset_long[code - firstchar] = index;
+ else
+ export_font.offset[code - firstchar] = index;
+
+ export_font.width[code - firstchar] = w;
+
+ /* copy the glyph bitmap to a full sized glyph bitmap */
+ unsigned char* src = source->buffer;
+ unsigned char* tmpbuf = malloc(sizeof(unsigned char) * w * h);
+ memset(tmpbuf, 0xff, w*h);
+ int start_y = export_font.header.ascent - slot->bitmap_top;
+
+ int glyph_height = source->rows;
+ int stride = source->pitch;
+ unsigned char* buf = tmpbuf;
+ unsigned char* endbuf = tmpbuf + w*h;
+
+ int error = 0;
+ /* insert empty pixels on the left */
+ int col_off = w - stride;
+ if (col_off > 1) col_off /= 2;
+ if (col_off < 0) col_off = 0;
+
+ for(row=0; row < glyph_height; row++)
+ {
+ if(row+start_y < 0 || row+start_y >= h)
+ continue;
+ for(col = empty_first_col; col < stride; col++)
+ {
+ unsigned char *tsrc, *dst;
+ dst = buf + (w*(start_y+row)) + col + col_off;
+ tsrc = src + stride*row + col;
+ if (dst < endbuf && dst >= tmpbuf)
+ *dst = 0xff - *tsrc;
+ else {
+ error = 1;
+ printf("Error! row: %3d col: %3d\n", row, col);
+ }
+ }
+ }
+ if(error) print_raw_glyph(face);
+
+ buf = tmpbuf;
+ int numbits;
+ unsigned int field;
+ field = 0;
+ numbits = pixel_per_byte;
+
+ for(row=0; row < h; row++)
+ {
+ for(col=0; col < w; col++)
+ {
+ unsigned int src = *buf++;
+ unsigned int cur_col = (src + 8) / 17;
+ field |= (cur_col << (bit_shift*(pixel_per_byte-numbits)));
+
+ if (--numbits == 0)
+ {
+ export_font.chars_data[index++] = (unsigned char)field;
+ numbits = pixel_per_byte;
+ field = 0;
+ }
+ }
+ }
+
+ /* Pad last byte */
+ if (numbits != pixel_per_byte)
+ {
+ export_font.chars_data[index++] = (unsigned char)field;
+ }
+
+ if( dump_glyphs )
+ {
+ /* debug: dump char */
+ printf("\n---Converted Glyph Dump---\n");
+ unsigned char bit_max = (1 << bit_shift) - 1;
+ if ( code > 32 && code < 255 ) {
+ row = h;
+ if(use_long_offset)
+ buf = &(export_font.chars_data[export_font.offset_long[
+ code - firstchar]]);
+ else
+ buf = &(export_font.chars_data[export_font.offset[
+ code - firstchar]]);
+ unsigned char current_data;
+ unsigned char font_bits;
+ numbits = pixel_per_byte;
+ current_data = *buf;
+ do
+ {
+ col = w;
+ printf("-");
+ do
+ {
+ font_bits = current_data & bit_max;
+ if (font_bits==bit_max)
+ printf(" ");
+ else
+ {
+ if(font_bits > bit_max/2)
+ printf(".");
+ else
+ printf("@");
+ }
+ if (--numbits == 0)
+ {
+ current_data = *(++buf);
+ numbits = pixel_per_byte;
+ }
+ else
+ {
+ current_data >>= bit_shift;
+ }
+ } while (--col);
+ printf("-\n");
+ } while (--row);
+ }
+ buf = NULL;
+ printf("---End Glyph Dump---\n");
+ }
+
+ free(tmpbuf);
+ converted_char_count++;
+ done = (100*(converted_char_count))/char_count;
+ printf("Converted %s %d (%d%%)\e[K\r",
+ char_name,converted_char_count,done); fflush(stdout);
+ }
+
+ FILE *file = fopen(destfile, "w");
+ printf("Writing %s\n", destfile);
+
+ /* font info */
+ writestr(file, VERSION, 4);
+ writeshort(file, export_font.header.maxwidth);
+ writeshort(file, export_font.header.height);
+ writeshort(file, export_font.header.ascent);
+ writeshort(file, export_font.header.depth);
+ writeint(file, export_font.header.firstchar);
+ writeint(file, export_font.header.defaultchar);
+ writeint(file, export_font.header.size);
+ writeint(file, export_font.header.nbits);
+ writeint(file, export_font.header.noffset);
+ writeint(file, export_font.header.nwidth);
+
+ fwrite( (char*)export_font.chars_data, 1,
+ export_font.header.nbits, file);
+ free(export_font.chars_data);
+
+ int skip,i;
+ char pad[] = {0,0,0,0};
+ if ( use_long_offset )
+ {
+ skip = ((export_font.header.nbits + 3) & ~3) -
+ export_font.header.nbits;
+ fwrite(pad, 1, skip, file); /* pad */
+ for(i = 0; i < export_font.header.noffset; i++)
+ writeint(file, export_font.offset_long[i]);
+ }
+ else
+ {
+ skip = ((export_font.header.nbits + 1) & ~1) -
+ export_font.header.nbits;
+ fwrite(pad, 1, skip, file); /* pad */
+ for(i = 0; i < export_font.header.noffset; i++)
+ writeshort(file, export_font.offset[i]);
+ }
+
+ for(i = 0; i < export_font.header.nwidth; i++)
+ writebyte(file, export_font.width[i]);
+ free(export_font.width);
+
+ if ( use_long_offset )
+ free(export_font.offset_long);
+ else
+ free(export_font.offset);
+
+ fclose(file);
+ FT_Done_Face( face );
+ FT_Done_FreeType( library );
+ printf("done (converted %d glyphs, %d errors).\e[K\n\n",
+ converted_char_count, failed_char_count);
+
+}
+
+void convttc(char* path)
+{
+ struct ttc_table ttcname;
+ FT_Long i;
+
+ get_ttc_table(path, &ttcname);
+
+ if (ttcname.ttc_count == 0)
+ {
+ printf("This file is a not true type font.\n");
+ return;
+ }
+
+ /* default */
+ if (!flg_all_ttc && ttc_index == -1)
+ {
+ if (!oflag)
+ { /* generate filename */
+ snprintf(outfile, sizeof(outfile),
+ "%d-%s.fnt", pixel_size, basename(path));
+ }
+ convttf(path, outfile, (FT_Long) 0);
+ }
+
+ /* set face_index of ttc */
+ else if (!flg_all_ttc)
+ {
+ print_ttc_table(path);
+ if ( !oflag )
+ {
+ if (ttc_index >= 0 &&
+ ttc_index < ttcname.ttc_count)
+ {
+ if (strcmp(ttcname.ttf_name[ttc_index], "") != 0)
+ {
+ snprintf(outfile, sizeof(outfile), "%d-%s.fnt",
+ pixel_size, ttcname.ttf_name[ttc_index]);
+ }
+ else
+ {
+ snprintf(outfile, sizeof(outfile), "%d-%s-%ld.fnt",
+ pixel_size, basename(path), ttc_index);
+ }
+ }
+ else
+ {
+ printf("illegal face index of ttc.\n");
+ }
+ }
+ convttf(path, outfile, ttc_index);
+ }
+ else { /* convert all fonts */
+ print_ttc_table(path);
+ for(i = 0; i < ttcname.ttc_count; i++)
+ {
+ snprintf(outfile, sizeof(outfile), "%d-%s.fnt",
+ pixel_size, ttcname.ttf_name[i]);
+ convttf(path, outfile, i);
+ }
+ }
+
+ for(i = 0; i < ttcname.ttc_count; i++)
+ {
+ free(ttcname.ttf_name[i]);
+ }
+ free(ttcname.ttf_name);
+}
+
+
+
+/* parse command line options*/
+void getopts(int *pac, char ***pav)
+{
+ char *p;
+ char **av;
+ int ac;
+ ac = *pac;
+ av = *pav;
+
+ limit_char = max_char;
+ start_char = 0;
+
+ while (ac > 0 && av[0][0] == '-') {
+ p = &av[0][1];
+ while( *p)
+ switch(*p++) {
+ case 'h':case 'H':
+ usage();
+ break;
+ case ' ': /* multiple -args on av[]*/
+ while( *p && *p == ' ')
+ p++;
+ if( *p++ != '-') /* next option must have dash*/
+ p = "";
+ break; /* proceed to next option*/
+ case 'o': /* set output file*/
+ oflag = 1;
+ if (*p) {
+ strcpy(outfile, p);
+ while (*p && *p != ' ')
+ p++;
+ }
+ else {
+ av++; ac--;
+ if (ac > 0)
+ strcpy(outfile, av[0]);
+ }
+ break;
+ case 'l': /* set encoding limit*/
+ if (*p) {
+ limit_char = atoi(p);
+ while (*p && *p != ' ')
+ p++;
+ }
+ else {
+ av++; ac--;
+ if (ac > 0)
+ limit_char = atoi(av[0]);
+ }
+ break;
+ case 's': /* set encoding start*/
+ if (*p) {
+ start_char = atol(p);
+ while (*p && *p != ' ')
+ p++;
+ }
+ else {
+ av++; ac--;
+ if (ac > 0)
+ start_char = atol(av[0]);
+ }
+ break;
+ case 'p': /* set pixel size*/
+ if (*p) {
+ pixel_size = atoi(p);
+ while (*p && *p != ' ')
+ p++;
+ }
+ else {
+ av++; ac--;
+ if (ac > 0)
+ pixel_size = atoi(av[0]);
+ }
+ break;
+ case 'c': /* set spaece between characters */
+ {
+ if (*p) {
+ between_chr = atof(p);
+ while (*p && *p != ' ')
+ p++;
+ }
+ else {
+ av++; ac--;
+ if (ac > 0)
+ between_chr = atof(av[0]);
+ }
+ break;
+ }
+ case 'd':
+ dump_glyphs = 1;
+ while (*p && *p != ' ')
+ p++;
+ break;
+ case 'x':
+ trimming = 1;
+ while (*p && *p != ' ')
+ p++;
+ break;
+ case 'X':
+ if (*p) {
+ hv_resolution = atoi(p);
+ while (*p && *p != ' ')
+ p++;
+ }
+ else {
+ av++; ac--;
+ if (ac > 0)
+ hv_resolution = atoi(av[0]);
+ }
+ break;
+ case 'r':
+ if (*p) {
+ between_row = atof(p);
+ while (*p && *p != ' ')
+ p++;
+ }
+ else {
+ av++; ac--;
+ if (ac > 0)
+ between_row = atof(av[0]);
+ }
+ break;
+ case 'T':
+ if(*p == 'A') {
+ if(*(++p)) {
+ trim_ap = atoi(p);
+ while (*p && *p != ' ')
+ p++;
+ }
+ else {
+ av++; ac--;
+ if (ac > 0)
+ trim_ap = atoi(av[0]);
+ }
+ break;
+ }
+ if(*p == 'D') {
+ if(*(++p)) {
+ trim_dp = atoi(p);
+ while (*p && *p != ' ')
+ p++;
+ }
+ else {
+ av++; ac--;
+ if (ac > 0)
+ trim_dp = atoi(av[0]);
+ }
+ break;
+ }
+ if(*p == 'a') {
+ if(*(++p)) {
+ trim_aa = atoi(p);
+ while (*p && *p != ' ')
+ p++;
+ }
+ else {
+ av++; ac--;
+ if (ac > 0)
+ trim_aa = atoi(av[0]);
+ }
+ break;
+ }
+ if(*p == 'd') {
+ if(*(++p)) {
+ trim_da = atoi(p);
+
+ }
+ else {
+ av++; ac--;
+ if (ac > 0)
+ trim_da = atoi(av[0]);
+ }
+ break;
+ }
+ fprintf(stderr, "Unknown option ignored: %s\n", p-1);
+ while (*p && *p != ' ')
+ p++;
+ break;
+ case 't': /* display ttc table */
+ if (*p == 't') {
+ pct = 1;
+ while (*p && *p != ' ')
+ p++;
+ }
+
+ else if (*p == 'a') {
+ flg_all_ttc = 1;
+ while (*p && *p != ' ')
+ p++;
+ }
+
+ else if (*p) {
+ ttc_index = atoi(p);
+ while (*p && *p != ' ')
+ p++;
+ }
+ else {
+ av++; ac--;
+ if (ac > 0)
+ ttc_index = atoi(av[0]);
+ }
+ break;
+
+ default:
+ fprintf(stderr, "Unknown option ignored: %s\n", p-1);
+ while (*p && *p != ' ')
+ p++;
+ }
+ ++av; --ac;
+ }
+ *pac = ac;
+ *pav = av;
+}
+
+
+int main(int ac, char **av)
+{
+ int ret = 0;
+
+ ++av; --ac; /* skip av[0]*/
+
+ getopts(&ac, &av); /* read command line options*/
+
+ if (ac < 1)
+ {
+ usage();
+ }
+ if (oflag)
+ {
+ if (ac > 1)
+ {
+ usage();
+ }
+ }
+
+ if (limit_char < start_char)
+ {
+ usage();
+ exit(0);
+ }
+
+ while (pct && ac > 0)
+ {
+ print_ttc_table(av[0]);
+ ++av; --ac;
+ exit(0);
+ }
+
+ while (ac > 0)
+ {
+ convttc(av[0]);
+ ++av; --ac;
+ }
+
+ exit(ret);
+}
+
+
+
+/*
+ * Trie node structure.
+ */
+typedef struct {
+ unsigned short key; /* Key value. */
+ unsigned short val; /* Data for the key. */
+ unsigned long sibs; /* Offset of siblings from trie beginning. */
+ unsigned long kids; /* Offset of children from trie beginning. */
+} node_t;
+
+/*
+ * The trie used for remapping codes.
+ */
+static node_t *nodes;
+static unsigned long nodes_used = 0;
+
+int
+otf2bdf_remap(unsigned short *code)
+{
+ unsigned long i, n, t;
+ unsigned short c, codes[2];
+
+ /*
+ * If no mapping table was loaded, then simply return the code.
+ */
+ if (nodes_used == 0)
+ return 1;
+
+ c = *code;
+ codes[0] = (c >> 8) & 0xff;
+ codes[1] = c & 0xff;
+
+ for (i = n = 0; i < 2; i++) {
+ t = nodes[n].kids;
+ if (t == 0)
+ return 0;
+ for (; nodes[t].sibs && nodes[t].key != codes[i]; t = nodes[t].sibs);
+ if (nodes[t].key != codes[i])
+ return 0;
+ n = t;
+ }
+
+ *code = nodes[n].val;
+ return 1;
+}
diff --git a/tools/root.make b/tools/root.make
index 85a996fc62..20b11ae1fb 100644
--- a/tools/root.make
+++ b/tools/root.make
@@ -21,7 +21,7 @@ ASMFLAGS = -D__ASSEMBLER__ # work around gcc 3.4.x bug with -std=gnu99, onl
TOOLS = $(TOOLSDIR)/rdf2binary $(TOOLSDIR)/convbdf \
$(TOOLSDIR)/codepages $(TOOLSDIR)/scramble $(TOOLSDIR)/bmp2rb \
$(TOOLSDIR)/uclpack $(TOOLSDIR)/mkboot $(TOOLSDIR)/iaudio_bl_flash.c \
- $(TOOLSDIR)/iaudio_bl_flash.h
+ $(TOOLSDIR)/iaudio_bl_flash.h $(TOOLSDIR)/convttf
ifeq (,$(PREFIX))
diff --git a/tools/tools.make b/tools/tools.make
index 64a47c53de..c143157dab 100644
--- a/tools/tools.make
+++ b/tools/tools.make
@@ -33,6 +33,11 @@ $(TOOLSDIR)/uclpack: $(TOOLSDIR)/ucl/uclpack.c $(wildcard $(TOOLSDIR)/ucl/src/*.
$(call PRINTS,CC $(@F))$(HOSTCC) $(TOOLSCFLAGS) -I$(TOOLSDIR)/ucl \
-I$(TOOLSDIR)/ucl/include -o $@ $^
+$(TOOLSDIR)/convttf: $(TOOLSDIR)/convttf.c
+ $(call PRINTS,CC $(@F))
+ $(SILENT)$(HOSTCC) $(TOOLSFLAGS) -lm -O2 -Wall -g $+ -o $@ \
+ `freetype-config --libs` `freetype-config --cflags`
+
# implicit rule for simple tools
$(TOOLSDIR)/%: $(TOOLSDIR)/%.c
$(call PRINTS,CC $(subst $(ROOTDIR)/,,$@))