QT/Embedded从ttf字库中提取指定汉字生成qpf字库的办法
2013-03-08
刘志文
标签: Qt ttf字库

解决思路: 获取汉字的unicode编码,使用unicode编码来获取ttf字库中的汉字来生成qpf字库.

首先对我所用的linux环境作以下说明:

Linux系统:

Redhat Linux 9

QT:

qt-embedded-free-3.3.3.tar.bz2

下面正式开始了:

1. 在根目录下新建一个目录

mkdir qte

2. 把qt-embedded-free-3.3.3.tar.bz2移到qte目录

mv qt-embedded-free-3.3.3.tar.bz2/qte

3. 解压qt-embedded-free-3.3.3.tar.bz2

tar -jxvf qt-embedded-free-3.3.3.tar.bz2

4. 重命名qt-embedded-free-3.3.3.tar.bz2文件夹

mv qt-embedded-free-3.3.3 qte

5. 在根目录的qte目录下写如下shell脚本并保存成buildqte

#!/bin/sh

cd qte

export QTDIR=$PWD

export PATH=$QTDIR/bin:$PATH

export LD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH

./configure -qt-gfx-transformed -qvfb

make -C src#这样只是编译src目录下的源码 如果你没有 moc uic 工具就全部编译你可以直接make而不要后面的 -C src

cd ..

6. 执行buildqte脚本编译x86版本的qte库.

./buildqte

7. 检查/qte/qte/bin目录是否有以下工具 qmake moc

如果有就行了,没有就请仔细看第5步,或许你的机器已经安装了qt3 x11版本,可以把uic她拷贝到/qte/qte/bin下使用.

8. 修改/qte/qte/src/kernel/qmemorymamager_qws.cpp文件。(修改的代码很少,这也是最关键的部分。)

说明:为什么要改这个文件

请进入如下目录 /qte/qte/tools/makeqpf/ 打开main.cpp文件(这是makeqpf工具的源码)

请关注下面的代码

129 class MakeQPF : public QMainWindow

130 {

131Q_OBJECT

132QListView* view;

133public:

134MakeQPF()

135{

136view = new QListView(this);

137view->addColumn("Family");

138view->addColumn("Size");

139view->addColumn("Weight");

140view->addColumn("Style");

141setCentralWidget(view);

142QString fontdir = qws_topdir() + "/lib/fonts";

143readFontDir(fontdir);

144

145connect(view,SIGNAL(selectionChanged(QListViewItem*)),this,SLOT(renderAndSave(QListViewItem*)));

146}

重点关注145行,在这里调用了renderAndSave(QListViewItem*)槽

234

235private slots:

236void renderAndSave(QListViewItem* i)

237{

238((FontViewItem*)i)->renderAndSave();

239}

重点关注238行

54void renderAndSave()

55{

56font = QFont(family,pointSize,weight,italic);

57 #ifdef Q_WS_QWS

58memorymanager->savePrerenderedFont((QMemoryManager::FontID)font.handle());

59 #endif

60setHeight(QFontMetrics(font).lineSpacing());

61repaint();

62}

重点关注58行

33 #ifdef Q_WS_QWS

34 #include

35 #endif

重点关注34行

58行中的memorymanager是在头文件qmemorymanager_qws.h中定义的。

打开/qte/qte/include/qmemorymanager_qws.h文件

77 #ifndef QT_NO_QWS_SAVEFONTS

78void savePrerenderedFont(const QFontDef&, bool all=TRUE);

79void savePrerenderedFont(FontID id, bool all=TRUE);

80 #endif

81bool fontSmooth(FontID id) const;

82int fontAscent(FontID id) const;

83int fontDescent(FontID id) const;

84int fontMinLeftBearing(FontID id) const;

85int fontMinRightBearing(FontID id) const;

86int fontLeading(FontID id) const;

87int fontMaxWidth(FontID id) const;

88int fontUnderlinePos(FontID id) const;

89int fontLineWidth(FontID id) const;

90int fontLineSpacing(FontID id) const;

91

92 private:

93QMap pixmap_map;

94int next_pixmap_id;

95QMap font_map;

96int next_font_id;

97 };

98

99 extern QMemoryManager* memorymanager;

重点关注79行和99行

79行的成员函数实现在/qte/qte/src/kernel/qmemorymanager_qws.cpp

