一. 系统IO与标准IO结合实例 -> 显示RGB组成BMP格式图片
1. BMP格式图片特点
由纯RGB三原色来组成,没有经过任何的压缩,文件相对于压缩过jpeg格式会比较大。
test.bmp -> 1MB
test.jpg -> 27KB
2. BMP图片既然是RGB组成,那么BMP图片像素点是如何组成?
一般BMP图片都是24位的,因为RGB各占8位,24位说明每一个像素点都是由3个字节字节,从高到低依次是: BGR
液晶LCD像素点,从高到低依次是: ARGB
图片总字节: 800*480*3
LCD总字节:800*480*4
二. 分析显示过程
1. test.bmp是普通文件,/dev/fb0是设备文件,所以访问对应文件需要使用不同的IO。
2. 大致过程如下:
1)使用标准IO访问test.bmp。
2)读取test.bmp的数据 -> 将每一个像素点都应该读取出来
3)使用系统IO访问液晶LCD。
4)将图片像素点数据写入到液晶LCD中。 -> 注意像素点的分布。
5)关闭文件和设备即可。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
char bmp_buf[800*480*3];//BMP格式图片缓冲区
char lcd_buf[800*480*4];//LCD液晶缓冲区
int ret,lcd;
int i,j;
//1. 访问BMP图片
FILE *fp = fopen("test.bmp","r");
if(fp == NULL)
printf("fopen error! ");
//2. 读取BMP图片的数据
ret = fread(bmp_buf,sizeof(bmp_buf),1,fp);
if(ret != 1)
printf("fread error! ");
//3. 访问LCD液晶
lcd = open("/dev/fb0",O_WRONLY);
if(lcd < 0)
printf("open error! ");
for(i=0,j=0;i<800*480*4;i+=4,j+=3)
{
lcd_buf[i] = 0;
lcd_buf[i+1] = bmp_buf[j+2];
lcd_buf[i+2] = bmp_buf[j+1];
lcd_buf[i+3] = bmp_buf[j];
}
//4. 将图片数据写入到LCD液晶屏幕上
ret = write(lcd,lcd_buf,sizeof(lcd_buf));
if(ret != sizeof(lcd_buf))
printf("write error! ");
//5. 关闭设备与文件
close(lcd);
fclose(fp);
return 0;
}
结果:
形状有了,颜色不对!
lcd_buf[0] -> 蓝色
lcd_buf[1] -> 绿色
lcd_buf[2] -> 红色
lcd_buf[3] -> 透明度
修改为:
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. 发现在LCD在开头有一些数据不是像素点来的,也被读取出来了
800*480*3=1152000 -> 实际像素点的字节数
图片实际字节数: 1152054 -> 有54个头数据!
4. 上下翻装
根据逻辑关系退出通项公式
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
char bmp_buf[800*480*3];//BMP格式图片缓冲区
char lcd_buf[800*480*4];//LCD液晶缓冲区
char show_buf[800*480*4];
int ret,lcd;
int i,j,x,y;
//1. 访问BMP图片
FILE *fp = fopen("test.bmp","r");
if(fp == NULL)
printf("fopen error! ");
//2. 跳过BMP图片的54个头数据
ret = fseek(fp,54,SEEK_SET);
if(ret != 0)
printf("fseek error! ");
//3. 读取BMP图片的数据
ret = fread(bmp_buf,sizeof(bmp_buf),1,fp);
if(ret != 1)
printf("fread error! ");
//4. 访问LCD液晶
lcd = open("/dev/fb0",O_WRONLY);
if(lcd < 0)
printf("open error! ");
//5. 像素点赋值
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;
}
//6. 上下翻转
for(y=0;y<480;y++)
{
for(x=0;x<800*4;x++)
{
show_buf[(479-y)*800*4+x] = lcd_buf[y*800*4+x];
}
}
//7. 将图片数据写入到LCD液晶屏幕上
ret = write(lcd,show_buf,sizeof(show_buf));
if(ret != sizeof(show_buf))
printf("write error! ");
//8. 关闭设备与文件
close(lcd);
fclose(fp);
return 0;
}
三. 目录IO
1. 如何访问(打开)目录? -> opendir() -> man 3 opendir
与windows不一样,linux下访问目录就仅仅是打开目录而已,与路径切换无关。
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
name: 需要打开的目录的路径
返回值:
成功: 目录流指针 -> 打开目录后,默认指向目录中最开头的一项!
失败: NULL
验证: 访问目录时,并没有切换到目录下。
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
system("pwd");
DIR *dp = opendir("./dir");
if(dp == NULL)
printf("opendir error! ");
system("pwd");
return 0;
}
2. 关闭目录? -> closedir() -> man 3 closedir
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
dirp: 目录流指针
返回值:
成功:0
失败:-1
3. 如何切换到目录下? -> chdir() -> man 2 chdir
#include <unistd.h>
int chdir(const char *path);
path: 需要切换的目录路径
返回值:
成功:0
失败:-1
注意:
chdir()参数不是填目录流指针,而是填目录路径。
4. 如何读取目录? -> readdir() -> man 3 readdir
#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_reclen:
公式: 12+X
. -> 1 -> 4 -> 12+4=16
.. -> 2 -> 4 -> 12+4=16
1.txt -> 5 -> 8 -> 12+8=20
3a.jpg -> 6 -> 8 -> 12+8=20
abcdef.jpg-> 10 -> 12 -> 12+12=24
d_type:
enum
{
DT_UNKNOWN = 0, -> 未知类型
DT_FIFO = 1, -> 管道文件
DT_CHR = 2, -> 字符设备文件
DT_DIR = 4, -> 目录文件
DT_BLK = 6, -> 块设备
DT_REG = 8, -> 普通文件
DT_LNK = 10, -> 链接文件
DT_SOCK = 12, -> 套接字文件
};
5. 重置目录指针? -> rewinddir() -> man 3 rewinddir
#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>
int main()
{
//1. 打开目录
DIR *dp = opendir("./dir");
if(dp == NULL)
printf("opendir error! ");
//2. 切换到目录下
chdir("./dir");
//3. 读取目录中每一项
struct dirent *ep = NULL;
while(1)
{
ep = readdir(dp);
if(ep == NULL) //读取完毕
break;
if(ep->d_name[0] == '.')
continue;
printf("ep->d_ino = %d ",(int)ep->d_ino);
printf("ep->d_off = %d ",(int)ep->d_off);
printf("ep->d_reclen = %d ",ep->d_reclen);
printf("ep->d_type = %d ",ep->d_type);
printf("ep->d_name = %s ",ep->d_name);
printf("================================ ");
}
//4. 关闭目录
closedir(dp);
return 0;
}
作业:
有一个目录,里面很多张800*480 bmp格式图片,执行程序后,先显示第一张图片,如果点击左边松手,则显示上一张,如果右边松手,下一张。要求五轮目录有多少张图片,程序都可以正常运行。