LVGL canvas的详细分析

LVGL的canvas组件提供了像素级别的绘制能力,适用于自定义图形和文本。本文介绍了canvas的相关函数,如创建、设置缓冲区、设置像素、设置调色板、复制缓冲区、填充背景等,通过示例展示了如何在LVGL应用程序中使用canvas进行图形绘制和处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

LVGL的canvas小部件是一个简单而强大的组件,它允许在一个小部件上绘制像素级的内容。这通常用于自定义图形和文本,或者作为更复杂图形元素的基础。Canvas小部件提供了一个缓冲区,可以在其中绘制任何您想要的内容。

函数解说

1. lv_canvas_create


   创建一个新的 `canvas` 小部件实例。它调用 `lv_obj_class_create_obj` 来创建对象,并初始化它。lv_canvas_create 函数是 LVGL 图形库中用于创建一个新的 canvas 小部件的函数。canvas 小部件是一个类似于画布的界面元素,开发者可以在其上进行绘制操作,如自定义图形、文本和图像等。

lv_obj_t * lv_canvas_create(lv_obj_t * parent)
{
    LV_LOG_INFO("begin");  // 记录日志信息

    // 创建一个新的 canvas 小部件作为 parent 的子对象
    lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
    if(obj == NULL) {
        return NULL;  // 如果创建失败,则返回 NULL
    }

    // 初始化新创建的 canvas 小部件
    lv_obj_class_init_obj(obj);  // 调用对象类的初始化函数

    return obj;  // 返回新创建的 canvas 小部件对象
}

  1. 函数参数:

    • lv_obj_t * parent: 指向父对象的指针,新的 canvas 小部件将作为这个父对象的子对象创建。如果 parent 为 NULL,则新创建的 canvas 将成为顶层对象。
  2. 函数逻辑:

    • 首先,函数记录一个日志信息 "begin",表示开始创建 canvas 小部件。
    • 接下来,函数调用 lv_obj_class_create_obj 来创建一个新的 canvas 小部件对象。这个函数是 LVGL 对象系统的一部分,它会根据提供的类和父对象来创建一个新的对象。
    • 如果创建成功,函数调用 lv_obj_class_init_obj 来初始化新创建的 canvas 小部件。这个函数是 canvas 类的构造函数,它会设置小部件的默认属性和状态。
    • 最后,函数返回新创建的 canvas 小部件对象的指针。
  3. 使用场景:

    • lv_canvas_create 函数通常在需要在 LVGL 应用程序中添加一个新的 canvas 小部件时使用。
    • 开发者可以在创建 canvas 后,对其进行配置和绘制,以实现自定义的图形用户界面元素。
  4. 注意事项:

    • 在调用 lv_canvas_create 之前,需要确保 parent 对象是有效的,且已经创建和初始化。
    • 如果 parent 为 NULL,则新创建的 canvas 将成为顶层对象,这意味着它将直接附加到屏幕(lv_scr_act)上。
    • 创建 canvas 小部件后,可能需要对其进行进一步的配置,如设置大小、位置、背景颜色等,以及关联的绘制缓冲区。
    • 如果 lv_obj_class_create_obj 返回 NULL,则表示创建失败,此时应该检查原因并进行相应的错误处理。

通过 lv_canvas_create 函数,开发者可以在 LVGL 应用程序中创建一个新的 canvas 小部件,为自定义绘制和图像处理提供了基础。这是实现复杂用户界面和动态图形效果的重要步骤。

2. lv_canvas_set_buffer


   设置 `canvas` 小部件的绘制缓冲区。lv_canvas_set_buffer 函数是 LVGL 图形库中用于为 canvas 小部件设置一个新的绘制缓冲区的函数。这个函数允许开发者提供一个自定义的缓冲区,用于存储 canvas 小部件的像素数据,从而实现更灵活的图像处理和绘制操作。

void lv_canvas_set_buffer(lv_obj_t * obj, void * buf, int32_t w, int32_t h, lv_color_format_t cf)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);  // 断言 obj 是一个有效的 canvas 对象
    LV_ASSERT_NULL(buf);          // 断言 buf 不为 NULL

    lv_canvas_t * canvas = (lv_canvas_t *)obj;
    uint32_t stride = lv_draw_buf_width_to_stride(w, cf);  // 计算缓冲区的跨度(stride)

    // 初始化新的绘制缓冲区
    lv_draw_buf_init(&canvas->static_buf, w, h, cf, stride, buf, stride * h);
    canvas->draw_buf = &canvas->static_buf;  // 设置 canvas 的绘制缓冲区为新初始化的缓冲区

    // 丢弃旧的图像源
    const void * src = lv_image_get_src(obj);
    if(src) {
        lv_image_cache_drop(src);
    }

    // 设置新的图像源为新的绘制缓冲区
    lv_image_set_src(obj, canvas->draw_buf);
    lv_image_cache_drop(canvas->draw_buf);  // 将新的绘制缓冲区添加到图像缓存中

    // 标记对象为无效,以便重新绘制
    lv_obj_invalidate(obj);
}

  1. 函数参数:

    • lv_obj_t * obj: 指向 canvas 小部件的指针。
    • void * buf: 指向新绘制缓冲区的指针。
    • int32_t w: 缓冲区的宽度(以像素为单位)。
    • int32_t h: 缓冲区的高度(以像素为单位)。
    • lv_color_format_t cf: 缓冲区的颜色格式。
  2. 函数逻辑:

    • 首先,函数通过 LV_ASSERT_OBJ 宏检查输入参数 obj 是否为有效的 canvas 小部件。
    • 然后,函数通过 LV_ASSERT_NULL 宏检查输入参数 buf 是否不为 NULL。
    • 接下来,函数计算新绘制缓冲区的跨度(stride),这是每一行像素的字节长度。
    • 函数使用 lv_draw_buf_init 初始化新的绘制缓冲区,这个函数会设置缓冲区的宽度、高度、颜色格式、跨度和数据指针。
    • 然后,函数将 canvas 小部件的 draw_buf 成员设置为新初始化的缓冲区。
    • 接下来,函数丢弃 canvas 小部件的旧图像源,如果是通过 lv_image_cache_get 获取的,则通过 lv_image_cache_drop 释放资源。
    • 函数将新的图像源设置为 canvas 小部件的 draw_buf 并将其添加到图像缓存中。
    • 最后,函数通过调用 lv_obj_invalidate 标记 canvas 小部件为无效,这将触发重新绘制 canvas 以反映新的绘制缓冲区。
  3. 使用场景:

    • lv_canvas_set_buffer 函数通常在以下场景中使用:
      • 当需要为 canvas 小部件提供一个自定义的绘制缓冲区时,例如,可能需要更大的缓冲区或者一个具有特定颜色格式的缓冲区。
      • 在实现自定义的绘制操作或者复杂的图像处理时,可能需要使用特定的绘制缓冲区。
      • 在动态调整 canvas 小部件的资源使用时,例如,在内存限制或性能优化的情况下。
  4. 注意事项:

    • 在调用 lv_canvas_set_buffer 之前,必须确保提供了一个有效的绘制缓冲区,并且该缓冲区的内存已经分配好。
    • 绘制缓冲区必须已经被正确初始化,且其大小要与 canvas 小部件的尺寸匹配。
    • 函数会自动处理旧绘制缓冲区的释放和新绘制缓冲区的缓存添加。
    • 修改绘制缓冲区后,可能需要重新绘制 canvas 小部件以显示更改。

