TGFX - 腾讯开源的轻量级 2D 渲染引擎

TGFX - 腾讯开源的轻量级 2D 渲染引擎

  • 首页
  • 下载
  • 文档
  • 案例
  • CN
  • GitHub
  • 论坛交流
  • Languages iconEN
    • CN

›图像与像素

快速开始

  • TGFX 简介
  • 平台与后端支持
  • 环境准备与编译
  • Hello2D 示例

API 参考与概述

    绘图基础

    • Canvas Overview
    • Paint Overview
    • Path Overview
    • BlendMode Overview
    • Picture 录制与回放

    几何与变换

    • 几何与变换

    图像与像素

    • Image
    • Bitmap 与像素操作
    • 图像编解码
    • 视频与外部纹理

    文本渲染

    • 文本与字体

    着色与效果

    • 着色与效果

    图层系统

    • 图层系统

    进阶主题

    • 自定义 Shader
    • 色彩管理

架构设计

  • 渲染管线
  • GPU 硬件抽象层
  • 图层渲染系统
  • 缓存系统
  • 文字图集渲染
  • GPU Hairline 极细描边
  • 广色域渲染
  • SIMD 加速

API 文档

  • API 文档

Image

Image 是 tgfx 中代表二维像素数组的最高层级抽象,也是绘图流水线中最核心的内容载体。

在现代图形引擎中,像素数据的流动极其频繁。Image 的设计动机在于屏蔽底层存储的多样性(无论像素是在磁盘、CPU 内存还是 GPU 显存中),并提供高性能的并发能力。

  • 不可变性 (Immutable):一旦创建,其尺寸、内容、色彩空间均不可更改。这种设计消除了状态竞争,使得同一个 Image 对象可以被多个 Canvas 同时绘制。
  • 线程安全 (Thread-safe):由于不可变特性,Image 可以在任何线程被传递和访问,无需外部加锁。
  • 延迟解码 (Lazy Decoding):Image 在创建时通常只是一个"元数据记录",真正的解码动作(IO 读取、压缩包解压)会推迟到该图像首次被提交给 GPU 绘制或显式调用 makeDecoded() 时。

1. 图像创建方式

根据应用场景的性能和内存需求,你可以从以下路径创建 Image:

1.1 从文件路径 / 编码数据 (推荐用于 UI)

  • MakeFromFile(path):建立一个文件引用。
  • MakeFromEncoded(data):包装内存中的 PNG/JPG/WebP 字节流。
  • 协作说明:这些 API 调用是轻量的,因为它们不会立即触发像素解码。
  • 性能注意:若在渲染帧循环中直接调用此方法并立即绘制,IO 和解码开销可能会导致首帧掉帧。建议在预加载阶段提前准备。

代码示例:

// Load from file path (lazy decoding)
auto image = Image::MakeFromFile("photo.png");

// Load from encoded memory data
auto data = Data::MakeWithCopy(buffer, size);
auto image2 = Image::MakeFromEncoded(data);

1.2 从 Bitmap / NativeImage (内存共享)

  • MakeFrom(Bitmap):包装 CPU 端像素数据。
  • MakeFrom(NativeImage):包装系统原生对象(Android Bitmap 或 Apple CGImage)。
  • 内存逻辑:Image 会共享底层的像素内存。若原始 Bitmap 随后被修改,Image 会通过 写时拷贝 (COW) 机制自动克隆一份内存副本,以确保持有内容的一致性。

代码示例:

// Wrap a Bitmap (COW shared)
Bitmap bitmap(200, 200);
// ... fill pixels ...
auto image = Image::MakeFrom(bitmap);

1.3 从原始像素数据

  • MakeFrom(ImageInfo, Data):直接从原始像素字节数据创建 Image。调用者需要确保像素数据在 Image 的整个生命周期内保持不变。
  • 应用场景:适用于已经在内存中准备好像素数据的场景,例如从自定义解码器或算法生成的像素。

代码示例:

