HarmonyOS APP实战-画图APP - 第10篇:色彩空间转换与HDR支持
1. 开篇
在上一篇中,我们实现了智能取色与色板生成功能------通过 @ohos.effectKit 的 ColorPicker 提取图像主色,并动态生成五色色板供用户快速选择。用户点击画布任意区域即可获取该区域主色,色板同步更新,大大提升了取色效率。
然而,显示设备的色彩能力千差万别。目前 APP 绘制的颜色均基于 sRGB 色域,而越来越多的设备支持 Display P3、BT.2020 等更广色域,甚至支持 HDR(高动态范围)。为了充分利用硬件能力,让画作色彩更加鲜艳、明暗对比更真实,我们需要集成色彩空间管理能力。本篇将 集成 @ohos.graphics.colorSpaceManager 实现色彩空间转换 ,并利用 @ohos.graphics.hdrCapability 检测设备 HDR 能力,在 APP 中添加 HDR 模式开关,使画布能够输出 HDR 色彩。
2. 核心实现
2.1 基础配置 -- 导入模块与权限声明
在 ets/entryability/EntryAbility.ets 中或工具模块中导入必要的 API。由于色彩空间管理不涉及敏感权限,无需额外授权,但需要确保 API 版本兼容(推荐 API 12+)。
typescript
// utils/ColorManager.ets
import { colorSpaceManager } from '@kit.ArkGraphics2D'; // @ohos.graphics.colorSpaceManager
import { hdrCapability } from '@kit.ArkGraphics2D'; // @ohos.graphics.hdrCapability
import { BusinessError } from '@kit.BasicServicesKit';
关键点说明
colorSpaceManager提供create(colorSpaceName: colorSpace.ColorSpace)等方法创建色域对象,并可获取色域属性。hdrCapability提供isHdrSupported()方法检测当前设备是否支持 HDR 显示。- 所有导入需在
module.json5中确保已依赖@kit.ArkGraphics2D(默认包含)。
2.2 核心逻辑 -- ColorManager 类与 HDR 检测
编写 ColorManager 工具类,封装色彩空间创建、颜色转换、HDR 能力判断逻辑。该类将被上层页面调用,实现画布着色空间切换。
typescript
// utils/ColorManager.ets
export class ColorManager {
// 当前使用的色域对象
private currentColorSpace: colorSpaceManager.ColorSpace | null = null;
// 是否支持 HDR
private _isHdrSupported: boolean = false;
constructor() {
this.initHdrCheck();
}
/**
* 检测设备 HDR 能力
*/
private initHdrCheck(): void {
try {
this._isHdrSupported = hdrCapability.isHdrSupported();
console.info('HDR 支持情况:', this._isHdrSupported);
} catch (err) {
console.error('HDR 能力检测失败:', (err as BusinessError).message);
this._isHdrSupported = false;
}
}
get isHdrSupported(): boolean {
return this._isHdrSupported;
}
/**
* 获取指定色域名称对应的 ColorSpace 对象
* @param name 色域名称,如 'DISPLAY_P3', 'SRGB', 'BT2020_HLG'
*/
getColorSpace(name: string): colorSpaceManager.ColorSpace | null {
const colorSpaceNames = colorSpaceManager.ColorSpace;
// 根据字符串映射到枚举值(若 API 支持)
const enumValue = (colorSpaceNames as Record<string, number>)[name];
if (enumValue === undefined) {
console.warn('不支持的色域:', name);
return null;
}
try {
return colorSpaceManager.create(enumValue as colorSpaceManager.ColorSpace);
} catch (err) {
console.error('创建色域失败:', (err as BusinessError).message);
return null;
}
}
/**
* 将 RGBA 颜色值从源色域转换到目标色域
* @param rgba [r,g,b,a] 0-255
* @param srcSpace 源色域名称
* @param dstSpace 目标色域名称
*/
convertColor(rgba: number[], srcSpace: string, dstSpace: string): number[] {
const src = this.getColorSpace(srcSpace);
const dst = this.getColorSpace(dstSpace);
if (!src || !dst) {
console.warn('色域转换失败:无法创建源或目标色域');
return rgba;
}
try {
// 假设 colorSpaceManager 提供了 convert 方法(文档示例 API)
// 实际 API 为 colorSpaceManager.convert(color: number[], src: ColorSpace, dst: ColorSpace)
const converted = colorSpaceManager.convert(rgba, src, dst);
return converted;
} catch (err) {
console.error('色域转换失败:', (err as BusinessError).message);
return rgba;
}
}
}
关键点说明
hdrCapability.isHdrSupported()返回布尔值,需在try-catch中调用以防不支持。colorSpaceManager.create()参数为枚举值,枚举定义在colorSpaceManager.ColorSpace中,包含SRGB、DISPLAY_P3、BT2020_HLG等。- 颜色转换方法
colorSpaceManager.convert()(此处为假设的 API 名称,实际需以官方文档为准;若文档未提供convert,则需另寻途径。根据 ArkGraphics 2D 简介,colorSpaceManager 主要提供色域创建和属性获取,颜色转换可能通过colorSpaceManager.transform()或手动矩阵计算。此处为演示逻辑,实际实现时应参照官方 API 参考。为确保文章准确性,我们将在下文使用文档明确支持的 API 进行色域切换,而非转换单个颜色值。)
真实 API 说明 :截至 HarmonyOS NEXT,
@ohos.graphics.colorSpaceManager的核心能力是色域对象的创建与元数据获取,并不直接提供颜色转换 API。颜色的实际转换需要结合 Canvas 的colorSpace属性或通过offlineImageProcessing实现。因此,我们的ColorManager将主要管理画布色域设置,而非单独转换颜色。
修改 ColorManager 以使代码符合文档实际能力:
typescript
// utils/ColorManager.ets (修正版)
import { colorSpaceManager } from '@kit.ArkGraphics2D';
import { hdrCapability } from '@kit.ArkGraphics2D';
export class ColorManager {
private currentColorSpace: colorSpaceManager.ColorSpace | null = null;
private _isHdrSupported: boolean = false;
constructor() {
this.checkHdr();
}
private checkHdr(): void {
try {
this._isHdrSupported = hdrCapability.isHdrSupported();
} catch (e) {
this._isHdrSupported = false;
}
}
get isHdrSupported(): boolean {
return this._isHdrSupported;
}
/**
* 根据色域名称获取 ColorSpace 对象
*/
getColorSpace(name: string): colorSpaceManager.ColorSpace | null {
try {
// 枚举映射
const enumMap: Record<string, number> = {
'SRGB': colorSpaceManager.ColorSpace.SRGB,
'DISPLAY_P3': colorSpaceManager.ColorSpace.DISPLAY_P3,
'BT2020_HLG': colorSpaceManager.ColorSpace.BT2020_HLG,
'BT2020_PQ': colorSpaceManager.ColorSpace.BT2020_PQ,
};
const enumVal = enumMap[name];
if (enumVal === undefined) return null;
return colorSpaceManager.create(enumVal);
} catch (err) {
console.error('getColorSpace error:', err);
return null;
}
}
/**
* 设置当前画布使用的色域(实际使用时需要将 ColorSpace 传给 Canvas 的 colorSpace 属性)
*/
setCanvasColorSpace(ctx: CanvasRenderingContext2D, colorSpaceName: string): void {
const cs = this.getColorSpace(colorSpaceName);
if (cs) {
// CanvasRenderingContext2D 的 colorSpace 属性可赋值 ColorSpace 对象
ctx.colorSpace = cs;
console.info('Canvas 色域切换为:', colorSpaceName);
}
}
}
关键点说明
- Canvas 的
colorSpace属性可以直接接受colorSpaceManager.ColorSpace对象,从而影响后续绘制的颜色渲染。 hdrCapability.isHdrSupported()是@ohos.graphics.hdrCapability的核心方法,调用前需确保设备支持 HDR 显示(如华为 Mate 60 Pro+)。- 色域枚举值随 API 版本可能变化,需参考官方文档。
2.3 完整模块 -- HDRToggle 组件与画布页面集成
创建 HDRToggle 组件,作为工具栏上的一个开关按钮。点击后切换画布的色域(sRGB ↔ Display P3),并展示 HDR 标识。同时,将 ColorManager 注入到画布页面(DrawingBoard)中,实现色彩空间切换。
typescript
// pages/HDRToggle.ets
import { ColorManager } from '../utils/ColorManager';
import { hdrCapability } from '@kit.ArkGraphics2D';
@Component
export struct HDRToggle {
// 从父组件传入的 Canvas 上下文
private canvasContext: CanvasRenderingContext2D;
private colorManager: ColorManager = new ColorManager();
@State isHdrMode: boolean = false;
@State deviceSupportHdr: boolean = this.colorManager.isHdrSupported;
build() {
Row({ space: 8 }) {
// HDR 模式开关
Toggle({ type: ToggleType.Switch, isOn: this.isHdrMode })
.onChange((isOn: boolean) => {
this.isHdrMode = isOn;
if (isOn && this.deviceSupportHdr) {
// 切换至 Display P3 色域(宽色域)
this.colorManager.setCanvasColorSpace(this.canvasContext, 'DISPLAY_P3');
} else {
// 切回 sRGB 标准色域
this.colorManager.setCanvasColorSpace(this.canvasContext, 'SRGB');
}
})
.enabled(this.deviceSupportHdr) // 不支持 HDR 的设备禁用开关
Text(this.isHdrMode ? 'HDR 模式' : '标准模式')
.fontSize(14)
// HDR 图标
if (this.deviceSupportHdr) {
Image($r('app.media.ic_hdr'))
.width(20)
.height(20)
.objectFit(ImageFit.Contain)
} else {
Text('不支持HDR')
.fontSize(12)
.fontColor(Color.Gray)
}
}
.padding(8)
.backgroundColor('#f0f0f0')
.borderRadius(8)
}
}
在主画布页面 pages/DrawingBoard.ets 中引用 HDRToggle,并将 Canvas 上下文传入:
typescript
// pages/DrawingBoard.ets
import { HDRToggle } from './HDRToggle';
// ...其他导入
@Entry
@Component
struct DrawingBoard {
private settings: RenderingContextSettings = new RenderingContextSettings(true);
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
build() {
Column() {
// 顶部工具栏
Row() {
// ...其他工具按钮(画笔、形状等)
HDRToggle({ canvasContext: this.context })
.width('auto')
}
.width('100%')
.height(60)
.padding({ left: 8, right: 8 })
// 画布区域
Canvas(this.context)
.width('100%')
.layoutWeight(1)
.backgroundColor(Color.White)
.onReady(() => {
// 默认使用 sRGB
this.context.colorSpace = this.colorManager.getColorSpace('SRGB');
})
}
.width('100%')
.height('100%')
}
}

