QgsSingleBandPseudoColorRenderer 完整详解(QGIS 3.40.13 C++)

一、基础定位、头文件、继承关系

1. 引入头文件

cpp 复制代码
#include <qgssinglebandpseudocolorrenderer.h>

2. 继承链

复制代码
QgsRasterRenderer
    ↳ QgsSingleBandRenderer
        ↳ QgsSingleBandPseudoColorRenderer
  • QgsRasterRenderer :栅格渲染器顶层抽象基类,所有栅格渲染器统一父类,定义 block()clone()、XML读写、透明度等通用接口;
  • QgsSingleBandRenderer:单波段渲染器公共父类,封装「渲染波段号」基础逻辑;
  • QgsSingleBandPseudoColorRenderer单波段伪彩色渲染器,专门实现单波段数值→渐变色/分级上色(DEM、NDVI、温度热力图底层渲染器)。

3. 完整渲染链路总览

复制代码
QgsRasterLayer
    ↓
QgsSingleBandPseudoColorRenderer (当前讲解对象:控制渲染波段、透明度、持有QgsRasterShader)
    ↓
QgsRasterShader (scale/offset、拉伸min/max、Nodata透明、亮度对比度)
    ↓
QgsColorRampShader (分段色标、插值渐变/离散/精确匹配逻辑)

4. 核心职责

  1. 指定要渲染的目标波段(1起始);
  2. 持有唯一 QgsRasterShader 着色器实例,所有数值转颜色逻辑由shader提供;
  3. 实现栅格像素块渲染入口 block(),从provider读取像素、调用shader上色、输出RGBA画布;
  4. 统一管理图层透明度、灰度转换、图层混合模式;
  5. 提供克隆、序列化XML(保存到qgs工程)。

二、构造函数

cpp 复制代码
// 空构造,无数据源、无shader,仅用于反序列化加载工程
QgsSingleBandPseudoColorRenderer();

// 标准业务构造(最常用)
// provider:栅格数据源;bandNo:渲染波段;shader:着色器(传入后renderer接管内存)
QgsSingleBandPseudoColorRenderer( QgsRasterDataProvider *provider,
                                  int bandNo,
                                  QgsRasterShader *shader = nullptr );

三、核心属性读写API

1. 渲染波段(继承自 QgsSingleBandRenderer)

cpp 复制代码
// 获取当前渲染波段
int band() const;
// 修改渲染波段,切换后需要重新统计极值、刷新shader拉伸区间
void setBand( int bandNo );

注意:波段号从1开始,传0会渲染失效。

2. 着色器 QgsRasterShader 管理(核心)

cpp 复制代码
// 获取内部着色器,可修改min/max、scale/offset、shaderFunction
QgsRasterShader *rasterShader() const;

// 设置新着色器,renderer 获得 shader 所有权,自动释放旧shader
void setRasterShader( QgsRasterShader *shader );

内存规则:

  • setRasterShader() 传入的shader由渲染器托管,外部禁止手动delete;
  • 替换shader时,旧着色器会自动销毁,无内存泄漏。

3. 图层全局透明度(继承 QgsRasterRenderer)

cpp 复制代码
// 透明度 0~100,0完全不透明,100完全透明
int opacity() const;
void setOpacity( int opacity );

4. 图层混合模式(叠加、正片叠底等)

cpp 复制代码
QPainter::CompositionMode compositionMode() const;
void setCompositionMode( QPainter::CompositionMode mode );

5. Nodata全局透明开关(兼容层,实际优先走shader透明配置)

cpp 复制代码
bool usesTransparentNodata() const;
void setUsesTransparentNodata( bool transparent );

四、核心渲染入口函数 block()

函数签名(重写父类虚函数)

cpp 复制代码
QgsRasterBlock *block(
    const QgsRectangle &extent,
    int width,
    int height,
    QgsRasterBlockFeedback *feedback = nullptr
) override;

功能:生成RGBA彩色像素块,供画布绘制