通过 lv_canvas_set_buffer 函数,开发者可以为 canvas 小部件指定一个新的绘制缓冲区,这对于实现高级的图像处理和自定义绘制操作非常有用。然而,直接操作绘制缓冲区也需要对 LVGL 的内部工作机制和内存管理有深入的理解。

3. lv_canvas_set_draw_buf


   通过 `lv_draw_buf_t` 结构体设置 `canvas` 小部件的绘制缓冲区。lv_canvas_set_draw_buf 函数是 LVGL 图形库中用于设置 canvas 小部件的绘制缓冲区的函数。这个函数允许开发者为 canvas 小部件指定一个新的绘制缓冲区,这个缓冲区将用于存储 canvas 的像素数据,从而实现自定义的绘制操作。

void lv_canvas_set_draw_buf(lv_obj_t * obj, lv_draw_buf_t * draw_buf)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);  // 断言 obj 是一个有效的 canvas 对象
    LV_ASSERT_NULL(draw_buf);      // 断言 draw_buf 不为 NULL

    lv_canvas_t * canvas = (lv_canvas_t *)obj;

    // 释放当前的绘制缓冲区(如果有的话)
    if(canvas->draw_buf) {
        lv_image_cache_drop(&canvas->draw_buf);
    }

    // 设置新的绘制缓冲区
    canvas->draw_buf = draw_buf;

    // 清除旧的图像源
    const void * src = lv_image_get_src(obj);
    if(src) {
        lv_image_cache_drop(src);
    }

    // 设置新的图像源为新的绘制缓冲区
    lv_image_set_src(obj, draw_buf);
    lv_image_cache_drop(draw_buf);  // 将新的绘制缓冲区添加到图像缓存中

    // 标记对象为无效,以便重新绘制
    lv_obj_invalidate(obj);
}

  1. 函数参数:

    • lv_obj_t * obj: 指向 canvas 小部件的指针。
    • lv_draw_buf_t * draw_buf: 指向新的绘制缓冲区的指针。
  2. 函数逻辑:

    • 首先,函数通过 LV_ASSERT_OBJ 宏检查输入参数 obj 是否为有效的 canvas 小部件。
    • 然后,函数通过 LV_ASSERT_NULL 宏检查输入参数 draw_buf 是否不为 NULL。
    • 接下来,函数释放 canvas 小部件当前的绘制缓冲区(如果有的话),这是通过调用 lv_image_cache_drop 函数完成的。
    • 然后,函数将 canvas 小部件的 draw_buf 成员设置为新的绘制缓冲区。
    • 接下来,函数清除 canvas 小部件的旧图像源,并将新的绘制缓冲区设置为图像源。
    • 最后,函数通过调用 lv_obj_invalidate 标记 canvas 小部件为无效,这将触发重新绘制 canvas 以反映新的绘制缓冲区。
  3. 使用场景:

    • lv_canvas_set_draw_buf 函数通常在以下场景中使用:
      • 当需要为 canvas 小部件更换一个新的绘制缓冲区时,例如,可能需要更大的缓冲区或者一个具有不同颜色格式的缓冲区。
      • 在实现自定义的绘制操作或者复杂的图像处理时,可能需要使用特定的绘制缓冲区。
      • 在动态调整 canvas 小部件的资源使用时,例如,在内存限制或性能优化的情况下。
  4. 注意事项:

    • 在调用 lv_canvas_set_draw_buf 之前,必须确保提供了一个有效的绘制缓冲区。
    • 绘制缓冲区必须已经被分配并正确初始化。
    • 函数会自动处理旧绘制缓冲区的释放和新绘制缓冲区的缓存添加。
    • 修改绘制缓冲区后,可能需要重新绘制 canvas 小部件以显示更改。

通过 lv_canvas_set_draw_buf 函数,开发者可以为 canvas 小部件指定一个新的绘制缓冲区,这对于实现高级的图像处理和自定义绘制操作非常有用。然而,直接操作绘制缓冲区也需要对 LVGL 的内部工作机制和内存管理有深入的理解。

4. lv_canvas_set_px


   在 `canvas` 小部件的指定位置设置像素颜色。lv_canvas_set_px 函数是 LVGL 图形库中用于在 canvas 小部件的指定像素位置上设置颜色的函数。这个函数允许开发者直接修改 canvas 小部件的像素数据,可以用于实现像素级的操作,如绘制、修改图像等。

