1# 图片解码 2<!--Kit: Image Kit--> 3<!--Subsystem: Multimedia--> 4<!--Owner: @aulight02--> 5<!--Designer: @liyang_bryan--> 6<!--Tester: @xchaosioda--> 7<!--Adviser: @zengyawen--> 8 9> **说明:** 10> 11> 当前开发指导使用的接口为[Image](../../reference/apis-image-kit/capi-image.md)模块下的C API,可完成图片编解码,图片接收器,处理图像数据等功能。这部分API在API 11之前发布,在后续的版本不再增加新功能,**不再推荐使用**。<br> 12> 开发者可使用[Image_NativeModule](../../reference/apis-image-kit/capi-image-nativemodule.md)模块下的C API,不仅提供上述图片框架基础功能,还可以完成多图编解码等新特性,相关开发指导请参考[图片开发指导(C/C++)](image-source-c.md)节点下的内容。这部分API从API 12开始支持,并将持续演进,**推荐开发者使用**。<br> 13> 两套C API不建议同时使用,在部分场景下存在不兼容的问题。 14 15将所支持格式的图片文件解码成PixelMap,以便在应用或系统中进行图片显示或[图片处理](image-transformation.md)。当前支持的图片文件格式包括JPEG、PNG、GIF、WebP、BMP、SVG、ICO、DNG、HEIF(不同硬件设备支持情况不同)。 16 17## 开发步骤 18 19图片解码相关API的详细介绍请参见:[图片解码接口文档](../../reference/apis-image-kit/arkts-apis-image-PixelMap.md)。 20 21### 添加依赖 22 23在进行应用开发之前,开发者需要打开native工程的src/main/cpp/CMakeLists.txt,在target_link_libraries依赖中添加libace_napi.z.so、libpixelmap_ndk.z.so、libimage_source_ndk.z.so、librawfile.z.so以及日志依赖libhilog_ndk.z.so。 24 25```txt 26target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so libpixelmap_ndk.z.so libimage_source_ndk.z.so librawfile.z.so) 27``` 28 29### 添加接口映射 30 31打开src/main/cpp/hello.cpp文件,在Init函数中添加getSyncPixelMap函数接口映射,作用是以同步的方式生成PixelMap,具体代码如下: 32 33```c++ 34EXTERN_C_START 35static napi_value Init(napi_env env, napi_value exports) 36{ 37 napi_property_descriptor desc[] = { 38 { "getSyncPixelMap", nullptr, getSyncPixelMap, nullptr, nullptr, nullptr, napi_default, nullptr }, 39 }; 40 41 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); 42 return exports; 43} 44EXTERN_C_END 45``` 46 47### JS侧调用 48 491. 打开src\main\cpp\types\libentry\index.d.ts(其中libentry根据工程名生成),导入如下引用文件: 50 51 ```js 52 import { image } from '@kit.ImageKit'; 53 import { resourceManager } from '@kit.LocalizationKit'; 54 55 // 同步调用,入参为资源管理器和图片资源名称,返回PixelMap。 56 export const getSyncPixelMap: (resMgr: resourceManager.ResourceManager, src: string) => image.PixelMap; 57 ``` 58 592. 准备图片资源文件,本示例文件名为example.jpg,导入到src\main\resources\rawfile\ 路径下。 60 613. 打开src\main\ets\pages\index.ets,导入"libentry.so(根据工程名生成)",调用Native接口,传入JS的资源对象。示例如下: 62 63 ```js 64 import testNapi from 'libentry.so'; 65 import { image } from '@kit.ImageKit'; 66 import { common } from '@kit.AbilityKit'; 67 @Entry 68 @Component 69 struct Index { 70 @State pixelMap : PixelMap | undefined = undefined; 71 aboutToAppear() { 72 // 请在组件内获取context,确保this.getUIContext().getHostContext()返回结果为UIAbilityContext 73 let context = this.getUIContext().getHostContext() as common.UIAbilityContext; 74 // 调用自定义的getSyncPixelMap接口,获取pixelMap。 75 this.pixelMap = testNapi.getSyncPixelMap(context.resourceManager, "example.jpg"); 76 } 77 78 build() { 79 Row() { 80 Column() { 81 Image(this.pixelMap) 82 .width(100) 83 .height(100) 84 } 85 .width('100%') 86 } 87 .height('100%') 88 } 89 } 90 ``` 91 92### Native接口调用 93 94具体接口说明请参考[API文档](../../reference/apis-image-kit/capi-image.md)。 95 96在hello.cpp文件中获取JS的资源对象,并转为Native的资源对象,即可调用Native接口,调用方式示例代码如下: 97 98**添加引用文件** 99 100```c++ 101// 引入图片框架、raw文件、raw文件管理和日志打印头文件。 102#include <cstdlib> 103#include <cstring> 104#include <multimedia/image_framework/image_source_mdk.h> 105#include <multimedia/image_framework/image_pixel_map_mdk.h> 106#include <rawfile/raw_file.h> 107#include <rawfile/raw_file_manager.h> 108#include <hilog/log.h> 109 110static napi_value getSyncPixelMap(napi_env env, napi_callback_info info) 111{ 112 size_t argc = 2; 113 napi_value args[2] = {nullptr}; 114 115 napi_get_cb_info(env, info, &argc, args , nullptr, nullptr); 116 117 napi_valuetype srcType; 118 napi_typeof(env, args[0], &srcType); 119 120 // 入参args[0]是资源管理器,用来初始化native层的资源管理器。 121 NativeResourceManager *mNativeResMgr = OH_ResourceManager_InitNativeResourceManager(env, args[0]); 122 123 size_t strSize; 124 char srcBuf[2048]; 125 // 入参args[1]是文件名称。 126 napi_get_value_string_utf8(env, args[1], srcBuf, sizeof(srcBuf), &strSize); 127 128 // 用资源管理器打开Raw文件。 129 RawFile * rawFile = OH_ResourceManager_OpenRawFile(mNativeResMgr, srcBuf); 130 if (rawFile != NULL) { 131 // 获取文件大小,并读取数据。 132 long len = OH_ResourceManager_GetRawFileSize(rawFile); 133 uint8_t * data = static_cast<uint8_t *>(malloc(len)); 134 int res = OH_ResourceManager_ReadRawFile(rawFile, data, len); 135 136 OhosImageSource imageSource_c; 137 imageSource_c.buffer = data; 138 imageSource_c.bufferSize = len; 139 140 OhosImageSourceOps ops{}; 141 napi_value imageSource; 142 napi_value pixelMap; 143 144 // 用读取到的Raw数据创建ImageSource。 145 int32_t ret = OH_ImageSource_Create(env, &imageSource_c, &ops, &imageSource); 146 147 // 初始化native层的ImageSource。 148 ImageSourceNative * imageSourceNative_c = OH_ImageSource_InitNative(env, imageSource); 149 OhosImageDecodingOps decodingOps{}; 150 // 创建pixelMap。 151 OH_ImageSource_CreatePixelMap(imageSourceNative_c, &decodingOps, &pixelMap); 152 153 // 下列方法,为gif等动图格式提供。 154 // napi_value pixelMapList; 155 // OH_ImageSource_CreatePixelMapList(imageSourceNative_c, &decodingOps, &pixelMapList); 156 // OhosImageSourceDelayTimeList list{}; 157 // OH_ImageSource_GetDelayTime(imageSourceNative_c, &list); 158 // uint32_t count; 159 // OH_ImageSource_GetFrameCount(imageSourceNative_c, &count); 160 161 OhosImageSourceInfo info{}; 162 // 读取图片宽高。 163 OH_ImageSource_GetImageInfo(imageSourceNative_c, 0, &info); 164 OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "[decode]", "imageInfo width:%{public}d , height:%{public}d", info.size.width, info.size.height); 165 166 // 读取ImageSource的ImageWidth配置参数并打印日志。 167 OhosImageSourceProperty target; 168 char exifKey_c[] = "ImageWidth"; 169 target.size = strlen(exifKey_c); 170 target.value = exifKey_c; 171 172 OhosImageSourceProperty response{}; 173 response.size = 20; 174 response.value = static_cast<char *>(malloc(20)); 175 OH_ImageSource_GetImageProperty(imageSourceNative_c, &target, &response); 176 OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "[decode]", "ImageProperty width after modify:%{public}s", response.value); 177 178 // 处理完毕,释放native层资源。 179 OH_ImageSource_Release(imageSourceNative_c); 180 OH_ResourceManager_CloseRawFile(rawFile); 181 return pixelMap; 182 } 183 OH_ResourceManager_ReleaseNativeResourceManager(mNativeResMgr); 184 return nullptr; 185} 186``` 187 188图片框架支持增量式解码,使用方法如下: 189 190```c++ 191// 引入图片框架、raw文件、raw文件管理和日志打印头文件。 192#include <cstdlib> 193#include <cstring> 194#include <multimedia/image_framework/image_source_mdk.h> 195#include <multimedia/image_framework/image_pixel_map_mdk.h> 196#include <rawfile/raw_file.h> 197#include <rawfile/raw_file_manager.h> 198#include <hilog/log.h> 199 200static napi_value getSyncPixelMap(napi_env env, napi_callback_info info) 201{ 202 size_t argc = 2; 203 napi_value args[2] = {nullptr}; 204 205 napi_get_cb_info(env, info, &argc, args , nullptr, nullptr); 206 207 napi_valuetype srcType; 208 napi_typeof(env, args[0], &srcType); 209 210 // 入参args[0]是资源管理器,用来初始化native层的资源管理器。 211 NativeResourceManager * mNativeResMgr = OH_ResourceManager_InitNativeResourceManager(env, args[0]); 212 213 size_t strSize; 214 char srcBuf[2048]; 215 // 入参args[1]是文件名称。 216 napi_get_value_string_utf8(env, args[1], srcBuf, sizeof(srcBuf), &strSize); 217 218 // 用资源管理器打开Raw文件。 219 RawFile * rawFile = OH_ResourceManager_OpenRawFile(mNativeResMgr, srcBuf); 220 if (rawFile != NULL) { 221 // 获取文件大小,若大于2048字节,则增量式解码,否则直接全部解码。 222 long len = OH_ResourceManager_GetRawFileSize(rawFile); 223 if (len > 2048) { 224 uint8_t * data = static_cast<uint8_t *>(malloc(len)); 225 // 读取文件全部数据。 226 int res = OH_ResourceManager_ReadRawFile(rawFile, data, len); 227 228 uint8_t * holderdata = static_cast<uint8_t *>(malloc(len)); 229 230 OhosImageSource imageSource_c; 231 // imageSource_c的buffer分配了空间,但是数据是空的。 232 imageSource_c.buffer = holderdata; 233 imageSource_c.bufferSize = len; 234 OhosImageSourceOps ops{}; 235 napi_value imageSource; 236 // 初始化增量ImageSource。 237 OH_ImageSource_CreateIncremental(env, &imageSource_c, &ops, &imageSource); 238 239 // 初始化native层的ImageSource。 240 ImageSourceNative * imageSourceNative_c = OH_ImageSource_InitNative(env, imageSource); 241 242 // 以下模拟分片加载场景,分两次加载分片。第一次加载2048字节,第二次加载剩余的数据。 243 OhosImageSourceUpdateData firstData{}; 244 firstData.buffer = data; // 图片数据。 245 firstData.bufferSize = len; // 图片数据总大小。 246 firstData.isCompleted = false; 247 firstData.offset = 0; // 第一次重头开始加载。 248 firstData.updateLength = 2048; // 第一次加载了2048字节。 249 OH_ImageSource_UpdateData(imageSourceNative_c, &firstData); 250 251 OhosImageSourceUpdateData secondData{}; 252 secondData.buffer = data; 253 secondData.bufferSize = len; 254 secondData.isCompleted = true; // 最后一次加载,要标记加载完成。 255 secondData.offset = 2048; // 已经加载过2048字节了,第二次偏移已经加载的量。 256 secondData.updateLength = len - 2048; // 第二次加载剩余的数据。 257 OH_ImageSource_UpdateData(imageSourceNative_c, &secondData); 258 259 napi_value pixelMap; 260 OhosImageDecodingOps decodingOps{}; 261 decodingOps.index = 0; 262 // 创建pixelMap。 263 OH_ImageSource_CreatePixelMap(imageSourceNative_c, &decodingOps, &pixelMap); 264 265 // 处理完毕,释放native层资源。 266 OH_ImageSource_Release(imageSourceNative_c); 267 OH_ResourceManager_CloseRawFile(rawFile); 268 return pixelMap; 269 } 270 // 读取Raw文件全部数据。 271 uint8_t * data = static_cast<uint8_t *>(malloc(len)); 272 int res = OH_ResourceManager_ReadRawFile(rawFile, data, len); 273 274 OhosImageSource imageSource_c; 275 imageSource_c.buffer = data; 276 imageSource_c.bufferSize = len; 277 278 OhosImageSourceOps ops{}; 279 napi_value imageSource; 280 napi_value pixelMap; 281 282 // 用读取到的Raw数据创建ImageSource。 283 int32_t ret = OH_ImageSource_Create(env, &imageSource_c, &ops, &imageSource); 284 285 // 初始化native层的ImageSource。 286 ImageSourceNative * imageSourceNative_c = OH_ImageSource_InitNative(env, imageSource); 287 OhosImageDecodingOps decodingOps{}; 288 289 // 创建pixelMap。 290 OH_ImageSource_CreatePixelMap(imageSourceNative_c, &decodingOps, &pixelMap); 291 292 // 处理完毕,释放native层资源。 293 OH_ImageSource_Release(imageSourceNative_c); 294 OH_ResourceManager_CloseRawFile(rawFile); 295 return pixelMap; 296 } 297 OH_ResourceManager_ReleaseNativeResourceManager(mNativeResMgr); 298 return nullptr; 299} 300``` 301