auto info = ImageInfo::Make(256, 256, ColorType::RGBA_8888);
auto pixels = Data::MakeWithCopy(rawPixelBuffer, info.byteSize());
auto image = Image::MakeFrom(info, pixels);

1.4 从 HardwareBuffer (高性能零拷贝)

  • MakeFrom(HardwareBuffer, ColorSpace):从单平面硬件缓冲区创建(RGB 格式)。
  • MakeFrom(HardwareBuffer, YUVColorSpace):从多平面硬件缓冲区创建(YUV 格式)。
  • 动机:这是处理视频帧和相机预览的最高效方式,数据直接在显存中流动,规避了昂贵的 CPU-GPU 搬运成本。
  • 平台映射:Android AHardwareBuffer、iOS/macOS CVPixelBuffer、Windows ID3D11Texture2D。

1.5 从 ImageGenerator (自定义数据源)

  • MakeFrom(Generator):通过自定义的 ImageGenerator 子类控制每一帧的像素生成逻辑。
  • 延迟特性:与文件源类似,像素生成会推迟到首次绘制时。适合包装自定义解码器或过程化生成器。

1.6 从 BackendTexture (GPU 纹理包装)

  • MakeFrom(Context*, BackendTexture, origin, colorSpace):直接包装现有的 GPU 纹理 ID。调用者必须确保原始纹理在 Image 生命周期内保持有效,Image 不会管理纹理的生命周期。
  • MakeAdopted(Context*, BackendTexture, origin, colorSpace):同样包装 GPU 纹理,但 Image 接管所有权——当 Image 销毁时,底层纹理会被自动释放。
  • origin 参数:ImageOrigin::TopLeft(默认)或 ImageOrigin::BottomLeft,用于指示纹理坐标原点。

代码示例:

// Wrap an existing GPU texture (caller manages lifetime)
auto image = Image::MakeFrom(context, backendTexture, ImageOrigin::TopLeft);

// Adopt an existing GPU texture (Image takes ownership)
auto image2 = Image::MakeAdopted(context, backendTexture);

1.7 从 Picture (矢量绘制命令)

  • MakeFrom(Picture, width, height, matrix, colorSpace):将已录制的绘制命令流封装为图像源。
  • 矢量特性:PictureImage 不会立即栅格化,只在绘制时按需渲染所需的区域到临时离屏图像。支持无限缩放而不损失精度。
  • 缓存建议:如果需要缓存全尺寸内容,可对返回的 Image 调用 makeRasterized()。

代码示例:

// Record drawing commands
PictureRecorder recorder;
auto* recordCanvas = recorder.beginRecording();
recordCanvas->drawCircle(200, 150, 100, paint);
auto picture = recorder.finishRecordingAsPicture();

// Create Image from Picture
auto image = Image::MakeFrom(picture, 400, 300);

1.8 从 ImageBuffer

  • MakeFrom(ImageBuffer):包装一个已准备好的 ImageBuffer 对象。通常用于从 ImageReader 获取的视频帧或从 Bitmap::makeBuffer() 生成的缓冲区。

2. 协作流程:从加载到渲染

tgfx 的图像处理遵循从资源引用到硬件缓存的清晰链路:

数据源 (File/Encoded) → Image (属性识别) → makeDecoded (预热解码) → Canvas (绘制合成)


3. 图像变换 (make...)

变换操作不会修改原图,而是返回一个新的"逻辑视图"。

3.1 内容裁剪与方向校正

  • makeSubset(Rect):逻辑裁剪,返回指定区域的视图。
    • 内存注意:子集图像仍会维持对原图全部数据的引用。若需从超大图中提取极小块并释放原图内存,建议配合 makeRasterized() 使用。
  • makeOriented(Orientation):基于 EXIF 标签自动校正图像的旋转与镜像方向。如果方向为 TopLeft(默认),则返回原 Image。

