当前位置: 首页 > news >正文

Day69 SQLite3动态库移植 + BMP图像解析显示 + 进度条控件设计与动态文本管理

day69 SQLite3动态库移植 + BMP图像解析显示 + 进度条控件设计与动态文本管理


一、SQLite3 动态库移植流程回顾与验证

1. 移植步骤总结

  1. 下载源码

    • 从官网或可信源获取 SQLite3 源码压缩包(如 sqlite-autoconf-xxxxxx.tar.gz)。
  2. 解压源码

    tar -zxvf sqlite-autoconf-xxxxxx.tar.gz
    cd sqlite-autoconf-xxxxxx
    
  3. 配置编译环境
    使用 ./configure 命令,关键参数如下:

    ./configure \CC=arm-linux-gnueabihf-gcc \      # 指定交叉编译器--host=arm-linux \                # 指定目标平台--prefix=/your/absolute/path      # 指定安装路径(必须为绝对路径!)
    

    ⚠️ 注意:--prefix 必须使用绝对路径,否则 make install 无法正确部署。

  4. 编译与安装

    make
    make install
    
    • 生成的动态库(如 libsqlite3.so)将被安装到 --prefix 指定目录下的 lib/ 中。
  5. 部署到开发板

    • 将生成的 libsqlite3.so 及其符号链接文件(共约4个相关文件)完整拷贝到开发板的 /lib/usr/lib
    • 重要:若开发板原已有 libsqlite3.so必须先删除旧文件,避免冲突。
  6. 验证移植结果

    • 编写一个独立的测试程序(不要直接在 SQLite 源码目录下运行示例),链接 -lsqlite3 并执行。
    • 若程序能正常运行,说明移植成功。

2. 注意事项

  • 动态库优于静态库:项目中优先使用动态库(.so),便于更新与节省空间。
  • 保留符号链接属性:拷贝时建议将整个 lib/ 目录打包(如 tar),再在开发板解压,确保链接关系不丢失。
  • 流程标准化:本次移植流程适用于其他开源库(如 zlib、curl 等),需形成通用方法论。

二、BMP 图像格式解析与显示

1. BMP 文件结构(以 24 位真彩色为例)

部分大小说明
文件头(File Header)14 字节包含类型(“BM”)、文件总大小、数据偏移量等
信息头(Info Header)40 字节包含宽、高、位深度(如24)、压缩方式(0=无压缩)等
调色板(Color Table)可选24位图无调色板
像素数据(Pixel Data)可变从文件偏移 54 字节 开始;按 BGR 顺序存储;从左下角开始逐行向上(底行 → 首行)

📌 关键点:

  • 像素排列:行首 → 行尾(每行从左到右)
  • 行顺序:底行 → 首行(文件先存最下面一行)
  • 字节序:小端(Little-Endian)

2. 准备测试图片

  1. 任选一张图片(如 JPG),用 Windows 画图 打开。
  2. 调整尺寸为 800×600 像素(或更小),且宽高均为 4 的整数倍
  3. 另存为 24 位 BMP 格式(如 test.bmp)。
  4. 拷贝到 Linux 虚拟机。

