1# Using Drawing to Draw and Display Graphics (C/C++)
2
3## When to Use
4
5The native drawing module provides APIs for drawing 2D graphics and text.
6
7The graphics and text drawn by using the APIs cannot be directly displayed on the screen. To display the drawn graphics and text, you'll need the capabilities provided by the **XComponent** and native window module.
8
9## Available APIs
10
11The table below lists the common native drawing APIs. For details about all the APIs, see [Drawing](../reference/apis-arkgraphics2d/_drawing.md).
12
13| API| Description|
14| -------- | -------- |
15| OH_Drawing_BitmapCreate (void) | Creates a bitmap object.|
16| OH_Drawing_BitmapBuild (OH_Drawing_Bitmap *, const uint32_t width, const uint32_t height, const OH_Drawing_BitmapFormat *) | Initializes the width and height of a bitmap and sets the pixel format for the bitmap.|
17| OH_Drawing_CanvasCreate (void) | Creates a canvas object.|
18| OH_Drawing_CanvasBind (OH_Drawing_Canvas *, OH_Drawing_Bitmap *) | Binds a bitmap to a canvas so that the content drawn on the canvas is output to the bitmap. (This process is called CPU rendering.)|
19| OH_Drawing_CanvasAttachBrush (OH_Drawing_Canvas *, const OH_Drawing_Brush *) | Attaches a brush to a canvas so that the canvas can use the style and color of the brush to fill in a shape.|
20| OH_Drawing_CanvasAttachPen (OH_Drawing_Canvas *, const OH_Drawing_Pen *) | Attaches a pen to a canvas so that the canvas can use the style and color of the pen to outline a shape.|
21| OH_Drawing_CanvasDrawPath (OH_Drawing_Canvas *, const OH_Drawing_Path *) | Draws a path.|
22| OH_Drawing_PathCreate (void) | Creates a path object.|
23| OH_Drawing_PathMoveTo (OH_Drawing_Path *, float x, float y) | Sets the start point of a path.|
24| OH_Drawing_PathLineTo (OH_Drawing_Path *, float x, float y) | Draws a line segment from the last point of a path to the target point.|
25| OH_Drawing_PathClose (OH_Drawing_Path *) | Draws a line segment from the current point to the start point of a path.|
26| OH_Drawing_PenCreate (void) | Creates a pen object.|
27| OH_Drawing_PenSetAntiAlias (OH_Drawing_Pen *, bool) | Checks whether anti-aliasing is enabled for a pen. If anti-aliasing is enabled, edges will be drawn with partial transparency.|
28| OH_Drawing_PenSetWidth (OH_Drawing_Pen *, float width) | Sets the thickness for a pen. This thickness determines the width of the outline of a shape.|
29| OH_Drawing_BrushCreate (void) | Creates a brush object.|
30| OH_Drawing_BrushSetColor (OH_Drawing_Brush *, uint32_t color) | Sets the color for a brush. The color will be used by the brush to fill in a shape.|
31| OH_Drawing_CreateTypographyStyle (void) | Creates a **TypographyStyle** object.|
32| OH_Drawing_CreateTextStyle (void) | Creates a **TextStyle** object.|
33| OH_Drawing_TypographyHandlerAddText (OH_Drawing_TypographyCreate *, const char *) | Adds text to the canvas.|
34| OH_Drawing_TypographyPaint (OH_Drawing_Typography *, OH_Drawing_Canvas *, double, double) | Paints text on the canvas.|
35
36## How to Develop
37
38### Development Process
39
40First, use the canvas and pen of the native drawing module to draw a basic 2D graphic, write the graphics content to the buffer provided by the native window module, and flush the buffer to the graphics queue. Then use the **XComponent** to connect the C++ code layer to the ArkTS layer. In this way, the drawing and display logic of the C++ code is called at the ArkTS layer, and the graphic is displayed on the screen.
41
42The following walks you through on how to draw and display 2D graphics and text.
43### Adding Dependencies
44
45**Adding Dynamic Link Libraries**
46
47Add the following libraries to **CMakeLists.txt**.
48
49```txt
50libace_napi.z.so
51libace_ndk.z.so
52libnative_window.so
53libnative_drawing.so
54```
55
56**Including Header Files**
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### Building a Drawing Environment Using XComponent
74
751. Add the **XComponent** to the **Index.ets** file.
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') // Multiple of 64
93          }.height('88%')
94        }
95      }
96    }
97    ```
98    The width of the **XComponent** must be a multiple of 64, for example, 640 px.
992. Obtain the native **XComponent** at the C++ layer. You are advised to save the **XComponent** in a singleton. This step must be performed during napi_init.
100
101    Create a **PluginManger** singleton to manage the native **XComponent**.
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    The **SampleBitMap** class will be created in the step of drawing a 2D graphic.
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. Register a callback, named **OnSurfaceCreated**, and obtain an **OHNativeWindow** instance through the callback. You are advised to save the **OHNativeWindow** instance in a singleton.
160    ```c++
161    // Define a callback.
162    void OnSurfaceCreatedCB(OH_NativeXComponent* component, void* window)
163    {
164        // Obtain an OHNativeWindow instance.
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        // Obtain an OHNativeWindow instance.
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        // Obtain an OHNativeWindow instance.
210        OHNativeWindow* nativeWindow = static_cast<OHNativeWindow*>(window);
211        // ...
212    }
213    void DispatchTouchEventCB(OH_NativeXComponent* component, void* window)
214    {
215        // Obtain an OHNativeWindow instance.
216        OHNativeWindow* nativeWindow = static_cast<OHNativeWindow*>(window);
217        // ...
218    }
219    ```
220    All callbacks of the **XComponent** must be initialized. You can define unnecessary callbacks as null pointers.
221    ```c++
222    // OH_NativeXComponent_Callback is a struct.
223    OH_NativeXComponent_Callback callback;
224    callback.OnSurfaceCreated = OnSurfaceCreatedCB;
225    callback.OnSurfaceChanged = OnSurfaceChangedCB;
226    callback.OnSurfaceDestroyed = OnSurfaceDestroyedCB;
227    callback.DispatchTouchEvent = DispatchTouchEventCB;
228    ```
2294. Register **OH_NativeXComponent_Callback** with a **NativeXComponent** instance.
230    ```c++
231    // Register the callback.
232    OH_NativeXComponent_RegisterCallback(nativeXComponent, &callback);
233    ```
234
235Now, the drawing environment is set up. You can use the native drawing APIs to draw graphics.
236
237### Drawing a 2D Graphic
238
239Follow the steps below to draw a 2D graphic by using the canvas and pen of the native drawing module.
240
2411. **Create a bitmap object.**
242
243    Use **OH_Drawing_BitmapCreate** in **drawing_bitmap.h** to create a bitmap object (named **cBitmap** in this example), and use **OH_Drawing_BitmapBuild** to specify its length, width, and pixel format.
244
245    Create a **SampleBitMap** class and declare the required private member variables.
246    ```c++
247    class SampleBitMap {
248    public:
249        // member functions
250    private:
251        OH_NativeXComponent_Callback renderCallback_;
252
253        uint64_t width_ = 0;
254        uint64_t height_ = 0;
255        OH_Drawing_Bitmap *cBitmap_ = nullptr;
256        OH_Drawing_Canvas *cCanvas_ = nullptr;
257        OH_Drawing_Path *cPath_ = nullptr;
258        OH_Drawing_Brush *cBrush_ = nullptr;
259        OH_Drawing_Pen *cPen_ = nullptr;
260        OHNativeWindow *nativeWindow_ = nullptr;
261        uint32_t *mappedAddr_ = nullptr;
262        BufferHandle *bufferHandle_ = nullptr;
263        struct NativeWindowBuffer *buffer_ = nullptr;
264        int fenceFd_ = 0;
265    };
266    ```
267
268    ```c++
269    // Create a bitmap object.
270    cBitmap_ = OH_Drawing_BitmapCreate();
271    // Define the pixel format of the bitmap.
272    OH_Drawing_BitmapFormat cFormat {COLOR_FORMAT_RGBA_8888, ALPHA_FORMAT_OPAQUE};
273    // Build a bitmap in the corresponding format. The width must be bufferHandle->stride / 4.
274    OH_Drawing_BitmapBuild(cBitmap_, width_, height_, &cFormat);
275    ```
276
2772. **Create a canvas object.**
278
279    Use **OH_Drawing_CanvasCreate** in **drawing_canvas.h** to create a canvas object (named **cCanvas** in this example), and use **OH_Drawing_CanvasBind** to bind **cBitmap** to this canvas. The content drawn on the canvas will be output to the bound **cBitmap** object.
280
281    ```c++
282    // Create a canvas object.
283    cCanvas_ = OH_Drawing_CanvasCreate();
284    // Bind the bitmap to the canvas. The content drawn on the canvas will be output to the bound bitmap memory.
285    OH_Drawing_CanvasBind(cCanvas_, cBitmap_);
286    // Use white to clear the canvas.
287    OH_Drawing_CanvasClear(cCanvas_, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0xFF, 0xFF));
288    ```
289
2903. **Construct a shape.**
291
292    Use the APIs provided in **drawing_path.h** to construct a pentagram, named **cPath**.
293
294    ```c++
295    int len = height_ / 4;
296    float aX = width_ / 2;
297    float aY = height_ / 4;
298    float dX = aX - len * std::sin(18.0f);
299    float dY = aY + len * std::cos(18.0f);
300    float cX = aX + len * std::sin(18.0f);
301    float cY = dY;
302    float bX = aX + (len / 2.0);
303    float bY = aY + std::sqrt((cX - dX) * (cX - dX) + (len / 2.0) * (len / 2.0));
304    float eX = aX - (len / 2.0);
305    float eY = bY;
306
307    // Create a path object and use the APIs to construct a pentagram.
308    cPath_ = OH_Drawing_PathCreate();
309    // Specify the start point of the path.
310    OH_Drawing_PathMoveTo(cPath_, aX, aY);
311    // Draw a line segment from the last point of a path to the target point.
312    OH_Drawing_PathLineTo(cPath_, bX, bY);
313    OH_Drawing_PathLineTo(cPath_, cX, cY);
314    OH_Drawing_PathLineTo(cPath_, dX, dY);
315    OH_Drawing_PathLineTo(cPath_, eX, eY);
316    // Close the path. Now the path is drawn.
317    OH_Drawing_PathClose(cPath_);
318    ```
319
3204. **Set the pen and brush styles.**
321
322    Use **OH_Drawing_PenCreate** in **drawing_pen.h** to create a pen object (named **cPen** in this example), and set the attributes such as anti-aliasing, color, and thickness. The pen is used to outline a shape.
323
324    Use **OH_Drawing_BrushCreate** in **drawing_brush.h** to create a brush object (named **cBrush** in this example), and set the brush color. The brush is used to fill in a shape.
325
326    Use **OH_Drawing_CanvasAttachPen** and **OH_Drawing_CanvasAttachBrush** in **drawing_canvas.h** to attach the pen and brush to the canvas.
327
328    ```c++
329    // Create a pen object and set the anti-aliasing, color, and thickness attributes.
330    cPen_ = OH_Drawing_PenCreate();
331    OH_Drawing_PenSetAntiAlias(cPen_, true);
332    OH_Drawing_PenSetColor(cPen_, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0x00, 0x00));
333    OH_Drawing_PenSetWidth(cPen_, 10.0);
334    OH_Drawing_PenSetJoin(cPen_, LINE_ROUND_JOIN);
335    // Attach the pen to the canvas.
336    OH_Drawing_CanvasAttachPen(cCanvas_, cPen_);
337
338    // Create a brush object and set the color.
339    cBrush_ = OH_Drawing_BrushCreate();
340    OH_Drawing_BrushSetColor(cBrush_, OH_Drawing_ColorSetArgb(0xFF, 0x00, 0xFF, 0x00));
341
342    // Attach the brush to the canvas.
343    OH_Drawing_CanvasAttachBrush(cCanvas_, cBrush_);
344    ```
345
3465. **Draw the pentagram.**
347
348    Use **OH_Drawing_CanvasDrawPath** in **drawing_canvas.h** to draw the pentagram on the canvas.
349
350    ```c++
351    // Draw a pentagram on the canvas. The outline of the pentagram is drawn by the pen, and the color is filled in by the brush.
352    OH_Drawing_CanvasDrawPath(cCanvas_, cPath_);
353    ```
354
355### Drawing Text
356
357The native drawing module provides two types of APIs for text drawing:
358
359- APIs with the typography customization capability. Example APIs are **OH_Drawing_Typography**, **OH_Drawing_TypographyStyle**, and **OH_Drawing_TextStyle**. This type of API allows you to set the typography style and text style. You can call **OH_Drawing_TypographyHandlerAddText** to add text, and call **OH_Drawing_TypographyLayout** and **OH_Drawing_TypographyPaint** to typeset and draw the text.
360- APIs that do not support typography customization. Example APIs are **OH_Drawing_Font**, **OH_Drawing_TextBlob**, and **OH_Drawing_RunBuffer**. If an application has its own typography capability, it can construct the typography result as an **OH_Drawing_TextBlob**. If an application uses the default typography capability, it can directly call **OH_Drawing_TextBlobCreateFromText** to construct an **OH_Drawing_TextBlob**. Finally, the application calls **OH_Drawing_CanvasDrawTextBlob** to draw the text block described in the **OH_Drawing_TextBlob**.
361
362The following describes how to use the two types of APIs to implement text drawing.
363
364#### Using APIs with Typography Customization to Draw Text
365
3661. **Create a bitmap and a canvas.**
367
368    ```c++
369    // Create a bitmap.
370    cBitmap_ = OH_Drawing_BitmapCreate();
371    OH_Drawing_BitmapFormat cFormat {COLOR_FORMAT_RGBA_8888, ALPHA_FORMAT_OPAQUE};
372    // The width must be bufferHandle->stride / 4.
373    OH_Drawing_BitmapBuild(cBitmap_, width_, height_, &cFormat);
374    // Create a canvas.
375    cCanvas_ = OH_Drawing_CanvasCreate();
376    OH_Drawing_CanvasBind(cCanvas_, cBitmap_);
377    OH_Drawing_CanvasClear(cCanvas_, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0xFF, 0xFF));
378    ```
379
3802. **Set the typography style.**
381
382    ```c++
383    // Set the typography attributes such as left to right (LTR) for the text direction and left-aligned for the text alignment mode.
384    OH_Drawing_TypographyStyle* typoStyle = OH_Drawing_CreateTypographyStyle();
385    OH_Drawing_SetTypographyTextDirection(typoStyle, TEXT_DIRECTION_LTR);
386    OH_Drawing_SetTypographyTextAlign(typoStyle, TEXT_ALIGN_LEFT);
387    ```
388
3893. **Set the text style.**
390
391    ```c++
392    // Set the text color, for example, black.
393    OH_Drawing_TextStyle* txtStyle = OH_Drawing_CreateTextStyle();
394    OH_Drawing_SetTextStyleColor(txtStyle, OH_Drawing_ColorSetArgb(0xFF, 0x00, 0x00, 0x00));
395    // Set other text attributes such as the font size and weight.
396    double fontSize = width_ / 15;
397    OH_Drawing_SetTextStyleFontSize(txtStyle, fontSize);
398    OH_Drawing_SetTextStyleFontWeight(txtStyle, FONT_WEIGHT_400);
399    OH_Drawing_SetTextStyleBaseLine(txtStyle, TEXT_BASELINE_ALPHABETIC);
400    OH_Drawing_SetTextStyleFontHeight(txtStyle, 1);
401    // If multiple measurements are required, it is recommended that fontCollection be used as a global variable to significantly reduce memory usage.
402    OH_Drawing_FontCollection* fontCollection = OH_Drawing_CreateSharedFontCollection();
403    // Register the customized font.
404    const char* fontFamily = "myFamilyName"; // myFamilyName is the family name of the customized font.
405    const char* fontPath = "/data/storage/el2/base/haps/entry/files/myFontFile.ttf"; // Set the sandbox path where the customized font is located.
406    OH_Drawing_RegisterFont(fontCollection, fontFamily, fontPath);
407    // Set the system font type.
408    const char* systemFontFamilies[] = {"Roboto"};
409    OH_Drawing_SetTextStyleFontFamilies(txtStyle, 1, systemFontFamilies);
410    OH_Drawing_SetTextStyleFontStyle(txtStyle, FONT_STYLE_NORMAL);
411    OH_Drawing_SetTextStyleLocale(txtStyle, "en");
412    // Set the customized font type.
413    auto txtStyle2 = OH_Drawing_CreateTextStyle();
414    OH_Drawing_SetTextStyleFontSize(txtStyle2, fontSize);
415    const char* myFontFamilies[] = {"myFamilyName"}; // If a customized font has been registered, enter the family name of the customized font to use the customized font.
416    OH_Drawing_SetTextStyleFontFamilies(txtStyle2, 1, myFontFamilies);
417    ```
418
4194. **Generate the final text display effect.**
420
421    ```c++
422    OH_Drawing_TypographyCreate* handler = OH_Drawing_CreateTypographyHandler(typoStyle,
423        fontCollection);
424    OH_Drawing_TypographyHandlerPushTextStyle(handler, txtStyle);
425    OH_Drawing_TypographyHandlerPushTextStyle(handler, txtStyle2);
426    // Set the text content.
427    const char* text = "Hello World Drawing\n";
428    OH_Drawing_TypographyHandlerAddText(handler, text);
429    OH_Drawing_TypographyHandlerPopTextStyle(handler);
430    OH_Drawing_Typography* typography = OH_Drawing_CreateTypography(handler);
431    // Set the maximum width.
432    double maxWidth = width_;
433    OH_Drawing_TypographyLayout(typography, maxWidth);
434    // Set the start position for drawing the text on the canvas.
435    double position[2] = {width_ / 5.0, height_ / 2.0};
436    // Draw the text on the canvas.
437    OH_Drawing_TypographyPaint(typography, cCanvas_, position[0], position[1]);
438    ```
4395. **Release the variables.**
440
441    ```c++
442    // Destroy the typography when it is no longer needed.
443    OH_Drawing_DestroyTypography(typography);
444    // Destroy the layout when it is no longer needed.
445    OH_Drawing_DestroyTypographyHandler(handler);
446    // Destroy the font collection when it is no longer needed.
447    OH_Drawing_DestroyFontCollection(fontCollection);
448    // Destroy the layout when it is no longer needed.
449    OH_Drawing_DestroyTextStyle(txtStyle);
450    OH_Drawing_DestroyTextStyle(txtStyle2);
451    // Destroy the layout when it is no longer needed.
452    OH_Drawing_DestroyTypographyStyle(typoStyle);
453    ```
454
455#### Using APIs Without Typography Customization to Draw Text
456
4571. **Create a bitmap and a canvas.**
458
459    ```c++
460    // Create a bitmap.
461    cBitmap_ = OH_Drawing_BitmapCreate();
462    OH_Drawing_BitmapFormat cFormat {COLOR_FORMAT_RGBA_8888, ALPHA_FORMAT_OPAQUE};
463    // The width must be bufferHandle->stride / 4.
464    OH_Drawing_BitmapBuild(cBitmap_, width_, height_, &cFormat);
465    // Create a canvas.
466    cCanvas_ = OH_Drawing_CanvasCreate();
467    OH_Drawing_CanvasBind(cCanvas_, cBitmap_);
468    OH_Drawing_CanvasClear(cCanvas_, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0xFF, 0xFF));
469    ```
470
4712. **Refer to the code snippet below for the application that has its own typography capability.**
472
473    ```c++
474    // Create a font and set the font size.
475    OH_Drawing_Font* font = OH_Drawing_FontCreate();
476    OH_Drawing_FontSetTextSize(font, 40);
477    // Create a text blob builder.
478    OH_Drawing_TextBlobBuilder* builder = OH_Drawing_TextBlobBuilderCreate();
479    // Apply for a memory block.
480    const OH_Drawing_RunBuffer* runBuffer = OH_Drawing_TextBlobBuilderAllocRunPos(builder, font, count, nullptr);
481    // glyphs, posX, and posY are data generated during typography. The data is used to fill in the memory.
482    for (int idx = 0; idx < count; idx++) {
483        runBuffer->glyphs[idx] = glyphs[idx];
484        runBuffer->pos[idx * 2] = posX[idx];
485        runBuffer->pos[idx * 2 + 1] = posY[idx];
486    }
487    // Create the text blob using the text blob builder.
488    OH_Drawing_TextBlob* textBlob = OH_Drawing_TextBlobBuilderMake(builder);
489    // Release the memory.
490    OH_Drawing_TextBlobBuilderDestroy(builder);
491    ```
492
4933. **Refer to the code snippet below for the application that uses the default typography capability.**
494
495    ```c++
496    // Create a font and set the font size.
497    OH_Drawing_Font* font = OH_Drawing_FontCreate();
498    OH_Drawing_FontSetTextSize(font, 40);
499    // Create the characters to be displayed.
500    size_t size = 19;
501    const char16_t* buffer = u"Hello World Drawing";
502    // Create the text blob based on the characters and corresponding encoding format.
503    OH_Drawing_TextBlob* textBlob = OH_Drawing_TextBlobCreateFromText(buffer, size * sizeof(char16_t), font, OH_Drawing_TextEncoding::TEXT_ENCODING_UTF16);
504    ```
505
5064. **Set the pen and brush styles.**
507
508    ```c++
509    // Create a brush object and set the color.
510    cBrush_ = OH_Drawing_BrushCreate();
511    OH_Drawing_BrushSetColor(cBrush_, OH_Drawing_ColorSetArgb(0xFF, 0x00, 0x00, 0x00));
512
513    // Attach the brush to the canvas.
514    OH_Drawing_CanvasAttachBrush(cCanvas_, cBrush_);
515    ```
516
5175. **Generate the final text display effect.**
518
519    ```c++
520    // Set the start position for drawing the text on the canvas.
521    double position[2] = {width_ / 5.0, height_ / 2.0};
522    // Draw the text on the canvas.
523    OH_Drawing_CanvasDrawTextBlob(canvas_, textBlob, position[0], position[1]);
524    // Release the memory.
525    OH_Drawing_TextBlobDestroy(textBlob);
526    OH_Drawing_FontDestroy(font);
527    ```
528
529### Displaying the Graphics and Text Drawn
530
531You have drawn a pentagon and text by using the native drawing APIs. Now you need to display them on the screen by using the native Window APIs.
532
5331. Request a native window buffer by using the native window pointer saved in the **OnSurfaceCreatedCB** callback.
534    ```c++
535    // Obtain an OHNativeWindowBuffer instance by calling OH_NativeWindow_NativeWindowRequestBuffer.
536    int32_t ret = OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow_, &buffer_, &fenceFd_);
537    ```
5382. Call **OH_NativeWindow_GetBufferHandleFromNative** to obtain the buffer handle.
539    ```c++
540    bufferHandle_ = OH_NativeWindow_GetBufferHandleFromNative(buffer_);
541    ```
5423. Call **mmap()** to obtain the memory virtual address of the buffer handle.
543    ```c++
544    mappedAddr_ = static_cast<uint32_t *>(
545        // Use mmap() to map the shared memory corresponding to the buffer handle to the user space. Image data can be written to the buffer handle by using the obtained virtual address.
546        // bufferHandle->virAddr indicates the start address of the buffer handle in the shared memory, and bufferHandle->size indicates the memory usage of the buffer handle in the shared memory.
547        mmap(bufferHandle_->virAddr, bufferHandle_->size, PROT_READ | PROT_WRITE, MAP_SHARED, bufferHandle_->fd, 0));
548    if (mappedAddr_ == MAP_FAILED) {
549        DRAWING_LOGE("mmap failed");
550    }
551    ```
5524. Use **OH_Drawing_BitmapGetPixels** in **drawing_bitmap.h** to obtain the pixel address of the bitmap bound to the canvas. The memory to which the address points contains the pixel data of the drawing on the canvas. Fill the drawn content to the native window buffer.
553    ```c++
554    // Obtain the pixel address after drawing. The memory to which the address points contains the pixel data of the drawing on the canvas.
555    void *bitmapAddr = OH_Drawing_BitmapGetPixels(cBitmap_);
556    uint32_t *value = static_cast<uint32_t *>(bitmapAddr);
557
558    // Use the address obtained by mmap() to access the memory.
559    uint32_t *pixel = static_cast<uint32_t *>(mappedAddr_);
560    for (uint32_t x = 0; x < width_; x++) {
561        for (uint32_t y = 0; y < height_; y++) {
562            *pixel++ = *value++;
563        }
564    }
565    ```
5665. Set the refresh region and display the content on the screen.
567    ```c++
568    // If Rect in Region is a null pointer or rectNumber is 0, all contents in the OHNativeWindowBuffer are changed.
569    Region region {nullptr, 0};
570    // Flush the buffer to the consumer through OH_NativeWindow_NativeWindowFlushBuffer, for example, by displaying it on the screen.
571    OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow_, buffer_, fenceFd_, region);
572    ```
5736. Release the memory.
574
575    Release the memory used by the native drawing module.
576
577    ```c++
578    // Unmap the memory.
579    int result = munmap(mappedAddr_, bufferHandle_->size);
580    if (result == -1) {
581        DRAWING_LOGE("munmap failed!");
582    }
583    // Destroy the created objects when they are no longer needed.
584    OH_Drawing_BrushDestroy(cBrush_);
585    cBrush_ = nullptr;
586    OH_Drawing_PenDestroy(cPen_);
587    cPen_ = nullptr;
588    OH_Drawing_PathDestroy(cPath_);
589    cPath_ = nullptr;
590    OH_Drawing_CanvasDestroy(cCanvas_);
591    cCanvas_ = nullptr;
592    OH_Drawing_BitmapDestroy(cBitmap_);
593    cBitmap_ = nullptr;
594    ```
595    Release the surface memory.
596
597    ```c++
598    void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window) {
599        DRAWING_LOGI("OnSurfaceDestroyedCB");
600        if ((component == nullptr) || (window == nullptr)) {
601            DRAWING_LOGE("OnSurfaceDestroyedCB: component or window is null");
602            return;
603        }
604        char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {'\0'};
605        uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
606        if (OH_NativeXComponent_GetXComponentId(component, idStr, &idSize) != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
607            DRAWING_LOGE("OnSurfaceDestroyedCB: Unable to get XComponent id");
608            return;
609        }
610        std::string id(idStr);
611        SampleBitMap::Release(id);
612    }
613    ```
614### Calling Code
615
616The preceding code is the C++ code at the native layer. To call the code, use the ArkTS layer code for interconnection.
6171. Define an ArkTS API file and name it **XComponentContext.ts**, which is used to connect to the C++ code.
618    ```ts
619    export default interface XComponentContext {
620      drawPattern(): void;
621      drawText(): void;
622    };
623    ```
624    Add the initialization function and code to the **SampleBitMap** class.
625    ```c++
626    void SampleBitMap::Export(napi_env env, napi_value exports) {
627        if ((env == nullptr) || (exports == nullptr)) {
628            DRAWING_LOGE("Export: env or exports is null");
629            return;
630        }
631        napi_property_descriptor desc[] = {
632            {"drawPattern", nullptr, SampleBitMap::NapiDrawPattern, nullptr, nullptr, nullptr, napi_default, nullptr},
633            {"drawText", nullptr, SampleBitMap::NapiDrawText, nullptr, nullptr, nullptr, napi_default, nullptr}};
634        napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
635        if (napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc) != napi_ok) {
636            DRAWING_LOGE("Export: napi_define_properties failed");
637        }
638    }
639    ```
6402. Add buttons for users to click and call the defined APIs.
641    ```ts
642    build() {
643      Column() {
644        Row() {
645          XComponent({ id: 'xcomponentId', type: 'surface', libraryname: 'entry' })
646            .onLoad((xComponentContext) => {
647              this.xComponentContext = xComponentContext as XComponentContext;
648            }).width('640px') // Multiples of 64
649          }.height('88%')
650          Row() {
651            Button('Draw Path')
652              .fontSize('16fp')
653              .fontWeight(500)
654              .margin({ bottom: 24, right: 12 })
655              .onClick(() => {
656                console.log(TAG, "Draw Path click");
657                if (this.xComponentContext) {
658                  console.log(TAG, "Draw Path");
659                  this.xComponentContext.drawPattern();
660                  }
661              })
662              .width('33.6%')
663              .height(40)
664              .shadow(ShadowStyle.OUTER_DEFAULT_LG)
665            Button('Draw Text')
666              .fontSize('16fp')
667              .fontWeight(500)
668              .margin({ bottom: 24, left: 12 })
669              .onClick(() => {
670                  console.log(TAG, "draw text click");
671                  if (this.xComponentContext) {
672                    console.log(TAG, "draw text");
673                    this.xComponentContext.drawText();
674                  }
675              })
676              .width('33.6%')
677              .height(40)
678              .shadow(ShadowStyle.OUTER_DEFAULT_LG)
679          }
680          .width('100%')
681          .justifyContent(FlexAlign.Center)
682          .shadow(ShadowStyle.OUTER_DEFAULT_SM)
683          .alignItems(VerticalAlign.Bottom)
684          .layoutWeight(1)
685        }
686    }
687    ```
688    The following figure shows the drawing and display effect.
689
690    | Home page                                | Pentagon drawn                                        | Text drawn                                           |
691    | ------------------------------------ |-----------------------------------------------| --------------------------------------------------- |
692    | ![main](./figures/drawIndex.jpg) | ![Draw Path](./figures/drawPath.jpg) | ![Draw Text](./figures/drawText.jpg) |
693
694