void lv_canvas_set_px(lv_obj_t * obj, int32_t x, int32_t y, lv_color_t color, lv_opa_t opa)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);  // 断言 obj 是一个有效的 canvas 对象

    lv_canvas_t * canvas = (lv_canvas_t *)obj;
    lv_draw_buf_t * draw_buf = canvas->draw_buf;

    // 检查坐标是否在绘制缓冲区的范围内
    if(x < 0 || x >= draw_buf->header.w || y < 0 || y >= draw_buf->header.h) {
        return;  // 如果坐标超出范围,则不执行操作
    }

    // 根据颜色格式,设置像素颜色
    lv_color_format_t cf = draw_buf->header.cf;
    uint32_t stride = draw_buf->header.stride;
    uint8_t * data = draw_buf->data;

    // 根据颜色格式处理颜色和不透明度
    if(LV_COLOR_FORMAT_IS_INDEXED(cf)) {
        // 索引颜色格式
        uint8_t * buf = (uint8_t *)data + y * stride + x;
        *buf = lv_color_index_to_8(color);
    } else if(cf == LV_COLOR_FORMAT_A8) {
        // A8 格式(只有一个 alpha 通道)
        data[y * stride + x] = (uint8_t)(opa);
    } else if(cf == LV_COLOR_FORMAT_RGB565) {
        // RGB565 格式
        lv_color16_t * buf = (lv_color16_t *)(data + y * stride);
        buf[x] = lv_color_to_16(color);
    } else if(cf == LV_COLOR_FORMAT_RGB888) {
        // RGB888 格式
        data[(y * stride + x * 3) + 0] = color.blue;
        data[(y * stride + x * 3) + 1] = color.green;
        data[(y * stride + x * 3) + 2] = color.red;
    } else if(cf == LV_COLOR_FORMAT_XRGB8888) {
        // XRGB8888 格式(带有 alpha 通道)
        lv_color32_t c = lv_color_to_32(color);
        c.alpha = (uint8_t)opa;
        *(lv_color32_t *)(data + y * stride + x * 4) = c;
    } else if(cf == LV_COLOR_FORMAT_ARGB8888) {
        // ARGB8888 格式(alpha 在最前面)
        lv_color32_t c = lv_color_to_32(color);
        c.alpha = (uint8_t)opa;
        *(lv_color32_t *)(data + y * stride + x * 4) = c;
    }

    // 标记对象为无效,以便重新绘制
    lv_obj_invalidate(obj);
}

  1. 函数参数:

    • lv_obj_t * obj: 指向 canvas 小部件的指针。
    • int32_t x: 像素的横坐标。
    • int32_t y: 像素的纵坐标。
    • lv_color_t color: 要设置的颜色值。
    • lv_opa_t opa: 颜色的不透明度。
  2. 函数逻辑:

    • 首先,函数通过 LV_ASSERT_OBJ 宏检查输入参数 obj 是否为有效的 canvas 小部件。
    • 然后,函数获取 canvas 小部件的绘制缓冲区 draw_buf 并检查坐标是否在缓冲区的有效范围内。如果坐标超出范围,则不执行操作。
    • 接下来,函数根据 draw_buf 的颜色格式 cf,使用不同的方法来设置像素颜色:
      • 对于索引颜色格式,函数将颜色转换为 8 位索引值并设置到缓冲区中。
      • 对于 LV_COLOR_FORMAT_A8 格式,函数只设置 alpha 分量。
      • 对于 LV_COLOR_FORMAT_RGB565 格式,函数将颜色转换为 16 位 RGB565 值并设置到缓冲区中。
      • 对于 LV_COLOR_FORMAT_RGB888 格式,函数设置 RGB 分量。
      • 对于 LV_COLOR_FORMAT_XRGB8888 和 LV_COLOR_FORMAT_ARGB8888 格式,函数设置带有不透明度的 32 位颜色值。
    • 最后,函数通过调用 lv_obj_invalidate 标记 canvas 小部件为无效,这将触发重新绘制 canvas 以反映像素的更改。
  3. 使用场景:

    • lv_canvas_set_px 函数通常在以下场景中使用:
      • 当需要在 canvas 小部件上绘制或修改单个像素时。
      • 在实现像素级图像处理或自定义绘制操作时。
      • 在需要精确控制 canvas 小部件上每个像素的颜色时。
  4. 注意事项:

    • 在调用 lv_canvas_set_px 之前,必须确保 canvas 小部件已经创建并配置了适当的缓冲区。
    • 像素坐标 (x, y) 必须在 canvas 小部件的有效范围内,否则函数不会执行任何操作。
    • 根据 canvas 小部件的颜色格式,color 参数和 opa 参数的使用方法可能会有所不同。
    • 修改像素后,可能需要重新绘制 canvas 小部件以显示更改。

通过 lv_canvas_set_px 函数,开发者可以精确地控制 canvas 小部件上的像素颜色,这对于实现高级图像处理和自定义绘制功能非常有用。然而,直接操作像素数据也需要对 LVGL 的内部表示和颜色格式有深入的理解。

5. lv_canvas_set_palette


   设置 `canvas` 小部件的调色板颜色。lv_canvas_set_palette 函数是 LVGL 图形库中用于设置 canvas 小部件的调色板颜色的函数。在 LVGL 中,调色板是一种用于存储预定义颜色数组的机制,这在处理索引颜色格式的图像时非常有用。索引颜色格式意味着每个像素不是由直接的颜色值表示,而是由一个索引值表示,该索引值在调色板中查找对应的颜色。

void lv_canvas_set_palette(lv_obj_t * obj, uint8_t index, lv_color32_t color)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);  // 断言 obj 是一个有效的 canvas 对象

    lv_canvas_t * canvas = (lv_canvas_t *)obj;

    // 确保 index 在调色板的有效范围内
    LV_ASSERT(index < LV_CANVAS_PALETTE_SIZE);

    // 获取 canvas 的绘制缓冲区
    lv_draw_buf_t * draw_buf = canvas->draw_buf;
    if(draw_buf == NULL || draw_buf->header.cf != LV_COLOR_FORMAT_INDEXED) {
        // 如果没有绘制缓冲区或者颜色格式不是索引颜色格式,则不执行操作
        return;
    }

    // 设置调色板颜色
    lv_draw_buf_set_palette(draw_buf, index, color);
    // 标记对象为无效,以便重新绘制
    lv_obj_invalidate(obj);
}

  1. 函数参数:

    • lv_obj_t * obj: 指向 canvas 小部件的指针。
    • uint8_t index: 调色板中颜色的索引位置。
    • lv_color32_t color: 要设置的 32 位颜色值。
  2. 函数逻辑:

    • 首先,函数通过 LV_ASSERT_OBJ 宏检查输入参数 obj 是否为有效的 canvas 小部件。
    • 然后,函数确保提供的 index 在调色板的有效范围内(LV_CANVAS_PALETTE_SIZE 是调色板大小的宏定义)。
    • 接下来,函数获取 canvas 小部件的绘制缓冲区 draw_buf,并检查其颜色格式是否为 LV_COLOR_FORMAT_INDEXED(索引颜色格式)。
    • 如果 draw_buf 存在且颜色格式正确,函数调用 lv_draw_buf_set_palette 来设置调色板中指定索引位置的颜色。
    • 最后,函数通过调用 lv_obj_invalidate 标记 canvas 小部件为无效,这将触发重新绘制 canvas 以反映调色板的更改。
  3. 使用场景:

    • lv_canvas_set_palette 函数通常在以下场景中使用:
      • 当需要动态更改 canvas 小部件的调色板颜色时。
      • 在使用索引颜色格式的图像时,需要更新调色板中的特定颜色。
      • 在实现自定义的图像处理或颜色调整算法时。
  4. 注意事项:

    • 在调用 lv_canvas_set_palette 之前,必须确保 canvas 小部件已经创建并配置了适当的缓冲区,且颜色格式为索引颜色格式。
    • 调色板的索引值 index 必须在有效范围内,否则会导致未定义的行为。
    • 修改调色板颜色后,可能需要重新绘制 canvas 小部件以显示更改。
    • 由于调色板更改会影响所有使用该调色板的像素,因此在进行修改时需要考虑到这一点。

