文档管理中心
我的

使用Image_NativeModule完成HDR图片解码

使用Image_NativeModule解码HDR图片,获取解码结果的动态范围信息,并根据业务需要处理HDR图片、SDR图片和带有GainMap辅助图的Picture对象。

HDR(High Dynamic Range,高动态范围)图片相比SDR(Standard Dynamic Range,标准动态范围)图片,可以记录更丰富的亮度层次和色彩信息。应用在解码HDR图片时,需要关注图片源是否包含HDR信息、设备是否支持HDR解码、解码结果是否仍为HDR,以及后续显示、编辑、编码或分享场景是否需要回退为SDR。当前系统仅支持JPEG格式和HEIF格式的HDR图片,且在接口调用方未主动配置相关参数的情况下,默认使用SDR处理。

HDR图片解码主要包含以下流程:

  1. 创建ImageSource实例。
  2. 根据业务需要选择解码路径:
    • PixelMap路径:创建解码参数,设置期望的动态范围,调用解码接口获取PixelMap。
    • Picture路径:解码为Picture对象,可分别获取SDR主图和GainMap增益图,并按需合成HDR图。
  3. 如果使用PixelMap路径,获取PixelMap图像信息,判断解码结果是否为HDR。
  4. 如果使用Picture路径,可根据业务场景进行以下处理:
  5. 使用完成后释放ImageSource、PixelMap、Picture和解码参数等资源。

基本概念

在进行HDR图片开发前,建议先了解以下概念。

展开
概念 说明
SDR 标准动态范围图像,适用于普通显示、编辑和分享场景。
HDR 高动态范围图像,可表达更高亮度范围和更丰富的明暗层次,显示效果依赖图片数据、设备能力和显示链路。
动态范围 表示图像亮度信息的表达范围。解码时可通过动态范围参数指定期望输出HDR或SDR。
GainMap 一种HDR兼容方案,图片中包含SDR主图和表示亮度增益信息的辅助图。支持HDR的设备可结合主图和GainMap生成HDR效果;不支持HDR时可使用SDR主图进行兼容显示。
Picture 多图对象,可承载主图和辅助图。对于带GainMap的图片,可通过Picture相关接口获取辅助图或合成HDR PixelMap。
说明

HDR解码结果受图片格式、图片元数据、设备能力、解码参数和内存类型等因素影响。源图为HDR图片时,解码结果不一定始终为HDR;当设备或参数不满足条件时,可能回退为SDR结果。

开发步骤

添加链接库

在进行应用开发之前,开发者需要打开native工程的src/main/cpp/CMakeLists.txt,在target_link_libraries依赖中添加libimage_source.so、libpixelmap.so、libpicture.so、libimage_packer.so以及日志功能依赖的libhilog_ndk.z.so。

收起
自动换行
深色代码主题
复制
  1. target_link_libraries(entry PUBLIC libhilog_ndk.z.so libimage_source.so libpixelmap.so libpicture.so libimage_packer.so)

Native接口调用

具体接口说明请参考Image_NativeModule。

