秋·风

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 :: 管理 ::

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 匹配。
  • 数据类型映射:精确使用 UInt32SinglePointer 等类型映射 C 层的 uint32_tfloatvoid*,保证数据类型的字节长度一致。

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 的标准内存布局。

 

posted on 2026-06-10 08:12  秋·风  阅读(24)  评论(1)    收藏  举报