3. BMP 解析核心代码(含内存对齐)

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>// 打包结构体,确保字节对齐为1字节(匹配BMP格式的紧凑布局)
#pragma pack(push, 1)
typedef struct __file_head {unsigned short bfType;       // BMP标识,应为"BM"(0x4D42)unsigned int   bfSize;       // 文件总大小(注释:wen jian da xiao)unsigned int   bfReserved1;  // 保留字段1unsigned int   bfReserved2;  // 保留字段2unsigned int   bfOffBits;    // 像素数据相对于文件头的偏移量
} file_head_t;typedef struct __info_head {unsigned int   biSize;       // 信息头大小(应为40字节)unsigned int   biWidth;      // 图像宽度(注释:width)unsigned int   biHeight;     // 图像高度(注释:height)unsigned short biPlanes;     // 颜色平面数(固定为1)unsigned short biBitCount;   // 每像素位数(注释:bits_per_pixel)unsigned int   biCompression;// 压缩方式(0为无压缩)unsigned int   biSizeImage;  // 像素数据大小unsigned int   biXPelsPerMeter; // 水平分辨率unsigned int   biYPelsPerMeter; // 垂直分辨率unsigned int   biClrUsed;    // 使用的颜色数unsigned int   biClrImportant;// 重要颜色数
} info_head_t;
#pragma pack(pop)int main(int argc, const char *argv[]) {file_head_t fh;info_head_t ih;// 打开BMP文件(请确保1.bmp存在于上级目录)int fd = open("../1.bmp", O_RDONLY);if (fd < 0) {perror("open file failed");return -1;}// 读取文件头if (read(fd, &fh, sizeof(fh)) != sizeof(fh)) {perror("read file head failed");close(fd);return -1;}// 读取信息头if (read(fd, &ih, sizeof(ih)) != sizeof(ih)) {perror("read info head failed");close(fd);return -1;}// 打印文件头大小(验证结构体打包是否正确)printf("sizeof file_head: %ld\n", sizeof(fh));// 打印BMP标识(应为"BM")printf("type: %c%c\n", ((char *)&fh.bfType)[0], ((char *)&fh.bfType)[1]);// 打印文件总大小、宽度、高度、每像素位数printf("size: %d\n", fh.bfSize);printf("width: %d\n", ih.biWidth);printf("height: %d\n", ih.biHeight);printf("bitcount: %d\n", ih.biBitCount);// 关闭文件close(fd);return 0;
}
代码说明:
  • 使用 #pragma pack(push, 1)#pragma pack(pop) 强制结构体按 1 字节对齐,避免编译器填充导致结构体大小错误。
  • 依次读取 BMP 文件头和信息头,并打印关键字段。
  • 理想输出示例:
    sizeof file_head: 14
    type: BM
    size: 1728054
    width: 800
    height: 600
    bitcount: 24
    

4. BMP 显示优化:整块读取 + 坐标映射

问题:逐像素读取效率极低

原始方式(低效):