3.2 解码与 GPU 优化

  • makeDecoded(Context*):核心优化 API。显式触发解码并将纹理上传至特定 GPU 上下文,同时立即调度一个异步解码任务,不会阻塞调用线程。
    • 应用场景:在后台线程预热图像,确保在 UI 线程绘制时能够立即可见。
    • 智能跳过:如果 Image 已完全解码(isFullyDecoded() 为 true)或已有对应纹理缓存,则直接返回原 Image。
  • makeMipmapped(enabled):启用或禁用多级纹理(Mipmap)。开启后,当图像缩小到极小尺寸时能有效抑制闪烁和视觉噪声。
  • makeTextureImage(Context*):获取一个由 GPU 纹理支撑的 Image。如果已存在纹理缓存则直接包装返回;否则立即创建纹理。返回后可安全释放原 Image 以减少 CPU 内存占用。

3.3 缩放与栅格化

  • makeScaled(newWidth, newHeight, sampling):返回指定尺寸的缩放视图。新 Image 保留原图的 Mipmap 和栅格化状态。
    • 如果原 Image 是已栅格化的,缩放后的 Image 也会被栅格化并缓存在新尺寸上。
    • 如果原 Image 未栅格化,缩放后的 Image 不会被缓存,每次绘制只渲染所需部分。需要缓存时请调用 makeRasterized()。
  • makeRasterized():将逻辑视图(如子集、缩放、Picture 源)栅格化为独立的 GPU 缓存。栅格化后的 Image 拥有独立的纹理资源,不再依赖原图数据。
    • 已栅格化的 Image(如直接由 ImageBuffer、ImageGenerator 或 GPU 纹理创建的)调用此方法会直接返回自身。

3.4 滤镜与特殊布局

  • makeWithFilter(filter, offset, clipRect):应用 ImageFilter(如模糊、色彩矩阵等)并返回结果图像。滤镜有可能改变图像边界,offset 参数用于记录平移偏移。
  • makeRGBAAA(displayWidth, displayHeight, alphaStartX, alphaStartY):特殊布局合成。将同一张图的不同象限合并为带 Alpha 通道的图像,常用于透明视频动效。

4. 绘制方式与采样控制

4.1 绘制 API

  • drawImage(image, x, y):最基础的位移绘制。将图像左上角定位到 (x, y)。
  • drawImage(image, sampling, paint):支持自定义采样选项的绘制方式。
  • drawImageRect(image, dstRect):将整个图像拉伸到目标矩形。
  • drawImageRect(image, srcRect, dstRect, sampling, paint, constraint):精准的区域拉伸绘制。从 srcRect 采样,绘制到 dstRect。

代码示例:

auto image = Image::MakeFromFile("photo.png");

// Simple draw at (50, 50)
canvas->drawImage(image, 50, 50);

// Draw with source-to-destination mapping
auto src = Rect::MakeXYWH(0, 0, 100, 100);
auto dst = Rect::MakeXYWH(50, 50, 200, 200);
canvas->drawImageRect(image, src, dst);

4.2 drawAtlas (图集绘制)

drawAtlas 利用图集技术,通过 单次绘制调用 (Draw Call) 渲染大量精灵 (Sprites),是粒子系统和高性能 UI 组件的首选。

void drawAtlas(std::shared_ptr<Image> atlas,
               const Matrix matrix[],    // Each sprite's transform
               const Rect tex[],         // Source rectangle in atlas for each sprite
               const Color colors[],     // Optional per-sprite tint color (nullptr to skip)
               size_t count,             // Number of sprites
               const SamplingOptions& sampling = {},
               const Paint* paint = nullptr);
  • atlas:包含所有精灵帧的图集图像。
  • matrix[]:每个精灵的独立变换矩阵,控制位置、旋转、缩放。
  • tex[]:每个精灵在图集中的源矩形区域。
  • colors[]:可选的逐精灵着色数组。传入 nullptr 时不着色。
  • 适用场景:粒子特效、弹幕动画、游戏精灵渲染等需要批量绘制大量小图的场景。

4.3 SamplingOptions (采样控制)

SamplingOptions 通过 FilterMode 和 MipmapMode 两个维度控制采样质量:

FilterMode:纹理过滤模式

模式算法特点
Nearest邻近采样(最近邻)性能最高,非整数缩放时产生锯齿,适合像素艺术风格。
Linear双线性过滤(2×2 插值)默认选择,缩放效果平滑,适合大多数 UI 场景。

