1# 画布的获取与绘制结果的显示(C/C++) 2 3 4## 场景介绍 5 6Canvas即画布,提供绘制基本图形的能力,用于在屏幕上绘制图形和处理图形。开发者可以通过Canvas实现自定义的绘图效果,增强应用的用户体验。 7 8Canvas是图形绘制的核心,本章中提到的所有绘制操作(包括基本图形的绘制、文字的绘制、图片的绘制、图形变换等)都是基于Canvas的。 9 10目前C/C++有两种获取Canvas的方式:获取可直接上屏显示的Canvas、获取离屏的Canvas,前者在调用绘制接口之后无需进行额外的操作即可完成绘制结果的上屏显示,而后者需要依靠已有的显示手段来显示绘制结果。 11 12 13## 接口说明 14 15创建Canvas常用接口如下表所示,详细的使用和参数说明请见[drawing_canvas.h](../reference/apis-arkgraphics2d/drawing__canvas_8h.md)。 16 17| 接口 | 描述 | 18| -------- | -------- | 19| OH_Drawing_Canvas\* OH_Drawing_CanvasCreate (void) | 用于创建一个画布对象。 | 20| void OH_Drawing_CanvasBind (OH_Drawing_Canvas\*, OH_Drawing_Bitmap\*) | 用于将一个位图对象绑定到画布中,使得画布绘制的内容输出到位图中。 | 21| OH_Drawing_Canvas\* OH_Drawing_SurfaceGetCanvas (OH_Drawing_Surface \*) | 通过surface对象获取画布对象。 | 22 23 24## 获取可直接显示的Canvas画布 25 26通过XComponent获取可直接显示的Canvas画布。 27 281. 从XComponent对应的NativeWindow中获取BufferHandle对象。NativeWindow相关的API请参考[_native_window](../reference/apis-arkgraphics2d/_native_window.md)。 29 30 ```c++ 31 uint64_t widht, height; 32 OHNativeWindow *nativeWindow; // NativeWindow及其宽高需要从XComponent获取 33 int32_t usage = NATIVEBUFFER_USAGE_CPU_READ | NATIVEBUFFER_USAGE_CPU_WRITE | NATIVEBUFFER_USAGE_MEM_DMA; 34 int ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, SET_USAGE, usage); 35 if (ret != 0) { 36 return; 37 } 38 39 struct NativeWindowBuffer *buffer = nullptr; 40 int fenceFd = 0; 41 ret = OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow, &buffer, &fenceFd); 42 if (ret != 0) { 43 return; 44 } 45 46 BufferHandle* bufferHandle = OH_NativeWindow_GetBufferHandleFromNative(buffer); 47 ``` 48 492. 从BufferHandle中获取对应的内存地址。 50 51 ```c++ 52 uint32_t* mappedAddr = static_cast<uint32_t *>(mmap(bufferHandle->virAddr, bufferHandle->size, PROT_READ | PROT_WRITE, MAP_SHARED, bufferHandle->fd, 0)); 53 ``` 54 553. 创建窗口画布。 56 57 ```c++ 58 OH_Drawing_Image_Info screenImageInfo = {static_cast<int32_t>(width), static_cast<int32_t>(height), COLOR_FORMAT_RGBA_8888, ALPHA_FORMAT_OPAQUE}; 59 OH_Drawing_Bitmap* screenBitmap = OH_Drawing_BitmapCreateFromPixels(&screenImageInfo, mappedAddr, bufferHandle->stride); 60 OH_Drawing_Canvas* screenCanvas = OH_Drawing_CanvasCreate(); 61 OH_Drawing_CanvasBind(screenCanvas, screenBitmap); 62 ``` 63 644. 利用上一步中得到的Canvas进行自定义的绘制操作,即本章下文中的内容。 65 665. 利用XComponent完成显示。 67 68 ```c++ 69 Region region {nullptr, 0}; 70 OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow, buffer, fenceFd, region); 71 ``` 72 73 74## 离屏Canvas画布的获取与显示 75 76目前有两种创建离屏Canvas的方式:创建CPU后端Canvas、创建GPU后端Canvas,这两种Canvas都需要依靠XComponent来完成绘制结果的上屏显示。由于历史原因,早期的Canvas都是CPU后端Canvas。目前已经支持GPU后端Canvas,GPU的并行计算能力更强,更适合图形绘制。但GPU后端Canvas对部分场景的支持还有欠缺,比如复杂的路径,对于简短文字的绘制性能也比不上CPU后端Canvas。 77 78 79### CPU后端Canvas的创建与显示 80 81目前C/C++接口的绘制需要依赖于NativeWindow,CPU后端Canvas需要先离屏绘制,生成位图(Bitmap),再借助XComponent将位图上屏。 82 83 841. 导入依赖的相关头文件。 85 86 ```c++ 87 #include <native_drawing/drawing_canvas.h> 88 #include <native_drawing/drawing_bitmap.h> 89 ``` 90 912. 创建基于CPU的Canvas。需要通过OH_Drawing_BitmapCreate()接口创建一个位图对象(具体可参考[图片绘制](pixelmap-drawing-c.md)),并通过OH_Drawing_CanvasBind()接口将位图绑定到Canvas中,从而使得Canvas绘制的内容可以输出到位图中。 92 93 ```c++ 94 // 创建一个位图对象 95 OH_Drawing_Bitmap* bitmap = OH_Drawing_BitmapCreate(); 96 OH_Drawing_BitmapFormat cFormat{COLOR_FORMAT_RGBA_8888, ALPHA_FORMAT_PREMUL}; 97 // 设置位图长宽(按需设置) 98 uint32_t width = 800; 99 uint32_t height = 800; 100 // 初始化位图 101 OH_Drawing_BitmapBuild(bitmap, width, height, &cFormat); 102 // 创建一个Canvas对象 103 OH_Drawing_Canvas* bitmapCanvas = OH_Drawing_CanvasCreate(); 104 // 将Canvas与bitmap绑定,Canvas绘制的内容会输出到绑定的bitmap内存中 105 OH_Drawing_CanvasBind(bitmapCanvas, bitmap); 106 ``` 107 108 如果需要将背景设置为白色,需要执行以下步骤: 109 110 ```c++ 111 OH_Drawing_CanvasClear(bitmapCanvas, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0xFF, 0xFF)); 112 ``` 113 1143. 将上一步中创建的位图绘制到[窗口画布](#获取可直接显示的canvas画布)上。 115 116 ```c++ 117 OH_Drawing_CanvasDrawBitmap(screenCanvas, bitmap, 0, 0); 118 ``` 119 120 121### GPU后端Canvas的创建与显示 122 123GPU后端Canvas指画布是基于GPU进行绘制的,GPU的并行计算能力优于CPU,适用于绘制图片或区域相对大的场景,但目前GPU后端的Canvas针对绘制复杂路径的能力还有欠缺。同CPU后端Canvas,目前C/C++接口的绘制需要依赖于XComponent,GPU后端Canvas需要先离屏绘制再借助XComponent上屏。 124 1251. 导入依赖的头文件。 126 127 ```c++ 128 #include <native_drawing/drawing_gpu_context.h> 129 #include <native_drawing/drawing_surface.h> 130 ``` 131 1322. 创建GPU后端Cnavas。GPU后端Canvas需要借助Surface对象来获取,需先创建surface,surface的API请参考[drawing_surface.h](../reference/apis-arkgraphics2d/drawing__surface_8h.md)。目前drawing支持基于OpenGL的GPU后端绘制,所以需要先通过OH_Drawing_GpuContextCreateFromGL接口创建绘图上下文,再将这个上下文作为参数创建surface,最后通过OH_Drawing_SurfaceGetCanvas接口从surface中获取到canvas。 133 134 ```c++ 135 // 设置宽高(按需设定) 136 int32_t cWidth = 800; 137 int32_t cHeight = 800; 138 // 设置图像,包括宽度、高度、颜色格式和透明度格式 139 OH_Drawing_Image_Info imageInfo = {cWidth, cHeight, COLOR_FORMAT_RGBA_8888, ALPHA_FORMAT_PREMUL}; 140 // GPU上下文的选项 141 OH_Drawing_GpuContextOptions options{false}; 142 // 创建一个使用OpenGL(GL)作为其GPU后端的绘图上下文 143 OH_Drawing_GpuContext *gpuContext = OH_Drawing_GpuContextCreateFromGL(options); 144 // 创建surface对象 145 OH_Drawing_Surface *surface = OH_Drawing_SurfaceCreateFromGpuContext(gpuContext, true, imageInfo); 146 // 创建一个canvas对象 147 OH_Drawing_Canvas* gpuCanvas = OH_Drawing_SurfaceGetCanvas(surface); 148 ``` 149 150 如果需要将背景设置为白色,需要执行以下步骤: 151 152 ```c++ 153 OH_Drawing_CanvasClear(gpuCanvas, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0xFF, 0xFF)); 154 ``` 155 1563. 将上一步中的绘制结果拷贝到[窗口画布](#获取可直接显示的canvas画布)上。 157 158 ```c++ 159 void* dstPixels = malloc(cWidth * cHeight * 4); // 4 for rgba 160 OH_Drawing_CanvasReadPixels(gpuCanvas, &imageInfo, dstPixels, 4 * cWidth, 0, 0); 161 OH_Drawing_Bitmap* bitmap = OH_Drawing_BitmapCreateFromPixels(&imageInfo, dstPixels, 4 * cWidth); 162 OH_Drawing_CanvasDrawBitmap(screenCanvas, bitmap, 0, 0); 163 ``` 164