打开上面的文件看到下面的代码( 生成qpf字库的工作就在下面做了, 下面是没有改动过的代码 )

991 #ifndef QT_NO_QWS_SAVEFONTS

992 void QMemoryManager::savePrerenderedFont(const QFontDef& f, bool all)

993 {

994QMemoryManagerFont* mmf = (QMemoryManagerFont*)refFont(f);

995savePrerenderedFont((FontID)mmf,all);

996 }

997

998 void QMemoryManager::savePrerenderedFont(FontID id, bool all)

999 {

1000QMemoryManagerFont* mmf = (QMemoryManagerFont*)id;

1001

1002if ( !mmf->renderer ) {

1003qWarning("Already a ROM font");

1004} else {

1005if ( !mmf->tree )

1006mmf->tree = new QGlyphTree(32,32,mmf->renderer); // 32 = " " - likely to be in the font

1007if ( all ) {

1008int j=0;

1009//qDebug("Rendering %s",fontFilename(mmf->def).ascii());

1010for (int i=0; i<=mmf->renderer->maxchar; i++) {

1011if ( mmf->renderer->inFont( i ) ) {

1012mmf->tree->get( i, mmf->renderer );

1013if ( !(j++ & 0x3f)) {

1014// XXX keep it from becoming degenerate - should be in QGlyphTree

1015mmf->tree->compress();

1016QGlyphTree::balance(mmf->tree);

1017}

1018}

1019}

1020}

1021mmf->tree->compress();

1022QGlyphTree::balance(mmf->tree);

1023//qDebug("DUMP..."); mmf->tree->dump();

1024QFile f(fontFilename(mmf->def));

1025f.open(IO_WriteOnly);

1026f.writeBlock((char*)&mmf->fm,sizeof(mmf->fm));

1027mmf->tree->write(f);

1028}

1029 }

1030 #endif

重点关注1010行到1019行

里面中的for循环的i变量就是unicode编码对应。

如果你只是要大小写字母,你可以将for循环改成下面这样

for (int i=0x21; i<=0x7e; i++) //大小写字母和英文标点符号uincode编码是从0x21 到 0x7e

{

if ( mmf->renderer->inFont( i ) )

{

mmf->tree->get( i, mmf->renderer );

if ( !(j++ & 0x3f))

{

// XXX keep it from becoming degenerate - should be in QGlyphTree

mmf->tree->compress();

QGlyphTree::balance(mmf->tree);

}

}

}

上面的循环就是生成只包含大小写字母和英文标点符号的qpf字库了。

现在我们的目标是生成指定汉字的qpf字库.

现在就以我修改的代码为例进行说明。

把qmemorymanager_qws.cpp中998-1029行中 void QMemoryManager::savePrerenderedFont(FontID id, bool all)

实现代码修改成如下代码:

void QMemoryManager::savePrerenderedFont(FontID id, bool all)