通过 lv_canvas_set_palette 函数,开发者可以动态地更新 canvas 小部件的调色板颜色,这对于实现动态颜色调整和图像处理功能非常有用。然而,直接操作调色板也需要对 LVGL 的内部表示和颜色格式有深入的理解。

6. lv_canvas_get_draw_buf


   获取 `canvas` 小部件当前使用的绘制缓冲区。lv_canvas_get_draw_buf 函数是 LVGL 图形库中用于获取 canvas 小部件当前使用的绘制缓冲区的函数。这个函数允许开发者直接访问和操作 canvas 小部件的缓冲区,可以用于高级图像处理或者自定义的绘制任务。

lv_draw_buf_t * lv_canvas_get_draw_buf(lv_obj_t * obj)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);  // 断言 obj 是一个有效的 canvas 对象

    lv_canvas_t * canvas = (lv_canvas_t *)obj;
    if(canvas->draw_buf == NULL) return NULL;  // 如果 canvas 没有绘制缓冲区,则返回 NULL

    return canvas->draw_buf;  // 返回 canvas 小部件的绘制缓冲区
}

  1. 函数参数:

    • lv_obj_t * obj: 指向 canvas 小部件的指针。
  2. 函数逻辑:

    • 首先,函数通过 LV_ASSERT_OBJ 宏检查输入参数 obj 是否为有效的 canvas 小部件。
    • 然后,函数获取 canvas 小部件的类型指针,并检查 canvas 的绘制缓冲区 draw_buf 是否已初始化。如果 draw_buf 为 NULL,说明 canvas 尚未准备好,函数将返回 NULL。
    • 如果 draw_buf 存在,函数直接返回 canvas 小部件的绘制缓冲区。
  3. 使用场景:

    • lv_canvas_get_draw_buf 函数通常在以下场景中使用:
      • 当需要直接访问和操作 canvas 小部件的像素数据进行图像处理或自定义绘制时。
      • 在需要将 canvas 小部件的内容与其他图像处理函数或库结合使用时。
      • 在需要对 canvas 小部件的绘制缓冲区进行优化或管理时。
  4. 注意事项:

    • 在调用 lv_canvas_get_draw_buf 之前,必须确保 canvas 小部件已经创建并配置了适当的缓冲区。
    • 返回的 lv_draw_buf_t 指针提供了对 canvas 小部件绘制缓冲区的直接访问,开发者需要谨慎操作,以避免破坏 canvas 小部件的显示内容。
    • 使用返回的 lv_draw_buf_t 指针时,应当注意 LVGL 的颜色格式和内存布局,确保正确地读取和写入像素数据。
    • 在对绘制缓冲区进行修改后,可能需要调用 lv_obj_invalidate 来标记小部件为无效并触发重新绘制。

通过 lv_canvas_get_draw_buf 函数,开发者可以获得 canvas 小部件的绘制缓冲区,从而进行更复杂的图像处理和自定义绘制操作。这对于实现高级图形功能和性能优化非常有用,但也需要对 LVGL 的内部工作机制有深入的理解。

7. lv_canvas_get_px


   获取 `canvas` 小部件指定位置的像素颜色。lv_canvas_get_px 函数是 LVGL 图形库中用于获取 canvas 小部件上特定像素位置的颜色值的函数。这个函数允许开发者读取 canvas 小部件的像素数据,可以用于实现像素级的操作,如图像处理、像素分析等。

