1 Skia 绘图概述
Skia 是 Google 一个底层的图形、文本、图像、动画等多方面的图形库,是 Android 中图形系统的引擎。 Skia 作为第三方软件放在 external 目录下: external/skia/ 。 skia 的源文件及部分头文件都在 src 目录下,导出的头文件在 include 目录下。
使用 Skia 的 API 进行图形绘制时主要会用到一下几个类:
SkBitmap 、 SkCanvas 、 SkPaint 和 SkRect ,其中 SkBitmap 用来设置像素, SkCanvas 写入位图, SkPaint 设置颜色和样式, SkRect 用来绘制矩形。其实现代码主要在 src/core 目录下。
2 使用 Skia 绘图的步骤
a) 定义一个位图 32 位像素并初始化
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config, 200, 200);
其中 setConfig 为设置位图的格式,原型为 void setConfig(Config, int width, int height, int rowBytes = 0)
Config 为一个数据结构
enum Config {
kNo_Config, // 不确定的位图格式
kA1_Config, //1 位 ( 黑 , 白 ) 位图
kA8_Config, //8 位 ( 黑 , 白 ) 位图
kIndex8_Config, // 类似 windows 下的颜色索引表,具体请查看 SkColorTable 类结构
kRGB_565_Config, //16 位象素 565 格式位图,详情请查看 SkColorPriv.h 文件
kARGB_4444_Config, //16 位象素 4444 格式位图,详情请查看 SkColorPriv.h 文件
kARGB_8888_Config, //32 位象素 8888 格式位图,详情请查看 SkColorPriv.h 文件
kRLE_Index8_Config,
kConfigCount
};
b) 分配位图所占的空间
bitmap.allocPixels()
其实 allocPixels 为重载函数,原型为 bool allocPixels(SkColorTable* ctable = NULL)
参数 ctable 为颜色索引表,一般情况下为 NULL 。
c) 指定输出设备
SkCanvas canvas(new SkDevice(bitmap));
其中 canvas 为一个多构造函数,原型为
explicit SkCanvas(const SkBitmap& bitmap) ,
explicit SkCanvas(SkDevice* device = NULL)
explicit 关健字的意思为:不允许类型转换
输出设备可以为一个上下文 Device, 也可以指定为一张位图。
d) 设备绘制的风格
Paint paint;
SkRect r;
paint.setARGB(255, 255, 0, 0);
r.set(25, 25, 145, 145);
canvas.drawRect(r, paint);
paint 可以指定绘图的颜色,文本的大小及对齐方式,编码格式等等,因为以前位图的格式设置为 kARGB_8888_Config ,所以这里要设置绘制的颜色 setARGB(255, 255, 0, 0) ,第一位参数为透明颜色通道,其它三位分别为 R 、 G 、 B 。 r 设置要绘制的范围,最后通过 drawRect 绘制出指定区域的一个方形。
这样,一个红色的矩形就绘制成功了。
SkCanvas 主要完成三种绘制功能:
a 基本图形绘制 ( 如 drawARGB,drawLine 函数 )
b 图像文件绘制( drawBitmap 函数)
c 文本绘制( drawText 函数)
相关 API 有:
canvas.drawRect(rect, paint);
canvas.drawOval(oval, paint);
canvas.drawCircle(x, y, radius, paint);
canvas.drawRoundRect(rect, rx, ry, paint);
canvas.drawPath(path, paint);
canvas.drawBitmap(bitmap, x, y, &paint);
canvas.drawBitmapRect(bitmap, &srcRect, dstRect, &paint);
canvas.drawBitmapMatrix(bitmap, matrix, &paint);
canvas.drawText(text, length, x, y, paint);
canvas.drawPosText(text, length, pos[], paint);
canvas.drawTextOnPath(text, length, path, paint);
e)
例程
i )画点、线、圆、文字
#include "SkBitmap.h"
#include "SkDevice.h"
#include "SkPaint.h"
#include "SkRect.h"
#include "SkImageEncoder.h"
#include "SkTypeface.h"
using namespace std;
int main()
{
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config,320,240);
bitmap.allocPixels();
SkCanvas canvas(new SkDevice(bitmap));
SkPaint paint;
// draw points with red.
paint.setARGB(255, 255, 0, 0);
paint.setStrokeWidth(4);
canvas.drawPoint(40,30, paint);
canvas.drawPoint(80,60, paint);
canvas.drawPoint(120,90, paint);
//draw a line with green.
paint.setARGB(255, 0, 255, 0);
paint.setStrokeWidth(4);
canvas.drawLine(160,10,320,110,paint);
//draw a circle with bule.
paint.setARGB(255, 0, 0, 255);
canvas.drawCircle(80,180,50,paint);
//draw text with red
SkTypeface *font = SkTypeface::CreateFromFile("simkai.ttf");
if ( font )
{
paint.setARGB(255, 255, 0, 0);
paint.setTypeface( font );
paint.setTextSize(24);
canvas.drawText("HELLO!:)", 8, 200, 180, paint);
}
SkImageEncoder::EncodeFile("snapshot.png", bitmap,SkImageEncoder::kPNG_Type,100);
return 0;
}
程序执行后,得到如下输出结果:
ii) 图像的编解码
该例程目前测试只支持 .png 格式的图片, .jpg 还不支持,还未找到原因。
#include "SkBitmap.h"
#include "SkDevice.h"
#include "SkPaint.h"
#include "SkRect.h"
#include "SkImageEncoder.h"
#include "SkImageDecoder.h"
#include
using namespace std;
int main()
{
int ret = -1;
SkBitmap bitmap;
//SkImageDecoder
ret = SkImageDecoder::DecodeFile("./old.png", &bitmap);
cout<< "get the decode type = "<< bitmap.config() << endl;
//SkImageEncoder
ret = SkImageEncoder::EncodeFile("new1.png",bitmap,SkImageEncoder::kPNG_Type,100);
cout<< "encode data to png result = "<< ret<< endl;
return 0;
}
SkImageDecoder::DecodeFile("./old.png", &bitmap);
将 png 转换成位图格式,并将数据放到 bitmap 变量中
SkImageEncoder::EncodeFile("snapshot.png", bitmap,SkImageEncoder::kPNG_Type,/* Quality ranges from 0..100 */ 100);
将 bitmap 中的数据编码输出为 .png 格式,第一位参数为 png 文件路径,第二位为指定的输出位图,第三位为文件的类型,第四位参数指定了输出位图的质量,范围为 0..100 ,默认为 80 。
3 图形图像特效
src/effects 目录的文件主要实现一些图形图像的特效,包括 遮罩、浮雕、模糊、滤镜、渐变色、离散、透明以及 PATH 的各种特效等。
4 动画
src/animator 目录的文件主要实现了 Skia 的动画效果,Android不支持。
5 界面 UI 库
src/view 目录 构建了一套界面 UI 库。
组件包括 Window,Menu, TextBox, ListView, ProgressBar, Widget, ScrollBar,TagList,Image 等。
6 其它
a) src/gl 目录: 这部分是 skia 调用 OpenGL 或 OpenGL ES 来实现 3D 效果。
如果定义了 MAC ,则使用 OpenGL ,如果定义了 Android ,则使用嵌入式 系统 上的 esgl 三维图形库。
b)src/images 目录: 主要是 SkImageDecoder 和 SkImageEncoder 以及 SkMovie 。主要是用来处理 images 的,能处理的图像类型包括: BMP 、
JPEG/PVJPEG 、 PNG 、 ICO ,而 SkMovie 是用来处理 gif 动画的。
c) src/opts 目录:性能优化的代码。
d) src/pdf 目录: 处理 PDF 文档,用了一个 fpdfemb 库。
e) src/ports 目录: 这部分是 skia 的一些接口在不同系统上的实现,平台相关的代码,比如字体、线程、时间等, 主要包括几个部分: Font , Event , File , Thread , Time , XMLParser
这些与 Skia 的接口,需要针对不同的 操作系统 实现。
f) src/svg 目录: 矢量图像,Android不支持。
SkSVGPath, SkSVGPolyline, SkSVGRect, SkSVGText, SkSVGLine, SkSVGImage, SkSVGEllipse 等等。
g) src/text 目录:???
h) src/utils 目录: 是一些辅助工具类。
SkCamera, SkColorMatrix,SkOSFile,SkProxyCanvas,SkInterpolator 等文件。
i) src/xml : 这是处理 xml 数据的部分, skia 在这里只是对 xml 解析器做了一层包装,具体的 xml 解析器的实现需要根据不同的操作系统及宿主程序来实现。
j) Third-party library
除了自身的所有文件外, skia 还使用了一些 third-party library 以及包含了不少 linux 上的头文件。
通过分析 skia 源程序,发现 skia 主要使用以下几个第三方库:
Zlib ,处理数据的压缩和解压缩
Jpeglib ,处理 jpeg 图像的编码解码
Pnglib ,处理 png 图像的编码解码
giflib ,处理 gif 图像
fpdfemb ,处理 pdf 文档
skia 还需要一些 linux/unix 下的头文件(可能还需要更多):
stdint.h
unistd.h
features.h
cdefs.h
stubs.h
posix_opt.h
types.h
wordsize.h
typesizes.h
confname.h
getopt.h
mman.h