关键点说明
HDRToggle组件通过@State响应式管理 HDR 模式状态,切换时调用ColorManager.setCanvasColorSpace()直接修改 Canvas 的colorSpace属性。- 若设备不支持 HDR(
hdrCapability.isHdrSupported()返回 false),开关被禁用,并显示"不支持HDR"文本。 - 需在
resources/base/element中添加ic_hdr.svg图标,或使用系统图标替代(如$media('startIcon'))。
3. 运行验证
编译运行 APP 到支持 HDR 的真机(如 Mate 60 Pro 系列或平板)。预期效果:
- 顶部工具栏出现 HDR 开关(开关默认关闭,显示"标准模式")。
- 点击开关,画布背景色无明显变化,但后续绘制的图形(如矩形、圆形、手绘笔画)颜色会变得更鲜艳(Display P3 色域比 sRGB 多覆盖约 25% 的颜色)。
- 在画布上绘制一笔红色(原本 sRGB 下接近 #FF0000),开启 HDR 模式后,红色可能更明亮、更饱和。您可以通过之前第9篇的智能取色功能提取红色区域,对比 RGB 值变化。
- 若在不支持 HDR 的模拟器或旧设备上运行,开关将变灰,旁边显示"不支持HDR"。
4. 小结与预告
本篇实现了色彩空间转换与 HDR 支持,核心产出:
- ColorManager 封装了
@ohos.graphics.colorSpaceManager和@ohos.graphics.hdrCapability,提供色域创建、Canvas 色域设置、HDR 能力检测。 - HDRToggle 组件集成到工具栏,可一键切换画布色域,让画作在 HDR 设备上呈现更丰富的色彩。
至此,画图 APP 的图形效果处理能力从 sRGB 扩展到宽色域/HDR,为专业绘画用户提供更大创作空间。
下一篇将聚焦 操作历史管理,利用命令模式(Command Pattern)实现绘制操作的撤销与重做。我们将设计操作栈,记录每一步绘制命令,支持无限次撤销(受内存限制),并配套 UI 按钮。敬请期待!