lv_color32_t lv_canvas_get_px(lv_obj_t * obj, int32_t x, int32_t y)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);  // 断言 obj 是一个有效的 canvas 对象

    lv_canvas_t * canvas = (lv_canvas_t *)obj;
    if(canvas->draw_buf == NULL) return lv_color_make(0, 0, 0, 0);  // 如果 canvas 没有绘制缓冲区,则返回黑色

    lv_image_header_t * header = &canvas->draw_buf->header;
    const uint8_t * px = lv_draw_buf_goto_xy(canvas->draw_buf, x, y);

    switch(header->cf) {
        case LV_COLOR_FORMAT_ARGB8888:
            return *(lv_color32_t *)px;
        case LV_COLOR_FORMAT_RGB888:
        case LV_COLOR_FORMAT_XRGB8888:
            return lv_color_make(px[2], px[1], px[0], 0xFF);
        case LV_COLOR_FORMAT_RGB565: {
            lv_color16_t * c16 = (lv_color16_t *)px;
            return lv_color_make(c16->red >> 3, c16->green >> 2, c16->blue >> 3, 0xFF);
        }
        case LV_COLOR_FORMAT_A8: {
            lv_color_t alpha_color = lv_obj_get_style_image_recolor(obj, LV_PART_MAIN);
            return lv_color_make(alpha_color.red, alpha_color.green, alpha_color.blue, px[0]);
        }
        default:
            // 如果颜色格式不支持,则返回黑色
            return lv_color_make(0, 0, 0, 0);
    }
}

  1. 函数参数:

    • lv_obj_t * obj: 指向 canvas 小部件的指针。
    • int32_t x: 像素的横坐标。
    • int32_t y: 像素的纵坐标。
  2. 函数逻辑:

    • 首先,函数通过 LV_ASSERT_OBJ 宏检查输入参数 obj 是否为有效的 canvas 小部件。
    • 然后,函数获取 canvas 小部件的类型指针,并检查 canvas 的绘制缓冲区 draw_buf 是否已初始化。如果 draw_buf 为 NULL,说明 canvas 尚未准备好,函数将返回黑色。
    • 如果 draw_buf 存在,函数使用 lv_draw_buf_goto_xy 定位到指定的像素位置 (x, y)
    • 接下来,函数根据 draw_buf 的颜色格式 header->cf,使用不同的方法来读取像素颜色:
      • 对于 LV_COLOR_FORMAT_ARGB8888 格式,函数直接将指针转换为 lv_color32_t 类型并返回。
      • 对于 LV_COLOR_FORMAT_RGB888 和 LV_COLOR_FORMAT_XRGB8888 格式,函数从缓冲区中提取红、绿、蓝分量,并构造一个 lv_color32_t 类型的颜色值。
      • 对于 LV_COLOR_FORMAT_RGB565 格式,函数需要将颜色值右移以获取正确的颜色分量,并构造一个 lv_color32_t 类型的颜色值。
      • 对于 LV_COLOR_FORMAT_A8 格式,函数获取对象的样式颜色,并将其与 alpha 分量结合,构造一个 lv_color32_t 类型的颜色值。
    • 如果颜色格式不支持或未处理,则函数返回黑色。
  3. 使用场景:

    • lv_canvas_get_px 函数通常在以下场景中使用:
      • 当需要读取 canvas 小部件上的像素颜色时。
      • 在实现图像处理算法或其他自定义绘制操作时,可能需要获取像素颜色。
      • 在需要对 canvas 小部件进行分析或调试时。
  4. 注意事项:

    • 在调用 lv_canvas_get_px 之前,必须确保 canvas 小部件已经创建并配置了适当的缓冲区。
    • 函数返回的颜色值取决于 canvas 小部件的颜色格式。在处理返回的颜色值时,需要考虑颜色格式的差异。
    • 像素坐标 (x, y) 必须在 canvas 小部件的有效范围内,否则可能会导致未定义的行为。

通过 lv_canvas_get_px 函数,开发者可以获取 canvas 小部件上特定位置的像素颜色,这对于实现像素级操作和图像处理功能非常有用。然而,直接操作像素数据也需要对 LVGL 的内部表示和颜色格式有深入的理解。

8. lv_canvas_get_image


   获取 `canvas` 小部件的图像描述符。lv_canvas_get_image 函数是 LVGL 图形库中用于获取 canvas 小部件的图像描述符的函数。这个函数提供了一种方式来访问 canvas 小部件的像素数据,以及与之相关的元数据,如图像的尺寸和颜色格式。

lv_image_dsc_t * lv_canvas_get_image(lv_obj_t * obj)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);  // 断言 obj 是一个有效的 canvas 对象

    lv_canvas_t * canvas = (lv_canvas_t *)obj;
    if(canvas->draw_buf == NULL) return NULL;  // 如果 canvas 没有绘制缓冲区,则返回 NULL

    // 返回指向绘制缓冲区的图像描述符
    return (lv_image_dsc_t *)canvas->draw_buf;
}

  1. 函数参数:

    • lv_obj_t * obj: 指向 canvas 小部件的指针。
  2. 函数逻辑:

    • 首先,函数通过 LV_ASSERT_OBJ 宏检查输入参数 obj 是否为有效的 canvas 小部件。
    • 然后,函数获取 canvas 小部件的类型指针,并检查 canvas 的绘制缓冲区 draw_buf 是否已初始化。如果 draw_buf 为 NULL,说明 canvas 尚未准备好,函数将返回 NULL。
    • 如果 draw_buf 存在,函数返回一个指向 canvas 小部件的绘制缓冲区的 lv_image_dsc_t 类型的指针。lv_image_dsc_t 是一个结构体,它包含了图像的描述信息,如宽度、高度、颜色格式等。
  3. 使用场景:

    • lv_canvas_get_image 函数通常在以下场景中使用:
      • 当需要获取 canvas 小部件的图像信息(如尺寸和颜色格式)时。
      • 在需要将 canvas 小部件的内容与其他图像处理函数或库一起使用时。
      • 在需要将 canvas 小部件的内容保存为图像文件或转换为其他图像格式时。
  4. 注意事项:

    • 在调用 lv_canvas_get_image 之前,必须确保 canvas 小部件已经创建并配置了适当的缓冲区。
    • 返回的 lv_image_dsc_t 指针提供了对 canvas 小部件图像数据的访问,但不包括对实际像素数据的直接访问。如果需要访问像素数据,可以使用 lv_canvas_get_buf 函数。
    • 使用返回的 lv_image_dsc_t 指针时,应当注意不要修改其内容,除非你确信这样做是安全的。错误的修改可能会导致 canvas 小部件的显示出现问题。

通过 lv_canvas_get_image 函数,开发者可以获取 canvas 小部件的图像描述符,从而访问和使用 canvas 的图像信息。这对于图像处理、数据交换和文件输出等操作非常有用。然而,直接操作图像描述符和像素数据需要对 LVGL 的内部表示和图像格式有深入的理解。

9. lv_canvas_get_buf


   获取 `canvas` 小部件的缓冲区数据。lv_canvas_get_buf 函数是 LVGL 图形库中用于获取 canvas 小部件的缓冲区数据的函数。这个函数允许开发者直接访问 canvas 小部件的像素数据,可以用于读取或修改 canvas 上的内容。

