2025年5月23日 星期五 乙巳(蛇)年 二月廿五 设为首页 加入收藏
rss
您当前的位置:首页 > 电子 > 嵌入式系统

粤嵌GEC6818实现图片显示

时间:03-12来源:作者:点击数:105

要求

练习: 完成一张图片在板子上的显示

要求: 任意路径的图片

任意大小的图片

在板子上的任意位置显示

思路

  • 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;
  • }

具体步骤

1、读取文件设置缓冲区

  • 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");

2、测量待显示图片的宽度、高度、色深

  • 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 ;//每一行后面的癞子数 跳过去。
  • }

注意事项

  • bmp图片需要传在GEC818上
    在这里插入图片描述
  • 如果要显示两张图片改变两张图片的起始位置即可
    在这里插入图片描述
  • width>0?x+x0:abs(width)+x-1-x0
    当width>0,也就是从左到右时,横坐标位置为x+x0
    当width<0,也就是从右到左时,横坐标位置为abs(width)+x-1-x0`
    在这里插入图片描述
  • 模块化思想:
  • 。。。
  • 只有一个唯一的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函数。
  • 注意: 每行跳过癞子。
  • 第五步: 关闭图片 //关闭帧缓冲 解除映射
  • }

效果图

在这里插入图片描述
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门