From 1aef871541c7018a332a5544ee9698398fc994a6 Mon Sep 17 00:00:00 2001 From: arpi Date: Mon, 13 Aug 2001 18:37:10 +0000 Subject: upgraded to 1.0b version by Artur Zaprzala git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@1506 b3059339-0415-0410-9bf9-f77b7e298cf2 --- TOOLS/subfont-c/Makefile | 22 +- TOOLS/subfont-c/README | 81 +++-- TOOLS/subfont-c/encodings/charmap2enc | 11 + TOOLS/subfont-c/encodings/osd-mplayer | 15 + TOOLS/subfont-c/encodings/runme-kr | 1 + TOOLS/subfont-c/osd/README | 3 + TOOLS/subfont-c/osd/gen.py | 441 +++++++++++++++++++++++ TOOLS/subfont-c/osd/osd.t1a | 589 ++++++++++++++++++++++++++++++ TOOLS/subfont-c/osd/runme | 5 + TOOLS/subfont-c/runme | 24 ++ TOOLS/subfont-c/subfont.c | 659 ++++++++++++++++++++++------------ 11 files changed, 1579 insertions(+), 272 deletions(-) create mode 100755 TOOLS/subfont-c/encodings/charmap2enc create mode 100644 TOOLS/subfont-c/encodings/osd-mplayer create mode 100755 TOOLS/subfont-c/encodings/runme-kr create mode 100644 TOOLS/subfont-c/osd/README create mode 100755 TOOLS/subfont-c/osd/gen.py create mode 100644 TOOLS/subfont-c/osd/osd.t1a create mode 100755 TOOLS/subfont-c/osd/runme create mode 100755 TOOLS/subfont-c/runme (limited to 'TOOLS/subfont-c') diff --git a/TOOLS/subfont-c/Makefile b/TOOLS/subfont-c/Makefile index 10e9e26879..23d35a07d4 100644 --- a/TOOLS/subfont-c/Makefile +++ b/TOOLS/subfont-c/Makefile @@ -1,24 +1,18 @@ -#font="/mnt/win/windows/fonts/arial.ttf" -#font="/mnt/win/windows/fonts/comic.ttf" -#font="/mnt/win/windows/fonts/verdanai.ttf" -font="/mnt/win/windows/fonts/verdana.ttf" - -#encoding=windows-1250 -encoding=iso-8859-2 - -fontsize=20 include ../../config.mak LDLIBS=-lm $(shell freetype-config --libs) CFLAGS=$(OPTFLAGS) $(shell freetype-config --cflags) +#CFLAGS+=-DOLD_FREETYPE2 +#CFLAGS+=-g +#CFLAGS+=-DDEBUG + + subfont: subfont.o -run: subfont - ./subfont $(encoding) $(fontsize) $(font) - cat font.desc.tail >> font.desc - cp font.desc *.raw ~/.mplayer/font/ +subfont.S: subfont.c + $(CC) $(CFLAGS) -S $^ -o $@ clean: - rm -f subfont subfont.o + rm -f subfont subfont.o core diff --git a/TOOLS/subfont-c/README b/TOOLS/subfont-c/README index b80eb900f4..5989787d1a 100644 --- a/TOOLS/subfont-c/README +++ b/TOOLS/subfont-c/README @@ -1,41 +1,62 @@ +Usage: +~~~~~~ +1. Make sure you have FreeType 2 installed. +2. Get a TrueType or Type 1 font. +3. Modify `runme' script for your encoding and font path. +4. Type: ./runme +5. Copy *.raw and font.desc files to ~/.mplayer/font/ +6. Run subfont alone to see more options. + + About: ~~~~~~ -`subfont' program renders antialiased fonts for mplayer using freetype library. -Should work with TrueType, Type1 and any other font supported by libfreetype. +`subfont' program renders antialiased OSD and subtitle fonts for mplayer. -Goals: - - internationalization: supports any 8 bit encoding (uses iconv). - - nice look: creates glyph `shadows' using algorithm derived from gaussian blur (slow!). +What you get are bitmap and alpha *.raw files and a font.desc. +What you need is TrueType, Type 1 or any other font supported by FreeType. +Alpha channel is created using outline and Gaussian blur filters. -Note: -~~~~~ -Starting x position of each char and the bitmap width is aligned to multiple of 8 -(required for under-development MMX renderer). +ANY encoding is now supported! That is, all 8-bit encodings known by libc +and user-supplied encodings (also multibyte) through custom encoding files. +I prepared also Type 1 font `osd.pfb' for OSD characters based on bitmaps +created by chass. -Usage: +Subfont was tested with Korean fonts from truetype-fonts-ko-2.0-1k.noarch.rpm +I found on http://rpmfind.net/ and euc-kr encoding. Custom encoding file +for euc-kr was generated from charmap I found in /usr/share/i18n/charmaps/EUC-KR.gz +(glibc package). This should work with -unicode switch for mplayer +(though it is not Unicode encoding). +It took about 14 seconds to render over 8000 characters on P3 @ 600MHz. + + +Custom encodings: +~~~~~~~~~~~~~~~~~ +For each character you want to render write the line consisting of: + hexadecimal Unicode character code, + followed by whitespace, + followed by hexadecimal number representing your encoding, + followed by new line character. + +Example: to render a single letter `aogonek' (Unicode 0x0105) and encode +it using iso-8859-2 encoding (0xB1), your custom encoding file will consist +of a sigle line: +0105 B1 + + +Notes: ~~~~~~ -Usage: subfont encoding ppem font [alphaFactor [minAlpha [radius]]] - Program creates 3 files: font.desc, -a.raw, -b.raw. - You should append font.desc.tail (desc for OSD characters by a'rpi & chass) to font.desc, - and copy font.desc and all *.raw files to ~/.mplayer/font/ directory. - - encoding must be 8 bit encoding, like iso-8859-2. - To list encodings available on your system use iconv -l. - ppem Font size in pixels (e.g. 24). - font Font file path. Any format supported by freetype library (*.ttf, *.pf?, *). - alphaFactor Alpha map scaling factor (default is 1.0), float. - minAlpha Alpha map minimum value (default is 1.0, max is 255), float. - radius Alpha map blur radius (default is 6 pixels), integer. - - -Example: -~~~~~~~~ -make -./subfont iso-8859-2 20 verdana.ttf -cat font.desc.tail >> font.desc -cp font.desc *.raw ~/.mplayer/font/ + + Starting x position of each character and the bitmap width is aligned +to multiple of 8 (required by mplayer). + + + Currently subfont won't work on big-endian systems. + + + My development platform is RedHat 7.1. FreeType versions tested are +2.0.1 through 2.0.4. + + + FreeType library has a bug that makes subfont display some warning message +about Unicode charmap for osd.pfb. Author: diff --git a/TOOLS/subfont-c/encodings/charmap2enc b/TOOLS/subfont-c/encodings/charmap2enc new file mode 100755 index 0000000000..e32d7a463b --- /dev/null +++ b/TOOLS/subfont-c/encodings/charmap2enc @@ -0,0 +1,11 @@ +#!/usr/bin/awk -f +# only for mostly 2-byte encodings like euc-kr + +$2~"^/x..$" { + c = substr($2, 3, 2) + if (c<"80") + print substr($1, 3, 4) "\t" c +} +$2~"^/x../x..$" { + print substr($1, 3, 4) "\t" substr($2, 3, 2) substr($2, 7, 2) +} diff --git a/TOOLS/subfont-c/encodings/osd-mplayer b/TOOLS/subfont-c/encodings/osd-mplayer new file mode 100644 index 0000000000..26ab043016 --- /dev/null +++ b/TOOLS/subfont-c/encodings/osd-mplayer @@ -0,0 +1,15 @@ +E001 01 +E002 02 +E003 03 +E004 04 +E005 05 +E006 06 +E007 07 +E008 08 +E009 09 +E00A 0A +E00B 0B +E010 10 +E011 11 +E012 12 +E013 13 diff --git a/TOOLS/subfont-c/encodings/runme-kr b/TOOLS/subfont-c/encodings/runme-kr new file mode 100755 index 0000000000..df4e81e15c --- /dev/null +++ b/TOOLS/subfont-c/encodings/runme-kr @@ -0,0 +1 @@ +gunzip -c /usr/share/i18n/charmaps/EUC-KR.gz | ./charmap2enc > euc-kr diff --git a/TOOLS/subfont-c/osd/README b/TOOLS/subfont-c/osd/README new file mode 100644 index 0000000000..9dec5e5971 --- /dev/null +++ b/TOOLS/subfont-c/osd/README @@ -0,0 +1,3 @@ +Requires t1utils and python. + +Based on font created by chass. diff --git a/TOOLS/subfont-c/osd/gen.py b/TOOLS/subfont-c/osd/gen.py new file mode 100755 index 0000000000..bf08fb8838 --- /dev/null +++ b/TOOLS/subfont-c/osd/gen.py @@ -0,0 +1,441 @@ +#!/usr/bin/python + +from math import * +import sys +import string + +k = (sqrt(2.)-1.)*4./3. + +chars = [] +encoding = [] +count = 1 +first = 1 + +def append(s): + chars.append(s) + +def rint(x): + return int(round(x)) +""" + if x>=0: + return int(x+0.5) + else: + return int(x-0.5) +""" + +class vec: + def __init__(self, x, y=0): + if type(x) is type(()): + self.x, self.y = x + else: + self.x = x + self.y = y + def set(self, x, y): + self.__init__(x, y) + def move(self, x, y): + self.x = self.x + x + self.y = self.y + y + def __add__(self, v): + return vec(self.x+v.x, self.y+v.y) + def __sub__(self, v): + return vec(self.x-v.x, self.y-v.y) + def int(self): + return vec(rint(self.x), rint(self.y)) + def t(self): + return (self.x, self.y) + +class pvec(vec): + def __init__(self, l, a): + self.x = l * cos(a) + self.y = l * sin(a) + + +pen = vec(0,0) + +def moveto(x, y=0): + global first + dx = rint(x-pen.x) + dy = rint(y-pen.y) + if dx!=0: + if dy!=0: + append("\t%i %i rmoveto" % (dx, dy)) + else: + append("\t%i hmoveto" % (dx)) + elif dy!=0: + append("\t%i vmoveto" % (dy)) + elif first: + append("\t0 hmoveto") + first = 0 + pen.x = pen.x+dx + pen.y = pen.y+dx + +def rlineto(v): + if v.x!=0: + if v.y!=0: + append("\t%i %i rlineto" % (v.x, v.y)) + else: + append("\t%i hlineto" % (v.x)) + elif v.y!=0: + append("\t%i vlineto" % (v.y)) + +def closepath(): + append("\tclosepath") + +history = [] +def movebase(x, y=0): + history.append((x,y)) + pen.move(-x, -y) + +def moveback(): + x, y = history.pop() + pen.move(x, y) + +def ellipse(rx, ry = None, half=0): + # rx>0 => counter-clockwise (filled) + # rx<0 => clockwise + + if ry==None: ry = abs(rx) + + dx1 = rint(k*rx) + dx2 = rx-dx1 + + dy1 = rint(k*ry) + dy2 = ry-dy1 + + rx = abs(rx) + moveto(0, -ry) + append("\t%i 0 %i %i 0 %i rrcurveto" % (+dx1, +dx2, +dy2, +dy1)) + append("\t0 %i %i %i %i 0 rrcurveto" % (+dy1, -dx2, +dy2, -dx1)) + if not half: + append("\t%i 0 %i %i 0 %i rrcurveto" % (-dx1, -dx2, -dy2, -dy1)) + append("\t0 %i %i %i %i 0 rrcurveto" % (-dy1, +dx2, -dy2, +dx1)) + closepath() + if half: + pen.set(0, ry) + else: + pen.set(0, -ry) + +circle = ellipse + +def rect(w, h): + moveto(0, 0) + if w>0: + append("\t%i hlineto" % (w)) + append("\t%i vlineto" % (h)) + append("\t%i hlineto" % (-w)) + pen.set(0, h) + else: + append("\t%i vlineto" % (h)) + append("\t%i hlineto" % (-w)) + append("\t%i vlineto" % (-h)) + pen.set(-w, 0) + closepath() + +def poly(p): + moveto(0, 0) + prev = vec(0, 0) + for q in p: + rlineto(vec(q)-prev) + prev = vec(q) + closepath() + pen.set(prev.x, prev.y) + +def line(w, l, a): + vw = pvec(w*.5, a-pi*.5) + vl = pvec(l, a) + p = vw + moveto(p.x, p.y) + p0 = p + #print '%%wla %i %i %.3f: %.3f %.3f' % (w, l, a, p0.x, p0.y) + p = p+vl + rlineto((p-p0).int()) + p0 = p + #print '%%wla %i %i %.3f: %.3f %.3f' % (w, l, a, p0.x, p0.y) + p = p-vw-vw + rlineto((p-p0).int()) + p0 = p + #print '%%wla %i %i %.3f: %.3f %.3f' % (w, l, a, p0.x, p0.y) + p = p-vl + #print '%%wla %i %i %.3f: %.3f %.3f' % (w, l, a, p.x, p.y) + rlineto((p-p0).int()) + closepath() + pen.set(p.x, p.y) + + +def begin(name, code, hsb, w): + global first, count, history + history = [] + pen.set(0, 0) + append("""\ +/uni%04X { %% %s + %i %i hsbw""" % (code+0xE000, name, hsb, w)) + i = len(encoding) + while i osd.t1a && +t1asm --pfb osd.t1a osd.pfb && +ftview 80 osd.pfb &> /dev/null & +#../subfont iso-8859-2 25 osd.pfb diff --git a/TOOLS/subfont-c/runme b/TOOLS/subfont-c/runme new file mode 100755 index 0000000000..484230993c --- /dev/null +++ b/TOOLS/subfont-c/runme @@ -0,0 +1,24 @@ +#!/bin/bash + +font=arial.ttf +encoding=iso-8859-2 +fontsize=24 +symbolssize=35 +blur=2 +outline=1.5 + +make || exit + +./subfont --blur $blur --outline $outline "$encoding" $fontsize "$font" &>log || exit +cat log +./subfont --append --blur $blur --outline $outline encodings/osd-mplayer $symbolssize osd/osd.pfb + +#cp font.desc *.raw ~/.mplayer/font/ + +exit + +SIZE=`awk '/^bitmap size/ {print $NF}' log`+800 +display -size $SIZE gray:$encoding-a.raw & +display -size $SIZE gray:$encoding-b.raw & +#convert -size $SIZE gray:$encoding-a.raw $encoding-a.png +#convert -size $SIZE gray:$encoding-b.raw $encoding-b.png diff --git a/TOOLS/subfont-c/subfont.c b/TOOLS/subfont-c/subfont.c index b72040776d..ba572273da 100644 --- a/TOOLS/subfont-c/subfont.c +++ b/TOOLS/subfont-c/subfont.c @@ -16,53 +16,72 @@ #include #include #include +#include + + +#ifndef OLD_FREETYPE2 -#if 0 /* freetype 2.0.1 */ -#include -#else /* freetype 2.0.3 */ #include #include FT_FREETYPE_H -#endif - #include FT_GLYPH_H +#else /* freetype 2.0.1 */ +#include +#include -#define f266toInt(x) (((x)+32)>>6) /* round fractional fixed point number to integer */ - /* coordinates are in 26.6 pixels (i.e. 1/64th of pixels) */ +#endif +#ifndef DEBUG +#define DEBUG 0 +#endif -int const test = 1; -/* default values */ +//// default values char *encoding = "iso-8859-1"; /* target encoding */ -/* gcc 2.1.3 doesn't support ucs-4le, but supports ucs-4 (==ucs-4be) */ -char *charmap = "ucs-4"; /* ucs-4le font charmap encoding */ -int ppem = 20; /* font size in pixels */ +char *charmap = "ucs-4"; /* font charmap encoding, I hope ucs-4 is always big endian */ + /* gcc 2.1.3 doesn't support ucs-4le, but supports ucs-4 (==ucs-4be) */ +int ppem = 22; /* font size in pixels */ + +double radius = 2; /* blur radius */ +double thickness = 1.5; /* outline thickness */ +int padding; + +char* font_desc = "font.desc"; +//char* font_desc = "/dev/stdout"; +//// constants int const colors = 256; int const maxcolor = 255; -int radius = 2; /* blur radius */ -double minalpha = 1.0; /* good value for minalpha is 0.5 */ -double alpha_factor = 1.0; - -int const first_char = 33; -int const charset_size = 256; +unsigned const base = 256; +unsigned const first_char = 33; +#define max_charset_size 60000 +//int const max_charset_size = 256; +unsigned charset_size = 0; +//// char *command; -char *font_path = NULL; -/*char *font_metrics = NULL;*/ - +char *font_path; +//char *font_metrics; +int append_mode = 0; -unsigned char *buffer; -unsigned char *ebuffer; // temporary buffer for alphamap creation (edges) -unsigned char *abuffer; +unsigned char *buffer, *abuffer; int width, height; -static FT_ULong ustring[256]; +static FT_ULong charset[max_charset_size]; /* characters we want to render; Unicode */ +static FT_ULong charcodes[max_charset_size]; /* character codes in 'encoding' */ +iconv_t cd; // iconv conversion descriptor + + #define eprintf(...) fprintf(stderr, __VA_ARGS__) -#define ERROR(msg, ...) (eprintf("%s: error: " msg "\n", command, ##__VA_ARGS__), exit(1)) -#define WARNING(msg, ...) eprintf("%s: warning: " msg "\n", command, ##__VA_ARGS__) +#define ERROR_(msg, ...) (eprintf("%s: error: " msg "\n", command, __VA_ARGS__), exit(1)) +#define WARNING_(msg, ...) eprintf("%s: warning: " msg "\n", command, __VA_ARGS__) +#define ERROR(...) ERROR_(__VA_ARGS__, NULL) +#define WARNING(...) WARNING_(__VA_ARGS__, NULL) + +#define f266toInt(x) (((x)+32)>>6) // round fractional fixed point number to integer + // coordinates are in 26.6 pixels (i.e. 1/64th of pixels) +#define ALIGN(x) (((x)+7)&~7) // 8 byte align @@ -80,6 +99,7 @@ void paste_bitmap(FT_Bitmap *bitmap, int x, int y) { buffer[drow+dp] = bitmap->buffer[srow+sp]; } + void write_header(FILE *f) { static unsigned char header[800] = "mhwanh"; int i; @@ -91,6 +111,7 @@ void write_header(FILE *f) { fwrite(header, 1, 800, f); } + void write_bitmap() { FILE *f; int const max_name = 128; @@ -98,38 +119,40 @@ void write_bitmap() { snprintf(name, max_name, "%s-b.raw", encoding); f = fopen(name, "wb"); - if (f==NULL) ERROR("fopen failed.",NULL); + if (f==NULL) ERROR("fopen failed."); write_header(f); fwrite(buffer, 1, width*height, f); fclose(f); snprintf(name, max_name, "%s-a.raw", encoding); f = fopen(name, "wb"); - if (f==NULL) ERROR("fopen failed.",NULL); + if (f==NULL) ERROR("fopen failed."); write_header(f); fwrite(abuffer, 1, width*height, f); fclose(f); } + void render() { FT_Library library; FT_Face face; FT_Error error; FT_GlyphSlot slot; - FT_ULong glyph_index; - FT_Glyph glyphs[charset_size]; + FT_ULong glyph_index, character, code; + //FT_Glyph glyphs[max_charset_size]; + FT_Glyph glyph; FILE *f; int const load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; int pen_x, pen_xa, pen_y, ymin, ymax; - int i, c; + int i, uni_charmap = 1; int baseline, space_advance = 20; /* initialize freetype */ error = FT_Init_FreeType(&library); - if (error) ERROR("Init_FreeType failed.",NULL); + if (error) ERROR("Init_FreeType failed."); error = FT_New_Face(library, font_path, 0, &face); - if (error) ERROR("New_Face failed.",NULL); + if (error) ERROR("New_Face failed."); /* if (font_metrics) { @@ -139,8 +162,39 @@ void render() { */ - if (face->charmap->encoding!=ft_encoding_unicode) - WARNING("Selected font has no unicode charmap. Very bad!",NULL); +#if 0 + /************************************************************/ + eprintf("Font encodings:\n"); + for (i = 0; inum_charmaps; ++i) + eprintf("'%.4s'\n", (char*)&face->charmaps[i]->encoding); + + //error = FT_Select_Charmap(face, ft_encoding_unicode); + //error = FT_Select_Charmap(face, ft_encoding_adobe_standard); + //error = FT_Select_Charmap(face, ft_encoding_adobe_custom); + //error = FT_Set_Charmap(face, face->charmaps[1]); + //if (error) WARNING("Select_Charmap failed."); +#endif +#if 0 + /************************************************************/ + if (FT_HAS_GLYPH_NAMES(face)) { + int const max_gname = 128; + char gname[max_gname]; + for (i = 0; inum_glyphs; ++i) { + FT_Get_Glyph_Name(face, i, gname, max_gname); + eprintf("%02x `%s'\n", i, gname); + } + + } +#endif + + + if (face->charmap==NULL || face->charmap->encoding!=ft_encoding_unicode) { + WARNING("Unicode charmap not available for this font. Very bad!"); + uni_charmap = 0; + error = FT_Set_Charmap(face, face->charmaps[0]); + if (error) WARNING("No charmaps! Strange."); + } + /* set size */ @@ -156,38 +210,46 @@ void render() { jppem = face->available_sizes[i].height; } } - WARNING("Selected font is not scalable. Using ppem=%i", face->available_sizes[j].height); + WARNING("Selected font is not scalable. Using ppem=%i.", face->available_sizes[j].height); error = FT_Set_Pixel_Sizes(face, face->available_sizes[j].width, face->available_sizes[j].height); } - if (error) WARNING("Set_Pixel_Sizes failed.",NULL); + if (error) WARNING("Set_Pixel_Sizes failed."); if (FT_IS_FIXED_WIDTH(face)) - WARNING("Selected font is fixed-width.",NULL); + WARNING("Selected font is fixed-width."); /* compute space advance */ error = FT_Load_Char(face, ' ', load_flags); - if (error) WARNING("spacewidth set to default.",NULL); - else space_advance = f266toInt(face->glyph->advance.x); /* +32 is for rounding */ + if (error) WARNING("spacewidth set to default."); + else space_advance = f266toInt(face->glyph->advance.x); /* create font.desc */ - f = fopen("font.desc", "w"); - if (f==NULL) ERROR("fopen failed.",NULL); + f = fopen(font_desc, append_mode ? "a":"w"); + if (f==NULL) ERROR("fopen failed."); /* print font.desc header */ - fprintf(f, "[info]\n"); - fprintf(f, "name 'File generated for %s encoding using `%s%s%s' face (%s), ppem=%i'\n", - encoding, - face->family_name, - face->style_name ? " ":"", face->style_name ? face->style_name:"", - font_path, - ppem); - fprintf(f, "descversion 1\n"); - fprintf(f, "spacewidth %i\n", 2*radius + space_advance); - fprintf(f, "charspace %i\n", -2*radius); - fprintf(f, "height %i\n", f266toInt(face->size->metrics.height)); + if (append_mode) { + fprintf(f, "\n\n# Subtitle font for %s encoding, face \"%s%s%s\", ppem=%i\n", + encoding, + face->family_name, + face->style_name ? " ":"", face->style_name ? face->style_name:"", + ppem); + } else { + fprintf(f, "# This file was generated with subfont for Mplayer.\n# Subfont by Artur Zaprzala .\n\n"); + fprintf(f, "[info]\n"); + fprintf(f, "name 'Subtitle font for %s encoding, face \"%s%s%s\", ppem=%i'\n", + encoding, + face->family_name, + face->style_name ? " ":"", face->style_name ? face->style_name:"", + ppem); + fprintf(f, "descversion 1\n"); + fprintf(f, "spacewidth %i\n", 2*padding + space_advance); + fprintf(f, "charspace %i\n", -2*padding); + fprintf(f, "height %i\n", f266toInt(face->size->metrics.height)); + } fprintf(f, "\n[files]\n"); fprintf(f, "alpha %s-a.raw\n", encoding); fprintf(f, "bitmap %s-b.raw\n", encoding); @@ -199,288 +261,429 @@ void render() { pen_y = 0; ymin = INT_MAX; ymax = INT_MIN; - for (c= first_char, i= 0; c255 ? '.':code); + continue; + } } error = FT_Load_Glyph(face, glyph_index, load_flags); if (error) { - WARNING("Load_Glyph %3u|%2X (char %3i|%2X|U%04X) failed.", glyph_index, glyph_index, c, c, ustring[i]); + WARNING("Load_Glyph 0x%02x (char 0x%02x|U+%04X) failed.", glyph_index, code, character); continue; } slot = face->glyph; - error = FT_Get_Glyph(slot, &glyphs[i]); + error = FT_Get_Glyph(slot, &glyph); - FT_Glyph_Get_CBox(glyphs[i], ft_glyph_bbox_pixels, &bbox); + FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_pixels, &bbox); if (pen_y+bbox.yMax>ymax) { ymax = pen_y+bbox.yMax; - /* eprintf("%3i: ymax %i (%c)\n", c, ymax, c); */ + // eprintf("%3i: ymax %i (%c)\n", code, ymax, code); } if (pen_y+bbox.yMinadvance.x) + 2*radius; - /* pen_y += f266toInt(slot->advance.y); // for vertical layout */ + pen_xa = pen_x + f266toInt(slot->advance.x) + 2*padding; + // pen_y += f266toInt(slot->advance.y); // for vertical layout /* font.desc */ - if (c=='\'') - fprintf(f, "\"%c\" %i %i\n", c, pen_x, pen_xa-1); - else - fprintf(f, "'%c' %i %i\n", c, pen_x, pen_xa-1); - pen_x = (pen_xa+7)&~7; /* 8 byte align */ + fprintf(f, "0x%02x %i %i;\tU+%04X|%c\n", code, pen_x, pen_xa-1, character, code<' '||code>255 ? '.':code); + pen_x = ALIGN(pen_xa); } fclose(f); - if (ymax<=ymin) ERROR("Something went wrong.",NULL); + if (ymax<=ymin) ERROR("Something went wrong. Use the source!"); width = pen_x; - height = ymax - ymin + 2*radius; - baseline = ymax + radius; + height = ymax - ymin + 2*padding; + baseline = ymax + padding; eprintf("bitmap size: %ix%i\n", width, height); buffer = (unsigned char*)malloc(width*height); - ebuffer = (unsigned char*)malloc(width*height); abuffer = (unsigned char*)malloc(width*height); - if (buffer==NULL || abuffer==NULL) ERROR("malloc failed.",NULL); + if (buffer==NULL || abuffer==NULL) ERROR("malloc failed."); + + memset(buffer, 0, width*height); /* render glyphs */ pen_x = 0; pen_y = baseline; - for (c= first_char, i= 0; cglyph, ft_render_mode_normal); - if (error) WARNING("Render_Glyph %3i|%2X (char %3i|%2X|U%04X) failed.", glyph_index, glyph_index, c, c, ustring[i]); + if (error) WARNING("Render_Glyph 0x%02x (char 0x%02x|U+%04X) failed.", glyph_index, code, character); slot = face->glyph; paste_bitmap(&slot->bitmap, - pen_x + radius + slot->bitmap_left, + pen_x + padding + slot->bitmap_left, pen_y - slot->bitmap_top ); /* advance pen */ - pen_x += f266toInt(slot->advance.x) + 2*radius; - /* pen_y += f266toInt(slot->advance.y); // for vertical layout */ - pen_x = (pen_x+7)&~7; /* 8 byte align */ + pen_x += f266toInt(slot->advance.x) + 2*padding; + // pen_y += f266toInt(slot->advance.y); // for vertical layout + pen_x = ALIGN(pen_x); } error = FT_Done_FreeType(library); - if (error) ERROR("Done_FreeType failed.",NULL); + if (error) ERROR("Done_FreeType failed."); } + +/* decode from 'encoding' to unicode */ +FT_ULong decode_char(char c) { + FT_ULong o; + char *inbuf = &c; + char *outbuf = (char*)&o; + int inbytesleft = 1; + int outbytesleft = sizeof(FT_ULong); + + size_t count = iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); + if (count==-1) o = 0; + + /* convert unicode BE -> LE */ + o = ((o>>24)&0xff) + | ((o>>8)&0xff00) + | ((o&0xff00)<<8) + | ((o&0xff)<<24); + + /* we don't want control characters */ + if (o>=0x7f && o<0xa0) o = 0; + return o; +} + + void prepare_charset() { - iconv_t cd; - unsigned char text[charset_size]; - char *inbuf = text; - char *outbuf = (char*) ustring; - int inbuf_left = charset_size; - int outbuf_left = 4*charset_size; - int i; - size_t count; - - for (i = first_char; i LE */ - for (i = 0; i<256; ++i){ - FT_ULong x=ustring[i]; - x= ((x>>24)&255) - | (((x>>16)&255)<<8) - | (((x>> 8)&255)<<16) - | ((x&255)<<24); - ustring[i]=x; + if (charset_size==0) ERROR("No characters to render!"); +} + + +// general outline +void outline( + unsigned char *s, + unsigned char *t, + int width, + int height, + int *m, + int r, + int mwidth) { + + int x, y, mx, my; + for (y = 0; y= height) break; + + for (mx = -r; mx<=r; ++mx) { + unsigned v; + if (x+mx < 0) continue; + if (x+mx >= width) break; + + v = srow[mx] * mrow[mx]; + if (v>max) max = v; + } + } + *t = (max + base/2) / base; + } } +} + +// 1 pixel outline +void outline1( + unsigned char *s, + unsigned char *t, + int width, + int height) { + + int x, y, mx, my; + + for (x = 0; xmaxcolor ? maxcolor : v; + } + *t++ = *s++; + } + for (x = 0; x= height) break; + + for (mx = -r; mx<=r; ++mx) { + if (x+mx < 0) continue; + if (x+mx >= width) break; + + sum+= srow[mx] * mrow[mx]; + } + } + *t = (sum + volume/2) / volume; } - if (test) eprintf("\n"); } - printf("gauss sum = %d\n",sum); - - /* This is not a gaussian blur! */ - /* And is very slow */ - - // PASS-1 : build edge mask: - memset(ebuffer,0,width*height); // clear - for (y = 1; y255)?255:p; +} + + +void alpha() { + int const g_r = ceil(radius); + int const o_r = ceil(thickness); + int const g_w = 2*g_r+1; // matrix size + int const o_w = 2*o_r+1; // matrix size + double const A = log(1.0/base)/(radius*radius*2); + + int mx, my; + unsigned volume = 0; // volume under Gaussian area is exactly -pi*base/A + + unsigned *gm = (unsigned*)malloc(g_w*g_w * sizeof(unsigned)); + unsigned *om = (unsigned*)malloc(o_w*o_w * sizeof(unsigned)); + unsigned char *tbuffer = (unsigned char*)malloc(width*height); + if (gm==NULL || om==NULL || tbuffer==NULL) ERROR("malloc failed."); + + + /* Gaussian matrix */ + for (my = 0; my0 && ay0 && x+mx255) max=255; - abuffer[x+y*width] = max; + + /* outline matrix */ + for (my = 0; my=1 ? base : d<=0 ? 0 : (d*base + .5); + if (DEBUG) eprintf("%3i ", om[mx+my*o_w]); } -// printf("\n"); + if (DEBUG) eprintf("\n"); } + if (DEBUG) eprintf("\n"); + + + outline(buffer, tbuffer, width, height, om, o_r, o_w); // solid outline + //outline(buffer, tbuffer, width, height, gm, g_r, g_w); // Gaussian outline + //outline1(buffer, tbuffer, width, height); // solid 1 pixel outline + + blur(tbuffer, abuffer, width, height, gm, g_r, g_w, volume); - free(m); + free(gm); + free(om); + free(tbuffer); } + void usage() { - printf("Usage: %s encoding ppem font [alphaFactor [minAlpha [radius]]]\n", command); - printf( + printf("Usage: %s [--append] [--blur b] [--outline o] encoding ppem font\n", command); + printf("\n" " Program creates 3 files: font.desc, -a.raw, -b.raw.\n" - " You should append font.desc.tail (desc for OSD characters by a'rpi & chass) to font.desc,\n" - " and copy font.desc and all *.raw files to ~/.mplayer/font/ directory.\n" "\n" - " encoding must be 8 bit encoding, like iso-8859-2.\n" - " To list encodings available on your system use iconv -l.\n" - " ppem Font size in pixels (e.g. 24).\n" - " font Font file path. Any format supported by freetype library (*.ttf, *.pf?, *).\n" - " alphaFactor Alpha map scaling factor (default is 1.0), float.\n" - " minAlpha Alpha map minimum value (default is 1.0, max is 255), float.\n" - " radius Alpha map blur radius (default is 6 pixels), integer.\n" + " --append append results to existing font.desc.\n" + " --blur b specify blur radius, float.\n" + " --outline o specify outline thickness, float.\n" + " encoding must be an 8 bit encoding, like iso-8859-2, or path to custom encoding file (see README).\n" + " To list encodings available on your system use iconv --list.\n" + " ppem Font size in pixels (e.g. 24).\n" + " font Font file path. Any format supported by the freetype library (*.ttf, *.pfb, ...).\n" ); exit(1); } + void parse_args(int argc, char **argv) { - int i; + int i, a = 0; double d; - command = strrchr(argv[0], '/'); - if (command==NULL) command = argv[0]; + command = strrchr(argv[a], '/'); + if (command==NULL) command = argv[a]; else ++command; + ++a; --argc; - if (argc<4) usage(); - - encoding = argv[1]; + if (argc==0) usage(); + if (strcmp(argv[a], "--append")==0) { + append_mode = 1; + ++a; --argc; + } - i = atoi(argv[2]); - if (i>1) ppem = i; - font_path = argv[3]; + if (argc==0) usage(); + if (strcmp(argv[a], "--blur")==0) { + ++a; --argc; + if (argc==0) usage(); - if (argc>4) { - d = atof(argv[4]); - if (d>0.001 && d<1000.) alpha_factor = d; - else WARNING("alphaFactor set to default.",NULL); + d = atof(argv[a]); + if (d>=0 && d<20) radius = d; + else WARNING("using default blur radius."); + ++a; --argc; } - if (argc>5) { - d = atof(argv[5]); - if (d>0.1 && d<=maxcolor) minalpha = d; - else WARNING("minAlpha set to default.",NULL); - } - if (argc>6) { - i = atoi(argv[6]); - if (i>=0 && i<20) radius = i; - else WARNING("radius set to default.",NULL); + + if (argc==0) usage(); + if (strcmp(argv[a], "--outline")==0) { + ++a; --argc; + if (argc==0) usage(); + + d = atof(argv[a]); + if (d>=0 && d<20) thickness = d; + else WARNING("using default outline thickness."); + ++a; --argc; } + + if (argc<3) usage(); + + if (argv[a][0]!=0) + encoding = argv[a]; + ++a; --argc; + + i = atoi(argv[a]); + if (i>1) ppem = i; + ++a; --argc; + + font_path = argv[a]; + ++a; --argc; } + int main(int argc, char **argv) { parse_args(argc, argv); + padding = ceil(radius) + ceil(thickness); prepare_charset(); render(); - blur(); + alpha(); write_bitmap(); free(buffer); free(abuffer); - puts( - "\n" - "*****************************************\n" - "* Remember to run: *\n" - "* cat font.desc.tail >> font.desc *\n" - "*****************************************" - ); - +// fflush(stderr); return 0; } -- cgit v1.2.3