const void * lv_canvas_get_buf(lv_obj_t * obj)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);  // 断言 obj 是一个有效的 canvas 对象

    lv_canvas_t * canvas = (lv_canvas_t *)obj;
    if(canvas->draw_buf == NULL) return NULL;  // 如果 canvas 没有绘制缓冲区,则返回 NULL

    // 返回绘制缓冲区的未对齐数据指针
    return canvas->draw_buf->unaligned_data;
}

  1. 函数参数:

    • lv_obj_t * obj: 指向 canvas 小部件的指针。
  2. 函数逻辑:

    • 首先,函数通过 LV_ASSERT_OBJ 宏检查输入参数 obj 是否为有效的 canvas 小部件。
    • 然后,函数获取 canvas 小部件的类型指针,并检查 canvas 的绘制缓冲区 draw_buf 是否已初始化。如果 draw_buf 为 NULL,说明 canvas 尚未准备好,函数将返回 NULL。
    • 如果 draw_buf 存在,函数返回 canvas 小部件的绘制缓冲区的未对齐数据指针。这个指针可以直接用于读取或修改 canvas 小部件的像素数据。
  3. 使用场景:

    • lv_canvas_get_buf 函数通常在以下场景中使用:
      • 当需要直接访问 canvas 小部件的像素数据进行处理或分析时。
      • 在实现图像处理算法或其他自定义绘制操作时,可能需要直接操作像素数据。
      • 在需要将 canvas 小部件的内容导出到其他图像格式或文件时。
  4. 注意事项:

    • 在调用 lv_canvas_get_buf 之前,必须确保 canvas 小部件已经创建并配置了适当的缓冲区。
    • 返回的缓冲区数据指针是未对齐的,这意味着它可能不指向内存中的字节边界。在使用这些数据时,需要确保正确处理内存对齐问题,特别是在使用如 struct 等数据结构时。
    • 修改 canvas 小部件的像素数据可能会影响其显示内容,因此在进行修改后可能需要调用 lv_obj_invalidate 来标记小部件为无效并触发重新绘制。

通过 lv_canvas_get_buf 函数,开发者可以直接访问和操作 canvas 小部件的像素数据,这为实现复杂的图像处理和自定义绘制操作提供了灵活性。然而,直接操作像素数据也需要对 LVGL 的内部工作方式有深入的理解,以避免潜在的错误和性能问题。

10. lv_canvas_copy_buf


    将 `canvas` 小部件的缓冲区内容复制到另一个缓冲区。lv_canvas_copy_buf 函数是 LVGL 图形库中用于将 canvas 小部件的缓冲区内容复制到另一个缓冲区的函数。这个函数在需要对 canvas 内容进行备份、处理或者用于其他图层时非常有用。

void lv_canvas_copy_buf(lv_obj_t * obj, const lv_area_t * canvas_area, lv_draw_buf_t * dest_buf, const lv_area_t * dest_area)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);    // 断言 obj 是一个有效的 canvas 对象
    LV_ASSERT_NULL(canvas_area && dest_buf);  // 断言 canvas_area 和 dest_buf 都不为 NULL

    lv_canvas_t * canvas = (lv_canvas_t *)obj;
    if(canvas->draw_buf == NULL) return;  // 如果 canvas 没有绘制缓冲区,则直接返回

    LV_ASSERT_MSG(canvas->draw_buf->header.cf == dest_buf->header.cf, "Color formats must be the same");

    lv_draw_buf_copy(canvas->draw_buf, canvas_area, dest_buf, dest_area);  // 复制缓冲区内容
}

  1. 函数参数:

    • lv_obj_t * obj: 指向 canvas 小部件的指针,其缓冲区内容将被复制。
    • const lv_area_t * canvas_area: 指向一个 lv_area_t 结构体的指针,定义了 canvas 中要复制的区域。
    • lv_draw_buf_t * dest_buf: 指向目标 lv_draw_buf_t 结构体的指针,这是要复制内容到的缓冲区。
    • const lv_area_t * dest_area: 指向一个 lv_area_t 结构体的指针,定义了目标缓冲区中的目标区域。
  2. 函数逻辑:

    • 首先,函数通过 LV_ASSERT_OBJ 和 LV_ASSERT_NULL 宏检查输入参数的有效性。确保 obj 是一个有效的 canvas 对象,canvas_area 和 dest_buf 都不为 NULL。
    • 然后,函数获取 canvas 小部件的类型指针,并检查 canvas 的绘制缓冲区 draw_buf 是否已初始化。如果 draw_buf 为 NULL,说明 canvas 尚未准备好,函数将返回。
    • 接下来,函数使用 LV_ASSERT_MSG 宏确保源缓冲区和目标缓冲区的颜色格式相同。这是必要的,因为不同的颜色格式可能会导致不兼容的像素数据布局。
    • 最后,函数调用 lv_draw_buf_copy,将 canvas 小部件中指定的区域内容复制到目标缓冲区的指定区域。
  3. 使用场景:

    • lv_canvas_copy_buf 函数通常用于以下场景:
      • 当需要将 canvas 的内容备份到另一个缓冲区时。
      • 在多个图层之间共享或传递 canvas 内容时。
      • 在图像处理或特效应用中,需要将 canvas 的一部分或全部内容复制到另一个图像缓冲区时。
  4. 注意事项:

    • 在调用 lv_canvas_copy_buf 之前,必须确保 canvas 小部件已经创建并配置了适当的缓冲区。
    • 源缓冲区和目标缓冲区必须具有相同的颜色格式,否则复制操作可能失败或产生不正确的结果。
    • canvas_area 和 dest_area 定义的区域必须在各自缓冲区的尺寸范围内,否则可能会导致访问越界的错误。

通过 lv_canvas_copy_buf 函数,开发者可以在不同的缓冲区之间传输 canvas 小部件的内容,这对于图像处理、图层管理和复杂的用户界面设计非常有用。

11. lv_canvas_fill_bg


    使用指定颜色填充 `canvas` 小部件的背景。lv_canvas_fill_bg 函数是 LVGL 图形库中用于填充 canvas 小部件背景的函数。这个函数通常用于在绘制新的图形内容之前清除 canvas 上的现有内容,或者用于创建一个具有特定颜色背景的绘图区域。

