Skia是Google开发的跨平台2D图形库,核心组件包括:SkCanvas(绘图入口)、SkPaint(画笔样式)、SkPath(几何形状)、SkImage/SkBitmap(图片处理)、SkFont/SkTypeface(文本渲染)以及SkSurface(画布载体)。支持CPU/GPU/PDF/SVG多种渲染后端,广泛应用于Chrome、Flutter等项目中,提供从基础绘图到高级特效的全套图形能力。调用流程为创建Surface→获取Canvas→设置Paint→执行绘制→输出结果,形成完整的图形渲染解决方案。
Skia 是 Google 开发的一个高性能、跨平台的 2D 图形库,被广泛应用于 Chrome、Android、Flutter 等项目。它的主要作用是提供底层的图形绘制能力,比如画线、画圆、渲染文本、处理图片等。
下面用通俗易懂的方式介绍 Skia 的主要组成部分:
Skia 支持多种底层渲染后端:
+-------------------+
| 应用层(如Flutter、Chrome) |
+-------------------+
|
v
+-------------------+
| Skia API | <--- SkCanvas, SkPaint, SkPath, SkImage, SkFont, etc.
+-------------------+
|
v
+-------------------+
| 渲染后端(CPU/GPU/PDF/SVG) |
+-------------------+
下面我会分三部分继续详细介绍:
Skia 的源码结构非常清晰,主要目录和功能如下(以 Skia GitHub 主干为例):
目录/文件 | 主要内容说明 |
---|---|
include/ | Skia 对外公开的 C++ 头文件(API 入口) |
src/ | Skia 的核心实现代码(大部分功能都在这里) |
src/core/ | 2D 图形核心算法(如 SkCanvas、SkPaint、SkPath、SkImage 等的实现) |
src/gpu/ | GPU 渲染相关代码(OpenGL、Vulkan、Metal、D3D 后端) |
src/sksl/ | Skia Shading Language(SkSL)着色器语言相关 |
src/pdf/ | PDF 输出相关实现 |
src/svg/ | SVG 解析与输出相关实现 |
src/utils/ | 各种工具类、辅助功能 |
src/text/ | 文字排版与渲染相关实现 |
modules/ | 可选模块(如 SkParagraph、Skottie、SkShaper 等) |
tools/ | Skia 的测试工具、示例程序 |
gm/ | 图形测试用例 |
platform_tools/ | 平台相关的工具(如 Android、iOS、Windows、Linux 的适配代码) |
third_party/ | 依赖的第三方库(如 HarfBuzz、libpng、zlib 等) |
experimental/ | 实验性功能 |
tests/ | 单元测试代码 |
常用入口文件:
include/core/SkCanvas.h
include/core/SkPaint.h
include/core/SkPath.h
include/core/SkImage.h
include/core/SkFont.h
include/core/SkSurface.h
drawRect
、drawCircle
、drawPath
、drawImage
、drawTextBlob
、drawLine
等。save()
/restore()
:保存/恢复画布状态(如变换、裁剪等)。translate()
、scale()
、rotate()
:变换画布。setColor()
:设置颜色setStrokeWidth()
:线宽setStyle()
:填充/描边setAntiAlias()
:抗锯齿setShader()
:渐变、图案等moveTo()
、lineTo()
、quadTo()
、cubicTo()
、arcTo()
、close()
addRect()
、addCircle()
、addOval()
、addPath()
MakeFromEncoded()
:从字节流解码图片readPixels()
、peekPixels()
:访问像素数据SkFont::setSize()
:字号SkFont::setTypeface()
:字体SkCanvas::drawString()
、drawTextBlob()
:绘制文本MakeRaster()
:创建内存画布MakeRenderTarget()
:创建 GPU 画布getCanvas()
:获取 SkCanvasSkShader::MakeLinearGradient()
、MakeRadialGradient()
等SkColorFilter::MakeLightingFilter()
等SkMaskFilter::MakeBlur()
等SkDocument::MakePDF()
、MakeXPS()
、MakeSVG()
自定义绘制(CustomPainter)时,Flutter 的 Canvas API 其实就是 Skia 的 Canvas 的 Dart 封装。
Chrome 的 PDF 导出、SVG 渲染等也用 Skia 的相关模块。
下面我分别给出 Skia 的 C++ 原生绘图代码示例,以及 Flutter(Dart)中自定义绘制的代码示例,并简单说明 Chrome/Blink 的调用关系。
假设你已经集成好 Skia,可以这样用 C++ 代码画一个红色圆和一段文字:
#include "include/core/SkCanvas.h"
#include "include/core/SkSurface.h"
#include "include/core/SkPaint.h"
#include "include/core/SkFont.h"
#include "include/core/SkImageEncoder.h"
#include "include/core/SkStream.h"
int main() {
// 创建一个 400x400 的内存画布
sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(400, 400);
SkCanvas* canvas = surface->getCanvas();
// 填充白色背景
SkPaint paint;
paint.setColor(SK_ColorWHITE);
canvas->drawPaint(paint);
// 画一个红色圆
paint.setColor(SK_ColorRED);
paint.setAntiAlias(true);
canvas->drawCircle(200, 200, 100, paint);
// 画一段文字
SkFont font;
font.setSize(32);
paint.setColor(SK_ColorBLACK);
canvas->drawString("Hello Skia!", 100, 350, font, paint);
// 保存为 PNG 文件
sk_sp<SkImage> img = surface->makeImageSnapshot();
SkFILEWStream out("output.png");
img->encodeToStream(&out, SkEncodedImageFormat::kPNG, 100);
return 0;
}
编译说明:需要链接 Skia 的库,具体编译方式请参考 Skia 官方文档。
效果:输出一个包含红色圆和文字的 PNG 图片。
Flutter 的 Canvas
API 底层就是 Skia。下面是一个自定义画圆和文字的例子:
import 'package:flutter/material.dart';
class MyPainter extends CustomPainter {
void paint(Canvas canvas, Size size) {
// 画红色圆
var paint = Paint()
..color = Colors.red
..isAntiAlias = true;
canvas.drawCircle(Offset(size.width/2, size.height/2), 100, paint);
// 画文字
var textPainter = TextPainter(
text: TextSpan(
text: 'Hello Skia!',
style: TextStyle(color: Colors.black, fontSize: 32),
),
textDirection: TextDirection.ltr,
);
textPainter.layout();
textPainter.paint(canvas, Offset(100, 350));
}
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
class MySkiaDemo extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
body: CustomPaint(
size: Size(400, 400),
painter: MyPainter(),
),
);
}
}
效果:在 Flutter 界面上显示一个红色圆和一段文字。
在 Chrome/Blink 里,Web 页面上的 Canvas、SVG、图片、文本等,最终都会转成 Skia 的绘图命令。
你可以在 Chromium 源码的 third_party/skia
目录下找到 Skia 的集成代码。
例如,HTML5 Canvas 的 fillRect
最终会调用 SkCanvas::drawRect,fillText
会调用 SkCanvas::drawTextBlob 等。
// 画一个线性渐变矩形
SkPoint pts[2] = { {0, 0}, {400, 0} };
SkColor colors[2] = { SK_ColorBLUE, SK_ColorGREEN };
sk_sp<SkShader> shader = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp);
SkPaint paint;
paint.setShader(shader);
canvas->drawRect(SkRect::MakeXYWH(0, 0, 400, 100), paint);
// 画一个路径
SkPath path;
path.moveTo(50, 300);
path.cubicTo(150, 200, 250, 400, 350, 300);
paint.setShader(nullptr);
paint.setColor(SK_ColorMAGENTA);
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(4);
canvas->drawPath(path, paint);