之前学习的时候一个作业,趁机会发表一下做个记录,bmp图片较为简单就可以实现了,关于bmp图片的原理可参考这个链接https://blog.csdn.net/u013066730/article/details/82625158,jpg的话是使用了官方的jpg库,可自行去官方下载http://www.ijg.org/
下面是一些代码
main.c 的内容
/*查找整个系统中的bmp和jpg格式图片,并打印出他们的信息,同时在开发板上显示这张图片*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define BLACK 0x000000
int read_JPEG_file (char * filename,int *lcd); //读取JPG格式图片信息
/*显示.JPG格式的图片*/
void show_jpg(char *photo_path)
{
//打开需要映射的硬件设备
int lcd_fd = open("/dev/fb0",O_RDWR);
if(lcd_fd < 0)
{
perror("open fail");
exit(0);
}
//映射文件到虚拟内存空间中
int *lcd_p = mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcd_fd,0);
//对JPEG 图片解码并显示
read_JPEG_file(photo_path,lcd_p);
sleep(1);
int i=0;
for(i=0;i<800*480;i++)
{
*(lcd_p+i) = BLACK;
}
//关闭映射和打开的文件
munmap(lcd_p,800*480*4);
close(lcd_fd);
}
/*显示.BMP格式的图片*/
void show_bmp(char *photo_path)
{
//打开需要映射的硬件设备
int lcd_fd = open("/dev/fb0",O_RDWR);
if(!lcd_fd)
{
perror("open");
exit(1);
}
//映射文件到虚拟内存空间中
int *lcd_p = mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcd_fd,0);
int bmp_fd = open(photo_path,O_RDWR);
if(!bmp_fd)
{
perror("open");
exit(2);
}
//读取图片的头信息
unsigned char head[54]={0};
read(bmp_fd,head,54);
//处理头数据
int chang = *((int *)&head[18]);
int kuan = *((int *)&head[22]);
int bit = *((int *)&head[28]);
printf("chang=%d,kuan=%d,bit=%d\n",chang,kuan,bit);
//根据头数据定义像素数据的缓存地址
char color_buf[chang*kuan*(bit/8)];
int size = read(bmp_fd,color_buf,sizeof(color_buf));
printf("size=%d\n",size);
//定义一个数据的缓冲区
int buf24[chang*kuan];
int i=0;
for(i=0;i<chang*kuan;i++)
{
buf24[i] = color_buf[i*3+0] | color_buf[i*3+1]<< 8 | color_buf[i*3+2] << 16;
//B 0-7 G 8-15 R:16 - 23
}
//把图像的数据写入到lcd屏幕设备中
int x=0,y=0;
for(y=0;y<kuan;y++)
{
for(x=0;x<chang;x++)
{
//超出显示屏范围跳出
if(x >= 800 || y >= 480)
break;
//图片没有超出显示屏范围
else if(chang <= 800 && kuan <= 480 )
{
*(lcd_p + (800*(480-kuan)/2 + (800-chang)/2) + x + y*800) = buf24[x + (kuan-1-y)*chang];
}
// 图片长和宽都超出屏幕,显示图片中间800*480部分
else if(chang > 800 && kuan > 480)
{
*(lcd_p + x + y*800) = buf24[(chang-800)/2 + x + (kuan - (kuan-480)/2 - 1 - y) * chang];
}
// 图片长超出,宽没有,居中显示
else if(chang > 800 && kuan <= 480)
{
*(lcd_p + (800*(480-kuan)/2) + x + y*800) = buf24[(chang-800)/2 + x + (kuan-1-y)*chang];
}
// 图片宽超出,长没有,居中显示
else if(chang <= 800 && kuan > 480)
{
*(lcd_p + (800-chang)/2 + x + y*800) = buf24[x + (kuan - (kuan-480)/2 - 1 - y) * chang];
}
}
}
/*图片显示一秒后清屏进入下一张图片*/
sleep(1);
for(i=0;i<800*480;i++)
{
*(lcd_p+i) = BLACK;
}
//关闭映射和打开的文件
munmap(lcd_p,800*480*4);
close(bmp_fd);
close(lcd_fd);
}
/*实现搜索整个系统中的 .bmp .jpg 文件 */
int find(char *path)
{
DIR *dir=opendir(path);
if(dir==NULL)
{
/*根目录下一些文件无法打开,为了不影响观看效果,不打印错误结果*/
//perror("opedndir");
return -1;
}
while(1)
{
struct dirent *ep = readdir(dir);
if(ep==NULL)
{
break;
}
//跳过隐藏文件
if( ep->d_name[0] == '.' )
{
continue;
}
//目录
if(ep->d_type==DT_DIR)
{
char buf[4096]={0};
if(strcmp(path,"/")==0)
sprintf(buf,"%s%s",path,ep->d_name);
else
sprintf(buf,"%s/%s",path,ep->d_name);
// printf("%s\n",buf);
find(buf);
}
//文件
if(ep->d_type==DT_REG)
{
/* *.bmp 文件 */
if(strstr(ep->d_name,".bmp") != NULL )
{
if(strcmp(strstr(ep->d_name,".bmp"),".bmp") == 0)
{
if(strcmp(path,"/")==0)
printf("%s%s",path,ep->d_name);
else
printf("%s/%s\n",path,ep->d_name);
char buf1[4096]={0};
if(strcmp(path,"/")==0)
sprintf(buf1,"%s%s",path,ep->d_name);
else
sprintf(buf1,"%s/%s",path,ep->d_name);
show_bmp(buf1);
}
}
/* *.jpg 文件 */
if(strstr(ep->d_name,".jpg") != NULL)
{
if(strcmp(strstr(ep->d_name,".jpg"),".jpg") == 0)
{
if(strcmp(path,"/")==0)
printf("%s%s",path,ep->d_name);
else
printf("%s/%s\n",path,ep->d_name);
char buf2[4096]={0};
if(strcmp(path,"/")==0)
sprintf(buf2,"%s%s",path,ep->d_name);
else
sprintf(buf2,"%s/%s",path,ep->d_name);
show_jpg(buf2);
}
}
}
}
closedir(dir);
}
int main(int argc,char *argv[])
{
find("/");
printf("\nOver!!!");
printf("\n\n");
}
jpg.c的内容
#include
#include "jpeglib.h"
#include
extern JSAMPLE * image_buffer; /* Points to large array of R,G,B-order data */
extern int image_height; /* Number of rows in image */
extern int image_width; /* Number of columns in image */
struct my_error_mgr {
struct jpeg_error_mgr pub; /* "public" fields */
jmp_buf setjmp_buffer; /* for return to caller */
};
typedef struct my_error_mgr * my_error_ptr;
/*
* Here's the routine that will replace the standard error_exit method:
*/
METHODDEF(void)
my_error_exit (j_common_ptr cinfo)
{
/* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
my_error_ptr myerr = (my_error_ptr) cinfo->err;
/* Always display the message. */
/* We could postpone this until after returning, if we chose. */
(*cinfo->err->output_message) (cinfo);
/* Return control to the setjmp point */
longjmp(myerr->setjmp_buffer, 1);
}
//功能:读取jpeg 文件中的数据转换成 r g b 值
int read_JPEG_file (char * filename,int *lcd)
{
//定义一个 jpeg 的解码对象
struct jpeg_decompress_struct cinfo;
//定义一个jpeg 的出错对象
struct my_error_mgr jerr;
/* More stuff */
FILE * infile; /*源文件*/
JSAMPARRAY buffer; /*输出行缓存*/
int row_stride; /*输出行缓存的宽度*/
//打开源文件
if ((infile = fopen(filename, "rb")) == NULL) {
fprintf(stderr, "can't open %s\n", filename);
return 0;
}
/* Step 1: 初始化JPEG 解码对象*/
/*初始化出错对象 */
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
/* Establish the setjmp return context for my_error_exit to use. */
if (setjmp(jerr.setjmp_buffer)) {
jpeg_destroy_decompress(&cinfo);
fclose(infile);
return 0;
}
/*初始化解码对象*/
jpeg_create_decompress(&cinfo);
/* Step 2: 关联源文件与解码对象*/
jpeg_stdio_src(&cinfo, infile);
/* Step 3: 读取jpeg图像的头数据*/
(void) jpeg_read_header(&cinfo, TRUE);
/* Step 5: 开始解码*/
(void) jpeg_start_decompress(&cinfo);
/* 一行所占用的字节数 */
row_stride = cinfo.output_width * cinfo.output_components;
/*为输出行缓存分配堆空间*/
buffer = (*cinfo.mem->alloc_sarray)
((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
//cinfo.output_width * cinfo.output_components
int buf24[cinfo.output_width*cinfo.output_height];
//重点!!!!! 循环对每一行数据进行解码!!
while (cinfo.output_scanline < cinfo.output_height)
{
//printf("%d\n",cinfo.output_scanline);
//读取一行数据进行解码 并 写入到 buffer 中
(void) jpeg_read_scanlines(&cinfo, buffer, 1);
char *p = buffer[0]; //指向数据的R G B 数据的缓存首地址
int i=0;
for(i=0;i<cinfo.output_width;i++) //把一行的 R G B 值全部都取出来
{
char r = *p++;
char g = *p++;
char b = *p++;
buf24[i + (cinfo.output_scanline-1) * cinfo.output_width] = r << 16 | g << 8 | b; // 处理 jpeg 中的RGB 数据
}
}
//把图像的数据写入到lcd屏幕设备中
int x = 0, y = 0;
for(y=0;y<cinfo.output_height;y++)
{
for(x=0;x<cinfo.output_width;x++)
{
//超出显示屏范围跳出
if(x >= 800 || y >= 480)
break;
//图片没有超出显示屏范围
else if(cinfo.output_width <= 800 && cinfo.output_height <= 480 )
{
*(lcd + (800*(480-cinfo.output_height)/2 + (800-cinfo.output_width)/2) + x + y*800) = buf24[x + y*cinfo.output_width];
}
// 图片长和宽都超出屏幕,显示图片中间800*480部分
else if(cinfo.output_width > 800 && cinfo.output_height > 480)
{
*(lcd + x + y*800) = buf24[(cinfo.output_width-800)/2 + x + ((cinfo.output_height-480)/2 + y) * cinfo.output_width];
}
// 图片长超出,宽没有,居中显示
else if(cinfo.output_width > 800 && cinfo.output_height <= 480)
{
*(lcd + (800*(480-cinfo.output_height)/2) + x + y*800) = buf24[(cinfo.output_width-800)/2 + x + y*cinfo.output_width];
}
// 图片宽超出,长没有,居中显示
else if(cinfo.output_width <= 800 && cinfo.output_height > 480)
{
*(lcd + (800-cinfo.output_width)/2 + x + y*800) = buf24[x + ((cinfo.output_height-480)/2 +y) * cinfo.output_width];
}
}
}
//*(lcd + (cinfo.output_scanline - 1)*800 + i) = color; //把转换后的颜色数据赋值给 lcd 屏幕
//cinfo.output_scanline*800 第几行
//把解码后的数据输出 LCD 屏幕中
// put_scanline_someplace(buffer[0], row_stride);
/* Step 7: Finish decompression */
(void) jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
fclose(infile);
return 1;
}
测试用的机器是arm架构、linux系统的粤嵌公司的6818开发板,最终实现效果就是在屏幕上轮流播放内存里面的所有bmp和jpg格式的图片。