内部完整执行步骤
  1. 调用 provider->readBlock(band(), extent, width, height) 读取原始单波段浮点像素块;
  2. 创建RGBA 4通道输出像素块(Byte类型,0~255);
  3. 遍历每一行每一列像素:
    • 判断是否Nodata:若shader开启透明Nodata,直接填充Alpha=0;
    • 取出原始rawVal,交给 rasterShader()->shade() 计算RGBA;
    • 应用图层全局透明度opacity衰减Alpha通道;
  4. 返回彩色RGBA像素块,上层绘图组件渲染;
  5. 进度反馈 feedback 用于大影像渲染时进度条、取消渲染。

五、克隆、序列化(工程保存/加载必备)

1. 深度克隆 clone()

cpp 复制代码
QgsRasterRenderer *clone() const override;
  • 完整复制:波段号、透明度、混合模式、内部完整QgsRasterShader(连带内部QgsColorRampShader色标列表深度拷贝);
  • 返回全新渲染器对象,使用完成必须手动delete。

2. XML读写 writeXml / readXml

cpp 复制代码
void writeXml( QDomDocument &doc, QDomElement &parentElem ) const override;
void readXml( const QDomElement &rendererElem ) override;

存储内容:

  • 渲染波段、透明度、混合模式;
  • 完整序列化 QgsRasterShader(min/max、scale/offset、亮度对比度、transparentNodata);
  • 嵌套序列化 QgsColorRampShader(全部色标、插值模式clip开关等)。
    QGIS工程保存、样式文件(.qml)读写底层依赖这两个接口。

六、自动生成拉伸区间工具函数(高频业务接口)

cpp 复制代码
// 根据栅格波段统计,自动填充shader的min/max(原始像素值,scale=offset=0场景)
void setShaderMinMaxToNone();
void setShaderMinMaxToFullExtent();
void setShaderMinMaxToCurrentExtent( const QgsRectangle &currentExtent );

常用场景

cpp 复制代码
// 自动用整幅栅格的波段极值填充shader拉伸窗口
renderer->setShaderMinMaxToFullExtent();

内部逻辑:调用provider->bandStatistics()获取min/max,赋值给shader的minimumValue/maximumValue。

七、完整分层协作示例代码(DEM伪彩色渲染)

cpp 复制代码
#include <qgsrasterdataprovider.h>
#include <qgsrasterbandstats.h>
#include <qgsrastershader.h>
#include <qgsrastercolorrampshader.h>
#include <qgssinglebandpseudocolorrenderer.h>
#include <qgsrasterlayer.h>

// DEM单波段伪彩色渲染封装函数
void setupDemPseudoColorRender(QgsRasterLayer* demLayer)
{
    QgsRasterDataProvider* prov = demLayer->dataProvider();
    if (!prov || !prov->isValid()) return;

    int renderBand = 1;
    // 1. 统计波段原始极值
    QgsRasterBandStats stats = prov->bandStatistics(
        renderBand, QgsRasterBandStats::Min | QgsRasterBandStats::Max
    );
    if (!stats.isValid()) return;

    // 2. 构建色标(无scale/offset,displayVal=rawVal)
    QList<QgsColorRampItem> items;
    items.append(QgsColorRampItem(stats.minVal, QColor(10, 40, 200), "低海拔"));
    items.append(QgsColorRampItem((stats.minVal+stats.maxVal)/2, QColor(30, 190, 50), "中海拔"));
    items.append(QgsColorRampItem(stats.maxVal, QColor(210, 20, 20), "高海拔"));

    // 3. 色带着色函数
    QgsColorRampShader* rampFunc = new QgsColorRampShader(items, QgsColorRampShader::Interpolated);
    rampFunc->setClipBelow(true);
    rampFunc->setClipAbove(true);

    // 4. 外层Shader
    QgsRasterShader* shader = new QgsRasterShader();
    shader->setMinimumValue(stats.minVal);
    shader->setMaximumValue(stats.maxVal);
    shader->setTransparentNodata(true);
    shader->setRasterShaderFunction(rampFunc);

    // 5. 创建伪彩色渲染器(核心类)
    QgsSingleBandPseudoColorRenderer* render = new QgsSingleBandPseudoColorRenderer(prov, renderBand, shader);
    render->setOpacity(90); // 图层透明度90%
    render->setCompositionMode(QPainter::CompositionMode_SourceOver);

    // 6. 绑定到栅格图层
    demLayer->setRenderer(render);
    demLayer->triggerRepaint(); // 刷新画布
}