Min / Mag 分离控制

SamplingOptions 支持独立设置缩小(min)和放大(mag)时的过滤模式:

// Default: both Linear
SamplingOptions sampling;  // min = Linear, mag = Linear

// Same filter for both
SamplingOptions sampling(FilterMode::Nearest);  // min = Nearest, mag = Nearest

// Different filters for min and mag
SamplingOptions sampling(FilterMode::Linear,   // minFilterMode (shrink)
                         FilterMode::Nearest,  // magFilterMode (enlarge)
                         MipmapMode::Linear);  // mipmapMode

MipmapMode:多级渐远纹理模式

模式行为适用场景
None禁用 Mipmap,仅从基础层采样。图像始终以原始尺寸或接近原始尺寸绘制时。
Nearest从最近的 Mipmap 层级采样。性能优先的缩小场景。
Linear在两个最近层级之间插值。默认值。图像缩至极小尺寸时,有效抑制闪烁和锯齿。

注意:Mipmap 模式仅在 Image 启用了 makeMipmapped(true) 后才生效。否则,无论 MipmapMode 设置为何值,实际行为等同于 None。

4.4 SrcRectConstraint (源矩形约束)

在 drawImageRect 中,SrcRectConstraint 控制源矩形边缘的采样行为:

模式行为
Fast默认。允许在源矩形边界外采样,性能更高。
Strict严格限制在源矩形内采样,禁用 Mipmap。适用于图集拼接场景,防止相邻精灵的像素渗透。

5. 作为 Shader 使用

通过 Shader::MakeImageShader 可将 Image 转化为动态"画笔纹理",在填充任意形状时提供图像采样。

5.1 TileMode (平铺模式)

模式行为
Clamp默认。拉伸边缘像素填充超出部分。
Repeat重复平铺图像。
Mirror镜像翻转重复,相邻图像自然无缝衔接。
Decal超出边界返回透明(transparent-black)。

5.2 基础用法

auto image = Image::MakeFromFile("pattern.png");
// Create a repeating image shader
auto shader = Shader::MakeImageShader(image, TileMode::Repeat, TileMode::Repeat);
Paint paint;
paint.setShader(shader);
// Fill any path with the image texture
canvas->drawPath(path, paint);

5.3 局部变换

通过 shader->makeWithMatrix(matrix) 为 Shader 设置独立的变换矩阵,例如在路径填充时对纹理进行旋转或缩放:

auto shader = Shader::MakeImageShader(image, TileMode::Repeat, TileMode::Repeat);
// Rotate the texture pattern by 45 degrees
Matrix matrix = Matrix::MakeRotate(45);
auto rotatedShader = shader->makeWithMatrix(matrix);
Paint paint;
paint.setShader(rotatedShader);
canvas->drawRect(rect, paint);

6. 渲染效果参考

基础变换效果

从大图中提取中心 400×400 子集,应用高斯模糊滤镜后绘制:

auto image = Image::MakeFromFile("bridge.jpg");

// Crop center 400x400 region
float x = static_cast<float>(image->width() - 400) / 2.0f;
float y = static_cast<float>(image->height() - 400) / 2.0f;
auto subset = image->makeSubset(Rect::MakeXYWH(x, y, 400.0f, 400.0f));

// Apply blur filter
auto filter = ImageFilter::Blur(10.0f, 10.0f);
auto filteredImage = subset->makeWithFilter(filter);

// Draw
auto surface = Surface::Make(context, 400, 400);
auto canvas = surface->getCanvas();
canvas->drawImage(filteredImage, 0, 0, SamplingOptions(FilterMode::Linear));

Image Tutorial Result

Shader TileMode 对比

将同一张小图作为 Shader 源,分别使用四种 TileMode 填充 200×200 区域(左上 Repeat、右上 Mirror、左下 Clamp、右下 Decal):

auto tile = image->makeScaled(80, 80, SamplingOptions(FilterMode::Linear));

