fb show bmp

原创   bitmap convert to RGB565 display 收藏

 

http://blog.youkuaiyun.com/nitghost/archive/2009/02/23/3925678.aspx

 

 

  bitmap图片是一个RGB888,每个像素由3个字节组成,R->8bit,G->8bit,B->8bit;

  RGB565 的每个pixels是由2字节组成,R->5bit,G->6bit,B->5bit。

转换的思路是取出原图的点,对没个采样进行运算。

  1. #define RGB565_MASK_RED        0xF800   
  2. #define RGB565_MASK_GREEN                         0x07E0   
  3. #define RGB565_MASK_BLUE                         0x001F   
  4.   
  5. void  rgb565_2_rgb24( BYTE  *rgb24,  WORD  rgb565)  
  6. {   
  7.  //extract RGB   
  8.  rgb24[2] = (rgb565 & RGB565_MASK_RED) >> 11;     
  9.  rgb24[1] = (rgb565 & RGB565_MASK_GREEN) >> 5;  
  10.  rgb24[0] = (rgb565 & RGB565_MASK_BLUE);  
  11.   
  12.  //amplify the image   
  13.  rgb24[2] <<= 3;  
  14.  rgb24[1] <<= 2;  
  15.  rgb24[0] <<= 3;  
  16. }   

  1. USHORT  rgb_24_2_565( int  r,  int  g,  int  b)  
  2. {  
  3.     return  ( USHORT )(((unsigned(r) << 8) & 0xF800) |   
  4.             ((unsigned(g) << 3) & 0x7E0)  |  
  5.             ((unsigned(b) >> 3)));  
  6. }  

  1. USHORT  rgb_24_2_555( int  r,  int  g,  int  b)  
  2. {  
  3.     return  ( USHORT )(((unsigned(r) << 7) & 0x7C00) |   
  4.             ((unsigned(g) << 2) & 0x3E0)  |  
  5.             ((unsigned(b) >> 3)));  
  6. }  
  7.   
  8. COLORREF  rgb_555_2_24( int  rgb555)  
  9. {  
  10.     unsigned r = ((rgb555 >> 7) & 0xF8);  
  11.     unsigned g = ((rgb555 >> 2) & 0xF8);  
  12.     unsigned b = ((rgb555 << 3) & 0xF8);  
  13.     return  RGB(r,g,b);  
  14. }  
  15.   
  16. void  rgb_555_2_bgr24( BYTE * p,  int  rgb555)  
  17. {  
  18.     p[0] = ((rgb555 << 3) & 0xF8);  
  19.     p[1] = ((rgb555 >> 2) & 0xF8);  
  20.     p[2] = ((rgb555 >> 7) & 0xF8);  
  21. }  

  1. #define RGB565_Val(r,g,b) (WORD)((r)<<11 | (g)<<5 | (b))   
  2. WORD  rgb555_2_rgb565( WORD  rgb555)  
  3. {  
  4.    BYTE  r,g,b;  
  5.    FLOAT  fRate = 63/31;  
  6.    //Get R G B    
  7.    r = (BYTE )(((rgb555 >> 7) & 0xF8)>>3);  
  8.    g = (BYTE )((((rgb555 >> 2) & 0xF8)>>3)*fRate);  
  9.    b = (BYTE )(((rgb555 << 3) & 0xF8)>>3);  
  10.    *(WORD  *)pDest = RGB565_Val(RDest,GDest,BDest);  

#include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <unistd.h> #include <string.h> #include <strings.h> #include <time.h> #include <errno.h> #include <sys/mman.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #include <dirent.h> #include <linux/input.h> #include <pthread.h> /* 全局变量定义 */ int volume = -25; // 默认音量值 // 12个MP3文件名数组 char mp3_name[12][8] = {"d1.mp3", "d2.mp3", "d3.mp3", "d4.mp4", "d5.mp3", "d6.mp3", "d7.mp3", "d8.mp3", "d9.mp3", "d10.mp3", "d11.mp3", "d12.mp3"}; // 音量显示图片数组 char bmp[12][8] = {"0.bmp", "1.bmp", "2.bmp", "3.bmp", "4.bmp", "5.bmp", "6.bmp", "7.bmp", "8.bmp", "9.bmp", "10.bmp"}; // 相册图片数组 char album_bmp[4][20] = {"1.bmp", "2.bmp", "3.bmp", "4.bmp"}; int lcd_fd = -1; // LCD文件描述符 int ts_fd = -1; // 触摸屏文件描述符 int *fb_mem = NULL; // 帧缓冲内存映射指针 #define LCD_WIDTH 800 // LCD宽度 #define LCD_HEIGHT 480 // LCD高度 /** * 显示BMP图片函数 * @param bmpname 图片文件名 * @param w 图片宽度 * @param h 图片高度 * @param x 显示x坐标 * @param y 显示y坐标 * @return 成功返回0,失败返回-1 */ int showbmp_wh_xy(char *bmpname, int w, int h, int x, int y) { // 计算每行字节数(考虑4字节对齐) int row_size = ((w * 24 + 31) / 32) * 4; // 24位BMP每像素3字节 int padding = row_size - w * 3; // 每行填充字节数 // 分配缓冲区 unsigned char *bmp_buf = malloc(row_size * h); unsigned int *lcd_buf = malloc(w * h * sizeof(unsigned int)); if (!bmp_buf || !lcd_buf) { printf("内存分配失败\n"); free(bmp_buf); free(lcd_buf); return -1; } // 打开BMP文件 int bmp = open(bmpname, O_RDONLY); if (bmp == -1) { printf("打开%s失败\n", bmpname); free(bmp_buf); free(lcd_buf); return -1; } // 跳过BMP文件头和信息头(共54字节) lseek(bmp, 54, SEEK_SET); // 读取全部像素数据(包含对齐字节) read(bmp, bmp_buf, row_size * h); close(bmp); // 初始化LCD设备(如果尚未初始化) if (lcd_fd == -1) { lcd_fd = open("/dev/fb0", O_RDWR); if (lcd_fd == -1) { printf("打开lcd屏幕失败\n"); free(bmp_buf); free(lcd_buf); return -1; } // 内存映射帧缓冲 fb_mem = mmap(NULL, LCD_WIDTH * LCD_HEIGHT * 4, PROT_READ | PROT_WRITE, MAP_SHARED, lcd_fd, 0); if (fb_mem == (void *)-1) { printf("mmap失败\n"); close(lcd_fd); lcd_fd = -1; free(bmp_buf); free(lcd_buf); return -1; } } // BGR -> RGB 转换,并去除对齐字节 int i, j; for (j = 0; j < h; j++) { for (i = 0; i < w; i++) { int bmp_idx = j * row_size + i * 3; int lcd_idx = j * w + i; // BGR -> RGB 并转换为32位格式 lcd_buf[lcd_idx] = bmp_buf[bmp_idx] | // Blue (bmp_buf[bmp_idx + 1] << 8) | // Green (bmp_buf[bmp_idx + 2] << 16); // Red } } // 显示到LCD(考虑坐标越界) int display_width = (w < LCD_WIDTH - x) ? w : (LCD_WIDTH - x); int display_height = (h < LCD_HEIGHT - y) ? h : (LCD_HEIGHT - y); for (j = 0; j < display_height; j++) { for (i = 0; i < display_width; i++) { // 垂直翻转(BMP存储顺序是从下到上) int src_idx = (h - 1 - j) * w + i; int dst_idx = (j + y) * LCD_WIDTH + (i + x); fb_mem[dst_idx] = lcd_buf[src_idx]; } } // 释放资源 free(bmp_buf); free(lcd_buf); return 0; } /** * 打开LCD设备 * @return 成功返回0,失败返回-1 */ int lcd_open() { lcd_fd = open("/dev/fb0", O_RDWR); if (lcd_fd == -1) { perror("open lcd failed"); return -1; } fb_mem = mmap(NULL, LCD_WIDTH*LCD_HEIGHT*4, PROT_READ|PROT_WRITE, MAP_SHARED, lcd_fd, 0); if (fb_mem == (int *)-1) { perror("mmap failed"); close(lcd_fd); lcd_fd = -1; return -1; } return 0; } /** * 关闭LCD设备 */ void lcd_close() { if (fb_mem) { munmap(fb_mem, LCD_WIDTH*LCD_HEIGHT*4); fb_mem = NULL; } if (lcd_fd != -1) { close(lcd_fd); lcd_fd = -1; } } /** * 打开触摸屏设备 * @return 成功返回0,失败退出程序 */ int ts_open() { ts_fd = open("/dev/input/event0", O_RDWR); if (ts_fd == -1) { perror("open ts failed"); exit(1); } return 0; } /** * 关闭触摸屏设备 */ void ts_close() { if (ts_fd != -1) { close(ts_fd); ts_fd = -1; } } /** * 获取触摸屏坐标 * @param x 返回x坐标 * @param y 返回y坐标 */ void get_xy(int *x, int *y) { struct input_event info; *x = *y = -1; while (1) { bzero(&info, sizeof(info)); read(ts_fd, &info, sizeof(info)); if (info.type == EV_ABS) { // 绝对坐标事件 if (info.code == ABS_X) *x = info.value*800/1024; // 转换x坐标 if (info.code == ABS_Y) *y = info.value*480/600; // 转换y坐标 } // 检测触摸释放事件 if (info.type == EV_KEY && info.code == BTN_TOUCH && info.value == 0) { if (*x != -1 && *y != -1) break; } } } /** * 显示电子钢琴界面 */ void show_piano() { showbmp_wh_xy("background.bmp", 800, 480, 0, 0); // 背景 showbmp_wh_xy("bar.bmp", 800, 47, 0, 0); // 顶部栏 // 绘制12个琴键 int a = 10; for (int i = 0; i < 12; i++) { showbmp_wh_xy("key_off.bmp", 64, 280, a + (65 * i), 47); } showbmp_wh_xy("logo.bmp", 344, 66, 229, 381); // 底部logo } /** * 钢琴按键处理函数 * @param x 触摸x坐标 * @param y 触摸y坐标 * @return 按键编号(1-12:琴键,13:退出,14:音量减,15:音量加,-1:无效区域) */ int piano_play(int x, int y) { if (y >= 47 && y <= 327) { // 琴键区域 return (x - 10) / 65 + 1; } else if ((x >= 229 && x <= 570) && (y >= 381 && y <= 446)) { return 13; // 退出钢琴 } else if ((x >= 741 && x <= 800) && (y >= 421 && y <= 480)) { return 14; // 减小音量 } else if ((x >= 741 && x <= 790) && (y >= 360 && y <= 420)) { return 15; // 增大音量 } else { return -1; // 无效区域 } } /** * 电子钢琴主函数 */ void piano_main() { int old = -1, new = -1; // 记录新旧按键状态 ts_open(); // 打开触摸屏 show_piano(); // 显示钢琴界面 while (1) { old = new; int x = -1, y = -1; get_xy(&x, &y); // 获取触摸坐标 new = piano_play(x, y); // 转换为按键编号 if (new == 13) { // 退出钢琴 break; } // 音量控制 if (new == 14) { // 减小音量 if (volume > -50) { volume -= 5; int i = (volume + 50) / 5; showbmp_wh_xy(bmp[i], 20, 20, 689, 408); // 更新音量显示 } } else if (new == 15) { // 增大音量 if (volume < 0) { volume += 5; int i = (volume + 50) / 5; showbmp_wh_xy(bmp[i], 20, 20, 689, 408); // 更新音量显示 } } else if (1 <= new && new <= 12) { // 琴键操作 if (new != old) { system("killall -9 madplay"); // 停止当前播放 char buf[100] = {0}; int idx = new - 1; sprintf(buf, "madplay %s &", mp3_name[idx]); // 播放对应音符 system(buf); // 更新琴键显示状态 if (old != -1) { showbmp_wh_xy("key_on.bmp", 64, 280, 10 + 65 * (old - 1), 47); } showbmp_wh_xy("key_on.bmp", 64, 280, 10 + 65 * (new - 1), 47); old = new; } } } ts_close(); // 关闭触摸屏 showbmp_wh_xy("ui.bmp",800,480, 0, 0); // 返回主界面 } /** * 加载钢琴声音(示例函数) */ void load_piano_sounds() { printf("进入电子钢琴功能\n"); piano_main(); } /** * 自动播放相册 */ void auto_album() { for (int i = 0; i < 4; i++) { showbmp_wh_xy(album_bmp[i], 555, 333, 120, 75); sleep(2); // 每张图片显示2秒 } } /** * 手动播放相册 */ void manual_album() { int i = 0; while (1) { showbmp_wh_xy(album_bmp[i], 555, 333, 120, 75); int x = -1, y = -1; get_xy(&x, &y); // 根据触摸位置翻页 if (x >= 0 && x < 300) { // 上翻页 i--; if (i == -1) i = 3; } else if (x >= 300 && x < 600) { // 下翻页 i++; if (i == 4) i = 0; } else if (x >= 600 && x < 800) { // 退出 break; } } } int main() { // 初始化设备 lcd_open(); ts_open(); showbmp_wh_xy("zhu.bmp", 800, 480, 0, 0); // 显示启动画面 sleep(3); // 主循环 while (1) { // 显示主界面 showbmp_wh_xy("ui.bmp", 800, 480, 0, 0); int x = -1, y = -1; get_xy(&x, &y); // 获取触摸坐标 // 主界面选项处理 if (x > 32 && x < 192 && y > 160 && y < 320) { // 自动播放 auto_album(); } else if (x > 224 && x < 384 && y > 160 && y < 320) { // 手动播放 manual_album(); } else if (x > 416 && x < 576 && y > 160 && y < 320) { // 电子钢琴 load_piano_sounds(); } else if (x > 608 && x < 768 && y > 160 && y < 320) { // 退出 break; } } // 清理资源 lcd_close(); ts_close(); return 0; }根据上述代码写一份课设报告3000字
最新发布
06-23
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值