要求
练习: 完成一张图片在板子上的显示
要求: 任意路径的图片
任意大小的图片
在板子上的任意位置显示
思路
void show_bmp (char * pathname , int x,int y) { 第一步:打开图片 ,读取宽度 高度 色深 第二步: 确定总字节数 然后malloc对应大小的内来保存这些颜色。unsigned char * p = malloc(total_bytes); //第三步: 打开帧缓冲设备 映射 init(); end(); 第四步: 把颜色的值写进去 要一个字节一个字节地写入 为什么呢? 因为32位和24位地A是不一样的。 unsigned char a,r,g,b ; 我们把前面保存的像素数组的对应内容 一个一个字节地给我的argb 。 24位的像素数组只有RGB a直接给0 32位的像素数组有a 需要给一个字节给a 每写完四个字节 写完一个argb 。 这四个字节是不是就是组成一个color ? 这个时候是不是就该调用我们draw_point函数。 注意: 每行跳过癞子。 第五步: 关闭图片 //关闭帧缓冲 解除映射 }
代码
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <sys/mman.h> #include <math.h> #include <stdlib.h> int * p = NULL ; void draw_point(int x,int y,int color) { if(x>=0 && x<800 && y>=0 && y<480 ) { *(p+800*y+x) = color ; } } /* 函数功能:在屏幕的任意一个位置 显示任意一张 任意大小的bmp图片 函数参数: @pathname : 要显示的图片 的路径名 @x : 在屏幕X轴值为x的地方开始显示 @y : 在屏幕Y轴值为y的地方开始显示 */ void show_bmp (char * pathname ,int x ,int y) { int fd = open(pathname,O_RDONLY); if(fd == -1) { perror("open error\n"); return ; } int fd1 = open("/dev/fb0",O_RDWR); if(fd1 == -1) { perror("open error\n"); return ; } printf("open success\n"); p = mmap(NULL,800*480*4,PROT_READ | PROT_WRITE,MAP_SHARED ,fd1,0); if(p == NULL ) { perror("mmap error\n"); return ; } int width,height; short depth; unsigned char buf[4] ; //读取宽度 lseek(fd,0x12,SEEK_SET); read(fd,buf,4); width = buf[3]<<24 | buf[2]<< 16 | buf[1] << 8 | buf[0]; //读取高度 read(fd,buf,4); height = buf[3]<<24 | buf[2]<< 16 | buf[1] << 8 | buf[0]; //读取色深 lseek(fd,0x1c,SEEK_SET); read(fd,buf,2); depth = buf[1] << 8 | buf[0]; //打印信息 printf("width = %d height = %d depth = %d \n",width,height,depth); //像素数组 int line_valid_bytes = abs(width) * depth / 8 ; //一行本有的有效字节 int laizi=0;//填充字节 if( (line_valid_bytes % 4) !=0 ) { laizi = 4 - line_valid_bytes%4; } int line_bytes = line_valid_bytes + laizi ;//一行所有的字节数 int total_bytes = line_bytes * abs(height) ; //整个像素数组的大小 unsigned char * p1 = malloc(total_bytes); lseek(fd,54,SEEK_SET); read(fd,p1,total_bytes); //调用draw_point 函数 。 unsigned char a ,r ,g, b ; int i = 0;//用来做指针运动的 int x0=0,y0=0; //用来循环计数 int color ; for(y0=0;y0<abs(height);y0++)//画满每一列 { for(x0=0;x0<abs(width);x0++)//画满每一行 { //现在开始一个字节一个字节写入颜色 // i++ 先用后加 // ++i 先加后用 b = p1[i++]; g = p1[i++]; r = p1[i++]; if(depth == 32) { a=p1[i++]; } if(depth == 24) { a = 0; } color = a << 24 | r << 16 | g << 8 | b ; draw_point(width>0?x+x0:abs(width)+x-1-x0, height>0? y+height-1-y0 : y+y0,color); } i = i +laizi ;//每一行后面的癞子数 跳过去。 } free(p1); close(fd1); munmap(p,800*480*4); close(fd); } int main() { show_bmp("1.bmp",-100 ,-100); //show_bmp("3.bmp",0,0); return 0; }
具体步骤
1、读取文件设置缓冲区
int fd = open(pathname,O_RDONLY); if(fd == -1) { perror("open error\n"); return ; } int fd1 = open("/dev/fb0",O_RDWR); if(fd1 == -1) { perror("open error\n"); return ; } printf("open success\n");
2、测量待显示图片的宽度、高度、色深
p = mmap(NULL,800*480*4,PROT_READ | PROT_WRITE,MAP_SHARED ,fd1,0); if(p == NULL ) { perror("mmap error\n"); return ; } int width,height; short depth; unsigned char buf[4] ; //读取宽度 lseek(fd,0x12,SEEK_SET); read(fd,buf,4); width = buf[3]<<24 | buf[2]<< 16 | buf[1] << 8 | buf[0]; //读取高度 read(fd,buf,4); height = buf[3]<<24 | buf[2]<< 16 | buf[1] << 8 | buf[0]; //读取色深 lseek(fd,0x1c,SEEK_SET); read(fd,buf,2); depth = buf[1] << 8 | buf[0]; //打印信息 printf("width = %d height = %d depth = %d \n",width,height,depth);
BMP图片的显示 :
bmp:bit map picture 位图
bmp文件格式的图片, 没有经过任何压缩技术生成的图片。
无压缩:保存了图片的每一个像素点的rgb颜色分量的值。
我们按照bmp图片文件的固定的内容格式将他的数据读出来,进行一些简单的操作。我们就可以完成这个图片的显示。
BMP图片文件格式
见图:
头两个字节 BM 我们是自己用BMP图片 所以就不用判定。
宽度: 一行有多少个像素点: 偏移量:0x12 大小: 4个字节 可正可负 正负只表示一行像素点的存储方式 为正说明行像素点是从左到右排列 为负说明行像素点是从右往左排列 高度: 一列有多少个像素点 偏移量:0X16 大小 : 4个字节 可正可负 正负只表示一列像素点的存储方式 为正说明行像素点是从下到上排列 为负说明行像素点是从上往下排列 色深: 每个像素所占的位数 bit 怎么求每个像素的大小?字节 色深/8 24 32 偏移量:0x1c 大小: 2个字节
小端模式和大端模式
小端模式: 存储器(内存)的低地址 存放 寄存器(数据)的低地址字节
大端模式: 存储器(内存)的低地址 存放 寄存器(数据)的高地址字节
两者的区别就是 高字节位、低字节位存放次序不同;小端先存低,大端先存高,大端模式用于比较高端的场景,处理速度快。
获取图片的宽度 高度 色深信息。 思路: int width,height; short depth; unsigned char buf[4]; 第一步: 打开图片 open("./1.bmp") 第二步: lseek 偏移对应偏移量大小 read 读取对应数据大小的内容 。。。。。 第三步: 关闭图片 buf[4] buf[0] buf[1] buf[2] buf[3] 我们真正想要的正确的数据是多少 buf[3] buf[2] buf[1] buf[0] buf[0] buf[1] buf[2] buf[3] ---> buf[3] buf[2] buf[1] buf[0] buf[3] << 24 buf[3] _______ ________ _________ buf[2] << 16 _________ buf[2] __________ ___________ buf[1] << 8 __________ _______ buf[1] ____________ buf[0] _________ _________ ________ buf[0] width = buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0]
将图像字节写入一个数组
//像素数组 int line_valid_bytes = abs(width) * depth / 8 ; //一行本有的有效字节 int laizi=0;//填充字节 if( (line_valid_bytes % 4) !=0 ) { laizi = 4 - line_valid_bytes%4; } int line_bytes = line_valid_bytes + laizi ;//一行所有的字节数 int total_bytes = line_bytes * abs(height) ; //整个像素数组的大小 unsigned char * p1 = malloc(total_bytes);
像素数组: 保存了图片像素点的所有argb颜色分量的值
偏移量: 54 大小: ??? 大小需要根据宽度和高度和色深来求 。 格式规定图片每行的字节数为4字节的倍数 大小: 图片的宽度的绝对值 * 图片的高度的绝对值 * 色深/ 8 if(depth == 32) { (图片的宽度的绝对值 * 32/ 8) % 4 一定为0 ; } if(depth == 24 ) { (图片的宽度的绝对值 * 24 / 8) % 4 不一定为 0 ; } 是不是我们24位的图片就需要填充若干个字节 来满足每行大小为4字节倍数要求 这些填充的字节数 我们叫癞子。 那我们怎么求出每行的填充的字节数呢?癞子? int laizi; if ( ( 宽度*色深/8 ) %4 !=0 ) { laizi = 4 - 宽度*色深/8 ) %4 ; } 我真正意义上一行的字节数 是多少? line_bytes = ( 宽度*色深/8 ) %4 + laizi ; 总共的字节数呢? total_bytes = line_bytes * height unsigned char * p = malloc(total_bytes);
将图像字节写入屏幕
void draw_point(int x,int y,int color) { if(x>=0 && x<800 && y>=0 && y<480 ) { *(p+800*y+x) = color ; } }
lseek(fd,54,SEEK_SET); read(fd,p1,total_bytes); //调用draw_point 函数 。 unsigned char a ,r ,g, b ; int i = 0;//用来做指针运动的 int x0=0,y0=0; //用来循环计数 int color ; for(y0=0;y0<abs(height);y0++)//画满每一列 { for(x0=0;x0<abs(width);x0++)//画满每一行 { //现在开始一个字节一个字节写入颜色 // i++ 先用后加 // ++i 先加后用 b = p1[i++]; g = p1[i++]; r = p1[i++]; if(depth == 32) { a=p1[i++]; } if(depth == 24) { a = 0; } color = a << 24 | r << 16 | g << 8 | b ; draw_point(width>0?x+x0:abs(width)+x-1-x0, height>0? y+height-1-y0 : y+y0,color); } i = i +laizi ;//每一行后面的癞子数 跳过去。 }
注意事项
- bmp图片需要传在GEC818上
- 如果要显示两张图片改变两张图片的起始位置即可
width>0?x+x0:abs(width)+x-1-x0
当width>0,也就是从左到右时,横坐标位置为x+x0
当width<0,也就是从右到左时,横坐标位置为abs(width)+x-1-x0`
模块化思想: 。。。 只有一个唯一的main函数‘ 一个或者多个功能函数 main.c lcd.c lcd.h bmp.c bmp.h led.c led.h beef.c beef.h ..... .h怎么写? 例:led.h #ifndef __LED_H__ #define __LED_H__ // 变量的定义 // 函数的声明 //。。。 #endif 功能函数: 封装一个函数 /* 功能函数:对一个坐标点为(x,y)的像素点上色。 参数: @x : 像素点的X轴坐标值 @y :像素点的Y轴坐标值 @color : 要画的颜色 */ void draw_point ( int x, int y, int color ) { if(x>=0 && x<800 && y>=0 && y<480) *(p + 800*y +x ) = 0x00ff0000 ;//p定义成全局变量 } BMP图片的显示 : bmp:bit map picture 位图 bmp文件格式的图片, 没有经过任何压缩技术生成的图片。 无压缩:保存了图片的每一个像素点的rgb颜色分量的值。 我们按照bmp图片文件的固定的内容格式将他的数据读出来,进行一些简单的操作。我们就可以完成这个图片的显示。 BMP图片文件格式 见图: 头两个字节 BM 我们是自己用BMP图片 所以就不用判定。 宽度: 一行有多少个像素点: 偏移量:0x12 大小: 4个字节 可正可负 正负只表示一行像素点的存储方式 为正说明行像素点是从左到右排列 为负说明行像素点是从右往左排列 高度: 一列有多少个像素点 偏移量:0X16 大小 : 4个字节 可正可负 正负只表示一列像素点的存储方式 为正说明行像素点是从下到上排列 为负说明行像素点是从上往下排列 色深: 每个像素所占的位数 bit 怎么求每个像素的大小?字节 色深/8 24 32 偏移量:0x1c 大小: 2个字节 小端模式和大端模式 小端模式: 存储器(内存)的低地址 存放 寄存器(数据)的低地址字节 大端模式: 存储器(内存)的低地址 存放 寄存器(数据)的高地址字节 练习: 获取图片的宽度 高度 色深信息。 思路: int width,height; short depth; unsigned char buf[4]; 第一步: 打开图片 open("./1.bmp") 第二步: lseek 偏移对应偏移量大小 read 读取对应数据大小的内容 。。。。。 第三步: 关闭图片 buf[4] buf[0] buf[1] buf[2] buf[3] 我们真正想要的正确的数据是多少 buf[3] buf[2] buf[1] buf[0] buf[0] buf[1] buf[2] buf[3] ---> buf[3] buf[2] buf[1] buf[0] buf[3] << 24 buf[3] _______ ________ _________ buf[2] << 16 _________ buf[2] __________ ___________ buf[1] << 8 __________ _______ buf[1] ____________ buf[0] _________ _________ ________ buf[0] width = buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0] 同样的方法求高度 色深... 见code : 像素数组: 保存了图片像素点的所有argb颜色分量的值 偏移量: 54 大小: ??? 大小需要根据宽度和高度和色深来求 。 大小: 图片的宽度的绝对值 * 图片的高度的绝对值 * 色深/ 8 if(depth == 32) { (图片的宽度的绝对值 * 32/ 8) % 4 一定为0 ; } if(depth == 24 ) { (图片的宽度的绝对值 * 24 / 8) % 4 不一定为 0 ; } 是不是我们24位的图片就需要填充若干个字节 来满足每行大小为4字节倍数要求 这些填充的字节数 我们叫癞子。 那我们怎么求出每行的填充的字节数呢?癞子? int laizi; if ( ( 宽度*色深/8 ) %4 !=0 ) { laizi = 4 - 宽度*色深/8 ) %4 ; } 我真正意义上一行的字节数 是多少? line_bytes = ( 宽度*色深/8 ) %4 + laizi ; 总共的字节数呢? total_bytes = line_bytes * height unsigned char * p = malloc(total_bytes); 练习: 完成一张图片在板子上的显示 要求: 任意路径的图片 任意大小的图片 在板子上的任意位置显示 void show_bmp (char * pathname , int x,int y) { 第一步:打开图片 ,读取宽度 高度 色深 第二步: 确定总字节数 然后malloc对应大小的内来保存这些颜色。unsigned char * p = malloc(total_bytes); //第三步: 打开帧缓冲设备 映射 init(); end(); 第四步: 把颜色的值写进去 要一个字节一个字节地写入 为什么呢? 因为32位和24位地A是不一样的。 unsigned char a,r,g,b ; 我们把前面保存的像素数组的对应内容 一个一个字节地给我的argb 。 24位的像素数组只有RGB a直接给0 32位的像素数组有a 需要给一个字节给a 每写完四个字节 写完一个argb 。 这四个字节是不是就是组成一个color ? 这个时候是不是就该调用我们draw_point函数。 注意: 每行跳过癞子。 第五步: 关闭图片 //关闭帧缓冲 解除映射 }
效果图