Android 图形库skia 显示字体

时间:2022-08-23 00:14:41

在图像是显示字体,Skiaapi中就有,直接可以将文字显示出现。如下代码:

 

    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)

 Android 图形库skia 显示字体

 

       除了上述的方法还可以使用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);

}

       

      其中第一个参数namettf字体的Font Family name,查看方法是使用gnome-font-viewer查看到“Name”一项的内容,和具体的文件的名字没有关系。如下图:

Android 图形库skia 显示字体 

       另外一个要注意的是,当前版本的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

 

*/

生成的图片效果:

Android 图形库skia 显示字体


       调用api固然简单,我最终的目的是尽量接近Android的显示方式。开始是看android文本布局引擎讲解是大概这样做的。他的文章中是基于使用PyhoneFreetype写的例子,我这里使用skiaFreetype写的例子,他文章的重点是Text Layout Engine TextLayoutShaper,就是排版引擎,所以这里的工作只算是完成了android中的skiafreetype的工作。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我知道更是一个主角关于文字显示,闲聊文本渲染技术的近期发展讲解了它与它的邻居们的关系