{

QMemoryManagerFont* mmf = (QMemoryManagerFont*)id;

if ( !mmf->renderer )

{

qWarning("Already a ROM font");

}

else

{

if ( !mmf->tree )

mmf->tree = new QGlyphTree(32,32,mmf->renderer); // 32 = " " - likely to be in the font

if ( all )

{

int j=0;

qDebug("Rendering %s",fontFilename(mmf->def).ascii());

//for (int i=0; i<=mmf->renderer->maxchar; i++) {

printf("mmf->renderer->maxchar=%u\n", mmf->renderer->maxchar);

for (int i=0x21; i<=0x7e; i++)//大小写字母和英文标点符号uincode编码是从0x21 到 0x7e(这是一般字库都要有的)

{

if ( mmf->renderer->inFont( i ) )

{

mmf->tree->get( i, mmf->renderer );

if ( !(j++ & 0x3f))

{

// XXX keep it from becoming degenerate - should be in QGlyphTree

mmf->tree->compress();

QGlyphTree::balance(mmf->tree);

}

}

}

//把你需要的汉字加入到 tmp 中去,这样一来就可以实现从ttf中提取指定汉字的qpf字库了.

//本人的方法笨就笨在这里,每次添加了汉字就要重新编译qte库和makeqpf

QString tmp("开始停止登录退出参数设置户代码用户密码提示信息你输设置图像摄像图片预览图片浏览摄像状态信息设备状态通道检测");

//注意现在只能处理utf-8的汉字编码,我是由汉字的utf-8编码来获取汉字unicode编码 关于utf-8, 参考utf-8的相关信息

unsigned int len = tmp.length();

const char *ch = tmp.latin1();

unsigned int n;

unsigned int count = 0;

printf( "len=%u\n",len );

for( n=0;n

{

if( ( (unsigned char)ch[n] ) >> 4 == 0xE)//0xE开始是汉字 汉字3字节

{

unsigned int sp1=0;

unsigned int sp2=0;

unsigned int sp3=0;

//以下是utf-8 转换成 unicode编码的过程

//分别获取三个字节,分别转换,然后三个相加就是所需的汉字unicode编码

sp1 =(unsigned int)( (unsigned char)ch[n] - 0xe0 );

sp2 =(unsigned int)( (unsigned char)ch[n+1] - 0x80 );

sp3 =(unsigned int)( (unsigned char)ch[n+2] - 0x80 );

//printf( "0x%x 0x%x 0x%x \n", sp1, sp2, sp3 );

sp1 = sp1 << 12;

sp2 = sp2 << 6;

sp3 = sp1 + sp2 + sp3;

//printf( "0x%x\n\n", sp3 );

if ( mmf->renderer->inFont( sp3 ) )

{

mmf->tree->get( sp3, mmf->renderer );

if ( !(j++ & 0x3f))

{

// XXX keep it from becoming degenerate - should be in QGlyphTree

mmf->tree->compress();

QGlyphTree::balance(mmf->tree);

}

}

n += 3;

count++;

}

else if ( ( (unsigned char)ch[n] ) >> 7 == 0x0 )//单字节

{

n ++;

}

else if( ( (unsigned char)ch[n]) >> 5 == 0x6 )//双字节

{

n += 2;

}

}

}

mmf->tree->compress();

QGlyphTree::balance(mmf->tree);

//qDebug("DUMP..."); mmf->tree->dump();

QFile f(fontFilename(mmf->def));

f.open(IO_WriteOnly);

f.writeBlock((char*)&mmf->fm,sizeof(mmf->fm));

mmf->tree->write(f);

}

}

以上就是修改代码的过程

9.修改buildqte shell脚本.

把buildqte脚本中的下面一行注释掉

./configure -qt-gfx-transformed -qvfb

./buildqte 重新编译qte库

10.编译makeqpf工具(qte用这个工具来生成qpf字库).

注意:makeqpf一定要编译成qte的版本,不能编译成x11版本

cd /qte/qte/tools/makeqpf

../../bin/qmake -project

../../bin/qmake

make

(请按上面的命令执行)

11. 修该fontdir文件

fontdir文件一般默认在/usr/lib/qt-3.1/lib/fonts/目录下

具体修改,应该大家都清楚怎么做了.

下面是我的fontdir文件的内容

unifontunifont_160_50.qpfQPF n 50 160 su

#simfangsimfang.bdfBDF n 50 140 su

#simfangsimfang.ttfFTn 50 140 su

#simfnagsimfang.pcfPCF n 50 140 su

#simfangsimfang_140_50.qpfQPF n 50 140 su

#simfangsimfang.ttfFTn 50 120 su

#simfangsimhei_120_50.qpfQPF n 50 120 su

#simheisimhei.ttfFTn 50 140 su

#simheisimhei_140_50.qpfQPF n 50 140 su

#simkaisimkai.ttfFTn 50 130 su

#simkaisimkai_130_50.qpfQPF n 50 130 su

#

zysong zysong.ttfFT n 50 120 su

zysong zysong_120_50.qpfQPF n 50 120 su

12. 最后就是运行makeqpf生成qpf字库.

makeqpf可以在framebuffer中运行,也可以在qvfb中运行.

运行后你可以去看看自己的成果了,字库是不是小了.

后记:

字库提取的问题困扰了很久,我只用几百个汉字,但是每次生成的字库很大,对嵌入式来说存储空间是很不划算的.现在我的办法有点笨,但是总算能解决这个问题了,所以第一时间给大家共享出来,希望也能帮上你的忙.也希望大家提出建议和指出错误,如果有有心人,还希望能够在完善这个过程.(因为本人的办法确实还是比较麻烦.)

可能会用到的工具/仪表
本站简介 | 意见建议 | 免责声明 | 版权声明 | 联系我们
CopyRight@2024-2039 嵌入式资源网
蜀ICP备2021025729号