// Repeat: tiles the image seamlessly
auto repeatShader = Shader::MakeImageShader(tile, TileMode::Repeat, TileMode::Repeat);
paint.setShader(repeatShader);
canvas->drawRect(Rect::MakeWH(200, 200), paint);

// Mirror: alternating flip for seamless edges
auto mirrorShader = Shader::MakeImageShader(tile, TileMode::Mirror, TileMode::Mirror);

// Clamp: stretches edge pixels beyond bounds
auto clampShader = Shader::MakeImageShader(tile, TileMode::Clamp, TileMode::Clamp);

// Decal: transparent beyond bounds
auto decalShader = Shader::MakeImageShader(tile, TileMode::Decal, TileMode::Decal);

Image Shader Tiling

Picture + drawAtlas

通过 PictureRecorder 录制矢量绘制命令,创建为 Image,再使用 drawAtlas 批量绘制 4×3 精灵网格,每个精灵带有不同的着色:

// 1. Record drawing commands into a Picture
PictureRecorder recorder;
auto* recordCanvas = recorder.beginRecording();
Paint circlePaint = {};
circlePaint.setColor(Color::FromRGBA(60, 120, 240, 255));
recordCanvas->drawCircle(40, 40, 35, circlePaint);
circlePaint.setColor(Color::FromRGBA(240, 80, 60, 200));
recordCanvas->drawCircle(60, 60, 25, circlePaint);
auto picture = recorder.finishRecordingAsPicture();

// 2. Create Image from Picture (100x100)
auto pictureImage = Image::MakeFrom(picture, 100, 100);

// 3. Batch draw 12 sprites with drawAtlas
size_t count = 12;
std::vector<Matrix> matrices(count);
std::vector<Rect> texRects(count);
std::vector<Color> colors(count);
auto texRect = Rect::MakeWH(100, 100);
for (size_t i = 0; i < count; ++i) {
    int col = static_cast<int>(i) % 4;
    int row = static_cast<int>(i) / 4;
    matrices[i] = Matrix::MakeTrans(col * 100.0f, row * 100.0f);
    texRects[i] = texRect;
    float t = static_cast<float>(i) / static_cast<float>(count - 1);
    colors[i] = Color::FromRGBA(static_cast<uint8_t>(255 * (1 - t)),
                                static_cast<uint8_t>(200 * t),
                                static_cast<uint8_t>(100 + 155 * t), 255);
}
canvas->drawAtlas(pictureImage, matrices.data(), texRects.data(), colors.data(), count);

Image Picture And Atlas

← 几何与变换Bitmap 与像素操作 →
  • 1. 图像创建方式
    • 1.1 从文件路径 / 编码数据 (推荐用于 UI)
    • 1.2 从 Bitmap / NativeImage (内存共享)
    • 1.3 从原始像素数据
    • 1.4 从 HardwareBuffer (高性能零拷贝)
    • 1.5 从 ImageGenerator (自定义数据源)
    • 1.6 从 BackendTexture (GPU 纹理包装)
    • 1.7 从 Picture (矢量绘制命令)
    • 1.8 从 ImageBuffer
  • 2. 协作流程:从加载到渲染
  • 3. 图像变换 (make...)
    • 3.1 内容裁剪与方向校正
    • 3.2 解码与 GPU 优化
    • 3.3 缩放与栅格化
    • 3.4 滤镜与特殊布局
  • 4. 绘制方式与采样控制
    • 4.1 绘制 API
    • 4.2 drawAtlas (图集绘制)
    • 4.3 SamplingOptions (采样控制)
    • 4.4 SrcRectConstraint (源矩形约束)
  • 5. 作为 Shader 使用
    • 5.1 TileMode (平铺模式)
    • 5.2 基础用法
    • 5.3 局部变换
  • 6. 渲染效果参考
    • 基础变换效果
    • Shader TileMode 对比
    • Picture + drawAtlas
公司地址:广东省深圳市南山区海天二路33号腾讯滨海大厦Copyright © 2018 - 2026 Tencent. All Rights Reserved.联系电话:0755-86013388隐私政策