在DevEco Studio新建Native C++应用,默认生成的项目中包含index.ets文件,在entry\src\main\cpp目录下会自动生成一个cpp文件(hello.cpp或napi_init.cpp,本示例以hello.cpp文件名为例)。在hello.cpp中实现C API接口调用逻辑,示例代码如下:

  1. 导入相关头文件。

    收起
    自动换行
    深色代码主题
    复制
    1. #include <cstring>
    2. #include <string>
    3. #include <hilog/log.h>
    4. #include <multimedia/image_framework/image/image_common.h>
    5. #include <multimedia/image_framework/image/image_source_native.h>
    6. #include <multimedia/image_framework/image/pixelmap_native.h>
    7. #include <multimedia/image_framework/image/picture_native.h>
    8. #include <multimedia/image_framework/image/image_packer_native.h>
    9. #include "napi/native_api.h"
    10. #include <imageKits.h>
  2. 日志宏定义可参考下述代码按实际需求自行修改。

    收起
    自动换行
    深色代码主题
    复制
    1. #undef LOG_DOMAIN
    2. #undef LOG_TAG
    3. #define LOG_DOMAIN 0x3200
    4. #define LOG_TAG "IMAGE_SAMPLE"
  3. 定义HDR图片解码相关类,用于保存ImageSource、PixelMap、Picture和解码结果信息。

    收起
    自动换行
    深色代码主题
    复制
    1. class ImageHdrColorSpaceNative {
    2. public:
    3. OH_ImageSourceNative *source = nullptr;
    4. OH_PixelmapNative *pixelMap = nullptr;
    5. OH_PixelmapNative *mainPixelMap = nullptr;
    6. OH_PixelmapNative *gainmapPixelMap = nullptr;
    7. OH_PixelmapNative *hdrPixelMap = nullptr;
    8. OH_Pixelmap_ImageInfo *pixelMapImageInfo = nullptr;
    9. OH_PictureNative *picture = nullptr;
    10. bool isHdr = false;
    11. ImageHdrColorSpaceNative() {}
    12. ~ImageHdrColorSpaceNative() {}
    13. };
  4. 创建ImageHdrColorSpaceNative实例。

    收起
    自动换行
    深色代码主题
    复制
    1. static ImageHdrColorSpaceNative *g_hdrColorSpace = new ImageHdrColorSpaceNative();
  5. 创建GetJsResult函数处理napi返回值。

    收起
    自动换行
    深色代码主题
    复制
    1. // 处理napi返回值。
    2. napi_value GetJsResult(napi_env env, int result)
    3. {
    4. napi_value resultNapi = nullptr;
    5. napi_create_int32(env, result, &resultNapi);
    6. return resultNapi;
    7. }
  6. 常量定义。

    收起
    自动换行
    深色代码主题
    复制
    1. const int MAX_STRING_LENGTH = 1024;
  7. 创建ImageSource实例。

    ImageSource用于管理图片源数据。后续HDR解码、Picture解码和图片信息获取均基于ImageSource完成。

    收起
    自动换行
    深色代码主题
    复制
    1. napi_value CreateHdrImageSource(napi_env env, napi_callback_info info)
    2. {
    3. napi_value argValue[1] = {nullptr};
    4. size_t argCount = 1;
    5. if (napi_get_cb_info(env, info, &argCount, argValue, nullptr, nullptr) != napi_ok ||
    6. argCount < 1 || argValue[0] == nullptr) {
    7. OH_LOG_ERROR(LOG_APP, "CreateHdrImageSource napi_get_cb_info failed!");
    8. return GetJsResult(env, IMAGE_BAD_PARAMETER);
    9. }
    10. if (g_hdrColorSpace->source != nullptr) {
    11. ReleaseHdrColorSpaceSource(env, info);
    12. }
    13. char filePath[MAX_STRING_LENGTH];
    14. size_t pathSize = MAX_STRING_LENGTH;
    15. napi_get_value_string_utf8(env, argValue[0], filePath, MAX_STRING_LENGTH, &pathSize);
    16. Image_ErrorCode errCode = OH_ImageSourceNative_CreateFromUri(filePath, pathSize, &g_hdrColorSpace->source);
    17. return ReturnHdrErrorCode(env, errCode, "OH_ImageSourceNative_CreateFromUri");
    18. }
  8. 设置动态范围并解码为PixelMap。

    使用OH_DecodingOptions_SetDesiredDynamicRange设置期望的解码动态范围。常用动态范围策略如下:

    展开
    动态范围策略 说明
    IMAGE_DYNAMIC_RANGE_AUTO 根据图片源和设备能力自适应解码。源图为HDR且设备支持时,解码结果可能为HDR;否则可能输出SDR。
    IMAGE_DYNAMIC_RANGE_HDR 期望输出HDR结果。实际结果仍受图片源、设备能力和解码条件影响。
    IMAGE_DYNAMIC_RANGE_SDR 期望输出SDR结果,适用于普通显示、编辑、分享或兼容性优先的场景。
    收起
    自动换行
    深色代码主题
    复制
    1. napi_value DecodeHdrPixelMap(napi_env env, napi_callback_info info)
    2. {
    3. if (g_hdrColorSpace->source == nullptr) {
    4. OH_LOG_ERROR(LOG_APP, "ImageSource is nullptr.");
    5. return GetJsResult(env, IMAGE_BAD_PARAMETER);
    6. }
    7. OH_DecodingOptions *opts = nullptr;
    8. Image_ErrorCode errCode = OH_DecodingOptions_Create(&opts);
    9. if (errCode != IMAGE_SUCCESS || opts == nullptr) {
    10. return ReturnHdrErrorCode(env, errCode, "OH_DecodingOptions_Create");
    11. }
    12. OH_DecodingOptions_SetDesiredDynamicRange(opts, IMAGE_DYNAMIC_RANGE_AUTO);
    13. ReleasePixelMap(&g_hdrColorSpace->pixelMap);
    14. errCode = OH_ImageSourceNative_CreatePixelmap(g_hdrColorSpace->source, opts, &g_hdrColorSpace->pixelMap);
    15. OH_DecodingOptions_Release(opts);
    16. opts = nullptr;
    17. return ReturnHdrErrorCode(env, errCode, "OH_ImageSourceNative_CreatePixelmap");
    18. }
  9. 判断PixelMap解码结果是否为HDR。

    解码完成后,可以通过OH_PixelmapNative_GetImageInfo获取PixelMap图像信息,再通过OH_PixelmapImageInfo_GetDynamicRange判断解码结果是否为HDR。该结果表示当前PixelMap的动态范围,不等同于源图片文件一定是HDR或SDR。

    收起
    自动换行
    深色代码主题
    复制
    1. napi_value CheckHdrDynamicRange(napi_env env, napi_callback_info info)
    2. {
    3. if (g_hdrColorSpace->pixelMap == nullptr) {
    4. OH_LOG_ERROR(LOG_APP, "PixelMap is nullptr.");
    5. return GetJsResult(env, IMAGE_BAD_PARAMETER);
    6. }
    7. Image_ErrorCode errCode = OH_PixelmapImageInfo_Create(&g_hdrColorSpace->pixelMapImageInfo);
    8. if (errCode != IMAGE_SUCCESS || g_hdrColorSpace->pixelMapImageInfo == nullptr) {
    9. return ReturnHdrErrorCode(env, errCode, "OH_PixelmapImageInfo_Create");
    10. }
    11. errCode = OH_PixelmapNative_GetImageInfo(g_hdrColorSpace->pixelMap, g_hdrColorSpace->pixelMapImageInfo);
    12. if (errCode != IMAGE_SUCCESS) {
    13. OH_PixelmapImageInfo_Release(g_hdrColorSpace->pixelMapImageInfo);
    14. g_hdrColorSpace->pixelMapImageInfo = nullptr;
    15. return ReturnHdrErrorCode(env, errCode, "OH_PixelmapNative_GetImageInfo");
    16. }
    17. bool isHdr = false;
    18. errCode = OH_PixelmapImageInfo_GetDynamicRange(g_hdrColorSpace->pixelMapImageInfo, &isHdr);
    19. if (errCode == IMAGE_SUCCESS) {
    20. g_hdrColorSpace->isHdr = isHdr;
    21. OH_LOG_INFO(LOG_APP, "PixelMap dynamic range is %{public}s.", isHdr ? "HDR" : "SDR");
    22. }
    23. OH_PixelmapImageInfo_Release(g_hdrColorSpace->pixelMapImageInfo);
    24. g_hdrColorSpace->pixelMapImageInfo = nullptr;
    25. return ReturnHdrErrorCode(env, errCode, "OH_PixelmapImageInfo_GetDynamicRange");
    26. }
  10. 以SDR方式解码图片。

    当应用需要兼容普通显示、编辑、分享或不支持HDR的场景时,可以将期望动态范围设置为IMAGE_DYNAMIC_RANGE_SDR。该方式可作为HDR解码失败或设备不支持HDR时的降级处理。

    收起
    自动换行
    深色代码主题
    复制
    1. napi_value DecodeSdrPixelMap(napi_env env, napi_callback_info info)
    2. {
    3. if (g_hdrColorSpace->source == nullptr) {
    4. OH_LOG_ERROR(LOG_APP, "ImageSource is nullptr.");
    5. return GetJsResult(env, IMAGE_BAD_PARAMETER);
    6. }
    7. OH_DecodingOptions *opts = nullptr;
    8. Image_ErrorCode errCode = OH_DecodingOptions_Create(&opts);
    9. if (errCode != IMAGE_SUCCESS || opts == nullptr) {
    10. return ReturnHdrErrorCode(env, errCode, "OH_DecodingOptions_Create");
    11. }
    12. OH_DecodingOptions_SetDesiredDynamicRange(opts, IMAGE_DYNAMIC_RANGE_SDR);
    13. ReleasePixelMap(&g_hdrColorSpace->pixelMap);
    14. errCode = OH_ImageSourceNative_CreatePixelmap(g_hdrColorSpace->source, opts, &g_hdrColorSpace->pixelMap);
    15. OH_DecodingOptions_Release(opts);
    16. opts = nullptr;
    17. return ReturnHdrErrorCode(env, errCode, "OH_ImageSourceNative_CreatePixelmap");
    18. }
  11. 解码为Picture。

    Picture是Image Kit中用于承载主图和辅助图的图像结构。对于带GainMap的HDR图片,Picture可以同时提供SDR主图、GainMap增益图和合成后的HDR图,方便应用根据设备能力和业务场景选择不同处理路径:

    • 需要兼容普通显示或分享时,可使用SDR主图。
    • 需要用于HDR显示或处理时,可合成HDR PixelMap。
    收起
    自动换行
    深色代码主题
    复制
    1. napi_value DecodeHdrPicture(napi_env env, napi_callback_info info)
    2. {
    3. if (g_hdrColorSpace->source == nullptr) {
    4. OH_LOG_ERROR(LOG_APP, "ImageSource is nullptr.");
    5. return GetJsResult(env, IMAGE_BAD_PARAMETER);
    6. }
    7. OH_DecodingOptionsForPicture *options = nullptr;
    8. Image_ErrorCode errCode = OH_DecodingOptionsForPicture_Create(&options);
    9. if (errCode != IMAGE_SUCCESS || options == nullptr) {
    10. return ReturnHdrErrorCode(env, errCode, "OH_DecodingOptionsForPicture_Create");
    11. }
    12. Image_AuxiliaryPictureType desiredAuxiliaryPictures[] = { AUXILIARY_PICTURE_TYPE_GAINMAP };
    13. errCode = OH_DecodingOptionsForPicture_SetDesiredAuxiliaryPictures(options, desiredAuxiliaryPictures, 1);
    14. if (errCode != IMAGE_SUCCESS) {
    15. OH_DecodingOptionsForPicture_Release(options);
    16. options = nullptr;
    17. return ReturnHdrErrorCode(env, errCode, "OH_DecodingOptionsForPicture_SetDesiredAuxiliaryPictures");
    18. }
    19. if (g_hdrColorSpace->picture != nullptr) {
    20. OH_PictureNative_Release(g_hdrColorSpace->picture);
    21. g_hdrColorSpace->picture = nullptr;
    22. }
    23. errCode = OH_ImageSourceNative_CreatePicture(g_hdrColorSpace->source, options, &g_hdrColorSpace->picture);
    24. OH_DecodingOptionsForPicture_Release(options);
    25. options = nullptr;
    26. return ReturnHdrErrorCode(env, errCode, "OH_ImageSourceNative_CreatePicture");
    27. }
  12. 从Picture获取SDR主图。

    SDR主图可用于普通显示、编辑、分享或HDR处理失败时的回退显示。对于带GainMap的HDR图片,主图通常是兼容SDR显示链路的图像数据。

    收起
    自动换行
    深色代码主题
    复制
    1. napi_value GetMainPixelmapFromPicture(napi_env env, napi_callback_info info)
    2. {
    3. if (g_hdrColorSpace->picture == nullptr) {
    4. OH_LOG_ERROR(LOG_APP, "Picture is nullptr.");
    5. return GetJsResult(env, IMAGE_BAD_PARAMETER);
    6. }
    7. ReleasePixelMap(&g_hdrColorSpace->mainPixelMap);
    8. Image_ErrorCode errCode = OH_PictureNative_GetMainPixelmap(g_hdrColorSpace->picture,
    9. &g_hdrColorSpace->mainPixelMap);
    10. return ReturnHdrErrorCode(env, errCode, "OH_PictureNative_GetMainPixelmap");
    11. }
  13. 从Picture获取GainMap增益图。

    GainMap记录用于从SDR主图还原或增强HDR效果的增益信息。应用如果需要自定义HDR处理,可获取GainMap PixelMap进行后续处理。

    收起
    自动换行
    深色代码主题
    复制
    1. napi_value GetGainmapPixelmapFromPicture(napi_env env, napi_callback_info info)
    2. {
    3. if (g_hdrColorSpace->picture == nullptr) {
    4. OH_LOG_ERROR(LOG_APP, "Picture is nullptr.");
    5. return GetJsResult(env, IMAGE_BAD_PARAMETER);
    6. }
    7. ReleasePixelMap(&g_hdrColorSpace->gainmapPixelMap);
    8. Image_ErrorCode errCode = OH_PictureNative_GetGainmapPixelmap(g_hdrColorSpace->picture,
    9. &g_hdrColorSpace->gainmapPixelMap);
    10. return ReturnHdrErrorCode(env, errCode, "OH_PictureNative_GetGainmapPixelmap");
    11. }
  14. 从Picture获取HDR合成图。

    当Picture中包含有效GainMap时,可直接获取合成后的HDR PixelMap。若Picture中不包含GainMap,接口可能返回IMAGE_UNSUPPORTED_OPERATION,应用可回退到SDR主图。

    收起
    自动换行
    深色代码主题
    复制
    1. napi_value GetHdrComposedPixelmapFromPicture(napi_env env, napi_callback_info info)
    2. {
    3. if (g_hdrColorSpace->picture == nullptr) {
    4. OH_LOG_ERROR(LOG_APP, "Picture is nullptr.");
    5. return GetJsResult(env, IMAGE_BAD_PARAMETER);
    6. }
    7. ReleasePixelMap(&g_hdrColorSpace->hdrPixelMap);
    8. Image_ErrorCode errCode = OH_PictureNative_GetHdrComposedPixelmap(g_hdrColorSpace->picture,
    9. &g_hdrColorSpace->hdrPixelMap);
    10. return ReturnHdrErrorCode(env, errCode, "OH_PictureNative_GetHdrComposedPixelmap");
    11. }
  15. 对HDR PixelMap进行编码。

    如果应用需要将处理后的HDR PixelMap保存为文件,可通过ImagePacker设置编码参数。编码结果是否为HDR与源PixelMap动态范围、编码格式、设备能力和编码参数有关。若业务仅要求兼容分享或普通显示,可优先编码为SDR结果。

    收起
    自动换行
    深色代码主题
    复制
    1. napi_value PackHdrPixelMap(napi_env env, napi_callback_info info)
    2. {
    3. if (g_hdrColorSpace->pixelMap == nullptr) {
    4. OH_LOG_ERROR(LOG_APP, "PixelMap is nullptr.");
    5. return GetJsResult(env, IMAGE_BAD_PARAMETER);
    6. }
    7. napi_value argValue[1] = {nullptr};
    8. size_t argCount = 1;
    9. if (napi_get_cb_info(env, info, &argCount, argValue, nullptr, nullptr) != napi_ok ||
    10. argCount < 1 || argValue[0] == nullptr) {
    11. OH_LOG_ERROR(LOG_APP, "PackHdrPixelMap napi_get_cb_info failed!");
    12. return GetJsResult(env, IMAGE_BAD_PARAMETER);
    13. }
    14. int32_t fd = -1;
    15. napi_get_value_int32(env, argValue[0], &fd);
    16. OH_ImagePackerNative *packer = nullptr;
    17. Image_ErrorCode errCode = OH_ImagePackerNative_Create(&packer);
    18. if (errCode != IMAGE_SUCCESS || packer == nullptr) {
    19. return ReturnHdrErrorCode(env, errCode, "OH_ImagePackerNative_Create");
    20. }
    21. OH_PackingOptions *packingOptions = nullptr;
    22. errCode = OH_PackingOptions_Create(&packingOptions);
    23. if (errCode != IMAGE_SUCCESS || packingOptions == nullptr) {
    24. OH_ImagePackerNative_Release(packer);
    25. packer = nullptr;
    26. return ReturnHdrErrorCode(env, errCode, "OH_PackingOptions_Create");
    27. }
    28. char type[] = "image/jpeg";
    29. Image_MimeType mimeType = {type, strlen(type)};
    30. OH_PackingOptions_SetMimeType(packingOptions, &mimeType);
    31. // 设置编码质量。quality默认值为0,建议不低于80;本示例统一设置为90,兼顾图片质量和文件体积。
    32. uint32_t quality = 90;
    33. OH_PackingOptions_SetQuality(packingOptions, quality);
    34. OH_PackingOptions_SetDesiredDynamicRange(packingOptions, IMAGE_PACKER_DYNAMIC_RANGE_AUTO);
    35. errCode = OH_ImagePackerNative_PackToFileFromPixelmap(packer, packingOptions, g_hdrColorSpace->pixelMap, fd);
    36. OH_PackingOptions_Release(packingOptions);
    37. packingOptions = nullptr;
    38. OH_ImagePackerNative_Release(packer);
    39. packer = nullptr;
    40. return ReturnHdrErrorCode(env, errCode, "OH_ImagePackerNative_PackToFileFromPixelmap");
    41. }
  16. 释放资源。

    使用完成后,需要释放ImageSource、PixelMap、Picture等资源,避免内存泄漏。

    收起
    自动换行
    深色代码主题
    复制
    1. napi_value ReleaseHdrColorSpaceSource(napi_env env, napi_callback_info info)
    2. {
    3. Image_ErrorCode errCode = IMAGE_SUCCESS;
    4. ReleasePixelMap(&g_hdrColorSpace->hdrPixelMap);
    5. ReleasePixelMap(&g_hdrColorSpace->gainmapPixelMap);
    6. ReleasePixelMap(&g_hdrColorSpace->mainPixelMap);
    7. if (g_hdrColorSpace->picture != nullptr) {
    8. errCode = OH_PictureNative_Release(g_hdrColorSpace->picture);
    9. g_hdrColorSpace->picture = nullptr;
    10. }
    11. ReleasePixelMap(&g_hdrColorSpace->pixelMap);
    12. if (g_hdrColorSpace->source != nullptr) {
    13. errCode = OH_ImageSourceNative_Release(g_hdrColorSpace->source);
    14. g_hdrColorSpace->source = nullptr;
    15. }
    16. g_hdrColorSpace->isHdr = false;
    17. return ReturnHdrErrorCode(env, errCode, "ReleaseHdrColorSpaceSource");
    18. }

约束与限制

  • HDR解码结果受图片源、设备能力、解码参数、内存类型和系统能力影响。源图为HDR时,解码结果不一定为HDR。
  • 使用IMAGE_DYNAMIC_RANGE_AUTO时,系统会根据图片源和设备能力选择合适的解码结果。应用可通过OH_PixelmapImageInfo_GetDynamicRange确认实际结果。
  • IMAGE_DYNAMIC_RANGE_SDR可作为兼容性优先场景的选择。
  • 编码HDR图片时,需要结合编码格式、源PixelMap动态范围和设备能力进行判断;如果编码失败,会返回错误码,应用需处理该错误,提供SDR编码兜底或错误提示。