八、与其他栅格渲染器对比区分

渲染器类 用途 是否依赖 QgsRasterShader
QgsSingleBandPseudoColorRenderer 单波段渐变/分级伪彩色(DEM、NDVI、热力图) ✅ 必须依赖
QgsSingleBandGrayRenderer 单波段黑白灰度拉伸 ✅ 依赖灰度shader
QgsMultiBandColorRenderer RGB三波段真彩色遥感影像 ❌ 无shader,直接合成三色
QgsPalettedRasterRenderer 索引色栅格(自带色表)

关键区分

QgsSingleBandGrayRendererQgsSingleBandPseudoColorRenderer 同属单波段渲染器,都持有QgsRasterShader

  • 灰度渲染器内部shaderFunction是灰度映射;
  • 伪彩色渲染器搭配 QgsColorRampShader 实现多色渐变分级。

九、开发高频踩坑点

1. 内存所有权问题

cpp 复制代码
// 正确:renderer接管shader,无需手动delete shader
QgsRasterShader* shader = new QgsRasterShader();
QgsSingleBandPseudoColorRenderer* render = new QgsSingleBandPseudoColorRenderer(prov, 1, shader);

// 错误:外部手动delete shader,渲染器析构时二次释放崩溃
delete shader;

2. scale/offset 存在时,shader min/max 不能填原始波段极值

QgsSingleBandPseudoColorRenderer 只负责持有shader,不会自动换算scale/offset后的区间;

需要手动计算 displayMin = (rawMin-offset)*scale 赋值给shader。

3. 切换波段后极值不刷新

调用 setBand(2) 切换渲染波段后,旧shader的min/max仍是波段1的区间,必须重新统计并更新shader拉伸窗口。

4. 浮点栅格使用 Exact 模式匹配失败

Exact精确匹配仅适合整型分类栅格,浮点存在精度误差,渲染器会大面积透明。

5. 渲染器替换后图层不刷新

修改完renderer必须调用 layer->triggerRepaint() 触发画布重绘。

6. 多线程渲染限制

block() 内部会读取provider,GDAL驱动非线程安全,多线程并行渲染同一图层需要加互斥锁。

十、典型业务使用场景

  1. DEM数字高程模型渐变伪彩色渲染;
  2. NDVI、NDWI植被指数热力分级;
  3. 气温、降雨量、污染物浓度热力图;
  4. 坡度、地形起伏度离散分级设色;
  5. 单波段灰度数据自定义渐变色展示。

十一、类层级结构精简总结

复制代码
QgsRasterRenderer (顶层栅格渲染器)
└── QgsSingleBandRenderer (单波段公共父类:管理波段号)
    └── QgsSingleBandPseudoColorRenderer
        ├─ 成员:QgsRasterShader* mShader
        ├─ 核心方法:block() 输出RGBA彩色像素块
        ├─ 辅助:setShaderMinMaxToFullExtent() 自动拉伸
        ├─ 生命周期:clone()、writeXml/readXml 序列化
        └─ 配置:透明度、图层混合模式
相关推荐
王维同学2 小时前
[原创][Windows C++]LSA 认证、安全与通知包的注册表枚举
c++·windows·安全
刘较瘦_2 小时前
AI 开发中的 Git Submodule 父子仓库模式:前后端分仓管理与协作实践
前端·github
yaoxin5211232 小时前
470. Java 反射 - Member 接口与 AccessFlag
java·开发语言·python
牧艺2 小时前
cos-design WeatherBackground:用 Canvas 做一个「会变天」的背景引擎
前端·canvas·视觉设计
groundhappy2 小时前
idalib安装和codex ida-mcp配置
linux·开发语言·python
OpenTiny社区2 小时前
深度解析 LSP 如何为 AI 装上“眼睛”
前端·ai编程
布列瑟农的星空3 小时前
流程类SVG画布的通用开发范式
前端
fsssb3 小时前
Chromium 源码学习笔记(七):那些跨进程的调用,底下都是同一个东西——Mojo
前端
_wyt0013 小时前
完全背包问题详解
c++·背包dp