使用Image_NativeModule解码GIF、WebP等动图资源,获取动图帧数、帧延迟时间,并根据业务需要选择全量解码或逐帧解码方式获取PixelMap。
动图解码主要包含以下流程:
在进行应用开发之前,开发者需要打开native工程的src/main/cpp/CMakeLists.txt,在target_link_libraries依赖中添加libimage_source.so、libpixelmap.so以及日志功能依赖的libhilog_ndk.z.so。
target_link_libraries(entry PUBLIC libhilog_ndk.z.so libimage_source.so libpixelmap.so)
具体接口说明请参考Image_NativeModule。
在DevEco Studio新建Native C++应用,默认生成的项目中包含index.ets文件,在entry\src\main\cpp目录下会自动生成一个cpp文件(hello.cpp或napi_init.cpp,本示例以hello.cpp文件名为例)。在hello.cpp中实现C API接口调用逻辑,示例代码如下:
动图解码接口使用示例
导入相关头文件。
#include <string> #include <hilog/log.h> #include <multimedia/image_framework/image/image_source_native.h> #include <multimedia/image_framework/image/image_common.h> #include <multimedia/image_framework/image/pixelmap_native.h> #include "napi/native_api.h" #include <imageKits.h>
日志宏定义可参考下述代码按实际需求自行修改。
#undef LOG_DOMAIN #undef LOG_TAG #define LOG_DOMAIN 0x3200 #define LOG_TAG "IMAGE_SAMPLE"
定义动图解码相关类,用于保存ImageSource实例、帧数和解码得到的PixelMap对象。
class ImageAnimatedNative {
public:
OH_ImageSourceNative *source = nullptr;
OH_PixelmapNative **pixelMapList = nullptr;
OH_PixelmapNative *pixelMap = nullptr;
uint32_t frameCnt = 0;
size_t pixelMapListSize = 0;
ImageAnimatedNative() {}
~ImageAnimatedNative() {}
}; 创建ImageAnimatedNative实例。
static ImageAnimatedNative *g_thisAnimated = new ImageAnimatedNative();
创建GetJsResult函数处理napi返回值。
// 处理napi返回值。
napi_value GetJsResult(napi_env env, int result)
{
napi_value resultNapi = nullptr;
napi_create_int32(env, result, &resultNapi);
return resultNapi;
} 常量定义。
const int ANIMATED_MAX_STRING_LENGTH = 1024;
创建ImageSource实例。
// 创建ImageSource实例。
napi_value CreateAnimatedImageSource(napi_env env, napi_callback_info info)
{
napi_value argValue[1] = {nullptr};
size_t argCount = 1;
if (napi_get_cb_info(env, info, &argCount, argValue, nullptr, nullptr) != napi_ok ||
argCount < 1 || argValue[0] == nullptr) {
OH_LOG_ERROR(LOG_APP, "CreateAnimatedImageSource napi_get_cb_info failed!");
return GetJsResult(env, IMAGE_BAD_PARAMETER);
}
char filePath[ANIMATED_MAX_STRING_LENGTH];
size_t pathSize = ANIMATED_MAX_STRING_LENGTH;
napi_get_value_string_utf8(env, argValue[0], filePath, ANIMATED_MAX_STRING_LENGTH, &pathSize);
if (g_thisAnimated->source != nullptr) {
ReleaseAnimatedImageSource(env, info);
}
Image_ErrorCode errCode = OH_ImageSourceNative_CreateFromUri(filePath, pathSize, &g_thisAnimated->source);
return ReturnAnimatedErrorCode(env, errCode, "OH_ImageSourceNative_CreateFromUri");
} 获取图片帧数。帧数大于1时,可按动图处理。
// 获取图像帧数。帧数大于1时,可按动图处理。
napi_value GetAnimatedFrameCount(napi_env env, napi_callback_info info)
{
if (g_thisAnimated->source == nullptr) {
OH_LOG_ERROR(LOG_APP, "ImageSource is nullptr.");
return GetJsResult(env, IMAGE_BAD_PARAMETER);
}
Image_ErrorCode errCode = OH_ImageSourceNative_GetFrameCount(g_thisAnimated->source, &g_thisAnimated->frameCnt);
if (errCode != IMAGE_SUCCESS) {
return ReturnAnimatedErrorCode(env, errCode, "OH_ImageSourceNative_GetFrameCount");
}
OH_LOG_INFO(LOG_APP, "Frame count: %{public}u.", g_thisAnimated->frameCnt);
return GetJsResult(env, g_thisAnimated->frameCnt);
} 获取动图帧延迟时间列表。延迟时间列表用于控制每帧显示时长。
// 获取图像延迟时间列表。
napi_value GetAnimatedDelayTimeList(napi_env env, napi_callback_info info)
{
if (g_thisAnimated->source == nullptr || g_thisAnimated->frameCnt == 0) {
OH_LOG_ERROR(LOG_APP, "Invalid ImageSource or frame count.");
return GetJsResult(env, IMAGE_BAD_PARAMETER);
}
int32_t *delayTimeList = new int32_t[g_thisAnimated->frameCnt];
size_t size = g_thisAnimated->frameCnt;
Image_ErrorCode errCode = OH_ImageSourceNative_GetDelayTimeList(g_thisAnimated->source, delayTimeList, size);
if (errCode == IMAGE_SUCCESS) {
for (size_t index = 0; index < size; index++) {
OH_LOG_INFO(LOG_APP, "Frame %{public}zu delay time: %{public}d ms.", index, delayTimeList[index]);
}
}
delete[] delayTimeList;
delayTimeList = nullptr;
return ReturnAnimatedErrorCode(env, errCode, "OH_ImageSourceNative_GetDelayTimeList");
} 解码动图帧。
动图帧解码可以根据业务场景选择全量解码或逐帧解码。
全量解码动图帧示例如下。
// 通过图片解码参数创建PixelMap列表。
napi_value CreateAnimatedPixelmapList(napi_env env, napi_callback_info info)
{
if (g_thisAnimated->source == nullptr || g_thisAnimated->frameCnt == 0) {
OH_LOG_ERROR(LOG_APP, "Invalid ImageSource or frame count.");
return GetJsResult(env, IMAGE_BAD_PARAMETER);
}
ReleaseAnimatedPixelmapList();
OH_DecodingOptions *opts = nullptr;
Image_ErrorCode errCode = OH_DecodingOptions_Create(&opts);
if (errCode != IMAGE_SUCCESS || opts == nullptr) {
return ReturnAnimatedErrorCode(env, errCode, "OH_DecodingOptions_Create");
}
g_thisAnimated->pixelMapList = new OH_PixelmapNative *[g_thisAnimated->frameCnt]();
g_thisAnimated->pixelMapListSize = g_thisAnimated->frameCnt;
errCode = OH_ImageSourceNative_CreatePixelmapList(g_thisAnimated->source, opts,
g_thisAnimated->pixelMapList, g_thisAnimated->pixelMapListSize);
OH_DecodingOptions_Release(opts);
opts = nullptr;
if (errCode != IMAGE_SUCCESS) {
ReleaseAnimatedPixelmapList();
return ReturnAnimatedErrorCode(env, errCode, "OH_ImageSourceNative_CreatePixelmapList");
}
OH_LOG_INFO(LOG_APP, "Create %{public}zu pixelmaps.", g_thisAnimated->pixelMapListSize);
return GetJsResult(env, errCode);
} 按索引解码指定帧示例如下。
// 通过帧索引创建指定帧PixelMap。
napi_value CreateAnimatedPixelmapByIndex(napi_env env, napi_callback_info info)
{
if (g_thisAnimated->source == nullptr || g_thisAnimated->frameCnt == 0) {
OH_LOG_ERROR(LOG_APP, "Invalid ImageSource or frame count.");
return GetJsResult(env, IMAGE_BAD_PARAMETER);
}
napi_value argValue[1] = {nullptr};
size_t argCount = 1;
if (napi_get_cb_info(env, info, &argCount, argValue, nullptr, nullptr) != napi_ok ||
argCount < 1 || argValue[0] == nullptr) {
OH_LOG_ERROR(LOG_APP, "CreateAnimatedPixelmapByIndex napi_get_cb_info failed!");
return GetJsResult(env, IMAGE_BAD_PARAMETER);
}
uint32_t index = 0;
napi_get_value_uint32(env, argValue[0], &index);
if (index >= g_thisAnimated->frameCnt) {
OH_LOG_ERROR(LOG_APP, "Invalid frame index: %{public}u.", index);
return GetJsResult(env, IMAGE_BAD_PARAMETER);
}
OH_DecodingOptions *opts = nullptr;
Image_ErrorCode errCode = OH_DecodingOptions_Create(&opts);
if (errCode != IMAGE_SUCCESS || opts == nullptr) {
return ReturnAnimatedErrorCode(env, errCode, "OH_DecodingOptions_Create");
}
OH_DecodingOptions_SetIndex(opts, index);
if (g_thisAnimated->pixelMap != nullptr) {
OH_PixelmapNative_Release(g_thisAnimated->pixelMap);
g_thisAnimated->pixelMap = nullptr;
}
errCode = OH_ImageSourceNative_CreatePixelmap(g_thisAnimated->source, opts, &g_thisAnimated->pixelMap);
OH_DecodingOptions_Release(opts);
opts = nullptr;
return ReturnAnimatedErrorCode(env, errCode, "OH_ImageSourceNative_CreatePixelmap");
} 释放资源。
使用完成后,需要释放ImageSource、PixelMap列表、单帧PixelMap等资源。
// 释放动图解码相关资源。
napi_value ReleaseAnimatedImageSource(napi_env env, napi_callback_info info)
{
ReleaseAnimatedPixelmapList();
if (g_thisAnimated->pixelMap != nullptr) {
OH_PixelmapNative_Release(g_thisAnimated->pixelMap);
g_thisAnimated->pixelMap = nullptr;
}
Image_ErrorCode errCode = IMAGE_SUCCESS;
if (g_thisAnimated->source != nullptr) {
errCode = OH_ImageSourceNative_Release(g_thisAnimated->source);
g_thisAnimated->source = nullptr;
}
g_thisAnimated->frameCnt = 0;
return ReturnAnimatedErrorCode(env, errCode, "OH_ImageSourceNative_Release");
}