说明
HarmonyOs ArkGraphics 2D(方舟2D图形服务 )提供的绘制引擎,如果在 ArkUI 侧绘制,对绘制性能有高要求的话,那就直接放弃,转Native绘制配合 GPU 后端渲染。(想到这儿我浑身难受)
图形绘制流程
理解图形绘制的基本流程,再调用 api 就好理解一些。
- 画布的创建,画布作为图形绘制的承载,是最基本最关键的。(必须)
- 进行画布操作,例如旋转、裁剪、缩放操作(可选)
- 设置绘制效果,比如填充什么颜色,画笔的颜色,画笔的轮廓等(可选)
- 绘制图元,图形绘制最后一步即为图元的绘制,不论多么复杂的图形,都是基础图元的不同组合。(必须)
画布的获取
- 添加链接库 libnative_drawing.so
target_link_libraries(entry PUBLIC libnative_drawing.so)- 导入依赖的相关头文件
#include <native_drawing/drawing_canvas.h>#include <native_drawing/drawing_surface.h>- 从XComponent对应的NativeWindow中获取BufferHandle对象。NativeWindow相关的API请参考native_window。
uint64_twidth,height;OHNativeWindow*nativeWindow;// NativeWindow及其宽高需要从XComponent获取// 设置本地窗口缓冲区读写方式int32_tusage=NATIVEBUFFER_USAGE_CPU_READ|NATIVEBUFFER_USAGE_CPU_WRITE|NATIVEBUFFER_USAGE_MEM_DMA;intret=OH_NativeWindow_NativeWindowHandleOpt(nativeWindow,SET_USAGE,usage);if(ret!=0){return;}// 通过OHNativeWindow对象申请一块OHNativeWindowBuffer,用以内容生产structNativeWindowBuffer*buffer=nullptr;intfenceFd=0;ret=OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow,&buffer,&fenceFd);if(ret!=0){return;}// 通过OHNativeWindowBuffer获取该buffer的BufferHandle指针。BufferHandle*bufferHandle=OH_NativeWindow_GetBufferHandleFromNative(buffer);4.从BufferHandle中获取对应的内存地址。
uint32_t* mappedAddr=static_cast<uint32_t *>(mmap(bufferHandle->virAddr, bufferHandle->size, PROT_READ|PROT_WRITE, MAP_SHARED, bufferHandle->fd,0));5.创建窗口画布
// 创建 OH_Drawing_Bitmap 将其作为画布铺在 OH_Drawing_Canvas 上。这样就可以开始作画了。 cScreenBitmap_=OH_Drawing_BitmapCreate();// 定义bitmap的像素格式 OH_Drawing_BitmapFormat cFormat{COLOR_FORMAT_RGBA_8888, ALPHA_FORMAT_OPAQUE};// 构造对应格式的bitmap uint32_t width=static_cast<uint32_t>(bufferHandle_->stride /4);// 初始化位图对象的宽度和高度,并且为该位图设置像素格式。 OH_Drawing_BitmapBuild(cScreenBitmap_, width, height_,&cFormat);// 创建一块画板,画布是 cScreenBitmap_。 OH_Drawing_Canvas* screenCanvas=OH_Drawing_CanvasCreate();// 将画布铺在画板上 OH_Drawing_CanvasBind(screenCanvas, cScreenBitmap_);- 绘制内容(作画)
// 创建画笔 OH_Drawing_Pen *pen=OH_Drawing_PenCreate()// 设置抗锯齿 OH_Drawing_PenSetAntiAlias(pen,true);// 设置画布颜色为红色 OH_Drawing_PenSetColor(pen, OH_Drawing_ColorSetArgb(0xFF, 0xFF, 0x00, 0x00));// 设置线帽样式为圆头 OH_Drawing_PenSetCap(pen, LINE_ROUND_CAP);// 设置线段转角样式为圆头 OH_Drawing_PenSetJoin(pen, LINE_ROUND_JOIN)// 绑定画布screenCanvas OH_Drawing_CanvasAttachPen(screenCanvas, pen)// 绘制一个矩形 OH_Drawing_Rect* rect=OH_Drawing_RectCreate(50,50,200,300);OH_Drawing_CanvasDrawRect(screenCanvas, rect);// 解绑画笔 OH_Drawing_CanvasDetachPen(screenCanvas);// 销毁画布 OH_Drawing_CanvasDestroy(screenCanvas);- 利用XComponent完成显示。
// 画完后获取像素地址,地址指向的内存包含画布画的像素数据 void *bitmapAddr=OH_Drawing_BitmapGetPixels(cScreenBitmap_);uint32_t *value=static_cast<uint32_t *>(bitmapAddr);// 使用mmap获取到的地址来访问内存 uint32_t *pixel=static_cast<uint32_t *>(mappedAddr);if(pixel==nullptr){SAMPLE_LOGE("pixel is null");return;}if(value==nullptr){SAMPLE_LOGE("value is null");return;}// 将 cScreenBitmap_ 绘制的像素复制给 mappedAddrfor(uint32_t x=0;x<width_;x++){for(uint32_t y=0;y<height_;y++){*pixel++=*value++;}}// 设置刷新区域,如果Region中的Rect为nullptr,或者rectNumber为0,则认为OHNativeWindowBuffer全部有内容更改。 Region region{nullptr,0};// 通过OH_NativeWindow_NativeWindowFlushBuffer 提交给消费者使用,例如:显示在屏幕上。 OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow_, buffer_, fenceFd_, region);// 内存使用完记得去掉内存映射 int result=munmap(mappedAddr_, bufferHandle_->size);if(result==-1){SAMPLE_LOGE("munmap failed!");}