目录

Image Decoding

Image files in supported formats can be decoded into PixelMaps for image display or image processing in an app or system.

Currently supported image file formats include JPEG, PNG, GIF, WebP, BMP, SVG, ICO, DNG, HEIC, WBMP23+, HEIFS23+, and TIFF23+.

Starting from API version 26.0.0, AVIF and AVIS formats are also supported.

The decoding capability for some formats depends on the specific device hardware. You are advised to call image.getImageSourceSupportedFormats before decoding to dynamically query the decoding capabilities of the current device.

This guide uses the APIs provided by the Image module, which supports basic functionalities such as image encoding/decoding, image receiver operations, and image data processing. These APIs are introduced prior to API version 11, and no additional features will be added in later versions. Therefore, these APIs are not recommended.

You can also use the C APIs provided by the Image_NativeModule module, which includes all the foundational features of the Image module while adding new capabilities like multi-image encoding/decoding. For details about the development guide, see Using Image_NativeModule to Decode Images (C/C++). These APIs are available since API version 12 and are expected to keep evolving. You are encouraged to use them.

You are not advised to use both sets of C APIs in your code as it may cause compatibility issues in some scenarios.

How to Develop

For details about image decoding APIs, see image_source_mdk.h.

[h2]Adding Dependencies

Open the src/main/cpp/CMakeLists.txt file of the native project, add libace_napi.z.so, libpixelmap_ndk.z.so, libimage_source_ndk.z.so, librawfile.z.so, and libhilog_ndk.z.so (on which the native log APIs depend) to the target_link_libraries dependency.

target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so libpixelmap_ndk.z.so libimage_source_ndk.z.so librawfile.z.so)

[h2]Adding API Mappings

Open the src/main/cpp/hello.cpp file, and add the mapping of the getSyncPixelMap function to the Init function. The getSyncPixelMap function is used to generate a PixelMap in synchronous mode. The code is as follows:

EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
    napi_property_descriptor desc[] = {
        { "getSyncPixelMap", nullptr, getSyncPixelMap, nullptr, nullptr, nullptr, napi_default, nullptr },
    };

    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

[h2]Calling APIs on the JS Side

  1. Open src\main\cpp\types*libentry\index.d.ts* (where libentry varies according to the project name), and import the following files:

    import { image } from '@kit.ImageKit';
    import { resourceManager } from '@kit.LocalizationKit';
    
    // Synchronous call. The input parameters are the resource manager and image resource name, and a PixelMap is returned.
    export const getSyncPixelMap: (resMgr: resourceManager.ResourceManager, src: string) => image.PixelMap;
  2. Prepare an image resource file, named example.jpg in this example, and import it to *src\main\resources\rawfile*.

  3. Open src\main\ets\pages\index.ets, import libentry.so (where libentry varies according to the project name), call the native APIs, and pass in the JS resource object. The following is an example:

    import testNapi from 'libentry.so';
    import { image } from '@kit.ImageKit';
    import { common } from '@kit.AbilityKit';
    @Entry
    @Component
    struct Index {
      @State pixelMap : PixelMap | undefined = undefined;
      aboutToAppear() {
         // Obtain the context from the component and ensure that the return value of this.getUIContext().getHostContext() is UIAbilityContext.
         let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
         // Call the custom getSyncPixelMap function to obtain a PixelMap.
         this.pixelMap = testNapi.getSyncPixelMap(context.resourceManager, "example.jpg");
      }
    
      build() {
         Row() {
            Column() {
            Image(this.pixelMap)
               .width(100)
               .height(100)
            }
            .width('100%')
         }
         .height('100%')
      }
    }

[h2]Calling the Native APIs

For details about specific APIs, refer to Image.

Obtain the JS resource object from the hello.cpp file and convert it to a native resource object. Then you can call native APIs.

Adding Reference Files

// Include the image framework, raw file, raw file management, and log print header files.
#include <cstdlib>
#include <cstring>
#include <multimedia/image_framework/image_source_mdk.h>
#include <multimedia/image_framework/image_pixel_map_mdk.h>
#include <rawfile/raw_file.h>
#include <rawfile/raw_file_manager.h>
#include <hilog/log.h>

