文件IO(刷BMP格式图片、JPG格式图片)
一、BMP图的实现
练习1:
再实现一张BMP图
//打开lcd
int lcd = open("/dev/fb0",O_RDWR);
if(lcd < 0)
{
perror("open error!\n");
return -1;
}
//lcd映射
//指针指向一个像素点
int *p = mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcd,0);
if(p == NULL)
{
perror("mmap fail!\n");
return -1;
}
//打开bmp图片
int lcd_bmp = open("1.bmp",O_RDWR);
if(lcd_bmp < 0)
{
printf("open bmp fail!\n");
return -1;
}
//去除掉头54个字节
lseek(lcd_bmp,54,SEEK_SET);
//存储bmp图片的buffer:800*480*3
char buf[800*480*3] = {0};
//读bmp图片
read(lcd_bmp,buf,800*480*3);
//将buf数据通过指针p填充到LCD中
// int i;
// for(i=0;i<800*480;i++)
// {
// *(p+i) = buf[3*i] |buf[3*i+1]<<8 |buf[3*i+2]<<16;
// }
//将buf数据通过指针p填充到LCD中
int x;//x表示横轴
int y;//y表示纵轴
for(y=0;y<480;y++)
{
for(x=0;x<800;x++)
{
/*
将buf[]里面的数据由BGR换成RGB
将3个字节封装成4个字节
*/
*(p+((479-y)*800+x)) = (buf[3*(y*800+x)+0]) | (buf[3*(y*800+x)+1]<<8) | (buf[3*(y*800+x)+2]<<16);
/*
0 = buf[0] | buf[1]<<8 | buf[2]<<16
1 = buf[3] | buf[4]<<8 | buf[5]<<16
2 = buf[6] | buf[7]<<8 | buf[8]<<16
800 = buf[800*3] | buf[800*3+1]<<8 | buf[800*3+2]<<16
*/
}
}
//lcd映射释放
munmap(p,800*480*4);
//关闭lcd\bmp
close(lcd);
close(lcd_bmp);
练习2:
实现3张照片的轮流播放
sleep(1);//延时1秒
usleep(1); //延时微秒
推展:能否将你实现bmp照片的代码封装成一个函数
int show_pic(int *p,char *bmp_path)
{
//打开bmp图片
int bmp = open(bmp_path,O_RDWR);
if(bmp < 0)
{
printf("open bmp fail!\n");
return -1;
}
//去除掉头54个字节
lseek(bmp,54,SEEK_SET);
//存储bmp图片的buffer:800*480*3
char buf[800*480*3] = {0};
int ret1 = read(bmp,buf,800*480*3);
sleep(1);
//读bmp图片
//将buf数据通过指针p填充到LCD中
int x;//x表示横轴
int y;//y表示纵轴
for(y=0;y<480;y++)
{
for(x=0;x<800;x++)
{
/*
将buf[]里面的数据由BGR换成RGB
将3个字节封装成4个字节
*/
*(p+((479-y)*800+x)) = (buf[3*(y*800+x)+0]) | (buf[3*(y*800+x)+1]<<8) | (buf[3*(y*800+x)+2]<<16);
/*
0 = buf[0] | buf[1]<<8 | buf[2]<<16
1 = buf[3] | buf[4]<<8 | buf[5]<<16
2 = buf[6] | buf[7]<<8 | buf[8]<<16
800 = buf[800*3] | buf[800*3+1]<<8 | buf[800*3+2]<<16
*/
}
}
close(bmp);
return 0;
}
int main(int argc,char *argv[])
{
//打开lcd
int lcd = open("/dev/fb0",O_RDWR);
if(lcd < 0)
{
perror("open lcd error!\n");
return -1;
}
//lcd映射
//指针指向一个像素点
int *p = mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcd,0);
if(p == NULL)
{
perror("mmap fail!\n");
return -1;
}
//指针数组存储字符串
char *bmp_path[] = {"1.bmp","zhao.bmp","guo.bmp","curry.bmp"};
int n = 4;
int i =0 ;
while(1)
{
for(i=0;i<4;i++)
{
show_pic(p,bmp_path[i]);
sleep(1);
}
}
//lcd映射释放
munmap(p,800*480*4);
//关闭lcd\bmp
close(lcd);
return 0;
}
命名规则:
1.windows里面的命名
以大写字母开头来区分与单词之间
ShowBmp
2. linux里面的命名
以"_"来区分与单词之间
show_bmp
3.驼峰命名法
1)小驼峰:
int myStudentCount;
变量myStudentCount第一个单词是全部小写,后面的单词首字母大写。
2)大驼峰
public class DataBaseUser
相比小驼峰法,大驼峰法(即帕斯卡命名法)把第一个单词的首字母也大写了
4.具体用什么方法来命名
由老板来决定
二、计算bmp图片的宽度和高度
通过bmp图片的头54个字节来计算bmp图片的高度和宽度
那如果是一张800*480的图片,那么他的
int hight = 480
int width = 800
lseek(fd_bmp,18,SEEK_SET); //光标是在18位置
read(fd_bmp,&width,4); //光标是在22位置
read(fd_bmp,&hight,4);
printf("width=%d hight=%d\n",width,hight);
int bmp_fd = open(argv[1], O_RDWR);
if (bmp_fd == -1) {
printf("打开失败\n");
return -1;
}
char header[54]; //储存头文件数据
read(bmp_fd, header, 54); //读取头文件数据
int w, h; //定义宽、高变量
lseek(bmp_fd,18,SEEK_SET);
read(bmp_fd,&w,4);
read(bmp_fd,&h,4);
printf("h:%d w:%d\n",h,w);
close(bmp_fd);
二、如何使用jpg图片
bmp图片:优点:读取数据方便,实现一张800*480代码比较简单;缺点:图片太大,要增加硬件成本
jpg图片:优点:图片小便于存储;缺点:要解压图片代码比较复杂
1.如何使用第三方库来解压jpg图片
1)如何使用第三方库(别人开发的库文件--外库)----->移植
三大神步骤
配置 ./configure
编译 make
安装 make install
2)如何来移植一个jpeg库
移植成功之后开发板的操作:
[root@GEC6818 /IOT/bling]#chmod 777 main
[root@GEC6818 /IOT/bling]#
[root@GEC6818 /IOT/bling]#./main (没移植库前会出现如下错误)
./main: error while loading shared libraries: libjpeg.so.9: cannot open shared object file: No such file or directory
[root@GEC6818 /IOT/bling]#chmod 777 libjpeg.so.9(一定要修改库的权限)
[root@GEC6818 /IOT/bling]#
[root@GEC6818 /IOT/bling]#cp libjpeg.so.9 /lib/
三、安装小工具
如何开火车和养猫
sudo apt-get install sl //火车 sl --help
sudo apt-get install oneko //hellokitty 猫 oneko --help
oneko -bg red 给猫一个红色
说明:
(前提需要ubuntu联外网)
sudo apt-get update //更新软件源
作业1:
实现4张照片的轮流播放
2张bmp(800*480)
2张jpg(400*240)这两张放同一平面上
lcdjpg.c
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <stdlib.h>
#include "lcdjpg.h"
#include "jpeglib.h"
#include <sys/stat.h>
static char g_color_buf[FB_SIZE]={0};
static int g_fb_fd;
static int *g_pfb_memory;
/* video_chat.c ?-?D?-??ê?μ?×?±ê */
volatile int g_jpg_in_jpg_x;
volatile int g_jpg_in_jpg_y;
unsigned long file_size_get(const char *pfile_path)
{
unsigned long filesize = -1;
struct stat statbuff;
if(stat(pfile_path, &statbuff) < 0)
{
return filesize;
}
else
{
filesize = statbuff.st_size;
}
return filesize;
}
//LCD?-μ?
void lcd_draw_point(unsigned int x,unsigned int y, unsigned int color)
{
*(g_pfb_memory+y*800+x)=color;
}
int lcd_draw_jpg(unsigned int x,unsigned int y,const char *pjpg_path,char *pjpg_buf,unsigned int jpg_buf_size,unsigned int jpg_half)
{
//3?ê??ˉLCD
g_fb_fd = open("/dev/fb0", O_RDWR);
if(g_fb_fd<0)
{
printf("open lcd error\n");
return -1;
}
g_pfb_memory = (int *)mmap( NULL, //ó3é???μ??aê?μ??·£?éè???aNULLê±±íê?óé?μí3???¨ó3é???μ??eê?μ??·
FB_SIZE, //ó3é???μ?3¤?è
PROT_READ|PROT_WRITE, //?úèY?éò?±??áè?oíD′è?
MAP_SHARED, //12?í?ú′?
g_fb_fd, //óDD§μ????t?èê?′ê
0 //±?ó3é????ó?úèYμ??eμ?
);
/*?¨ò??a?????ó£?′í?ó′|àí???ó*/
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
char *pcolor_buf = g_color_buf;
char *pjpg;
unsigned int i=0;
unsigned int color =0;
unsigned int count =0;
unsigned int x_s = x;
unsigned int x_e ;
unsigned int y_e ;
int jpg_fd;
unsigned int jpg_size;
unsigned int jpg_width;
unsigned int jpg_height;
if(pjpg_path!=NULL)
{
/* éê??jpg×ê?′£?è¨?T?é?á?éD′ */
jpg_fd=open(pjpg_path,O_RDWR);
if(jpg_fd == -1)
{
printf("open %s error\n",pjpg_path);
return -1;
}
/* ??è?jpg???tμ?′óD? */
jpg_size=file_size_get(pjpg_path);
/* ?ajpg???téê???ú′????? */
pjpg = malloc(jpg_size);
/* ?áè?jpg???t?ùóD?úèYμ??ú′? */
read(jpg_fd,pjpg,jpg_size);
}
else
{
jpg_size = jpg_buf_size;
pjpg = pjpg_buf;
}
/*×¢2á3?′í′|àí*/
cinfo.err = jpeg_std_error(&jerr);
/*′′?¨?a??*/
jpeg_create_decompress(&cinfo);
/*?±?ó?a???ú′?êy?Y*/
jpeg_mem_src(&cinfo,pjpg,jpg_size);
/*?á???tí·*/
jpeg_read_header(&cinfo, TRUE);
/*?aê??a??*/
jpeg_start_decompress(&cinfo);
if(jpg_half)
{
x_e = x_s+(cinfo.output_width/2);
y_e = y +(cinfo.output_height/2);
/*?á?a??êy?Y*/
while(cinfo.output_scanline < cinfo.output_height)
{
pcolor_buf = g_color_buf;
/* ?áè?jpgò?DDμ?rgb?μ */
jpeg_read_scanlines(&cinfo,(JSAMPARRAY)&pcolor_buf,1);
/* ?ù?áè?jpgò?DDμ?rgb?μ */
jpeg_read_scanlines(&cinfo,(JSAMPARRAY)&pcolor_buf,1);
for(i=0; i<(cinfo.output_width/2); i++)
{
/* ??è?rgb?μ */
color = *(pcolor_buf+2);
color = color | *(pcolor_buf+1)<<8;
color = color | *(pcolor_buf)<<16;
/* ??ê?????μ? */
lcd_draw_point(x,y,color);
pcolor_buf +=6;
x++;
}
/* ??DD */
y++;
x = x_s;
}
}
else
{
x_e = x_s+cinfo.output_width;
y_e = y +cinfo.output_height;
/*?á?a??êy?Y*/
while(cinfo.output_scanline < cinfo.output_height )
{
pcolor_buf = g_color_buf;
/* ?áè?jpgò?DDμ?rgb?μ */
jpeg_read_scanlines(&cinfo,(JSAMPARRAY)&pcolor_buf,1);
for(i=0; i<cinfo.output_width; i++)
{
/* ??è?rgb?μ */
color = *(pcolor_buf+2);
color = color | *(pcolor_buf+1)<<8;
color = color | *(pcolor_buf)<<16;
/* ??ê?????μ? */
lcd_draw_point(x,y,color);
pcolor_buf +=3;
x++;
}
/* ??DD */
y++;
x = x_s;
}
}
/*?a??íê3é*/
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
if(pjpg_path!=NULL)
{
/* 1?±?jpg???t */
close(jpg_fd);
/* êí·?jpg???t?ú′????? */
free(pjpg);
}
//LCD1?±?
/* è????ú′?ó3é? */
munmap(g_pfb_memory, FB_SIZE);
/* 1?±?LCDéè±? */
close(g_fb_fd);
return 0;
}
lcdjpg.h
#ifndef __LCDJPG_H__
#define __LCDJPG_H__
#define LCD_WIDTH 800
#define LCD_HEIGHT 480
#define FB_SIZE (LCD_WIDTH * LCD_HEIGHT * 4)
//my_head.h
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <stdbool.h>
#include <errno.h>
int show_pic(int *p,char *bmp_path);
/* video_chat.c 画中画显示的坐标 */
extern volatile int g_jpg_in_jpg_x;
extern volatile int g_jpg_in_jpg_y;
void lcd_draw_point(unsigned int x,unsigned int y, unsigned int color);
int lcd_draw_jpg(unsigned int x,unsigned int y,const char *pjpg_path,char *pjpg_buf,unsigned int jpg_buf_size,unsigned int jpg_half);
#endif
main.c
#include <stdio.h>
#include "lcdjpg.h"
/*
参数说明:
0:x坐标
0:y坐标
./2.jpg:图片的名字
NULL:pjpg_buf
0:jpg_buf_size
0:jpg_half
编译:
arm-linux-gcc *.c -o main -I./libjpeg -L./libjpeg -ljpeg
*/
int main(void)
{
//打开lcd
int lcd = open("/dev/fb0",O_RDWR);
if(lcd < 0)
{
perror("open lcd error!\n");
return -1;
}
//lcd映射
//指针指向一个像素点
int *p = mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcd,0);
if(p == NULL)
{
perror("mmap fail!\n");
return -1;
}
//指针数组存储字符串
char *bmp_path[] = {"zhao.bmp","guo.bmp"};
int n = 2;
int i =0 ;
while(1)
{
for(i=0;i<2;i++)
{
show_pic(p,bmp_path[i]);
sleep(1);
lcd_draw_jpg(0,0,"./curry.jpg",NULL,0,0);
sleep(1);
lcd_draw_jpg(400,0,"./tom.jpg",NULL,0,0);
sleep(1);
lcd_draw_jpg(0,240,"./james.jpg",NULL,0,0);
sleep(1);
lcd_draw_jpg(400,240,"./jr.jpg",NULL,0,0);
sleep(1);
}
}
//lcd映射释放
munmap(p,800*480*4);
//关闭lcd\bmp
close(lcd);
return 0;
}
show_pic_fun.c
#include "my_head.h"
int show_pic(int *p,char *bmp_path)
{
//打开bmp图片
int bmp = open(bmp_path,O_RDWR);
if(bmp < 0)
{
printf("open bmp fail!\n");
return -1;
}
//去除掉头54个字节
lseek(bmp,54,SEEK_SET);
//存储bmp图片的buffer:800*480*3
char buf[800*480*3] = {0};
int ret1 = read(bmp,buf,800*480*3);
sleep(1);
//读bmp图片
//将buf数据通过指针p填充到LCD中
int x;//x表示横轴
int y;//y表示纵轴
for(y=0;y<480;y++)
{
for(x=0;x<800;x++)
{
/*
将buf[]里面的数据由BGR换成RGB
将3个字节封装成4个字节
*/
*(p+((479-y)*800+x)) = (buf[3*(y*800+x)+0]) | (buf[3*(y*800+x)+1]<<8) | (buf[3*(y*800+x)+2]<<16);
/*
0 = buf[0] | buf[1]<<8 | buf[2]<<16
1 = buf[3] | buf[4]<<8 | buf[5]<<16
2 = buf[6] | buf[7]<<8 | buf[8]<<16
800 = buf[800*3] | buf[800*3+1]<<8 | buf[800*3+2]<<16
*/
}
}
close(bmp);
return 0;
}
编译:
arm-linux-gcc *.c -o main -I./libjpeg -L./libjpeg -ljpeg
附加题:(前提条件小于800*480)
通过读取bmp图片的高度和宽度来实现任意一张任意大小的bmp图片
/*
说明:
图片的宽度一定要是4的倍数,如果不是4的倍数,需要做像素点补偿(专业)
所以我们自己制作bmp图片,宽度要做成4的倍数
图片的大小和你的偏移量合起来不能超过整个屏幕
*/
int show_bmp_size(int *p,char *bmp_path,int offset_x,int offset_y)
{
//打开bmp图片
int lcd_bmp = open(bmp_path,O_RDWR);//800*480的图片
if(lcd_bmp < 0)
{
printf("open bmp fail!\n");
return -1;
}
int wide=0,hight=0;
lseek(lcd_bmp,18,SEEK_SET);
read(lcd_bmp,&wide,4);
read(lcd_bmp,&hight,4);
printf("hight:%d wideZ:%d\n",hight,wide);
//去除掉头54个字节
lseek(lcd_bmp,54,SEEK_SET);
//存储bmp图片的buffer:800*480*3
char buf[wide*hight*3];
//读bmp图片
read(lcd_bmp,buf,wide*hight*3);
// int offset_x = 100;//图片x起始位置
// int offset_y = 100;//图片y起始位置
printf("offset_x:%d offset_y:%d\n",offset_x,offset_y);
//将buf数据通过指针p填充到LCD中
int x;//x表示横轴
int y;//y表示纵轴
for(y=0;y<hight;y++)
{
for(x=0;x<wide;x++)
{
/*
屏幕的起始坐标值应该从偏移量开始
offset_y+hight 是最后一行起始点的纵轴坐标
offset_x是最后一行起始点横轴坐标
*/
*(p+(offset_y+hight-1-y)*800+offset_x+x) = (buf[3*(y*wide+x)+0])
| (buf[3*(y*wide+x)+1]<<8)
| (buf[3*(y*wide+x)+2]<<16);
/*
0 = buf[0] | buf[1]<<8 | buf[2]<<16
1 = buf[3] | buf[4]<<8 | buf[5]<<16
2 = buf[6] | buf[7]<<8 | buf[8]<<16
800 = buf[800*3] | buf[800*3+1]<<8 | buf[800*3+2]<<16
*/
}
}
close(lcd_bmp);
return 0;
}
int main(int argc,char *argv[])
{
if(argc !=4)
{
printf("./a.out <bmp_path> <offset_x> <offset_y>");
return -1;
}
//打开lcd
int lcd = open("/dev/fb0",O_RDWR);
if(lcd < 0)
{
perror("open error!\n");
return -1;
}
//lcd映射
//指针指向一个像素点
int *p = mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcd,0);
if(p == NULL)
{
perror("mmap fail!\n");
return -1;
}
//argv[1]照片名字
//atoiargv[2]照片x轴起始位置
//atoiargv[3]照片y轴起始位置
show_bmp_size(p,argv[1],atoi(argv[2]),atoi(argv[3]));
//lcd映射释放
munmap(p,800*480*4);
//关闭lcd\bmp
close(lcd);
return 0;
}