diff options
Diffstat (limited to 'glcdgraphics/font.c')
-rw-r--r-- | glcdgraphics/font.c | 262 |
1 files changed, 140 insertions, 122 deletions
diff --git a/glcdgraphics/font.c b/glcdgraphics/font.c index 3b71247..db14638 100644 --- a/glcdgraphics/font.c +++ b/glcdgraphics/font.c @@ -9,7 +9,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2004-2010 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2010-2011 Wolfgang Astleitner <mrwastl AT users sourceforge net> + * Andreas 'randy' Weinberger */ #include <stdio.h> @@ -18,9 +20,7 @@ #include <fcntl.h> #include <unistd.h> -#include <cstring> #include <algorithm> -#include <cstring> #include "common.h" #include "font.h" @@ -28,6 +28,9 @@ #ifdef HAVE_FREETYPE2 #include <ft2build.h> #include FT_FREETYPE_H +#include <iconv.h> +#else +#include <string.h> #endif namespace GLCD @@ -64,13 +67,13 @@ private: protected: cBitmapCache *next; // next bitmap cBitmap *ptr; - int charcode; + uint32_t charcode; public: cBitmapCache(); ~cBitmapCache(); - void PushBack(int ch, cBitmap *bitmap); - cBitmap *GetBitmap(int ch) const; + void PushBack(uint32_t ch, cBitmap *bitmap); + cBitmap *GetBitmap(uint32_t ch) const; }; cBitmapCache::cBitmapCache() @@ -86,7 +89,7 @@ cBitmapCache::~cBitmapCache() delete next; } -void cBitmapCache::PushBack(int ch, cBitmap *bitmap) +void cBitmapCache::PushBack(uint32_t ch, cBitmap *bitmap) { if (!ptr) { @@ -102,7 +105,7 @@ void cBitmapCache::PushBack(int ch, cBitmap *bitmap) next->PushBack(ch, bitmap); } -cBitmap *cBitmapCache::GetBitmap(int ch) const +cBitmap *cBitmapCache::GetBitmap(uint32_t ch) const { if (ptr && charcode==ch) return ptr; @@ -124,11 +127,12 @@ cFont::~cFont() Unload(); } -bool cFont::LoadFNT(const std::string & fileName) +bool cFont::LoadFNT(const std::string & fileName, const std::string & encoding) { // cleanup if we already had a loaded font Unload(); - loadedFontType = lftFNT; //original fonts + fontType = ftFNT; //original fonts + isutf8 = (encoding == "UTF-8"); FILE * fontFile; int i; @@ -148,6 +152,7 @@ bool cFont::LoadFNT(const std::string & fileName) buffer[3] != kFontFileSign[3]) { fclose(fontFile); + syslog(LOG_ERR, "cFont::LoadFNT(): Cannot open file: %s - not the correct fileheader.\n",fileName.c_str()); return false; } @@ -165,11 +170,32 @@ bool cFont::LoadFNT(const std::string & fileName) character = chdr[0] | (chdr[1] << 8); charWidth = chdr[2] | (chdr[3] << 8); fread(buffer, fontHeight * ((charWidth + 7) / 8), 1, fontFile); - if (characters[character]) - delete characters[character]; - characters[character] = new cBitmap(charWidth, fontHeight, buffer); - if (characters[character]->Width() > maxWidth) - maxWidth = characters[character]->Width(); +#ifdef HAVE_DEBUG + printf ("fontHeight %0d - charWidth %0d - character %0d - bytes %0d\n", fontHeight, charWidth, character,fontHeight * ((charWidth + 7) / 8)); +#endif + + int y; int loop; + int num = 0; + uint dot; uint b; + cBitmap * charBitmap = new cBitmap(charWidth, fontHeight); + charBitmap->SetMonochrome(true); + charBitmap->Clear(); + for (num=0; num<fontHeight * ((charWidth + 7) / 8);num++) { + y = (charWidth + 7) / 8; + for (loop=0;loop<((charWidth + 7) / 8); loop++) { + for (b=0;b<charWidth;b++) { + dot=buffer[num+loop] & (0x80 >> b); + if (dot) { + charBitmap->DrawPixel(b+((loop*8)),num/y,cColor::Black); + } + } + } + num=num+y-1; + } + SetCharacter(character, charBitmap); + + if (charWidth > maxWidth) + maxWidth = charWidth; } fclose(fontFile); @@ -197,7 +223,7 @@ bool cFont::SaveFNT(const std::string & fileName) const numChars = 0; for (i = 0; i < 256; i++) { - if (characters[i]) + if (GetCharacter(i)) { numChars++; } @@ -220,16 +246,20 @@ bool cFont::SaveFNT(const std::string & fileName) const // write font file header fwrite(fhdr, kFontHeaderSize, 1, fontFile); + const cBitmap* charbmp = NULL; for (i = 0; i < 256; i++) { - if (characters[i]) + charbmp = GetCharacter(i); + if (charbmp) { chdr[0] = (uint8_t) i; chdr[1] = (uint8_t) (i >> 8); - chdr[2] = (uint8_t) characters[i]->Width(); - chdr[3] = (uint8_t) (characters[i]->Width() >> 8); + chdr[2] = (uint8_t) charbmp->Width(); + chdr[3] = (uint8_t) (charbmp->Width() >> 8); fwrite(chdr, kCharHeaderSize, 1, fontFile); - fwrite(characters[i]->Data(), totalHeight * characters[i]->LineSize(), 1, fontFile); + const unsigned char* monobmp = cBitmap::ConvertTo1BPP(*charbmp); + fwrite(monobmp /*characters[i]->Data()*/, totalHeight * ((charbmp->Width() + 7) / 8), 1, fontFile); + delete[] monobmp; } } @@ -245,7 +275,9 @@ bool cFont::LoadFT2(const std::string & fileName, const std::string & encoding, { // cleanup if we already had a loaded font Unload(); - loadedFontType = lftFT2; // ft2 fonts + fontType = ftFT2; // ft2 fonts + isutf8 = (encoding == "UTF-8"); + #ifdef HAVE_FREETYPE2 if (access(fileName.c_str(), F_OK) != 0) { @@ -286,6 +318,40 @@ bool cFont::LoadFT2(const std::string & fileName, const std::string & encoding, // set Size FT_Set_Char_Size(face, 0, size * 64, 0, 0); + // generate lookup table for encoding conversions (encoding != UTF8) + if (! (isutf8 || dingBats) ) + { + iconv_t cd; + if ((cd = iconv_open("WCHAR_T", encoding.c_str())) == (iconv_t) -1) + { + syslog(LOG_ERR, "cFont::LoadFT2: Iconv encoding not supported: %s", encoding.c_str()); + error = FT_Done_Face(face); + syslog(LOG_ERR, "cFont::LoadFT2: FT_Done_Face(..) returned (%d)", error); + error = FT_Done_FreeType(library); + syslog(LOG_ERR, "cFont::LoadFT2: FT_Done_FreeType(..) returned (%d)", error); + return false; + } + for (int c = 0; c < 256; c++) + { + char char_buff = c; + wchar_t wchar_buff; + char * in_buff,* out_buff; + size_t in_len, out_len, count; + + in_len = 1; + out_len = 4; + in_buff = (char *) &char_buff; + out_buff = (char *) &wchar_buff; + count = iconv(cd, &in_buff, &in_len, &out_buff, &out_len); + iconv_lut[c] = ((size_t) -1 == count) ? (wchar_t)'?' : wchar_buff; + } + iconv_close(cd); + } else { + // don't leave LUT uninitialised + for (int c = 0; c < 256; c++) + iconv_lut[c] = (wchar_t)c; + } + // get some global parameters SetTotalHeight( (face->size->metrics.ascender >> 6) - (face->size->metrics.descender >> 6) ); SetTotalWidth ( face->size->metrics.max_advance >> 6 ); @@ -304,7 +370,7 @@ bool cFont::LoadFT2(const std::string & fileName, const std::string & encoding, #endif } -int cFont::Width(int ch) const +int cFont::Width(uint32_t ch) const { const cBitmap *bitmap = GetCharacter(ch); if (bitmap) @@ -313,72 +379,32 @@ int cFont::Width(int ch) const return 0; } -void cFont::Utf8CodeAdjustCounter(const std::string & str, int & c, unsigned int & i) -{ - int c0,c1,c2,c3; - if (i < str.length()) - { - c = str[i]; - c0 = str[i]; - c1 = (i+1 < str.length()) ? str[i+1] : 0; - c2 = (i+2 < str.length()) ? str[i+2] : 0; - c3 = (i+3 < str.length()) ? str[i+3] : 0; - c0 &=0xff; c1 &=0xff; c2 &=0xff; c3 &=0xff; - - if( c0 >= 0xc2 && c0 <= 0xdf && c1 >= 0x80 && c1 <= 0xbf ){ //2 byte UTF-8 sequence found - i+=1; - c = ((c0&0x1f)<<6) | (c1&0x3f); - }else if( (c0 == 0xE0 && c1 >= 0xA0 && c1 <= 0xbf && c2 >= 0x80 && c2 <= 0xbf) - || (c0 >= 0xE1 && c1 <= 0xEC && c1 >= 0x80 && c1 <= 0xbf && c2 >= 0x80 && c2 <= 0xbf) - || (c0 == 0xED && c1 >= 0x80 && c1 <= 0x9f && c2 >= 0x80 && c2 <= 0xbf) - || (c0 >= 0xEE && c0 <= 0xEF && c1 >= 0x80 && c1 <= 0xbf && c2 >= 0x80 && c2 <= 0xbf) ){ //3 byte UTF-8 sequence found - c = ((c0&0x0f)<<4) | ((c1&0x3f)<<6) | (c2&0x3f); - i+=2; - }else if( (c0 == 0xF0 && c1 >= 0x90 && c1 <= 0xbf && c2 >= 0x80 && c2 <= 0xbf && c3 >= 0x80 && c3 <= 0xbf) - || (c0 >= 0xF1 && c0 >= 0xF3 && c1 >= 0x80 && c1 <= 0xbf && c2 >= 0x80 && c2 <= 0xbf && c3 >= 0x80 && c3 <= 0xbf) - || (c0 == 0xF4 && c1 >= 0x80 && c1 <= 0x8f && c2 >= 0x80 && c2 <= 0xbf && c3 >= 0x80 && c3 <= 0xbf) ){ //4 byte UTF-8 sequence found - c = ((c0&0x07)<<2) | ((c1&0x3f)<<4) | ((c2&0x3f)<<6) | (c3&0x3f); - i+=3; - } - } -} - int cFont::Width(const std::string & str) const { - unsigned int i; - int sum = 0; - int symcount=0; - int c; - - for (i = 0; i < str.length(); i++) - { - Utf8CodeAdjustCounter(str, c, i); - symcount++; - sum += Width(c); - } - sum += spaceBetween * (symcount - 1); - return sum; + return Width(str, (unsigned int) str.length()); } int cFont::Width(const std::string & str, unsigned int len) const { unsigned int i; int sum = 0; - int symcount=0; - int c; + unsigned int symcount=0; + uint32_t c; - for (i = 0; i < str.length() && symcount < len; i++) + i = 0; + while (i < (unsigned int)str.length() && symcount < len) { - Utf8CodeAdjustCounter(str, c, i); + encodedCharAdjustCounter(IsUTF8(), str, c, i); symcount++; sum += Width(c); + i++; } sum += spaceBetween * (symcount - 1); return sum; } -int cFont::Height(int ch) const +int cFont::Height(uint32_t ch) const { const cBitmap *bitmap = GetCharacter(ch); if (bitmap) @@ -407,10 +433,10 @@ int cFont::Height(const std::string & str, unsigned int len) const return sum; } -const cBitmap * cFont::GetCharacter(int ch) const +const cBitmap * cFont::GetCharacter(uint32_t ch) const { #ifdef HAVE_FREETYPE2 - if ( loadedFontType == lftFT2 ) { + if ( fontType == ftFT2 ) { //lookup in cache cBitmap *ptr=characters_cache->GetBitmap(ch); if (ptr) @@ -419,7 +445,11 @@ const cBitmap * cFont::GetCharacter(int ch) const FT_Face face = (FT_Face) ft2_face; FT_UInt glyph_index; //Get FT char index - glyph_index = FT_Get_Char_Index(face, ch); + if (isutf8) { + glyph_index = FT_Get_Char_Index(face, ch); + } else { + glyph_index = FT_Get_Char_Index(face, iconv_lut[(unsigned char)ch]); + } //Load the char int error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); @@ -443,7 +473,8 @@ const cBitmap * cFont::GetCharacter(int ch) const } else { // now, fill our pixel data cBitmap *charBitmap = new cBitmap(face->glyph->advance.x >> 6, TotalHeight()); - charBitmap->Clear(); + charBitmap->Clear(cColor::White); + charBitmap->SetMonochrome(true); unsigned char * bufPtr = face->glyph->bitmap.buffer; unsigned char pixel; for (int y = 0; y < face->glyph->bitmap.rows; y++) @@ -454,7 +485,7 @@ const cBitmap * cFont::GetCharacter(int ch) const if (pixel) charBitmap->DrawPixel((face->glyph->metrics.horiBearingX >> 6) + x, (face->size->metrics.ascender >> 6) - (face->glyph->metrics.horiBearingY >> 6) + y, - GLCD::clrBlack); + /*GLCD::clrBlack*/ cColor::Black); } bufPtr += face->glyph->bitmap.pitch; } @@ -475,7 +506,7 @@ const cBitmap * cFont::GetCharacter(int ch) const void cFont::SetCharacter(char ch, cBitmap * bitmapChar) { #ifdef HAVE_FREETYPE2 - if ( loadedFontType == lftFT2 ) { + if ( fontType == ftFT2 ) { syslog(LOG_ERR, "cFont::SetCharacter: is not supported with FreeType2 fonts!!!"); return; } @@ -503,12 +534,12 @@ void cFont::Init() { characters[i] = NULL; } - loadedFontType = lftFNT; #ifdef HAVE_FREETYPE2 ft2_library = NULL; ft2_face = NULL; characters_cache = NULL; #endif + fontType = ftFNT; } void cFont::Unload() @@ -539,97 +570,84 @@ void cFont::WrapText(int Width, int Height, std::string & Text, int lineCount; int textWidth; std::string::size_type start; - std::string::size_type pos; + unsigned int pos; std::string::size_type posLast; + uint32_t c; Lines.clear(); - maxLines = 2000; + maxLines = 100; if (Height > 0) { maxLines = Height / LineHeight(); - if (maxLines == 0) - maxLines = 1; + //if (maxLines == 0) + maxLines += 1; } - lineCount = 0; + lineCount = 0; pos = 0; start = 0; posLast = 0; textWidth = 0; - while (pos < Text.length() && (Height == 0 || lineCount < maxLines)) + + while ((pos < Text.length()) && (lineCount <= maxLines)) { - if (Text[pos] == '\n') + unsigned int posraw = pos; + encodedCharAdjustCounter(IsUTF8(), Text, c, posraw); + + if (c == '\n') { Lines.push_back(trim(Text.substr(start, pos - start))); - start = pos + 1; - posLast = pos + 1; + start = pos /*+ 1*/; + posLast = pos /*+ 1*/; textWidth = 0; lineCount++; } - else if (textWidth > Width && (lineCount + 1) < maxLines) + else if (textWidth + this->Width(c) > Width && (lineCount + 1) < maxLines) { if (posLast > start) { Lines.push_back(trim(Text.substr(start, posLast - start))); - start = posLast + 1; + start = posLast /*+ 1*/; posLast = start; textWidth = this->Width(Text.substr(start, pos - start + 1)) + spaceBetween; } else { Lines.push_back(trim(Text.substr(start, pos - start))); - start = pos + 1; + start = pos /*+ 1*/; posLast = start; - textWidth = this->Width(Text[pos]) + spaceBetween; + textWidth = this->Width(c) + spaceBetween; } lineCount++; } - else if (Text[pos] == ' ') + else if (isspace(c)) { posLast = pos; - textWidth += this->Width(Text[pos]) + spaceBetween; + textWidth += this->Width(c) + spaceBetween; + } + else if ( (c < 0x80) && strchr("-.,:;!?_", (int)c) ) + { + posLast = pos+1; + textWidth += this->Width(c) + spaceBetween; } else { - textWidth += this->Width(Text[pos]) + spaceBetween; + textWidth += this->Width(c) + spaceBetween; } + pos = posraw; pos++; } + if (start < Text.length()) { + Lines.push_back(trim(Text.substr(start))); + } - if (Height == 0 || lineCount < maxLines) - { - if (textWidth > Width && (lineCount + 1) < maxLines) - { - if (posLast > start) - { - Lines.push_back(trim(Text.substr(start, posLast - start))); - start = posLast + 1; - posLast = start; - textWidth = this->Width(Text.substr(start, pos - start + 1)) + spaceBetween; - } - else - { - Lines.push_back(trim(Text.substr(start, pos - start))); - start = pos + 1; - posLast = start; - textWidth = this->Width(Text[pos]) + spaceBetween; - } - lineCount++; - } - if (pos > start) - { - Lines.push_back(trim(Text.substr(start))); - lineCount++; - } + if (ActualWidth) { textWidth = 0; for (int i = 0; i < lineCount; i++) textWidth = std::max(textWidth, this->Width(Lines[i])); textWidth = std::min(textWidth, Width); - } - else - textWidth = Width; - if (ActualWidth) *ActualWidth = textWidth; + } } } // end of namespace |