一、标准IO应用实例。 --- 显示bmp格式图片到lcd液晶设备上
1、分析lcd液晶设备参数。
分辨率:800* 480 --> 其实就是整个屏幕上像素点的总数
总字节数:800*480*4 --> 每一个像素点都是由4个字节组成
总结:每一个像素点之所以能够显示一种颜色,因为像素点是由三原色组成,分别是RGB,只需要将对应颜色数据放置到对应的位置上,就可以正确地显示颜色了。
每一个像素点组成:ARGB -> 透明度、红色、绿色、蓝色。
2、bmp格式图片。 --> 24位800*480的bmp格式图片
1)图片格式:
jpeg格式图片 --> 文件由于经过压缩,所以文件小,图片看起来比较模糊。
bmp格式图片 --> 没有经过任何的处理,直接由三原色组成的,文件比较大,看起来比较清楚。
2)800*480
代表图片总像素点是800*480
3)24位
24位 --> 3个字节 --> RGB --> 说明bmp格式图片每一个像素点都是由3个字节组成。
每一个像素点内容依次是BGR --> 蓝色、绿色、红色
二、大概思路。
先把图片的数据读取到缓冲区中,然后将缓冲区数据写入到lcd液晶设备。
1、先在windows中准备图片。
方式一:自己画。 --> 使用画图软件
1)重新调整大小 --> 去掉"保持纵横比"的√ --> 选择"像素" --> 水平:800 垂直:480
2)随便画
3)"文件" --- "另存为" -- "BMP图片" --> 命名为test.bmp
方式二:上网下载。
1)先上网下载随意一张图片。
2)右键选择该图片,使用画图软件打开。
3)"文件" --- "另存为" -- "BMP图片" --> 命名为test.bmp
记住:不要不要不要不要不要不要不要不要不要不要不要不要不要不要不要修改后缀就以为是BMP格式图片了。
2、将准备好的图片下载到开发板中。
3、根据思路写代码。
-------------------------------------------------------------
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
//1. 打开lcd液晶设备
int lcd = open("/dev/fb0",O_WRONLY);
if(lcd < 0)
printf("open fb0 error!\n");
//2. 打开bmp图片
FILE *fp = fopen("test.bmp","r");
if(fp == NULL)
printf("fopen test.bmp error!\n");
//3. 将图片数据读取到缓冲区中
char bmp_buf[800*480*3];
fread(bmp_buf,800*480*3,1,fp);
//4. 将缓冲区的数据写入到lcd液晶设备中
write(lcd,bmp_buf,sizeof(bmp_buf));
//5. 关闭lcd液晶设备
close(lcd);
//6. 关闭图片。
fclose(fp);
return 0;
}
---------------------------------------------------
运行结果:
1>. 显示图片缺失了4分之1。
2>. 形状不对。
3>. 颜色。
分析:图片缺少4分之1,因为write了800*480*3个字节进去,但是lcd液晶设备中有800*480*4个字节,所以缺少4分之1。
所以也引发颜色与形状都不对。
三、根据分析,修改代码。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
//1. 打开lcd液晶设备
int lcd = open("/dev/fb0",O_WRONLY);
if(lcd < 0)
printf("open fb0 error!\n");
//2. 打开bmp图片
FILE *fp = fopen("test.bmp","r");
if(fp == NULL)
printf("fopen test.bmp error!\n");
//3. 将图片数据读取到缓冲区中
char bmp_buf[800*480*3] = {0};
char lcd_buf[800*480*4] = {0};
fread(bmp_buf,800*480*3,1,fp);
//3.5 将图片数据经过"24位转32位"处理。
int i,j;
for(i=0,j=0;i<800*480*4;i+=4,j+=3)
{
lcd_buf[i+3] = bmp_buf[j];
lcd_buf[i+2] = bmp_buf[j+1];
lcd_buf[i+1] = bmp_buf[j+2];
lcd_buf[i] = 0;
}
//4. 将缓冲区的数据写入到lcd液晶设备中
write(lcd,lcd_buf,sizeof(lcd_buf));
//5. 关闭lcd液晶设备
close(lcd);
//6. 关闭图片。
fclose(fp);
return 0;
}
结果:
1、颜色不对。
2、形状有了,但是上下颠倒。
3、右边的像素点显示在左边了。
四、根据分析,修改代码。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
//1. 打开lcd液晶设备
int lcd = open("/dev/fb0",O_WRONLY);
if(lcd < 0)
printf("open fb0 error!\n");
//2. 打开bmp图片
FILE *fp = fopen("test.bmp","r");
if(fp == NULL)
printf("fopen test.bmp error!\n");
//3. 将图片数据读取到缓冲区中
char bmp_buf[800*480*3] = {0};
char lcd_buf[800*480*4] = {0};
fread(bmp_buf,800*480*3,1,fp);
//3.5 将图片数据经过"24位转32位"处理。
int i,j;
for(i=0,j=0;i<800*480*4;i+=4,j+=3)
{
lcd_buf[i] = bmp_buf[j];
lcd_buf[i+1] = bmp_buf[j+1];
lcd_buf[i+2] = bmp_buf[j+2];
lcd_buf[i+3] = 0;
}
//4. 将缓冲区的数据写入到lcd液晶设备中
write(lcd,lcd_buf,sizeof(lcd_buf));
//5. 关闭lcd液晶设备
close(lcd);
//6. 关闭图片。
fclose(fp);
return 0;
}
结果:
1、形状依然有的,但是上下颠倒。
2、右边的一些像素点显示在左边。
五、根据分析,修改代码。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
//1. 打开lcd液晶设备
int lcd = open("/dev/fb0",O_WRONLY);
if(lcd < 0)
printf("open fb0 error!\n");
//2. 打开bmp图片
FILE *fp = fopen("test.bmp","r");
if(fp == NULL)
printf("fopen test.bmp error!\n");
//2.5 跳过54个头数据
fseek(fp,54,SEEK_SET);
//3. 将图片数据读取到缓冲区中
char bmp_buf[800*480*3] = {0};
char lcd_buf[800*480*4] = {0};
fread(bmp_buf,800*480*3,1,fp);
//3.5 将图片数据经过"24位转32位"处理。
int i,j;
for(i=0,j=0;i<800*480*4;i+=4,j+=3)
{
lcd_buf[i] = bmp_buf[j];
lcd_buf[i+1] = bmp_buf[j+1];
lcd_buf[i+2] = bmp_buf[j+2];
lcd_buf[i+3] = 0;
}
//4. 将缓冲区的数据写入到lcd液晶设备中
write(lcd,lcd_buf,sizeof(lcd_buf));
//5. 关闭lcd液晶设备
close(lcd);
//6. 关闭图片。
fclose(fp);
return 0;
}
运行结果:
1、上下颠倒。
最终代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
//1. 打开lcd液晶设备
int lcd = open("/dev/fb0",O_WRONLY);
if(lcd < 0)
printf("open fb0 error!\n");
//2. 打开bmp图片
FILE *fp = fopen("test.bmp","r");
if(fp == NULL)
printf("fopen test.bmp error!\n");
//2.5 跳过54个头数据
fseek(fp,54,SEEK_SET);
//3. 将图片数据读取到缓冲区中
char bmp_buf[800*480*3] = {0};
char lcd_buf[800*480*4] = {0};
fread(bmp_buf,800*480*3,1,fp);
//3.5 将图片数据经过"24位转32位"处理。
int i,j;
for(i=0,j=0;i<800*480*4;i+=4,j+=3)
{
lcd_buf[i] = bmp_buf[j];
lcd_buf[i+1] = bmp_buf[j+1];
lcd_buf[i+2] = bmp_buf[j+2];
lcd_buf[i+3] = 0;
}
//3.8 上下颠倒
int x,y;
char show_buf[800*480*4] = {0};
for(y=0;y<480;y++)
{
for(x=0;x<800*4;x++)
{
show_buf[800*4*(479-y)+x] = lcd_buf[800*4*y+x];
}
}
//4. 将缓冲区的数据写入到lcd液晶设备中
write(lcd,show_buf,sizeof(show_buf));
//5. 关闭lcd液晶设备
close(lcd);
//6. 关闭图片。
fclose(fp);
return 0;
}
练习1: 先显示图片的代码封装成一个函数接口
show_bmp("test.bmp");
show_bmp("xx.bmp"); --> 实现传递什么,就显示什么。
练习2: 将显示图片加入到小项目中
如果用户未注册就登录,那么就会在lcd液晶显示not_register.bmp这张图片。
六、目录IO
1、为什么要学习目录IO?
目录是一种可以存放多个文件方式,如果有大量相同类型的文件,例如:有很多图片:1.bmp 2.bmp 3.bmp,把它们放在同一个目录下,那么管理这个目录,就等价于管理这个目录中所有的文件。
例如:
pic_data/
1.bmp 2.bmp 3.bmp 4.bmp 5.bmp...
usr_data/
ggy.txt abc.txt kkk.txt xxx.txt
2、访问文件与访问目录有什么区别?
访问文件,就可以得到文件里面的内容。
访问目录,就可以得到目录下的目录项(已经包含该目录项的名字、类型...)
七、目录IO函数接口。
1、如何打开一个目录? --> opendir() --> man 3 opendir
功能: open a directory
//打开一个目录
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
参数:
name: 需要打开的那个目录的路径。
返回值:
成功:目录指针
失败:NULL
思考:使用opendir()访问一个目录之后,是不是意味着已经切换到该目录下了?
不是,打开目录并没有切换进去,而是得到一个目录指针,该目录指针指向目录中第一项。
2、如何在程序中切换路径? --> chdir() --> man 2 chdir
功能: change working directory
//改变工作路径
#include <unistd.h>
int chdir(const char *path);
参数:
path:需要切换的那个目录的路径。
返回值:
成功:0
失败:-1
思考:切换到目录下有什么好处?
切换到目录之后,所有目录下的文件都是当前目录下的文件。
3、如何读取目录下的内容? --> readdir() --> man 3 readdir
功能:read a directory
//读取一个目录
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
参数:
dirp:目录指针
返回值:
成功:结构体指针 struct dirent *
失败:NULL --> 如果返回NULL,说明已经读取目录完毕。
struct dirent {
ino_t d_ino;
off_t d_off;
unsigned short d_reclen;
unsigned char d_type; --> 该目录项的类型
char d_name[256]; --> 该目录项的名字
};
d_type:类型
DT_UNKNOWN = 0, //未知类型
DT_FIFO = 1, //管道文件
DT_CHR = 2, //字符设备文件
DT_DIR = 4, //目录文件
DT_BLK = 6, //块设备文件
DT_REG = 8, //普通文件
DT_LNK = 10, //链接文件
DT_SOCK = 12, //套接字文件
d_name:文件名 -> 最多256个字符
4、关闭目录。 --> closedir() --> man 3 closedir
功能: close a directory
//关闭一个目录
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
参数:
dirp: 目录指针
返回值:
成功:0
失败:-1
5、重置目录指针。 --> rewinddir() --> man 3 rewinddir
功能: reset directory stream
//重置目录指针
#include <sys/types.h>
#include <dirent.h>
void rewinddir(DIR *dirp);
参数:
dirp:目录指针
返回值:无
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
//1. 打开目录。
DIR *dp = opendir("dir/");
if(dp == NULL)
printf("opendir error!\n");
//2. 切换到目录下。
int ret = chdir("dir/");
if(ret == -1)
printf("chdir error!\n");
//3. 读取目录下的内容。
struct dirent *ep = NULL;
while(1)
{
ep = readdir(dp);
if(ep == NULL) //说明已经读取完了
{
break;
}
if(ep->d_name[0] == '.')
{
continue;
}
printf("type:%d\n",ep->d_type);
printf("name:%s\n",ep->d_name);
printf("------------------------\n");
}
//4. 关闭目录
closedir(dp);
return 0;
}
练习3: 现在已经实现使用普通IO方式来显示bmp格式图片。(会出现花屏)
show_bmp("test.bmp");
现在要求你使用内存映射来实现显示bmp格式图片。(不会出现花屏)
mmap_show_bmp("test.bmp");
提示: show_buf[] -> 已经能显示的缓冲区
p = mmap();
memcpy(p,show_buf[??])
详细代码:show_bmp.c
(不需要使用目录IO)
练习4: 现在开发板中有一个目录叫bmp_dir/,里面存放着5张800*480的24位bmp格式图片,里面的图片分别是1.bmp 2.bmp 3.bmp
现在要求你写一个程序,当程序开始运行时,先显示pic_dir目录下第一张图片,然后点击触摸屏的左边区域松手,就显示上一张图片
点击触摸屏的右边区域松手,就显示下一张图片,点击触摸屏中间区域松手,就显示黑屏并退出程序。
如果当前显示第一张,那么点击左边,就显示最后一张。
如果当前显示最后一张,那么点击右边,就显示第一张。
详细代码:p4.c
(必须使用目录IO)
练习5: 现在开发板中有一个目录叫pic_dir,里面存放着???张800*480的24位bmp格式图片
现在要求你写一个程序,当程序开始运行时,先显示pic_dir目录下第一张图片,然后点击触摸屏的左边区域松手,就显示上一张图片
点击触摸屏的右边区域松手,就显示下一张图片,点击触摸屏中间区域松手,就显示黑屏并退出程序。
如果当前显示第一张,那么点击左边,就显示最后一张。
如果当前显示最后一张,那么点击右边,就显示第一张。