summaryrefslogtreecommitdiff
path: root/glcdgraphics/font.c
diff options
context:
space:
mode:
Diffstat (limited to 'glcdgraphics/font.c')
-rw-r--r--glcdgraphics/font.c262
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