static napi_value getSyncPixelMap(napi_env env, napi_callback_info info)
{
   size_t argc = 2;
   napi_value args[2] = {nullptr};

   napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);
   
   napi_valuetype srcType;
   napi_typeof(env, args[0], &srcType);

   // The input parameter args[0] indicates the resource manager, which is used to initialize the resource manager at the native layer.
   NativeResourceManager *mNativeResMgr = OH_ResourceManager_InitNativeResourceManager(env, args[0]);
   
   size_t strSize;
   char srcBuf[2048];
   // The input parameter args[1] indicates the file name.
   napi_get_value_string_utf8(env, args[1], srcBuf, sizeof(srcBuf), &strSize);

   // Use the resource manager to open the raw file.
   RawFile * rawFile = OH_ResourceManager_OpenRawFile(mNativeResMgr, srcBuf);
   if (rawFile != NULL) {
      // Obtain the file size and read data.
      long len = OH_ResourceManager_GetRawFileSize(rawFile);
      uint8_t * data = static_cast<uint8_t *>(malloc(len));
      int res = OH_ResourceManager_ReadRawFile(rawFile, data, len);

      OhosImageSource imageSource_c;
      imageSource_c.buffer = data;
      imageSource_c.bufferSize = len;

      OhosImageSourceOps ops{};
      napi_value imageSource;
      napi_value pixelMap;

      // Create an ImageSource object using the read raw data.
      int32_t ret = OH_ImageSource_Create(env, &imageSource_c, &ops, &imageSource);

      // Initialize the ImageSource object at the native layer.
      ImageSourceNative * imageSourceNative_c = OH_ImageSource_InitNative(env, imageSource);
      OhosImageDecodingOps decodingOps{};
      // Create a PixelMap.
      OH_ImageSource_CreatePixelMap(imageSourceNative_c, &decodingOps, &pixelMap);

      // The following methods are provided for animated image formats such as GIF.
      // napi_value pixelMapList;
      // OH_ImageSource_CreatePixelMapList(imageSourceNative_c, &decodingOps, &pixelMapList);
      // OhosImageSourceDelayTimeList list{};
      // OH_ImageSource_GetDelayTime(imageSourceNative_c, &list);
      // uint32_t count;
      // OH_ImageSource_GetFrameCount(imageSourceNative_c, &count);

      OhosImageSourceInfo info{};
      // Read the image width and height.
      OH_ImageSource_GetImageInfo(imageSourceNative_c, 0, &info);
      OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "[decode]", "imageInfo width:%{public}d , height:%{public}d", info.size.width, info.size.height);
      
      // Read the ImageWidth configuration of the image source and print logs.
      OhosImageSourceProperty target;
      char exifKey_c[] = "ImageWidth";
      target.size = strlen(exifKey_c);
      target.value = exifKey_c;

      OhosImageSourceProperty response{};
      response.size = 20;
      response.value = static_cast<char *>(malloc(20));
      OH_ImageSource_GetImageProperty(imageSourceNative_c, &target, &response);
      OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "[decode]", "ImageProperty width after modify:%{public}s", response.value);

      // After the processing is complete, release resources at the native layer.
      OH_ImageSource_Release(imageSourceNative_c);
      OH_ResourceManager_CloseRawFile(rawFile);
      return pixelMap;
   }
   OH_ResourceManager_ReleaseNativeResourceManager(mNativeResMgr);
   return nullptr;
}

The image framework supports incremental decoding. The method is as follows:

// Include the image framework, raw file, raw file management, and log print header files.
#include <cstdlib>
#include <cstring>
#include <multimedia/image_framework/image_source_mdk.h>
#include <multimedia/image_framework/image_pixel_map_mdk.h>
#include <rawfile/raw_file.h>
#include <rawfile/raw_file_manager.h>
#include <hilog/log.h>

