• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 使用Drawing实现图形绘制与显示
2
3## 场景介绍
4
5Native Drawing模块提供了一系列的接口用于基本图形和字体的绘制。
6
7Drawing绘制的内容无法直接在屏幕上显示,需要借用XComponent以及Native Window的能力支持,将绘制的内容通过Native Window送显。
8
9## 接口说明
10
11Drawing常用接口如下表所示,详细的接口说明请参考[Drawing](../reference/native-apis/_drawing.md)。
12
13| 接口名 | 描述 |
14| -------- | -------- |
15| OH_Drawing_BitmapCreate (void) | 创建一个位图对象。 |
16| OH_Drawing_BitmapBuild (OH_Drawing_Bitmap *, const uint32_t width, const uint32_t height, const OH_Drawing_BitmapFormat *) | 初始化位图对象的宽度和高度,并且为该位图设置像素格式。 |
17| OH_Drawing_CanvasCreate (void) | 创建一个画布对象。 |
18| OH_Drawing_CanvasBind (OH_Drawing_Canvas *, OH_Drawing_Bitmap *) | 将一个位图对象绑定到画布中,使得画布绘制的内容输出到位图中(即CPU渲染)。 |
19| OH_Drawing_CanvasAttachBrush (OH_Drawing_Canvas *, const OH_Drawing_Brush *) | 设置画刷给画布,画布将会使用设置的画刷样式和颜色去填充绘制的图形形状。 |
20| OH_Drawing_CanvasAttachPen (OH_Drawing_Canvas *, const OH_Drawing_Pen *) | 设置画笔给画布,画布将会使用设置画笔的样式和颜色去绘制图形形状的轮廓。 |
21| OH_Drawing_CanvasDrawPath (OH_Drawing_Canvas *, const OH_Drawing_Path *) | 画一个自定义路径。 |
22| OH_Drawing_PathCreate (void) | 创建一个路径对象。 |
23| OH_Drawing_PathMoveTo (OH_Drawing_Path *, float x, float y) | 设置自定义路径的起始点位置。 |
24| OH_Drawing_PathLineTo (OH_Drawing_Path *, float x, float y) | 添加一条到目标点的线段。 |
25| OH_Drawing_PathClose (OH_Drawing_Path *) | 闭合路径,会添加一条到路径起点位置的线段。 |
26| OH_Drawing_PenCreate (void) | 创建一个画笔对象。 |
27| OH_Drawing_PenSetAntiAlias (OH_Drawing_Pen *, bool) | 设置抗锯齿属性,如果为真则说明画笔会启用抗锯齿功能,在绘制图形时会对图形的边缘像素进行半透明的模糊处理。 |
28| OH_Drawing_PenSetWidth (OH_Drawing_Pen *, float width) | 设置画笔的厚度属性,厚度属性描述了画笔绘制图形轮廓的宽度。 |
29| OH_Drawing_BrushCreate (void) | 创建一个画刷对象。 |
30| OH_Drawing_BrushSetColor (OH_Drawing_Brush *, uint32_t color) | 设置画刷的颜色属性,颜色属性描述了画刷填充图形时使用的颜色,用一个32位(ARGB)的变量表示。 |
31| OH_Drawing_CreateTypographyStyle (void) | 创建一个排版对象,用于定义排版样式。 |
32| OH_Drawing_CreateTextStyle (void) | 创建一个文本对象,用于定义文本样式。 |
33| OH_Drawing_TypographyHandlerAddText (OH_Drawing_TypographyCreate *, const char *) | 设置文本内容。 |
34| OH_Drawing_TypographyPaint (OH_Drawing_Typography *, OH_Drawing_Canvas *, double, double) | 显示文本。 |
35
36## 图形绘制与显示开发步骤
37
38### 开发流程
39
40使用Drawing进行图形绘制与显示时,需要使用Native Drawing模块的画布画笔绘制一个基本的2D图形;并将图形内容写入Native Window提供的图形Buffer,将Buffer提交到图形队列;再利用XComponent将C++代码层与ArkTS层对接,实现在ArkTS层调用绘制和显示的逻辑,最终在应用上显示图形。
41
42本文以实现2D图形和文本的绘制与显示为例,给出具体的开发指导。
43### 添加开发依赖
44
45**添加动态链接库**
46
47CMakeLists.txt中添加以下lib。
48
49```txt
50libace_napi.z.so
51libace_ndk.z.so
52libnative_window.so
53libnative_drawing.so
54```
55
56**头文件**
57```c++
58#include <ace/xcomponent/native_interface_xcomponent.h>
59#include "napi/native_api.h"
60#include <native_window/external_window.h>
61#include <native_drawing/drawing_bitmap.h>
62#include <native_drawing/drawing_color.h>
63#include <native_drawing/drawing_canvas.h>
64#include <native_drawing/drawing_pen.h>
65#include <native_drawing/drawing_brush.h>
66#include <native_drawing/drawing_path.h>
67#include <cmath>
68#include <algorithm>
69#include <stdint.h>
70#include <sys/mman.h>
71```
72
73### 使用XComponent构建绘制环境
74
751. 在Index.ets文件中添加XComponent组件。
76    ```ts
77    import XComponentContext from "../interface/XComponentContext";
78
79    const TAG = '[Sample_DrawingAPI]';
80
81    @Entry
82    @Component
83    struct Index {
84      private xComponentContext: XComponentContext | undefined = undefined;
85
86      build() {
87          Column() {
88          Row() {
89              XComponent({ id: 'xcomponentId', type: 'surface', libraryname: 'entry' })
90              .onLoad((xComponentContext) => {
91                  this.xComponentContext = xComponentContext as XComponentContext;
92              }).width('640px') // 64的倍数
93          }.height('88%')
94        }
95      }
96    }
97    ```
98    若要改变XComponent的宽,值需为64的倍数,例如640px。
992. 在 Native C++层获取NativeXComponent。建议使用单例模式保存XComponent。此步骤需要在napi_init的过程中处理。
100
101    创建一个PluginManger单例类,用于管理NativeXComponent。
102    ```c++
103    class PluginManager {
104    public:
105        ~PluginManager();
106
107        static PluginManager *GetInstance();
108
109        void SetNativeXComponent(std::string &id, OH_NativeXComponent *nativeXComponent);
110        SampleBitMap *GetRender(std::string &id);
111        void Export(napi_env env, napi_value exports);
112    private:
113
114        std::unordered_map<std::string, OH_NativeXComponent *> nativeXComponentMap_;
115        std::unordered_map<std::string, SampleBitMap *> pluginRenderMap_;
116    };
117    ```
118    SampleBitMap类会在后面的绘制2D图形步骤中创建。
119    ```c++
120    void PluginManager::Export(napi_env env, napi_value exports) {
121        if ((env == nullptr) || (exports == nullptr)) {
122            DRAWING_LOGE("Export: env or exports is null");
123            return;
124        }
125
126        napi_value exportInstance = nullptr;
127        if (napi_get_named_property(env, exports, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) {
128            DRAWING_LOGE("Export: napi_get_named_property fail");
129            return;
130        }
131
132        OH_NativeXComponent *nativeXComponent = nullptr;
133        if (napi_unwrap(env, exportInstance, reinterpret_cast<void **>(&nativeXComponent)) != napi_ok) {
134            DRAWING_LOGE("Export: napi_unwrap fail");
135            return;
136        }
137
138        char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
139        uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
140        if (OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
141            DRAWING_LOGE("Export: OH_NativeXComponent_GetXComponentId fail");
142            return;
143        }
144
145        std::string id(idStr);
146        auto context = PluginManager::GetInstance();
147        if ((context != nullptr) && (nativeXComponent != nullptr)) {
148            context->SetNativeXComponent(id, nativeXComponent);
149            auto render = context->GetRender(id);
150            if (render != nullptr) {
151                render->RegisterCallback(nativeXComponent);
152                render->Export(env, exports);
153            } else {
154                DRAWING_LOGE("render is nullptr");
155            }
156        }
157    }
158    ```
1593. 注册回调函数。通过``OnSurfaceCreated``回调函数获取Native Window,建议将Native Window同样存储在单例中。
160    ```c++
161    // 定义回调函数
162    void OnSurfaceCreatedCB(OH_NativeXComponent* component, void* window)
163    {
164        // 可获取 OHNativeWindow 实例
165        OHNativeWindow* nativeWindow = static_cast<OHNativeWindow*>(window);
166        char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
167        uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
168        if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
169            DRAWING_LOGE("OnSurfaceCreatedCB: Unable to get XComponent id");
170            return;
171        }
172        std::string id(idStr);
173        auto render = SampleBitMap::GetInstance(id);
174        render->SetNativeWindow(nativeWindow);
175
176        uint64_t width;
177        uint64_t height;
178        int32_t xSize = OH_NativeXComponent_GetXComponentSize(component, window, &width, &height);
179        if ((xSize == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) && (render != nullptr)) {
180            render->SetHeight(height);
181            render->SetWidth(width);
182            DRAWING_LOGI("xComponent width = %{public}llu, height = %{public}llu", width, height);
183        }
184    }
185    void OnSurfaceChangedCB(OH_NativeXComponent* component, void* window)
186    {
187        // 可获取 OHNativeWindow 实例
188        OHNativeWindow* nativeWindow = static_cast<OHNativeWindow*>(window);
189        char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
190        uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
191        if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
192            DRAWING_LOGE("OnSurfaceChangedCB: Unable to get XComponent id");
193            return;
194        }
195        std::string id(idStr);
196        auto render = SampleBitMap::GetInstance(id);
197
198        uint64_t width;
199        uint64_t height;
200        int32_t xSize = OH_NativeXComponent_GetXComponentSize(component, window, &width, &height);
201        if ((xSize == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) && (render != nullptr)) {
202            render->SetHeight(height);
203            render->SetWidth(width);
204            DRAWING_LOGI("Surface Changed : xComponent width = %{public}llu, height = %{public}llu", width, height);
205        }
206    }
207    void OnSurfaceDestroyedCB(OH_NativeXComponent* component, void* window)
208    {
209        // 可获取 OHNativeWindow 实例
210        OHNativeWindow* nativeWindow = static_cast<OHNativeWindow*>(window);
211        // ...
212    }
213    void DispatchTouchEventCB(OH_NativeXComponent* component, void* window)
214    {
215        // 可获取 OHNativeWindow 实例
216        OHNativeWindow* nativeWindow = static_cast<OHNativeWindow*>(window);
217        // ...
218    }
219    ```
220    XComponent的所有Callback必须初始化,可以将不需要的Callback定义为空指针。
221    ```c++
222    // OH_NativeXComponent_Callback是个struct
223    OH_NativeXComponent_Callback callback;
224    callback.OnSurfaceCreated = OnSurfaceCreatedCB;
225    callback.OnSurfaceChanged = OnSurfaceChangedCB;
226    callback.OnSurfaceDestroyed = OnSurfaceDestroyedCB;
227    callback.DispatchTouchEvent = DispatchTouchEventCB;
228    ```
2294. 将``OH_NativeXComponent_Callback``注册给NativeXComponent。
230    ```c++
231    // 注册回调函数
232    OH_NativeXComponent_RegisterCallback(nativeXComponent, &callback);
233    ```
234
235经过以上步骤,绘制环境已搭建完成,接下来介绍如何使用Drawing接口进行内容绘制。
236
237### 绘制2D图形
238
239以下步骤描述了如何使用Native Drawing模块的画布画笔绘制一个基本的2D图形:
240
2411. **创建Bitmap实例**。使用drawing_bitmap.h的``OH_Drawing_BitmapCreate``接口创建一个Bitmap实例cBitmap并使用``OH_Drawing_BitmapBuild``指定其长宽大小和像素格式。
242
243    创建一个SampleBitMap类,并声明接下来需要的私有成员变量。
244    ```c++
245    class SampleBitMap {
246    public:
247        // member functions
248    private:
249        OH_NativeXComponent_Callback renderCallback_;
250
251        uint64_t width_ = 0;
252        uint64_t height_ = 0;
253        OH_Drawing_Bitmap *cBitmap_ = nullptr;
254        OH_Drawing_Canvas *cCanvas_ = nullptr;
255        OH_Drawing_Path *cPath_ = nullptr;
256        OH_Drawing_Brush *cBrush_ = nullptr;
257        OH_Drawing_Pen *cPen_ = nullptr;
258        OHNativeWindow *nativeWindow_ = nullptr;
259        uint32_t *mappedAddr_ = nullptr;
260        BufferHandle *bufferHandle_ = nullptr;
261        struct NativeWindowBuffer *buffer_ = nullptr;
262        int fenceFd_ = 0;
263    };
264    ```
265
266    ```c++
267    // 创建一个bitmap对象
268    cBitmap_ = OH_Drawing_BitmapCreate();
269    // 定义bitmap的像素格式
270    OH_Drawing_BitmapFormat cFormat {COLOR_FORMAT_RGBA_8888, ALPHA_FORMAT_OPAQUE};
271    // 构造对应格式的bitmap,width的值必须为 bufferHandle->stride / 4
272    OH_Drawing_BitmapBuild(cBitmap_, width_, height_, &cFormat);
273    ```
274
2752. **创建画布实例**。使用drawing_canvas.h的 ``OH_Drawing_CanvasCreate`` 接口创建一个画布实例cCanvas,并使用 ``OH_Drawing_CanvasBind`` 接口将cBitmap实例绑定到cCanvas上,后续在画布上绘制的内容会输出到绑定的cBitmap实例中。
276
277    ```c++
278    // 创建一个canvas对象
279    cCanvas_ = OH_Drawing_CanvasCreate();
280    // 将画布与bitmap绑定,画布画的内容会输出到绑定的bitmap内存中
281    OH_Drawing_CanvasBind(cCanvas_, cBitmap_);
282    // 使用白色清除画布内容
283    OH_Drawing_CanvasClear(cCanvas_, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0xFF, 0xFF));
284    ```
285
2863. **构造Path形状**。使用drawing_path.h提供的接口完成一个五角星形状的构造cPath。
287
288    ```c++
289    int len = height_ / 4;
290    float aX = width_ / 2;
291    float aY = height_ / 4;
292    float dX = aX - len * std::sin(18.0f);
293    float dY = aY + len * std::cos(18.0f);
294    float cX = aX + len * std::sin(18.0f);
295    float cY = dY;
296    float bX = aX + (len / 2.0);
297    float bY = aY + std::sqrt((cX - dX) * (cX - dX) + (len / 2.0) * (len / 2.0));
298    float eX = aX - (len / 2.0);
299    float eY = bY;
300
301    // 创建一个path对象,然后使用接口连接成一个五角星形状
302    cPath_ = OH_Drawing_PathCreate();
303    // 指定path的起始位置
304    OH_Drawing_PathMoveTo(cPath_, aX, aY);
305    // 用直线连接到目标点
306    OH_Drawing_PathLineTo(cPath_, bX, bY);
307    OH_Drawing_PathLineTo(cPath_, cX, cY);
308    OH_Drawing_PathLineTo(cPath_, dX, dY);
309    OH_Drawing_PathLineTo(cPath_, eX, eY);
310    // 闭合形状,path绘制完毕
311    OH_Drawing_PathClose(cPath_);
312    ```
313
3144. **设置画笔和画刷样式**。使用drawing_pen.h的``OH_Drawing_PenCreate``接口创建一个画笔实例cPen, 并设置抗锯齿、颜色、线宽等属性,画笔用于形状边框线的绘制。使用drawing_brush.h的``OH_Drawing_BrushCreate``接口创建一个画刷实例cBrush,并设置填充颜色, 画刷用于形状内部的填充。使用drawing_canvas.h的``OH_Drawing_CanvasAttachPen``和``OH_Drawing_CanvasAttachBrush``接口将画笔画刷的实例设置到画布实例中。
315
316    ```c++
317    // 创建一个画笔Pen对象,Pen对象用于形状的边框线绘制
318    cPen_ = OH_Drawing_PenCreate();
319    OH_Drawing_PenSetAntiAlias(cPen_, true);
320    OH_Drawing_PenSetColor(cPen_, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0x00, 0x00));
321    OH_Drawing_PenSetWidth(cPen_, 10.0);
322    OH_Drawing_PenSetJoin(cPen_, LINE_ROUND_JOIN);
323    // 将Pen画笔设置到canvas中
324    OH_Drawing_CanvasAttachPen(cCanvas_, cPen_);
325
326    // 创建一个画刷Brush对象,Brush对象用于形状的填充
327    cBrush_ = OH_Drawing_BrushCreate();
328    OH_Drawing_BrushSetColor(cBrush_, OH_Drawing_ColorSetArgb(0xFF, 0x00, 0xFF, 0x00));
329
330    // 将Brush画刷设置到canvas中
331    OH_Drawing_CanvasAttachBrush(cCanvas_, cBrush_);
332    ```
333
3345. **绘制Path形状**。使用drawing_canvas.h的``OH_Drawing_CanvasDrawPath``接口将五角星绘制到画布上。
335
336    ```c++
337    // 在画布上画path的形状,五角星的边框样式为pen设置,颜色填充为Brush设置
338    OH_Drawing_CanvasDrawPath(cCanvas_, cPath_);
339    ```
340
341### 文本绘制开发步骤
342
343以下步骤描述了如何使用Native Drawing模块的文字显示功能:
3441. **创建画布和bitmap实例**。
345
346    ```c++
347    // 创建bitmap
348    cBitmap_ = OH_Drawing_BitmapCreate();
349    OH_Drawing_BitmapFormat cFormat {COLOR_FORMAT_RGBA_8888, ALPHA_FORMAT_OPAQUE};
350    // width的值必须为bufferHandle->stride / 4
351    OH_Drawing_BitmapBuild(cBitmap_, width_, height_, &cFormat);
352    // 创建canvas
353    cCanvas_ = OH_Drawing_CanvasCreate();
354    OH_Drawing_CanvasBind(cCanvas_, cBitmap_);
355    OH_Drawing_CanvasClear(cCanvas_, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0xFF, 0xFF));
356    ```
357
3582. **设置排版风格**。
359
360    ```c++
361    // 选择从左到右/左对齐等排版属性
362    OH_Drawing_TypographyStyle* typoStyle = OH_Drawing_CreateTypographyStyle();
363    OH_Drawing_SetTypographyTextDirection(typoStyle, TEXT_DIRECTION_LTR);
364    OH_Drawing_SetTypographyTextAlign(typoStyle, TEXT_ALIGN_LEFT);
365    ```
366
3673. **设置文本风格**。
368
369    ```c++
370    // 设置文字颜色,例如黑色
371    OH_Drawing_TextStyle* txtStyle = OH_Drawing_CreateTextStyle();
372    OH_Drawing_SetTextStyleColor(txtStyle, OH_Drawing_ColorSetArgb(0xFF, 0x00, 0x00, 0x00));
373    // 设置文字大小、字重等属性
374    double fontSize = width_ / 15;
375    OH_Drawing_SetTextStyleFontSize(txtStyle, fontSize);
376    OH_Drawing_SetTextStyleFontWeight(txtStyle, FONT_WEIGHT_400);
377    OH_Drawing_SetTextStyleBaseLine(txtStyle, TEXT_BASELINE_ALPHABETIC);
378    OH_Drawing_SetTextStyleFontHeight(txtStyle, 1);
379    // 设置字体类型等
380    const char* fontFamilies[] = {"Roboto"};
381    OH_Drawing_SetTextStyleFontFamilies(txtStyle, 1, fontFamilies);
382    OH_Drawing_SetTextStyleFontStyle(txtStyle, FONT_STYLE_NORMAL);
383    OH_Drawing_SetTextStyleLocale(txtStyle, "en");
384    ```
385
3864. **生成最终文本显示效果**。
387
388    ```c++
389    OH_Drawing_TypographyCreate* handler = OH_Drawing_CreateTypographyHandler(typoStyle,
390        OH_Drawing_CreateFontCollection());
391    OH_Drawing_TypographyHandlerPushTextStyle(handler, txtStyle);
392    // 设置文字内容
393    const char* text = "Hello World Drawing\n";
394    OH_Drawing_TypographyHandlerAddText(handler, text);
395    OH_Drawing_TypographyHandlerPopTextStyle(handler);
396    OH_Drawing_Typography* typography = OH_Drawing_CreateTypography(handler);
397    // 设置页面最大宽度
398    double maxWidth = width_;
399    OH_Drawing_TypographyLayout(typography, maxWidth);
400    // 设置文本在画布上绘制的起始位置
401    double position[2] = {width_ / 5.0, height_ / 2.0};
402    // 将文本绘制到画布上
403    OH_Drawing_TypographyPaint(typography, cCanvas_, position[0], position[1]);
404    ```
405### 绘制内容送显
406
407前面我们已经通过Drawing API实现了Path绘制以及文字绘制。现在需要将其呈现在Native Window上。
408
4091. 通过前面``OnSurfaceCreatedCB``回调保存的Native Window指针,来申请Native Window Buffer。
410    ```c++
411    // 通过 OH_NativeWindow_NativeWindowRequestBuffer 获取 OHNativeWindowBuffer 实例
412    int32_t ret = OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow_, &buffer_, &fenceFd_);
413    ```
4142. 通过``OH_NativeWindow_GetBufferHandleFromNative``获取bufferHandle。
415    ```c++
416    bufferHandle_ = OH_NativeWindow_GetBufferHandleFromNative(buffer_);
417    ```
4183. 使用系统mmap接口拿到bufferHandle的内存虚拟地址。
419    ```c++
420    mappedAddr_ = static_cast<uint32_t *>(
421        // 使用内存映射函数mmap将bufferHandle对应的共享内存映射到用户空间,可以通过映射出来的虚拟地址向bufferHandle中写入图像数据
422        // bufferHandle->virAddr是bufferHandle在共享内存中的起始地址,bufferHandle->size是bufferHandle在共享内存中的内存占用大小
423        mmap(bufferHandle_->virAddr, bufferHandle_->size, PROT_READ | PROT_WRITE, MAP_SHARED, bufferHandle_->fd, 0));
424    if (mappedAddr_ == MAP_FAILED) {
425        DRAWING_LOGE("mmap failed");
426    }
427    ```
4284. 使用drawing_bitmap.h的``OH_Drawing_BitmapGetPixels``接口获取到画布绑定bitmap实例的像素地址,该地址指向的内存包含画布刚刚绘制的像素数据。将绘制内容填充到申请的Native Window Buffer中。
429    ```c++
430    // 画完后获取像素地址,地址指向的内存包含画布画的像素数据
431    void *bitmapAddr = OH_Drawing_BitmapGetPixels(cBitmap_);
432    uint32_t *value = static_cast<uint32_t *>(bitmapAddr);
433
434    // 使用mmap获取到的地址来访问内存
435    uint32_t *pixel = static_cast<uint32_t *>(mappedAddr_);
436    for (uint32_t x = 0; x < width_; x++) {
437        for (uint32_t y = 0; y < height_; y++) {
438            *pixel++ = *value++;
439        }
440    }
441    ```
4425. 设置刷新区域,并将其送显。
443    ```c++
444    // 如果Region中的Rect为nullptr,或者rectNumber为0,则认为OHNativeWindowBuffer全部有内容更改。
445    Region region {nullptr, 0};
446    // 通过OH_NativeWindow_NativeWindowFlushBuffer 提交给消费者使用,例如:显示在屏幕上。
447    OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow_, buffer_, fenceFd_, region);
448    ```
4496. 内存释放。
450
451    Drawing内存释放。
452
453    ```c++
454    // 去掉内存映射
455    int result = munmap(mappedAddr_, bufferHandle_->size);
456    if (result == -1) {
457        DRAWING_LOGE("munmap failed!");
458    }
459    // 销毁创建的对象
460    OH_Drawing_BrushDestroy(cBrush_);
461    cBrush_ = nullptr;
462    OH_Drawing_PenDestroy(cPen_);
463    cPen_ = nullptr;
464    OH_Drawing_PathDestroy(cPath_);
465    cPath_ = nullptr;
466    OH_Drawing_CanvasDestroy(cCanvas_);
467    cCanvas_ = nullptr;
468    OH_Drawing_BitmapDestroy(cBitmap_);
469    cBitmap_ = nullptr;
470    ```
471    Surface内存释放。
472
473    ```c++
474    void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window) {
475        DRAWING_LOGI("OnSurfaceDestroyedCB");
476        if ((component == nullptr) || (window == nullptr)) {
477            DRAWING_LOGE("OnSurfaceDestroyedCB: component or window is null");
478            return;
479        }
480        char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
481        uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
482        if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
483            DRAWING_LOGE("OnSurfaceDestroyedCB: Unable to get XComponent id");
484            return;
485        }
486        std::string id(idStr);
487        SampleBitMap::Release(id);
488    }
489    ```
490### 用户调用
491
492以上为Native层C++代码,用户想要调用还需要通过ArkTS层代码对接。
4931. 定义ArkTS接口文件,命名XComponentContext.ts,用来对接Native代码。
494    ```ts
495    export default interface XComponentContext {
496      drawPattern(): void;
497      drawText(): void;
498    };
499    ```
500    在SampleBitMap类中添加初始化函数以及代码。
501    ```c++
502    void SampleBitMap::Export(napi_env env, napi_value exports) {
503        if ((env == nullptr) || (exports == nullptr)) {
504            DRAWING_LOGE("Export: env or exports is null");
505            return;
506        }
507        napi_property_descriptor desc[] = {
508            {"drawPattern", nullptr, SampleBitMap::NapiDrawPattern, nullptr, nullptr, nullptr, napi_default, nullptr},
509            {"drawText", nullptr, SampleBitMap::NapiDrawText, nullptr, nullptr, nullptr, napi_default, nullptr}};
510        napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
511        if (napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc) != napi_ok) {
512            DRAWING_LOGE("Export: napi_define_properties failed");
513        }
514    }
515    ```
5162. 添加button控件供用户点击,并调用已定义的接口。
517    ```ts
518    build() {
519      Column() {
520        Row() {
521          XComponent({ id: 'xcomponentId', type: 'surface', libraryname: 'entry' })
522            .onLoad((xComponentContext) => {
523              this.xComponentContext = xComponentContext as XComponentContext;
524            }).width('640px') // Multiples of 64
525          }.height('88%')
526          Row() {
527            Button('Draw Path')
528              .fontSize('16fp')
529              .fontWeight(500)
530              .margin({ bottom: 24, right: 12 })
531              .onClick(() => {
532                console.log(TAG, "Draw Path click");
533                if (this.xComponentContext) {
534                  console.log(TAG, "Draw Path");
535                  this.xComponentContext.drawPattern();
536                  }
537              })
538              .width('33.6%')
539              .height(40)
540              .shadow(ShadowStyle.OUTER_DEFAULT_LG)
541            Button('Draw Text')
542              .fontSize('16fp')
543              .fontWeight(500)
544              .margin({ bottom: 24, left: 12 })
545              .onClick(() => {
546                  console.log(TAG, "draw text click");
547                  if (this.xComponentContext) {
548                    console.log(TAG, "draw text");
549                    this.xComponentContext.drawText();
550                  }
551              })
552              .width('33.6%')
553              .height(40)
554              .shadow(ShadowStyle.OUTER_DEFAULT_LG)
555          }
556          .width('100%')
557          .justifyContent(FlexAlign.Center)
558          .shadow(ShadowStyle.OUTER_DEFAULT_SM)
559          .alignItems(VerticalAlign.Bottom)
560          .layoutWeight(1)
561        }
562    }
563    ```
5643. 绘制与显示的效果图如下:
565
566    | 主页                                 | 绘制五角星                                         | 绘制文字                                            |
567    | ------------------------------------ |-----------------------------------------------| --------------------------------------------------- |
568    | ![main](./figures/drawIndex.jpg) | ![Draw Path](./figures/drawPath.jpg) | ![Draw Text](./figures/drawText.jpg) |
569
570##  相关实例
571
572以上代码为Drawing绘制关键代码,完整代码请参考下面sample。
573
574- [Native Drawing(API10)](https://gitee.com/openharmony/applications_app_samples/tree/OpenHarmony-4.0-Release/code/BasicFeature/Native/NdkDrawing)
575
576