练习: 完成一张图片在板子上的显示
要求: 任意路径的图片
任意大小的图片
在板子上的任意位置显示
- 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;
- }
-
- 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);
-
-
- 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 ;//每一行后面的癞子数 跳过去。
-
- }
-
-
-
- 模块化思想:
-
- 。。。
- 只有一个唯一的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函数。
-
-
- 注意: 每行跳过癞子。
-
- 第五步: 关闭图片 //关闭帧缓冲 解除映射
-
-
- }
-
-