Android图形库Skia 三 -结合Freetype显示文字
在图像是显示字体,Skia的api中就有,直接可以将文字显示出现。如下代码:
SkTypeface *font = SkTypeface::CreateFromFile("NotoSansHans-Regular.otf");if ( font ){ paint.setARGB(255, 255, 0, 0); paint.setTypeface( font ); paint.setTextSize(25); canvas.drawText("平凡之路!", 14, 0, 25, paint);}
显示效果(字号为25):
除了上述的方法还可以使用SkTypeface::CreateFromName创建face,但要注意,Skia是遍历SK_FONT_FILE_PREFIX(当前版本为:/usr/share/fonts/truetype/msttcorefonts)宏所指示的目录下所有*.ttf字库文件,并将其加载内存的。它的原型如下:
SkTypeface* SkTypeface::CreateFromName(const char name[], Style style) { return SkFontHost::CreateTypeface(NULL, name, NULL, 0, style);}
其中第一个参数name是ttf字体的Font Family name,查看方法是使用gnome-font-viewer查看到“Name”一项的内容,和具体的文件的名字没有关系。如下图:
另外一个要注意的是,当前版本的skia并不会遍历子目录,参考Skia中遍历Linux系统字库文件。
代码如下:
/* Simple Chinese Font demo utilizing Skia toolkit. * Authored by kangear <[email protected]> */#include "SkBitmap.h"#include "SkDevice.h"#include "SkPaint.h"#include "SkRect.h"#include "SkImageEncoder.h"#include "SkTypeface.h"//draw_content()int main(){ // Declare a raster bitmap, which has an integer width and height, // and a format (config), and a pointer to the actual pixels. // Bitmaps can be drawn into a SkCanvas, but they are also used to // specify the target of a SkCanvas' drawing operations. SkBitmap bitmap; bitmap.setConfig(SkBitmap::kARGB_8888_Config, 200, 200); bitmap.allocPixels(); // A Canvas encapsulates all of the state about drawing into a // device (bitmap). This includes a reference to the device itself, // and a stack of matrix/clip values. For any given draw call (e.g. // drawRect), the geometry of the object being drawn is transformed // by the concatenation of all the matrices in the stack. The // transformed geometry is clipped by the intersection of all of the // clips in the stack. SkCanvas canvas(bitmap); // SkPaint class holds the style and color information about how to // draw geometries, text and bitmaps. SkPaint paint; const char gText[] = "123平34凡之路12!"; //SkTypeface *font = SkTypeface::CreateFromFile("DroidSansFallbackFull.ttf"); //usr/share/fonts/truetype/msttcorefonts/DroidSansFallbackFull.ttf SkTypeface *font = SkTypeface::CreateFromName("Droid Sans Fallback", SkTypeface::kNormal); if ( font ) { paint.setARGB(255, 255, 0, 0); paint.setTypeface( font ); paint.setTextSize(25); canvas.drawText(gText, sizeof(gText)/sizeof(gText[0]), 0, 25, paint); } else { printf("font ==null !\n"); } // SkImageEncoder is the base class for encoding compressed images // from a specific SkBitmap. SkImageEncoder::EncodeFile("snapshot.png", bitmap, SkImageEncoder::kPNG_Type, /* Quality ranges from 0..100 */ 100); return 0;}/*build:g++ \-I./include \-I./include/core \-I./include/images \-I./include/config \-I./include/pdf/ \-Wall -o test-skia ./test-skia.cpp \out/src/images/SkImageDecoder_libpng.o \out/libskia.a \`pkg-config freetype2 --libs --cflags` \`pkg-config libpng --libs --cflags` \-lpthread -grun:./test-skia*/
生成的图片效果:
调用api固然简单,我最终的目的是尽量接近Android的显示方式。开始是看android文本布局引擎讲解是大概这样做的。他的文章中是基于使用Pyhone和Freetype写的例子,我这里使用skia和Freetype写的例子,他文章的重点是Text Layout Engine TextLayoutShaper,就是排版引擎,所以这里的工作只算是完成了Android中的skia和freetype的工作。TextLayoutShaper重点是排版。不过经过它这么重重的计算,似乎Android中并像本例子中的那样直接调用skia的文字绘制api来实现。这一关先到这里,至少稍微了解了一下。
上边的问题稍有见解了,Freetype使用方式有两种,一种是使用Skia封装好的Api;另一种是直接调用Freetype的标准Api如下:
...SkFontHost_FreeType.cpp:(.text+0x2185): undefined reference to `FT_Get_Advances'SkFontHost_FreeType.cpp:(.text+0x23e7): undefined reference to `FT_Get_Glyph_Name'SkFontHost_FreeType.cpp:(.text+0x2420): undefined reference to `FT_Get_FSType_Flags'SkFontHost_FreeType.cpp:(.text+0x244e): undefined reference to `FT_Done_FreeType'...
尽管我现在还没有对freetype有深刻的理解,根据这些个api也能明白个大概了,顾名思义。Android中很可能是直接基于Freetype的Api来实现的更高级的字体显示和排版效果,目前这个也是猜测,得好好的研究一番,才能下结论。
skia库显示中文的问题中讲到需要将中文转换成UTF8才能显示,我在Linux中的实验结果并没有这个需求,可能是那个要求只是在Windows上。如果写成专门的API供上层调用,我建议采用和Android一样的使用UTF-16作为统一接口。参见Android底层开发之字符绘制TextLayoutCache。
我真希望快点引出harfbuzz我知道更是一个主角关于文字显示,闲聊文本渲染技术的近期发展讲解了它与它的邻居们的关系。
再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.****.net/jiangjunshow