HarmonyOS APP实战-画图APP - 第10篇:色彩管理功能

HarmonyOS APP实战-画图APP - 第10篇:色彩空间转换与HDR支持

1. 开篇

在上一篇中,我们实现了智能取色与色板生成功能------通过 @ohos.effectKitColorPicker 提取图像主色,并动态生成五色色板供用户快速选择。用户点击画布任意区域即可获取该区域主色,色板同步更新,大大提升了取色效率。

然而,显示设备的色彩能力千差万别。目前 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 中,包含 SRGBDISPLAY_P3BT2020_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 系列或平板)。预期效果:

  1. 顶部工具栏出现 HDR 开关(开关默认关闭,显示"标准模式")。
  2. 点击开关,画布背景色无明显变化,但后续绘制的图形(如矩形、圆形、手绘笔画)颜色会变得更鲜艳(Display P3 色域比 sRGB 多覆盖约 25% 的颜色)。
  3. 在画布上绘制一笔红色(原本 sRGB 下接近 #FF0000),开启 HDR 模式后,红色可能更明亮、更饱和。您可以通过之前第9篇的智能取色功能提取红色区域,对比 RGB 值变化。
  4. 若在不支持 HDR 的模拟器或旧设备上运行,开关将变灰,旁边显示"不支持HDR"。

4. 小结与预告

本篇实现了色彩空间转换与 HDR 支持,核心产出:

  • ColorManager 封装了 @ohos.graphics.colorSpaceManager@ohos.graphics.hdrCapability,提供色域创建、Canvas 色域设置、HDR 能力检测。
  • HDRToggle 组件集成到工具栏,可一键切换画布色域,让画作在 HDR 设备上呈现更丰富的色彩。

至此,画图 APP 的图形效果处理能力从 sRGB 扩展到宽色域/HDR,为专业绘画用户提供更大创作空间。

下一篇将聚焦 操作历史管理,利用命令模式(Command Pattern)实现绘制操作的撤销与重做。我们将设计操作栈,记录每一步绘制命令,支持无限次撤销(受内存限制),并配套 UI 按钮。敬请期待!

相关推荐
●VON1 小时前
HarmonyKit | 鸿蒙开发协作:如何为 HarmonyKit 贡献一个新的工具
git·华为·harmonyos·鸿蒙
2301_768103491 小时前
HarmonyOS趣味相机实战第1篇:工程结构、相机权限申请与真实拍摄主流程
harmonyos·arkts·项目实战·水印相机·camerakit
木木子222 小时前
# [特殊字符] 养猫模拟器 — 鸿蒙ArkTS完整技术解析
华为·harmonyos
anling_li2 小时前
《图片华容道》三、HarmonyOS_ArkTS开发调试实战_崩溃修复全记录
ui·华为·harmonyos
千逐682 小时前
鸿蒙实战:元服务与卡片开发全攻略
华为·harmonyos·鸿蒙
国服第二切图仔11 小时前
HarmonyOS APP《画伴梦工厂》开发第61篇-鸿蒙内核应用快启与GraphicsAccelerateKit
华为·harmonyos
anling_li11 小时前
《随机乱序键盘》四、简约风格随机乱序键盘案例指南
ui·华为·harmonyos
w1395485642214 小时前
鸿蒙实战:PhoneLoginPage 6位验证码 Cell 设计与 60 秒倒计时
华为·harmonyos·鸿蒙系统
xd18557855514 小时前
敲门砖工坊-求职信定制的HarmonyOS开发实践
人工智能·华为·harmonyos·鸿蒙