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 |  |  |  | 693 694