void lv_canvas_fill_bg(lv_obj_t * obj, lv_color_t color, lv_opa_t opa)
{
    LV_ASSERT_OBJ(obj, MY_CLASS);

    lv_canvas_t * canvas = (lv_canvas_t *)obj;
    lv_draw_buf_t * draw_buf = canvas->draw_buf;
    if(draw_buf == NULL) return;

    lv_image_header_t * header = &draw_buf->header;
    uint32_t x;
    uint32_t y;
    uint32_t stride = header->stride;
    uint8_t * data = draw_buf->data;

    // 根据颜色格式,使用不同的填充方法
    if(header->cf == LV_COLOR_FORMAT_RGB565) {
        uint16_t c16 = lv_color_to_u16(color);
        for(y = 0; y < header->h; y++) {
            uint16_t * buf16 = (uint16_t *)(data + y * stride);
            for(x = 0; x < header->w; x++) {
                buf16[x] = c16;
            }
        }
    } else if(header->cf == LV_COLOR_FORMAT_XRGB8888 || header->cf == LV_COLOR_FORMAT_ARGB8888) {
        uint32_t c32;
        if(header->cf == LV_COLOR_FORMAT_ARGB8888) {
            c32 = (uint32_t)opa << 24;
            c32 |= lv_color_to_u32(color);
        } else {
            c32 = lv_color_to_u32(color) | (0xFF << 24);
        }
        for(y = 0; y < header->h; y++) {
            uint32_t * buf32 = (uint32_t *)(data + y * stride);
            for(x = 0; x < header->w; x++) {
                buf32[x] = c32;
            }
        }
    } else if(header->cf == LV_COLOR_FORMAT_RGB888) {
        for(y = 0; y < header->h; y++) {
            uint8_t * buf8 = (uint8_t *)(data + y * stride);
            for(x = 0; x < header->w * 3; x += 3) {
                buf8[x + 0] = color.blue;
                buf8[x + 1] = color.green;
                buf8[x + 2] = color.red;
            }
        }
    } else {
        // 如果颜色格式不支持,遍历每个像素并设置颜色
        for(y = 0; y < header->h; y++) {
            for(x = 0; x < header->w; x++) {
                lv_canvas_set_px(obj, x, y, color, opa);
            }
        }
    }

    lv_obj_invalidate(obj); // 标记对象为无效,以便重新绘制
}

  1. 函数参数:

    • lv_obj_t * obj: 指向 canvas 小部件的指针。
    • lv_color_t color: 要用于填充的背景颜色。
    • lv_opa_t opa: 颜色的不透明度。
  2. 函数逻辑:

    • 首先,函数通过 LV_ASSERT_OBJ 宏检查 obj 是否为有效的 canvas 小部件。
    • 然后,函数获取 canvas 小部件的 draw_buf(绘制缓冲区),这是存储绘制内容的内存区域。
    • 如果 draw_buf 为 NULL,说明 canvas 没有准备好进行绘制,函数将返回。
    • 根据 draw_buf 的颜色格式(color_format),函数使用不同的方法来填充背景颜色:
      • 对于 LV_COLOR_FORMAT_RGB565 格式,函数将颜色转换为 16 位表示,并遍历每个像素位置,设置相应的颜色值。
      • 对于 LV_COLOR_FORMAT_XRGB8888 或 LV_COLOR_FORMAT_ARGB8888 格式,函数将颜色转换为 32 位表示,并考虑不透明度(opa),然后遍历每个像素位置,设置相应的颜色值。
      • 对于 LV_COLOR_FORMAT_RGB888 格式,函数直接设置每个像素的红、绿、蓝分量。
      • 如果颜色格式不支持直接填充,函数将遍历每个像素并调用 lv_canvas_set_px 函数来设置颜色。
    • 最后,函数通过调用 lv_obj_invalidate 标记 canvas 小部件为无效,这将触发重新绘制 canvas
  3. 使用场景:

    • lv_canvas_fill_bg 函数通常在需要清除 canvas 上的现有内容或者在开始新的绘制之前设置背景颜色时使用。
  4. 注意事项:

    • 在调用 lv_canvas_fill_bg 之前,必须确保 canvas 小部件已经创建并配置了适当的缓冲区。
    • 该函数会根据 draw_buf 的颜色格式来决定如何填充背景颜色,因此在使用前应确保 canvas 的颜色格式符合预期。
    • 由于 lv_canvas_fill_bg 会直接操作 draw_buf 的数据,因此在调用此函数后,可能需要重新绘制 canvas 以确保内容正确显示。

通过 lv_canvas_fill_bg 函数,开发者可以快速地为 canvas 小部件设置一个统一的背景颜色,这在创建图形界面时非常有用,尤其是在需要清除旧内容或者为新内容准备背景时。

12. lv_canvas_init_layer


    初始化 `canvas` 小部件的图层。lv_canvas_init_layer 函数是 LVGL 图形库中用于初始化 canvas 小部件的图层的函数。图层是 LVGL 中的一个概念,它允许开发者在屏幕上的不同层次上绘制内容。通过使用图层,可以实现更复杂的用户界面效果,如覆盖、透明度和混合等。

void lv_canvas_init_layer(lv_obj_t * obj, lv_layer_t * layer)
{
    LV_ASSERT_NULL(obj);    // 断言 obj 不为 NULL
    LV_ASSERT_NULL(layer);   // 断言 layer 不为 NULL

    lv_canvas_t * canvas = (lv_canvas_t *)obj;
    if(canvas->draw_buf == NULL) return;

    lv_image_header_t * header = &canvas->draw_buf->header;
    lv_area_t canvas_area = {0, 0, header->w - 1, header->h - 1};
    lv_memzero(layer, sizeof(*layer));  // 将 layer 结构体的内存初始化为零

    layer->draw_buf = canvas->draw_buf;  // 设置图层的绘制缓冲区为 canvas 的缓冲区
    layer->color_format = header->cf;   // 设置图层的颜色格式
    layer->buf_area = canvas_area;     // 设置图层的缓冲区区域
    layer->clip_area = canvas_area;     // 设置图层的裁剪区域
}

  1. 函数参数:

    • lv_obj_t * obj: 指向 canvas 小部件的指针。
    • lv_layer_t * layer: 指向 lv_layer_t 结构体的指针,该结构体将被初始化为图层数据。
  2. 函数逻辑:

    • 首先,函数通过 LV_ASSERT_NULL 宏检查输入参数 obj 和 layer 是否为 NULL。如果任何一个参数为 NULL,则函数将直接返回,不执行任何操作。
    • 接下来,函数获取 canvas 小部件的类型指针,并检查 canvas 的绘制缓冲区 draw_buf 是否已初始化。如果 draw_buf 为 NULL,说明 canvas 尚未准备好,函数将返回。
    • 如果 draw_buf 存在,函数继续初始化 layer 结构体。它首先使用 lv_memzero 函数将 layer 的内存设置为零。
    • 然后,函数设置 layer 的 draw_buf 成员为 canvas 的 draw_buf,这样图层将使用相同的缓冲区进行绘制。
    • color_format 成员被设置为 canvas 的颜色格式,这决定了图层中每个像素的表示方式。
    • buf_area 成员定义了图层的缓冲区区域,即图层将占用的缓冲区范围。
    • clip_area 成员定义了图层的裁剪区域,这通常是图层的可视区域,用于限制图层内容的显示范围。
  3. 使用场景:

    • lv_canvas_init_layer 函数通常在需要将 canvas 小部件的内容作为图层显示时使用。例如,当你想要在屏幕上叠加多个图形元素时,可以将每个元素绘制到不同的 canvas 上,并使用此函数将它们初始化为图层。
  4. 注意事项:

    • 在调用 lv_canvas_init_layer 之前,必须确保 canvas 小部件已经创建并配置了适当的缓冲区。
    • layer 参数指向的 lv_layer_t 结构体必须已经被分配内存,且足够大以存储图层数据。
    • 一旦图层被初始化,它就可以通过 LVGL 的图层系统进行管理,例如使用 lv_layer_add 函数将其添加到屏幕上。