for (i = 0; i < height; i++) {for (j = 0; j < width; j++) {read(fd, &b, 1); // 每次读1字节,共需 width*height*3 次系统调用read(fd, &g, 1);read(fd, &r, 1);draw_point(...);}
}
  • 对于 800×480 图像,需 1,152,000 次 read(),I/O 开销巨大,画面刷新卡顿。
优化方案:一次性读取全部像素数据
int color_size = ih.biwidth * ih.biheight * ih.bibitcount / 8;
unsigned char *data = malloc(color_size);
read(fd, data, color_size); // 1次系统调用读完所有像素// 内存中顺序解析
unsigned char *p = data;
for (i = 0; i < ih.biheight; i++) {for (j = 0; j < ih.biwidth; j++) {c.col.b = *p++; // Bc.col.g = *p++; // Gc.col.r = *p++; // Rdraw_point(j + x0, ih.biheight - i - 1 + y0, c.l);}
}
free(data);
  • 效果:画面刷新流畅,无逐行扫描卡顿。
坐标映射说明:
  • BMP 像素数据存储顺序:从左下角开始,逐行向上(底行 → 首行)。
  • 屏幕坐标系:原点(0,0)在左上角
  • 映射公式:
    int screen_x = j + x0;                     // 横坐标正常偏移
    int screen_y = (ih.biheight - i - 1) + y0; // 纵坐标翻转 + 偏移
    

5. 多照片显示动图效果

while(1)
{int i = 0;for(i = 0; i < 23; i++){char path[100] = {0};sprintf(path, "./1/0e2db04a70904fcb911ee50436982e12a4odeoSJdCTgJ07X-%d.bmp", i);show_bmp(path, 100, 100);usleep(200 * 1000);}
}
代码说明:
  • 循环读取 23 张 BMP 图片,依次显示在屏幕 (100,100) 位置。
  • 每张图片显示 200ms(usleep(200 * 1000))。
  • 实现简单帧动画效果。

三、进度条控件(bar)设计与实现

1. 结构体定义

typedef struct __tag_bar
{unsigned int x0;unsigned int y0;unsigned int width;unsigned int height;unsigned int border_width;unsigned int border_color;unsigned int bar_bg_color;unsigned int bar_color;unsigned int min_value;unsigned int max_value;unsigned int value;unsigned int digit_color; // 新增:百分比数字的颜色
} bar_t;

2. 绘制逻辑

  • 边框:循环绘制多层矩形(层数 = border_width)。
  • 进度条
    1. 计算当前进度比例:
      bar_len = (value - min) / (max - min) * (width - 2*border_width)
    2. 逐列绘制竖线:
      • bar_len 列:进度条颜色
      • 剩余列:背景色

3. 完整功能演示(fb.c

int main() {fb_init();screen_clear();show_bmp("./2.bmp", 0, 0);          // 显示背景图lcd_draw_circle(400, 240, 100, 0xff0000); // 画圆lcd_show_string(100, 100, 200, 50, 32, "hello", 0xff00ff); // 显示文字// 创建并配置两个进度条bar_t *b1 = create_bar();bar_t *b2 = create_bar();set_bar_pos(b2, 20, 400);set_bar_size(b2, 600, 20);set_bar_border(b2, 4, 0xc0c0c0); // 灰色边框set_bar_range(b2, 0, 200);set_bar_color(b2, 0xffffff);     // 白色进度条set_bar_bg_color(b2, 0);         // 黑色背景set_bar_digit_color(b2, 0);      // 黑色数字// 动态更新int i = 0;while(1) {set_bar_value(b1, i);set_bar_value(b2, 2*i);bar_display(b1);bar_display(b2);usleep(100 * 1000);if (++i > 100) i = 0;}// 清理资源del_bar(b1); del_bar(b2);fb_deinit();return 0;
}

四、动态文本“重影”问题与解决方案

1. 问题引出

  • 现象:在进度条上直接显示百分比数字(如 “50%”)后,当进度值更新时,新数字会直接覆盖在旧数字之上,导致显示混乱(“重影”)。
  • 低效方案:每次更新都清屏并重绘整个界面。效率极低,不适用于复杂UI。
  • 正确思路:采用局部背景恢复技术。

2. 屏幕背景备份与恢复机制

新增全局备份缓冲区
// framebuffer.c
static unsigned char * p_mem; // 帧缓冲映射地址
static unsigned char * p_bk;  // 新增:背景备份缓冲区int fb_init(void) {// ... 初始化 p_mem ...p_bk = malloc(fb_size); // 分配备份内存return 0;
}void fb_deinit(void) {free(p_bk); // 释放备份内存// ...
}
核心API
  • save_mem(void):在完成初始界面绘制后,调用此函数将当前屏幕内容完整备份到 p_bk
  • recovery_mem(x0, y0, width, height):在绘制动态内容前,调用此函数将指定矩形区域从 p_bk 恢复到 p_mem
recovery_mem 实现
void recovery_mem(unsigned int x0, unsigned int y0, unsigned int width, unsigned int height) {for(int i = 0; i < height; i++) {unsigned char * p_src = p_bk + (info.xres_virtual * (y0 + i) + x0) * (info.bits_per_pixel / 8);unsigned char * p_dst = p_mem + (info.xres_virtual * (y0 + i) + x0) * (info.bits_per_pixel / 8);for(int j = 0; j < width * (info.bits_per_pixel / 8); j++) {*p_dst++ = *p_src++;}}
}

3. 进度条控件增强(支持动态百分比)

void bar_display(bar_t * bar) {// ... 绘制边框和进度条 ...// 1. 格式化百分比字符串char str[5] = {0};int percentage = (int)((100.0 * (bar->value - bar->min_value)) / (bar->max_value - bar->min_value));sprintf(str, "%d%%", percentage);// 2. 恢复数字区域的背景 (关键步骤!)recovery_mem(bar->x0, bar->y0 - 20, bar->width + 100, 20);// 3. 在恢复后的干净区域上绘制新数字lcd_show_string(bar->x0 + bar_len, // X坐标:进度条当前长度处bar->y0 - 20,      // Y坐标:进度条上方strlen(str) * 16, 50, // 宽高(足够容纳字符串)16,                // 字体大小str,               // 要显示的字符串bar->digit_color   // 颜色);
}
使用示例
fb_init();
screen_clear();
show_bmp("./2.bmp", 0, 0); // 1. 绘制背景图
save_mem();                // 2. 保存此时的完整背景// ... 其他静态UI绘制 ...while(1) {bar_display(b1);bar_display(b2);usleep(100 * 1000);
}

五、关键经验总结

  1. 内存对齐是二进制文件解析的常见陷阱,务必使用 #pragma pack
  2. 组件化设计(如 bar_t)极大提升代码复用性与可维护性。
  3. 批量 I/O 是性能优化的核心手段,避免高频小数据读写。
  4. 坐标系转换(BMP vs 屏幕)需显式处理,避免图像倒置。
  5. 多实例支持:通过动态分配结构体,避免全局变量限制。
  6. 局部更新:通过背景备份与恢复,实现高效、无闪烁的动态UI更新,这是所有GUI系统的基础。

💡 关键提醒:务必理解 save_memrecovery_mem 的调用时机。save_mem 应在所有静态背景绘制完成后调用一次;recovery_mem 则应在每次绘制动态前景前调用。

http://www.dtcms.com/a/520097.html

相关文章:

  • 通过自构建的时间服务器主机给客户端主机同步时间
  • [特殊字符] 软考架构师 vs. 考研408:全方位对比
  • C语言进阶:(一)深度剖析函数栈帧:从创建到销毁
  • 零基础从头教学Linux(Day 55)
  • 哪里有学做ppt的网站资阳的网站建设
  • Apple 开源FastVLM:AI看图说话更快更准
  • 交互式UTM坐标查询工具:让地理坐标转换变得简单
  • 初学者小白复盘15之指针(4)
  • 轻量级且简单的 macOS 应用 Forklift for mac
  • 和平板电脑厂商定制智慧养老平板有那种合作模式?
  • 无人机安防体系的音视频超低延迟重构:从“空地融合”到“实时智控”
  • 做网站推广业务怎么样专业仿站网站建设
  • 三分钟部署最新开源大模型!Amazon SageMaker JumpStart 生成式 AI 实战指南
  • AWS云服务故障复盘——从故障中汲取的 IT 运维经验
  • Adobe Dimension 2025 (3D可视化设计神器) 解锁版
  • CUDA安装备忘录
  • 泰安网站建设流程软文营销文章300字
  • 医院为什么要做门户网站建设无锡专业网站推广
  • freeRTOS学习
  • K8s 集群环境搭建 - yaml 版本(一)
  • RAM和ROM的定义和区别总结!!!
  • GELU(高斯误差线性单元)激活函数全面解析
  • 企业网站可以做淘宝客吗wordpress 用户密码加密
  • WordPress + React 无头架构搭建指南
  • 聚类算法实战:从 KMeans 到 DBSCAN
  • 网站信息登记表网络营销考试题及答案
  • 宁夏建设工程招投标管理中心网站工程建设标准化期刊网站
  • 网站建设模板ppt模板微信公众网站开发
  • ElasticSearch倒排索引、ES核心概念、JAVA集成ES操作
  • window安装Elasticsearch(es)