大海捞针 Skia(C++) 第 3 期:绘制文本

本文介绍了如何使用Skia库在C++中绘制文本,包括设置VisualStudio的UTF-8编码,创建SkBitmap,使用SkCanvas和SkFont进行文本绘制,最后将结果保存为PNG图像。示例代码详细展示了drawSimpleText和drawString方法的使用。
摘要由CSDN通过智能技术生成

前言

本期将正式给大家介绍Skia的使用。文章将涉及一个目的的多种方案多种情况。文章较长,请大家耐心阅读。

关键词:PNG图像、文件、文本、字符串、UTF8、UTF16、UTF32、编码转换、Visual Studio 设置、高级保存选项


案例

注意:接下来的案例都将使用PNG图像来存储查看绘制结果

Visual Studio 应将代码文件默认编码设置为UTF-8(建议不带BOM,即标准UTF8编码,操作教程如下:
Visual Studio 设置默认编码格式为 UTF-8 或 GB2312-80 与文件没有高级保存选项怎么显示

这里的常字符串不是专业术语,这里表达的意思是,代码中的字符串以及常量字符串。例如,我们在给一个string类付初始值时即会使用一个字符串例如"Hello, Skia!",这样的字符串是固定的,因为代码中就是这样。因此编译的程序里也一定默认这样初始化。至于常量字符串,则是指const char*

绘制代码中字符串步骤和上一期绘制"Hello, Skia!"一致,这里将详细介绍。
在绘制前,应确保你的Visual Studio项目已经配置好Skia库,具体步骤参考《大海捞针 Skia(C++) 第 1 期:Skia 环境搭建》。


绘制图像,就像画画一样,我们需要一个介质来存储我们的笔画痕迹。因而在Skia中,我们使用SkBitmap作为这个介质。

实例化一个SkBitmap

SkBitmap bitmap;

好比绘画所用的纸也有规格参数,同样,上述这个介质也需要。用于描述这个参数的类叫做SkImageInfo
我们可以通过如下方式,手动指定规格信息,但值得注意的是,生活中,绘画纸的参数是用于描述纸的,而在这里,参数是用于生成纸的,详情将在后面指出。这里,我们创建了一个信息块,同时为其填写信息,即:宽600px、高400px、RGBA颜色,同时设置使用Alpha通道。

SkImageInfo bitmapInfo = SkImageInfo::Make(600, 400, kRGBA_8888_SkColorType, kPremul_SkAlphaType);

接下来我们需要用这个信息分配空间。

bitmap.allocPixels(bitmapInfo);

接下来就是看起来不能理解但很合理的部分。bitmap作为我们绘制的介质我们却无法直接对其进行绘制,而提供一个SkCanvas供我们绘制。虽然显得有些繁琐,但其实却很合理。bitmap仅作为我们存储的地方。而SkCanvas作为绘制的部分。好比GUI程序界面与其内部数据是分离的,但却不可割舍其中一个。同理,绘制也是如此。SkCanvas并不存储数据,但却提供给我们绘制的方法;而SkBitmap不提供绘制方法,却允许我们将图像数据存储其中。这自然是很合理的。
那如何使用SkCanvas呢?首先,我们知道SkCanvas是不存储数据的,但提供绘制方法,那我们调用方法绘制时数据存何处?自然是SkBitmap,因此,我们需要为SkCanvas绑定一个存储数据的地方——SkBitmap。如下:

SkCanvas canvas(bitmap);

既然SkCanvas为我们提供了绘制的方法,那么,我们想要达成绘制字符串的目的,自然需要调用其中的方法。
这里有两个方法可以使用。
第一种,使用drawSimpleText方法;
第二种,使用drawString方法。
我相信大家也许去尝试使用这两个方法,然而发现这两个方法有许多参数。不急,我们慢慢解析。

第一种方法原型如下:

void drawSimpleText(const void *text, size_t byteLength, SkTextEncoding encoding,
  SkScalar x, SkScalar y, const SkFont &font, 
  SkPaint &paint);

text:待绘制的字符串
byteLength:字符串字节数
encoding:字符串编码
x:起点横坐标
y:起点纵坐标
font:字体
paint:画笔

绘制文本,自然需要我们给出字符串,那如何表示呢?std::string?实际上我们可以使用Skia提供的SkString类存储字符串。这里我们将定义两个字符串,分别用于两种绘制方法。

SkString str_Method1("Drawed by drawSimpleText"),
  str_Method2("Drawed by drawString");

第一个参数是字符串指针,我们只需调用SkStringc_str方法即可。第二个参数我们同样只需调用SkStringsize方法即可。第三个参数,因为我们已经设置代码文件编码为UTF8,因此我们只需设置编码为SkTextEncoding::kUTF8。第四五个参数,我们分别传入绘制起始点的坐标。第六个参数是字体。第七个参数是画笔。

不难发现,这一个方法就带了一堆参数。于是又扯到了字体和画笔上。
接下来,我们将对第六七个参数进行详解。

首先,我们先了解一下字体类——SkFont
顾名思义,这个类自然是对字体的设置。实例化一个对象不必多言,但我们如何初始化呢?
方法如下:

SkFont font(SkTypeface::MakeFromName("Consolas", SkFontStyle::Bold()), 20);

这里我们选择使用Consolas字体,同时设置风格为加粗,大小为20。

接下来就是画笔SkPaint了,其实字面上看,倒不如说是绘画更为贴切,但Skia使用“Paint”这个名字用来储存绘制动作的属性(包括颜色、透明度等),我们即将其叫做更为熟知的“画笔”。

SkPaint paint;
paint.setColor(SkColor(0xFF000000));

万事俱备,只欠东风。现在我们只需要调用drawSimpleText方法即可。

canvas.drawSimpleText(str_Method1.c_str(), str_Method1.size(), SkTextEncoding::kUTF8, 0, 20, font, paint);

至于drawString方法,原型如下:

void drawString(const SkString &str, SkScalar x, SkScalar y, const SkFont& font,
  const SkPaint& paint);

看到原型,相比大家已经知道如何使用了。这里不过多解释。

接下来就是输出为PNG图片了。原理很简单,我们只需声明一个文件输出流,然后使用SkEncodeImage函数编码即可。

SkFILEWStream stream("D:/test.png");
SkEncodeImage(&stream, bitmap, SkEncodedImageFormat::kPNG, 100);

值得注意的是,第四个参数是一个0-100的整数,用来表示图片质量,100为最大,并且,这个参数只会对jpeg和webp格式生效。


参考代码

#include "pch.h"

int main()
{
	SkBitmap bitmap;
	SkImageInfo bitmapInfo = SkImageInfo::Make(600, 400, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
	bitmap.allocPixels(bitmapInfo);
	SkCanvas canvas(bitmap);
	canvas.clear(0xFFFFFFFF); //注意,这里是ARGB,Alpha通道值在前

	SkString str_Method1("Drawed by drawSimpleText"),
		str_Method2("Drawed by drawString");

	SkFont font(SkTypeface::MakeFromName("Consolas", SkFontStyle::Bold()), 20);
	SkPaint paint;
	paint.setColor(SkColor(0xFF000000)); //同上
	canvas.drawSimpleText(str_Method1.c_str(), str_Method1.size(), SkTextEncoding::kUTF8, 0, 20, font, paint);
	canvas.drawString(str_Method2, 0, 50, font, paint);
	SkFILEWStream stream("D:/test.png");
	SkEncodeImage(&stream, bitmap, SkEncodedImageFormat::kPNG, 100);

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值