通过 lv_canvas_init_layer 函数,开发者可以更灵活地控制 canvas 小部件的渲染过程,实现复杂的用户界面效果。

13. lv_canvas_finish_layer


    完成 `canvas` 小部件的图层渲染任务。lv_canvas_finish_layer 函数是 LVGL 图形库中用于完成 canvas 小部件图层渲染任务的函数。这个函数是图层渲染流程的一部分,确保所有的绘制任务都已经被处理,并且图层的内容已经更新到屏幕上。

void lv_canvas_finish_layer(lv_obj_t * canvas, lv_layer_t * layer)
{
    while(layer->draw_task_head) {
        lv_draw_dispatch_wait_for_request();
        lv_draw_dispatch_layer(lv_obj_get_display(canvas), layer);
    }
}

  1. 函数参数:

    • lv_obj_t * canvas: 指向 canvas 小部件的指针,该小部件的图层需要完成渲染。
    • lv_layer_t * layer: 指向 lv_layer_t 结构体的指针,该结构体包含了需要完成的图层渲染任务。
  2. 函数逻辑:

    • 函数首先检查 layer 结构体中的 draw_task_head 成员。这是一个指向绘制任务链表的指针,其中包含了所有待处理的绘制任务。
    • 如果存在待处理的绘制任务,函数进入一个循环,循环体内执行以下两个步骤:
      • lv_draw_dispatch_wait_for_request(): 这个函数等待绘制请求,确保所有的绘制任务都已经提交给 LVGL 的绘制调度器。
      • lv_draw_dispatch_layer(lv_obj_get_display(canvas), layer): 这个函数将图层的绘制任务分派给 LVGL 的绘制引擎。它将图层的内容渲染到屏幕上,这通常涉及到将缓冲区中的数据传输到显示设备。
    • 循环会一直执行,直到所有的绘制任务都被处理完毕,即 draw_task_head 为 NULL。
  3. 使用场景:

    • lv_canvas_finish_layer 函数通常在开发者手动管理图层的绘制任务时调用。在某些情况下,开发者可能需要在特定的时刻确保所有的图层内容都已经渲染到屏幕上,例如在动画结束或者在准备进行屏幕截图时。
  4. 注意事项:

    • 在调用 lv_canvas_finish_layer 之前,必须确保 canvas 小部件和 layer 结构体已经被正确初始化,并且图层的绘制任务已经被添加到 layer 的任务列表中。
    • 该函数会阻塞直到所有绘制任务完成,这可能意味着在绘制任务较重的情况下,函数调用可能会花费一些时间。
    • 在正常情况下,LVGL 的绘制系统会自动管理图层的渲染,因此开发者通常不需要直接调用 lv_canvas_finish_layer。这个函数更多地用于特定的情况,其中需要显式地控制图层的渲染流程。

通过 lv_canvas_finish_layer 函数,开发者可以确保 canvas 小部件的图层内容被完全渲染到屏幕上,这对于确保用户界面的正确显示和响应用户操作非常重要。

14. lv_canvas_constructor和 lv_canvas_destructor


    分别是 `canvas` 小部件的构造函数和析构函数,用于初始化和清理资源。

 static void lv_canvas_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj) {
        // ...
    }
    static void lv_canvas_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj) {
        // ...
    }

示例 Demo

以下是一个示例,演示如何在一个 LVGL 应用程序中使用 `lv_canvas.c` 文件中定义的函数:

#include "lvgl/lvgl.h"

// 创建 `canvas` 小部件并设置缓冲区
void create_canvas(void) {
    // 创建 `canvas` 小部件
    lv_obj_t * canvas = lv_canvas_create(lv_scr_act(NULL), NULL);
    if(canvas == NULL) return;

    // 设置 `canvas` 小部件的大小
    lv_obj_set_size(canvas, 300, 200);

    // 创建一个缓冲区
    uint32_t buffer_size = lv_obj_get_width(canvas) * lv_obj_get_height(canvas) * LV_COLOR_SIZE;
    void * buffer = lv_mem_alloc(buffer_size);
    if(buffer == NULL) return;

    // 设置 `canvas` 小部件的缓冲区
    lv_canvas_set_buffer(canvas, buffer, lv_obj_get_width(canvas), lv_obj_get_height(canvas), LV_COLOR_FORMAT_RGB565);

    // 填充背景颜色
    lv_canvas_fill_bg(canvas, LV_COLOR_MAKE(0xFF, 0xFF, 0xFF), LV_OPA_COVER);

    // 在 `canvas` 上绘制一个像素
    lv_canvas_set_px(canvas, 100, 100, LV_COLOR_MAKE(0x00, 0x00, 0xFF), LV_OPA_COVER);

    // 释放缓冲区
    lv_mem_free(buffer);
}

int main(void) {
    // 初始化 LVGL
    lv_init();

    // 创建 `canvas` 小部件
    create_canvas();

    // 进入 LVGL 主循环
    while(1) {
        lv_task_handler();
        // 延时函数,根据需要添加
        // lv_delay(5);
    }

    return 0;
}

在这个示例中,我们首先创建了一个 `canvas` 小部件,并设置了它的大小。然后,我们创建了一个缓冲区,并将其设置为 `canvas` 小部件的缓冲区。接着,我们使用 `lv_canvas_fill_bg` 函数填充了背景颜色,并使用 `lv_canvas_set_px` 函数在 `canvas` 上绘制了一个蓝色的像素。最后,我们释放了之前分配的缓冲区。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值