在图像是显示字体,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):
显示效果(字号为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 <kangear@163.com>
*/
#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();
// 设置自己分配的内存
// void *pTempBuffer=malloc(1024);
// bitmap.setPixels(pTempBuffer);
// 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 -g
run:
./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我知道更是一个主角关于文字显示,闲聊文本渲染技术的近期发展讲解了它与它的邻居们的关系