lazarus鸿蒙开发13:使用鸿蒙原生API画图--lazarus侧关键代码
OHOS_Lazarus.lpr:
library OHOS_Lazarus;
{$mode objfpc}{$H+}
{$longstrings on}
{$packenum 4} //确保 Pascal 中的枚举类型和记录体在内存中的对齐方式与 C 语言完全一致,避免内存对齐导致的读取错误
{$packrecords C}//确保 Pascal 中的枚举类型和记录体在内存中的对齐方式与 C 语言完全一致,避免内存对齐导致的读取错误
uses
Classes, SysUtils, CTypes, Hilog, drawing_canvas;
const
LIBNAME = 'libnative_drawing.so';
type
TOH_Drawing_ColorFormat = (
COLOR_FORMAT_UNKNOWN, COLOR_FORMAT_ALPHA_8, COLOR_FORMAT_RGB_565,
COLOR_FORMAT_ARGB_4444, COLOR_FORMAT_RGBA_8888, COLOR_FORMAT_BGRA_8888
);
TOH_Drawing_AlphaFormat = (
ALPHA_FORMAT_UNKNOWN, ALPHA_FORMAT_OPAQUE, ALPHA_FORMAT_PREMUL, ALPHA_FORMAT_UNPREMUL
);
TOH_Drawing_BitmapFormat = record
colorFormat: TOH_Drawing_ColorFormat;
alphaFormat: TOH_Drawing_AlphaFormat;
end;
POH_Drawing_BitmapFormat = ^TOH_Drawing_BitmapFormat;
// --- 外部函数声明 ---
function OH_Drawing_BitmapCreate: POH_Drawing_Bitmap; cdecl; external LIBNAME;
procedure OH_Drawing_BitmapDestroy(bitmap: POH_Drawing_Bitmap); cdecl; external LIBNAME;
procedure OH_Drawing_BitmapBuild(bitmap: POH_Drawing_Bitmap; width: UInt32; height: UInt32; format: POH_Drawing_BitmapFormat); cdecl; external LIBNAME;
function OH_Drawing_BitmapGetPixels(bitmap: POH_Drawing_Bitmap): Pointer; cdecl; external LIBNAME; // ★ 获取像素数据指针
function OH_Drawing_CanvasCreate: POH_Drawing_Canvas; cdecl; external LIBNAME;
procedure OH_Drawing_CanvasDestroy(canvas: POH_Drawing_Canvas); cdecl; external LIBNAME;
procedure OH_Drawing_CanvasBind(canvas: POH_Drawing_Canvas; bitmap: POH_Drawing_Bitmap); cdecl; external LIBNAME;
procedure OH_Drawing_CanvasClear(canvas: POH_Drawing_Canvas; color: UInt32); cdecl; external LIBNAME;
procedure OH_Drawing_CanvasAttachPen(canvas: POH_Drawing_Canvas; pen: POH_Drawing_Pen); cdecl; external LIBNAME;
procedure OH_Drawing_CanvasAttachBrush(canvas: POH_Drawing_Canvas; brush: POH_Drawing_Brush); cdecl; external LIBNAME;
procedure OH_Drawing_CanvasDetachPen(canvas: POH_Drawing_Canvas); cdecl; external LIBNAME;
procedure OH_Drawing_CanvasDetachBrush(canvas: POH_Drawing_Canvas); cdecl; external LIBNAME;
procedure OH_Drawing_CanvasDrawLine(canvas: POH_Drawing_Canvas; x0: Single; y0: Single; x1: Single; y1: Single); cdecl; external LIBNAME;
procedure OH_Drawing_CanvasDrawRect(canvas: POH_Drawing_Canvas; rect: POH_Drawing_Rect); cdecl; external LIBNAME;
function OH_Drawing_PenCreate: POH_Drawing_Pen; cdecl; external LIBNAME;
procedure OH_Drawing_PenDestroy(pen: POH_Drawing_Pen); cdecl; external LIBNAME;
procedure OH_Drawing_PenSetColor(pen: POH_Drawing_Pen; color: UInt32); cdecl; external LIBNAME;
procedure OH_Drawing_PenSetWidth(pen: POH_Drawing_Pen; width: Single); cdecl; external LIBNAME;
function OH_Drawing_BrushCreate: POH_Drawing_Brush; cdecl; external LIBNAME;
procedure OH_Drawing_BrushDestroy(brush: POH_Drawing_Brush); cdecl; external LIBNAME;
procedure OH_Drawing_BrushSetColor(brush: POH_Drawing_Brush; color: UInt32); cdecl; external LIBNAME;
function OH_Drawing_RectCreate(left: Single; top: Single; right: Single; bottom: Single): POH_Drawing_Rect; cdecl; external LIBNAME;
procedure OH_Drawing_RectDestroy(rect: POH_Drawing_Rect); cdecl; external LIBNAME;
// ★ 全局变量,保存位图以便外部获取像素
var
g_Bitmap: POH_Drawing_Bitmap = nil;
// ★ 供外部调用的绘制函数
procedure DoDraw; cdecl; export;
var
canvas: POH_Drawing_Canvas;
pen: POH_Drawing_Pen;
brush: POH_Drawing_Brush;
rect: POH_Drawing_Rect;
bitmapFormat: TOH_Drawing_BitmapFormat;
begin
HILogInfo('=== 开始执行绘制 ===');
// 1. 创建位图
g_Bitmap := OH_Drawing_BitmapCreate();
bitmapFormat.colorFormat := COLOR_FORMAT_RGBA_8888;
bitmapFormat.alphaFormat := ALPHA_FORMAT_OPAQUE;
OH_Drawing_BitmapBuild(g_Bitmap, 400, 400, @bitmapFormat);
// 2. 创建画布并绑定
canvas := OH_Drawing_CanvasCreate();
OH_Drawing_CanvasBind(canvas, g_Bitmap);
// 3. 白色背景
OH_Drawing_CanvasClear(canvas, $FFFFFFFF);
// 4. 画笔 (黑色描边)
pen := OH_Drawing_PenCreate();
OH_Drawing_PenSetColor(pen, $FF000000);
OH_Drawing_PenSetWidth(pen, 5.0);
OH_Drawing_CanvasAttachPen(canvas, pen);
// 5. 画刷 (绿色填充)
brush := OH_Drawing_BrushCreate();
OH_Drawing_BrushSetColor(brush, $FF00FF00);
OH_Drawing_CanvasAttachBrush(canvas, brush);
// 6. 画线和矩形
OH_Drawing_CanvasDrawLine(canvas, 10.0, 10.0, 390.0, 10.0);
rect := OH_Drawing_RectCreate(50.0, 50.0, 350.0, 350.0);
OH_Drawing_CanvasDrawRect(canvas, rect);
HILogInfo('=== 绘制完成,像素保留在内存中 ===');
// 注意:这里不要销毁 g_Bitmap,否则像素就没了!
// 在实际应用中,渲染到屏幕后再销毁
end;
// ★ 供外部获取像素数据的指针
function GetBitmapPixels: Pointer; cdecl; export;
begin
if Assigned(g_Bitmap) then
Result := OH_Drawing_BitmapGetPixels(g_Bitmap)
else
Result := nil;
end;
exports
DoDraw name 'DoDraw',
GetBitmapPixels name 'GetBitmapPixels';
begin
// 这里什么都不要写!
end.
这程序的核心目的是在 OpenHarmony (OHOS) 系统上,利用其原生绘图 API (libnative_drawing.so) 进行离屏渲染,并将像素数据提供给外部程序使用。
以下是该代码的技术要点分析:
1. 跨语言与跨框架互操作 (FFI)
这是代码最核心的基础,实现了 Pascal 与 C 语言底层库的无缝对接:
- ABI 兼容性:通过编译指令
{$packenum 4}和{$packrecords C},确保 Pascal 中的枚举类型和记录体在内存中的对齐方式与 C 语言完全一致,避免内存对齐导致的读取错误。 - 调用约定:所有外部函数声明均使用
cdecl,这是 C/C++ 标准的调用约定,确保了参数入栈顺序和堆栈清理方式与libnative_drawing.so匹配。 - 数据类型映射:精确使用
UInt32、Single、Pointer等类型映射 C 层的uint32_t、float、void*,保证数据类型的字节长度一致。
2. 离屏渲染机制
代码没有直接将图形绘制到屏幕上,而是采用了典型的离屏渲染 模式:
- 创建画布与位图:先创建
Bitmap(像素缓冲区),再创建Canvas(画布)。 - 绑定目标:通过
OH_Drawing_CanvasBind(canvas, g_Bitmap)将画布与位图绑定,后续所有绘制操作(画线、画矩形)的实际像素数据都写入这块内存中。 - 用途:这种模式常用于生成纹理、图像处理后台计算,或作为中间件将绘制结果传递给其他 UI 框架(如代码文件名暗示的 Qt)。
3. 零拷贝的像素数据传递
代码通过全局变量和导出函数实现了一种高效的跨模块数据共享:
- 生命周期控制:
g_Bitmap被设计为全局变量,在DoDraw执行完毕后故意不销毁(代码中有明确注释),以保持像素数据在内存中有效。 - 直接暴露指针:
GetBitmapPixels函数直接返回底层像素数据的内存指针 (Pointer)。 - 零拷贝:外部程序(如 Qt)获取到这个指针后,可以直接读取或映射到自身的图像结构(如
QImage)中进行显示,无需进行内存拷贝,极大地提升了性能。
4. OpenHarmony Drawing API 的标准使用范式
代码展示了 OHOS 原生绘图的标准流程和面向对象的使用方式:
- 画笔与画刷分离:
Pen(画笔) 负责描边,设置为黑色、5像素宽度,用于画线 (DrawLine) 和矩形的边框。Brush(画刷) 负责填充,设置为绿色,用于矩形的内部填充 (DrawRect)。
- 状态挂载:通过
AttachPen和AttachBrush将画笔/画刷应用到画布上,绘制完毕后可Detach,这是一种典型的状态机绘图模式(类似 Skia,OHOS 底层正是基于 Skia)。
5. 动态链接库 (Shared Library) 设计
该文件被编译为动态库 (library),而非独立可执行文件:
- 明确的导出接口:使用
exports关键字只向外暴露DoDraw和GetBitmapPixels两个干净的功能接口,隐藏了内部的复杂绘图逻辑和 OHOS API 细节。 - 无副作用初始化:
begin ... end.之间为空,确保动态库在被dlopen加载时不会执行任何阻塞或可能导致崩溃的代码,保证了库加载的安全性。
6. 像素格式与色彩空间
- 指定了
COLOR_FORMAT_RGBA_8888,这是跨平台 UI 开发中最通用、兼容性最好的 32 位像素格式。 - 指定了
ALPHA_FORMAT_OPAQUE,表明图像不含透明通道,这允许底层图形库进行渲染优化。 - 颜色值使用 32 位十六进制(如
$FFFFFFFF为白色,$FF000000为黑色),符合 ARGB 的标准内存布局。

浙公网安备 33010602011771号