static napi_value getSyncPixelMap(napi_env env, napi_callback_info info)
{
   size_t argc = 2;
   napi_value args[2] = {nullptr};

   napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);
   
   napi_valuetype srcType;
   napi_typeof(env, args[0], &srcType);

   // The input parameter args[0] indicates the resource manager, which is used to initialize the resource manager at the native layer.
   NativeResourceManager * mNativeResMgr = OH_ResourceManager_InitNativeResourceManager(env, args[0]);
   
   size_t strSize;
   char srcBuf[2048];
   // The input parameter args[1] indicates the file name.
   napi_get_value_string_utf8(env, args[1], srcBuf, sizeof(srcBuf), &strSize);

   // Use the resource manager to open the raw file.
   RawFile * rawFile = OH_ResourceManager_OpenRawFile(mNativeResMgr, srcBuf);
   if (rawFile != NULL) {
      // Obtain the file size. If the file size is greater than 2048 bytes, incremental decoding is performed. Otherwise, full decoding is performed.
      long len = OH_ResourceManager_GetRawFileSize(rawFile);
      if (len > 2048) {
         uint8_t * data = static_cast<uint8_t *>(malloc(len));
         // Read all data in the file.
         int res = OH_ResourceManager_ReadRawFile(rawFile, data, len);
         
         uint8_t * holderdata = static_cast<uint8_t *>(malloc(len));

         OhosImageSource imageSource_c;
         // A buffer of imageSource_c is allocated, but no data is filled in.
         imageSource_c.buffer = holderdata;
         imageSource_c.bufferSize = len;
         OhosImageSourceOps ops{};
         napi_value imageSource;
         // Initialize the incremental ImageSource object.
         OH_ImageSource_CreateIncremental(env, &imageSource_c, &ops, &imageSource);

         // Initialize the ImageSource object at the native layer.
         ImageSourceNative * imageSourceNative_c = OH_ImageSource_InitNative(env, imageSource);

         // The following simulates segment loading. Segments are loaded twice. 2048 bytes of data are loaded for the first time, and the remaining data is loaded for the second time.
         OhosImageSourceUpdateData firstData{};
         firstData.buffer = data; // Image data.
         firstData.bufferSize = len; // Total size of the image data.
         firstData.isCompleted = false;
         firstData.offset = 0; // The first loading starts from the very beginning.
         firstData.updateLength = 2048; // 2048 bytes are loaded for the first time.
         OH_ImageSource_UpdateData(imageSourceNative_c, &firstData);

         OhosImageSourceUpdateData secondData{};
         secondData.buffer = data;
         secondData.bufferSize = len;
         secondData.isCompleted = true; // Last loading, indicating that loading is complete.
         secondData.offset = 2048; // 2048 bytes of data have been loaded. The offset is set to the amount already loaded.
         secondData.updateLength = len - 2048; // Load the remaining data for the second time.
         OH_ImageSource_UpdateData(imageSourceNative_c, &secondData);

         napi_value pixelMap;
         OhosImageDecodingOps decodingOps{};
         decodingOps.index = 0;
         // Create a PixelMap.
         OH_ImageSource_CreatePixelMap(imageSourceNative_c, &decodingOps, &pixelMap);

         // After the processing is complete, release resources at the native layer.
         OH_ImageSource_Release(imageSourceNative_c);
         OH_ResourceManager_CloseRawFile(rawFile);
         return pixelMap;
      }
      // Read all data in the raw file.
      uint8_t * data = static_cast<uint8_t *>(malloc(len));
      int res = OH_ResourceManager_ReadRawFile(rawFile, data, len);

      OhosImageSource imageSource_c;
      imageSource_c.buffer = data;
      imageSource_c.bufferSize = len;

      OhosImageSourceOps ops{};
      napi_value imageSource;
      napi_value pixelMap;

      // Create an ImageSource object using the read raw data.
      int32_t ret = OH_ImageSource_Create(env, &imageSource_c, &ops, &imageSource);

      // Initialize the ImageSource object at the native layer.
      ImageSourceNative * imageSourceNative_c = OH_ImageSource_InitNative(env, imageSource);
      OhosImageDecodingOps decodingOps{};

      // Create a PixelMap.
      OH_ImageSource_CreatePixelMap(imageSourceNative_c, &decodingOps, &pixelMap);

      // After the processing is complete, release resources at the native layer.
      OH_ImageSource_Release(imageSourceNative_c);
      OH_ResourceManager_CloseRawFile(rawFile);
      return pixelMap;
   }
   OH_ResourceManager_ReleaseNativeResourceManager(mNativeResMgr);
   return nullptr;
}