大图添加水印性能优化
==========

#### 问题现象

使用OffscreenCanvas离屏绘制图片和水印为图片添加水印，为滚动截图生成的长图添加水印时耗时长，是否有优化的方案。

#### 背景知识

*   [OffscreenCanvas](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-components-offscreencanvas)提供了可以在屏幕外渲染的画布，可以在单独的线程中完成渲染任务，避免影响应用程序主线程性能。OffscreenCanvas离屏绘制使用CPU进行绘制，绘制速度较慢，对绘制速度有要求的场景应避免使用离屏绘制。
*   [Drawing](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-graphics-drawing)模块支持创建GPU后端的离屏画布。GPU后端画布基于GPU进行绘制，GPU的并行计算能力优于CPU，适用于绘制图片或区域相对大的场景。具体可参考：[GPU后端Canvas的创建与显示](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/canvas-get-result-draw-c#gpu后端canvas的创建与显示)。

#### 解决方案

[OffscreenCanvas](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-components-offscreencanvas)使用CPU进程绘制，在绘制图片时速度较慢。使用[Drawing](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-graphics-drawing)模块的GPU离屏画布进行图片绘制，GPU的并行绘制能力强于CPU，绘制图片速度快。

1.  选择需要合成的原始图片文件和水印图片文件，使用[ImageSource](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-image-imagesource)解码图片文件为[PixelMap](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-image-pixelmap)，在解码水印图片时设置与原始图片相同的宽高。解码完成后，读取原始图片和水印图片的像素数据，传递到Native侧使用GPU画布离屏绘制。
    
    _/\*\*_
     _\* 通过资源目录下的资源ID，解码图片文件为指定宽高的PixelMap_
     _\* @param resId 资源目录下图片文件的资源ID_
     _\* @param width 可选，解码后的图片宽_
     _\* @param height 可选，解码后的图片高_
     _\*/_
    async loadResourcePixelMapById(resId: number, width: number | undefined = undefined,
      height: number | undefined = undefined): Promise<image.PixelMap> {
      const context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext;
      const resourceMgr: resourceManager.ResourceManager = context.resourceManager;
      try {
        const buffer: ArrayBuffer = resourceMgr.getMediaContentSync(resId).buffer.slice(0);
        const imageSource: image.ImageSource = image.createImageSource(buffer);
        let decodingOpts: image.DecodingOptions | undefined = undefined;
        if (width !== undefined && height !== undefined) {
          decodingOpts = {
            editable: true,
            desiredSize: {
              width: width,
              height: height,
            },
          };
        } else {
          decodingOpts = {
            editable: true,
          };
        }
        const pixelMap: image.PixelMap = await imageSource.createPixelMap(decodingOpts);
        await imageSource.release();
        return pixelMap;
      } catch (err) {
        return Promise.reject(err);
      }
    }
    
    _/\*\*_
     _\* 原始图片与水印合成_
     _\* @param baseResId 资源目录下的原始图片资源ID_
     _\* @param watermarkResId 资源目录下的水印图片资源文件ID_
     _\*/_
    async addWatermarkGPU(baseResId: number, watermarkResId: number): Promise<void> {
      try {
      _  // 原始图片PixelMap_
        const basePixelMap: image.PixelMap = await this.loadResourcePixelMapById(baseResId);
        const baseInfo: image.ImageInfo = await basePixelMap.getImageInfo();
        const baseHeight: number = baseInfo.size.height;
        const baseWidth: number = baseInfo.size.width;
      _  // 水印图片PixelMap_
        const markPixelMap: image.PixelMap = await this.loadResourcePixelMapById(watermarkResId, baseWidth, baseHeight);
      _  // 读取原始图片像素数据_
        const baseBuffer: ArrayBuffer = new ArrayBuffer(basePixelMap.getPixelBytesNumber());
        basePixelMap.readPixelsToBufferSync(baseBuffer);
      _  // 读取水印图片像素数据_
        const markBuffer: ArrayBuffer = new ArrayBuffer(markPixelMap.getPixelBytesNumber());
        markPixelMap.readPixelsToBufferSync(markBuffer);
       _ // 通过GPU离屏合成图片与水印，返回合成后的像素数据_
        let result: ArrayBuffer = testNapi.addMark(baseBuffer, markBuffer, baseWidth, baseHeight);
        if (this.pixelmap !== undefined) {
          await this.pixelmap.release();
        }
       _ // 通过合成后的像素数据创建PixelMap_
        this.pixelmap = await image.createPixelMap(result, {
          editable: true,
          size: { width: baseWidth, height: baseHeight },
          pixelFormat: image.PixelMapFormat.RGBA\_8888,
        });
      } catch (err) {
        return Promise.reject(err);
      }
      return Promise.resolve();
    }
    
2.  在Native侧，创建GPU后端的离屏画布，通过ArkTS传递的原始图片和水印图片的像素数据，生成[OH\_PixelmapNative](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-image-nativemodule-oh-pixelmapnative)对象，在GPU画布上先后绘制原始图片的PixelMap和水印图片的PixelMap完成图片水印添加。绘制完成后，读取画布像素数据，创建ArrayBuffer对象返回ArkTS侧。
    
    static napi\_value NativeDrawGPU(napi\_env env, napi\_callback\_info info)
    {
        size\_t argc = 4;
        napi\_value args\[4\] = {nullptr};
        napi\_get\_cb\_info(env, info, &argc, args, nullptr, nullptr);
    
      _  // 原始图片的像素数据buffer_
        bool isArrayBuffer = false;
        napi\_is\_arraybuffer(env, args\[0\], &isArrayBuffer);
        if (!isArrayBuffer) {
            napi\_throw\_type\_error(env, nullptr, "argument must be an ArrayBuffer");
            return nullptr;
        }
        void \*baseBuffer = nullptr;
        size\_t baseBufferLen = 0;
        napi\_status status = napi\_get\_arraybuffer\_info(env, args\[0\], &baseBuffer, &baseBufferLen);
        if (status != napi\_ok) {
            napi\_throw\_error(env, nullptr, "failed to get arraybuffer info");
            return nullptr;
        }
    
      _  // 水印图片的像素数据buffer_
        napi\_is\_arraybuffer(env, args\[1\], &isArrayBuffer);
        if (!isArrayBuffer) {
            napi\_throw\_type\_error(env, nullptr, "argument must be an ArrayBuffer");
            return nullptr;
        }
        void \*markBuffer = nullptr;
        size\_t markBufferLen = 0;
        status = napi\_get\_arraybuffer\_info(env, args\[1\], &markBuffer, &markBufferLen);
        if (status != napi\_ok) {
            napi\_throw\_error(env, nullptr, "failed to get arraybuffer info");
            return nullptr;
        }
    
      _  // 图片宽高_
        int32\_t width = 0;
        int32\_t height = 0;
        napi\_get\_value\_int32(env, args\[2\], &width);
        napi\_get\_value\_int32(env, args\[3\], &height);
    
      _  // 初始化EGL上下文_
        EGLDisplay bufDisplay;
        EGLint majorVersion;
        EGLint minorVersion;
        bufDisplay = eglGetDisplay(EGL\_DEFAULT\_DISPLAY);
        eglInitialize(bufDisplay, &majorVersion, &minorVersion);
    
        EGLConfig bufConfig;
        EGLint numConfigs;
        EGLint attribs\[\] = {
            EGL\_RENDERABLE\_TYPE, EGL\_OPENGL\_ES3\_BIT, EGL\_BLUE\_SIZE, 8, EGL\_GREEN\_SIZE, 8, EGL\_RED\_SIZE, 8, EGL\_NONE,
        };
        eglChooseConfig(bufDisplay, attribs, &bufConfig, 1, &numConfigs);
    
        EGLSurface bufSurface;
        EGLContext bufContext;
        EGLint contextAttribs\[\] = {EGL\_CONTEXT\_CLIENT\_VERSION, 3, EGL\_NONE};
        bufSurface = eglCreatePbufferSurface(bufDisplay, bufConfig, attribs);
        bufContext = eglCreateContext(bufDisplay, bufConfig, EGL\_NO\_CONTEXT, contextAttribs);
        eglMakeCurrent(bufDisplay, bufSurface, bufSurface, bufContext);
    
       _ // 创建GPU后端Canvas_
        OH\_Drawing\_Image\_Info imageInfo = {width, height, COLOR\_FORMAT\_RGBA\_8888, ALPHA\_FORMAT\_PREMUL};
        OH\_Drawing\_GpuContextOptions options{false};
        OH\_Drawing\_GpuContext \*gpuContext = OH\_Drawing\_GpuContextCreateFromGL(options);
        OH\_Drawing\_Surface \*drawSurface = OH\_Drawing\_SurfaceCreateFromGpuContext(gpuContext, true, imageInfo);
        OH\_Drawing\_Canvas \*gpuCanvas = OH\_Drawing\_SurfaceGetCanvas(drawSurface);
    
     _   // 通过原始图片像素数据创建PixelMap对象_
        OH\_Pixelmap\_InitializationOptions \*createOps1 = nullptr;
        OH\_PixelmapInitializationOptions\_Create(&createOps1);
        OH\_PixelmapInitializationOptions\_SetWidth(createOps1, width);
        OH\_PixelmapInitializationOptions\_SetHeight(createOps1, height);
        OH\_PixelmapInitializationOptions\_SetPixelFormat(createOps1, PIXEL\_FORMAT\_RGBA\_8888);
        OH\_PixelmapInitializationOptions\_SetAlphaType(createOps1, PIXELMAP\_ALPHA\_TYPE\_UNKNOWN);
        OH\_PixelmapNative \*pixelMapNative1 = nullptr;
        OH\_PixelmapNative\_CreatePixelmap((uint8\_t \*)baseBuffer, baseBufferLen, createOps1, &pixelMapNative1);
        OH\_Drawing\_PixelMap \*pixelMap1 = OH\_Drawing\_PixelMapGetFromOhPixelMapNative(pixelMapNative1);
        OH\_Drawing\_Rect \*src1 = OH\_Drawing\_RectCreate(0, 0, width, height);
        OH\_Drawing\_Rect \*dst1 = OH\_Drawing\_RectCreate(0, 0, width, height);
    
      _  // 通过水印图片像素数据创建PixelMap对象_
        OH\_Pixelmap\_InitializationOptions \*createOps2 = nullptr;
        OH\_PixelmapInitializationOptions\_Create(&createOps2);
        OH\_PixelmapInitializationOptions\_SetWidth(createOps2, width);
        OH\_PixelmapInitializationOptions\_SetHeight(createOps2, height);
        OH\_PixelmapInitializationOptions\_SetPixelFormat(createOps2, PIXEL\_FORMAT\_RGBA\_8888);
        OH\_PixelmapInitializationOptions\_SetAlphaType(createOps2, PIXELMAP\_ALPHA\_TYPE\_UNKNOWN);
        OH\_PixelmapNative \*pixelMapNative2 = nullptr;
        OH\_PixelmapNative\_CreatePixelmap((uint8\_t \*)markBuffer, markBufferLen, createOps2, &pixelMapNative2);
        OH\_Drawing\_PixelMap \*pixelMap2 = OH\_Drawing\_PixelMapGetFromOhPixelMapNative(pixelMapNative2);
        OH\_Drawing\_Rect \*src2 = OH\_Drawing\_RectCreate(0, 0, width, height);
        OH\_Drawing\_Rect \*dst2 = OH\_Drawing\_RectCreate(0, 0, width, height);
    
        OH\_Drawing\_SamplingOptions \*samplingOptions = OH\_Drawing\_SamplingOptionsCreate(
            OH\_Drawing\_FilterMode::FILTER\_MODE\_LINEAR, OH\_Drawing\_MipmapMode::MIPMAP\_MODE\_LINEAR);
      _  // 绘制原始图片_
        OH\_Drawing\_CanvasDrawPixelMapRect(gpuCanvas, pixelMap1, src1, dst1, samplingOptions);
      _  // 绘制水印图片_
        OH\_Drawing\_CanvasDrawPixelMapRect(gpuCanvas, pixelMap2, src2, dst2, samplingOptions);
    
      _  // 拷贝画布像素，获得合成后图片的像素数据_
        void \*dstPixels = malloc(width \* height \* 4);
        OH\_Drawing\_CanvasReadPixels(gpuCanvas, &imageInfo, dstPixels, 4 \* width, 0, 0);
    
      _  // 清理资源_
        OH\_Drawing\_RectDestroy(src1);
        OH\_Drawing\_RectDestroy(dst1);
        OH\_Drawing\_RectDestroy(src2);
        OH\_Drawing\_RectDestroy(dst2);
        OH\_PixelmapInitializationOptions\_Release(createOps1);
        OH\_PixelmapInitializationOptions\_Release(createOps2);
        OH\_PixelmapNative\_Destroy(&pixelMapNative1);
        OH\_PixelmapNative\_Destroy(&pixelMapNative2);
        OH\_Drawing\_CanvasDestroy(gpuCanvas);
    
       _ // 清理EGL上下文_
        eglDestroySurface(bufDisplay, bufSurface);
        eglDestroyContext(bufDisplay, bufContext);
        eglTerminate(bufDisplay);
    
      _  // 生成ArrayBuffer返回ArkTS侧_
        napi\_value result = nullptr;
        void \*bufferData = nullptr;
        napi\_create\_arraybuffer(env, width \* height \* 4, &bufferData, &result);
        if (bufferData != nullptr) {
            for (int j = 0; j < width \* height \* 4; j++) {
                ((uint8\_t \*)bufferData)\[j\] = ((uint8\_t \*)dstPixels)\[j\];
            }
        } else {
            OH\_LOG\_ERROR(LOG\_APP, "OOM");
        }
        free(dstPixels);
    
        return result;
    }
    

完整参考代码如下：

ArkTS侧：

import image from '@ohos.multimedia.image';
import { common } from '@kit.AbilityKit';
import { resourceManager } from '@kit.LocalizationKit';
import testNapi from 'libentry.so';

@Entry
@Component
struct Index {
  @State pixelmap: image.PixelMap | undefined = undefined;

  _/\*\*_
   _\* 通过资源目录下的资源ID，解码图片文件为指定宽高的PixelMap_
   _\* @param resId 资源目录下图片文件的资源ID_
   _\* @param width 可选，解码后的图片宽_
   _\* @param height 可选，解码后的图片高_
   _\*/_
  async loadResourcePixelMapById(resId: number, width: number | undefined = undefined,
    height: number | undefined = undefined): Promise<image.PixelMap> {
    const context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext;
    const resourceMgr: resourceManager.ResourceManager = context.resourceManager;
    try {
      const buffer: ArrayBuffer = resourceMgr.getMediaContentSync(resId).buffer.slice(0);
      const imageSource: image.ImageSource = image.createImageSource(buffer);
      let decodingOpts: image.DecodingOptions | undefined = undefined;
      if (width !== undefined && height !== undefined) {
        decodingOpts = {
          editable: true,
          desiredSize: {
            width: width,
            height: height,
          },
        };
      } else {
        decodingOpts = {
          editable: true,
        };
      }
      const pixelMap: image.PixelMap = await imageSource.createPixelMap(decodingOpts);
      await imageSource.release();
      return pixelMap;
    } catch (err) {
      return Promise.reject(err);
    }
  }

 _ /\*\*_
   _\* 原始图片与水印合成_
   _\* @param baseResId 资源目录下的原始图片资源ID_
   _\* @param watermarkResId 资源目录下的水印图片资源文件ID_
   _\*/_
  async addWatermarkGPU(baseResId: number, watermarkResId: number): Promise<void> {
    try {
    _  // 原始图片PixelMap_
      const basePixelMap: image.PixelMap = await this.loadResourcePixelMapById(baseResId);
      const baseInfo: image.ImageInfo = await basePixelMap.getImageInfo();
      const baseHeight: number = baseInfo.size.height;
      const baseWidth: number = baseInfo.size.width;
     _ // 水印图片PixelMap_
      const markPixelMap: image.PixelMap = await this.loadResourcePixelMapById(watermarkResId, baseWidth, baseHeight);
    _  // 读取原始图片像素数据_
      const baseBuffer: ArrayBuffer = new ArrayBuffer(basePixelMap.getPixelBytesNumber());
      basePixelMap.readPixelsToBufferSync(baseBuffer);
   _   // 读取水印图片像素数据_
      const markBuffer: ArrayBuffer = new ArrayBuffer(markPixelMap.getPixelBytesNumber());
      markPixelMap.readPixelsToBufferSync(markBuffer);
   _   // 通过GPU离屏合成图片与水印，返回合成后的像素数据_
      let result: ArrayBuffer = testNapi.addMark(baseBuffer, markBuffer, baseWidth, baseHeight);
      if (this.pixelmap !== undefined) {
        await this.pixelmap.release();
      }
   _   // 通过合成后的像素数据创建PixelMap_
      this.pixelmap = await image.createPixelMap(result, {
        editable: true,
        size: { width: baseWidth, height: baseHeight },
        pixelFormat: image.PixelMapFormat.RGBA\_8888,
      });
    } catch (err) {
      return Promise.reject(err);
    }
    return Promise.resolve();
  }

  build() {
    Column({ space: 20 }) {
      Image(this.pixelmap)
        .width('100%')
        .aspectRatio(1)
        .objectFit(ImageFit.None)
        .backgroundColor(Color.Black);

      Button() {
        Text('Draw WaterMark')
          .padding(5)
          .fontSize(30);
      }
      .onClick(async () => {
        await this.addWatermarkGPU($r('app.media.background\_bg').id, $r('app.media.watermark\_ng').id);
      });
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center);
  }
}

Native侧：

_/\*_
 _\* Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved._
 _\*/_
#include "hilog/log.h"
#include "napi/native\_api.h"
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <EGL/eglplatform.h>
#include <stdlib.h>
#include <cstdint>
#include <native\_drawing/drawing\_bitmap.h>
#include <native\_drawing/drawing\_canvas.h>
#include <native\_drawing/drawing\_color.h>
#include <native\_drawing/drawing\_font.h>
#include <native\_drawing/drawing\_gpu\_context.h>
#include <native\_drawing/drawing\_surface.h>
#include <native\_drawing/drawing\_text\_blob.h>
#include <native\_drawing/drawing\_sampling\_options.h>
#include <native\_drawing/drawing\_rect.h>
#include <multimedia/image\_framework/image/pixelmap\_native.h>
#include <native\_drawing/drawing\_pixel\_map.h>

#undef LOG\_DOMAIN
#undef LOG\_TAG
#define LOG\_DOMAIN 0x3200
#define LOG\_TAG "GPU\_WATERMARK"

static napi\_value NativeDrawGPU(napi\_env env, napi\_callback\_info info)
{
    size\_t argc = 4;
    napi\_value args\[4\] = {nullptr};
    napi\_get\_cb\_info(env, info, &argc, args, nullptr, nullptr);

   _ // 原始图片的像素数据buffer_
    bool isArrayBuffer = false;
    napi\_is\_arraybuffer(env, args\[0\], &isArrayBuffer);
    if (!isArrayBuffer) {
        napi\_throw\_type\_error(env, nullptr, "argument must be an ArrayBuffer");
        return nullptr;
    }
    void \*baseBuffer = nullptr;
    size\_t baseBufferLen = 0;
    napi\_status status = napi\_get\_arraybuffer\_info(env, args\[0\], &baseBuffer, &baseBufferLen);
    if (status != napi\_ok) {
        napi\_throw\_error(env, nullptr, "failed to get arraybuffer info");
        return nullptr;
    }

   _ // 水印图片的像素数据buffer_
    napi\_is\_arraybuffer(env, args\[1\], &isArrayBuffer);
    if (!isArrayBuffer) {
        napi\_throw\_type\_error(env, nullptr, "argument must be an ArrayBuffer");
        return nullptr;
    }
    void \*markBuffer = nullptr;
    size\_t markBufferLen = 0;
    status = napi\_get\_arraybuffer\_info(env, args\[1\], &markBuffer, &markBufferLen);
    if (status != napi\_ok) {
        napi\_throw\_error(env, nullptr, "failed to get arraybuffer info");
        return nullptr;
    }

   _ // 图片宽高_
    int32\_t width = 0;
    int32\_t height = 0;
    napi\_get\_value\_int32(env, args\[2\], &width);
    napi\_get\_value\_int32(env, args\[3\], &height);

   _ // 初始化EGL上下文_
    EGLDisplay bufDisplay;
    EGLint majorVersion;
    EGLint minorVersion;
    bufDisplay = eglGetDisplay(EGL\_DEFAULT\_DISPLAY);
    eglInitialize(bufDisplay, &majorVersion, &minorVersion);

    EGLConfig bufConfig;
    EGLint numConfigs;
    EGLint attribs\[\] = {
        EGL\_RENDERABLE\_TYPE, EGL\_OPENGL\_ES3\_BIT, EGL\_BLUE\_SIZE, 8, EGL\_GREEN\_SIZE, 8, EGL\_RED\_SIZE, 8, EGL\_NONE,
    };
    eglChooseConfig(bufDisplay, attribs, &bufConfig, 1, &numConfigs);

    EGLSurface bufSurface;
    EGLContext bufContext;
    EGLint contextAttribs\[\] = {EGL\_CONTEXT\_CLIENT\_VERSION, 3, EGL\_NONE};
    bufSurface = eglCreatePbufferSurface(bufDisplay, bufConfig, attribs);
    bufContext = eglCreateContext(bufDisplay, bufConfig, EGL\_NO\_CONTEXT, contextAttribs);
    eglMakeCurrent(bufDisplay, bufSurface, bufSurface, bufContext);

  _  // 创建GPU后端Canvas_
    OH\_Drawing\_Image\_Info imageInfo = {width, height, COLOR\_FORMAT\_RGBA\_8888, ALPHA\_FORMAT\_PREMUL};
    OH\_Drawing\_GpuContextOptions options{false};
    OH\_Drawing\_GpuContext \*gpuContext = OH\_Drawing\_GpuContextCreateFromGL(options);
    OH\_Drawing\_Surface \*drawSurface = OH\_Drawing\_SurfaceCreateFromGpuContext(gpuContext, true, imageInfo);
    OH\_Drawing\_Canvas \*gpuCanvas = OH\_Drawing\_SurfaceGetCanvas(drawSurface);

   _ // 通过原始图片像素数据创建PixelMap对象_
    OH\_Pixelmap\_InitializationOptions \*createOps1 = nullptr;
    OH\_PixelmapInitializationOptions\_Create(&createOps1);
    OH\_PixelmapInitializationOptions\_SetWidth(createOps1, width);
    OH\_PixelmapInitializationOptions\_SetHeight(createOps1, height);
    OH\_PixelmapInitializationOptions\_SetPixelFormat(createOps1, PIXEL\_FORMAT\_RGBA\_8888);
    OH\_PixelmapInitializationOptions\_SetAlphaType(createOps1, PIXELMAP\_ALPHA\_TYPE\_UNKNOWN);
    OH\_PixelmapNative \*pixelMapNative1 = nullptr;
    OH\_PixelmapNative\_CreatePixelmap((uint8\_t \*)baseBuffer, baseBufferLen, createOps1, &pixelMapNative1);
    OH\_Drawing\_PixelMap \*pixelMap1 = OH\_Drawing\_PixelMapGetFromOhPixelMapNative(pixelMapNative1);
    OH\_Drawing\_Rect \*src1 = OH\_Drawing\_RectCreate(0, 0, width, height);
    OH\_Drawing\_Rect \*dst1 = OH\_Drawing\_RectCreate(0, 0, width, height);

  _  // 通过水印图片像素数据创建PixelMap对象_
    OH\_Pixelmap\_InitializationOptions \*createOps2 = nullptr;
    OH\_PixelmapInitializationOptions\_Create(&createOps2);
    OH\_PixelmapInitializationOptions\_SetWidth(createOps2, width);
    OH\_PixelmapInitializationOptions\_SetHeight(createOps2, height);
    OH\_PixelmapInitializationOptions\_SetPixelFormat(createOps2, PIXEL\_FORMAT\_RGBA\_8888);
    OH\_PixelmapInitializationOptions\_SetAlphaType(createOps2, PIXELMAP\_ALPHA\_TYPE\_UNKNOWN);
    OH\_PixelmapNative \*pixelMapNative2 = nullptr;
    OH\_PixelmapNative\_CreatePixelmap((uint8\_t \*)markBuffer, markBufferLen, createOps2, &pixelMapNative2);
    OH\_Drawing\_PixelMap \*pixelMap2 = OH\_Drawing\_PixelMapGetFromOhPixelMapNative(pixelMapNative2);
    OH\_Drawing\_Rect \*src2 = OH\_Drawing\_RectCreate(0, 0, width, height);
    OH\_Drawing\_Rect \*dst2 = OH\_Drawing\_RectCreate(0, 0, width, height);

    OH\_Drawing\_SamplingOptions \*samplingOptions = OH\_Drawing\_SamplingOptionsCreate(
        OH\_Drawing\_FilterMode::FILTER\_MODE\_LINEAR, OH\_Drawing\_MipmapMode::MIPMAP\_MODE\_LINEAR);
  _  // 绘制原始图片_
    OH\_Drawing\_CanvasDrawPixelMapRect(gpuCanvas, pixelMap1, src1, dst1, samplingOptions);
   _ // 绘制水印图片_
    OH\_Drawing\_CanvasDrawPixelMapRect(gpuCanvas, pixelMap2, src2, dst2, samplingOptions);

  _  // 拷贝画布像素，获得合成后图片的像素数据_
    void \*dstPixels = malloc(width \* height \* 4);
    OH\_Drawing\_CanvasReadPixels(gpuCanvas, &imageInfo, dstPixels, 4 \* width, 0, 0);

   _ // 清理资源_
    OH\_Drawing\_RectDestroy(src1);
    OH\_Drawing\_RectDestroy(dst1);
    OH\_Drawing\_RectDestroy(src2);
    OH\_Drawing\_RectDestroy(dst2);
    OH\_PixelmapInitializationOptions\_Release(createOps1);
    OH\_PixelmapInitializationOptions\_Release(createOps2);
    OH\_PixelmapNative\_Destroy(&pixelMapNative1);
    OH\_PixelmapNative\_Destroy(&pixelMapNative2);
    OH\_Drawing\_CanvasDestroy(gpuCanvas);

   _ // 清理EGL上下文_
    eglDestroySurface(bufDisplay, bufSurface);
    eglDestroyContext(bufDisplay, bufContext);
    eglTerminate(bufDisplay);

  _  // 生成ArrayBuffer返回ArkTS侧_
    napi\_value result = nullptr;
    void \*bufferData = nullptr;
    napi\_create\_arraybuffer(env, width \* height \* 4, &bufferData, &result);
    if (bufferData != nullptr) {
        for (int j = 0; j < width \* height \* 4; j++) {
            ((uint8\_t \*)bufferData)\[j\] = ((uint8\_t \*)dstPixels)\[j\];
        }
    } else {
        OH\_LOG\_ERROR(LOG\_APP, "OOM");
    }
    free(dstPixels);

    return result;
}

EXTERN\_C\_START
static napi\_value Init(napi\_env env, napi\_value exports)
{
    napi\_property\_descriptor desc\[\] = {
        {"addMark", nullptr, NativeDrawGPU, nullptr, nullptr, nullptr, napi\_default, nullptr},
    };
    napi\_define\_properties(env, exports, sizeof(desc) / sizeof(desc\[0\]), desc);
    return exports;
}
EXTERN\_C\_END

static napi\_module demoModule = {
    .nm\_version = 1,
    .nm\_flags = 0,
    .nm\_filename = nullptr,
    .nm\_register\_func = Init,
    .nm\_modname = "entry",
    .nm\_priv = ((void \*)0),
    .reserved = {0},
};

extern "C" \_\_attribute\_\_((constructor)) void RegisterEntryModule(void) { napi\_module\_register(&demoModule); }