通过fb0显示图片

2023-10-28

通过fb0显示图片

代码

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <errno.h>

//14byte文件头
typedef struct
{
	char cfType[2];  //文件类型,"BM"(0x4D42)
	int  cfSize;     //文件大小(字节)
	int  cfReserved; //保留,值为0
	int  cfoffBits;  //数据区相对于文件头的偏移量(字节)
}__attribute__((packed)) BITMAPFILEHEADER;
//__attribute__((packed))的作用是告诉编译器取消结构在编译过程中的优化对齐

//40byte信息头
typedef struct
{
	char ciSize[4];          //BITMAPFILEHEADER所占的字节数
	int  ciWidth;            //宽度
	int  ciHeight;           //高度
	char ciPlanes[2];        //目标设备的位平面数,值为1
	int  ciBitCount;         //每个像素的位数
	char ciCompress[4];      //压缩说明
	char ciSizeImage[4];     //用字节表示的图像大小,该数据必须是4的倍数
	char ciXPelsPerMeter[4]; //目标设备的水平像素数/米
	char ciYPelsPerMeter[4]; //目标设备的垂直像素数/米
	char ciClrUsed[4];       //位图使用调色板的颜色数
	char ciClrImportant[4];  //指定重要的颜色数,当该域的值等于颜色数时(或者等于0时),表示所有颜色都一样重要
}__attribute__((packed)) BITMAPINFOHEADER;

typedef struct
{
	unsigned char blue;
	unsigned char green;
	unsigned char red;
	unsigned char reserved;
}__attribute__((packed)) PIXEL; //颜色模式RGB



typedef struct
{
	int          fbfd;
	char         *fbp;
	unsigned int xres;
	unsigned int yres;
	unsigned int xres_virtual;
	unsigned int yres_virtual;
	unsigned int xoffset;
	unsigned int yoffset;
	unsigned int bpp;
	unsigned long line_length;
	unsigned long size;

	struct fb_bitfield red;
	struct fb_bitfield green;
	struct fb_bitfield blue;
} FB_INFO;

typedef struct
{
	unsigned int width;
	unsigned int height;
	unsigned int bpp;
	unsigned long size;
	unsigned int data_offset;
} IMG_INFO;



FB_INFO fb_info;
IMG_INFO img_info;

int show_bmp(char *img_name);

static int cursor_bitmap_format_convert(char *dst,char *src, unsigned long img_len_one_line)
{
	int img_len ,fb_len ;
	char *p;
	__u32 val;
	PIXEL pix;

	p = (char *)&val;

	img_len = img_info.width; /*一行图片的长度*/
	fb_len = fb_info.xres; /*一行显示屏的长度*/

	/*进行x轴的偏移*/
	dst += fb_info.xoffset * (fb_info.bpp / 8);
	fb_len -= fb_info.xoffset;

	/*bmp 数据是上下左右颠倒的,这里只进行左右的处理*/
	/*先定位到图片的最后一个像素的地址,然后往第一个像素的方向处理,进行左右颠倒的处理*/
	src += img_len_one_line - 1;

	/*处理一行要显示的数据*/
	while(1) {
		if (img_info.bpp == 32)
			pix.reserved = *(src--);
		pix.red   = *(src--);
		pix.green = *(src--);
		pix.blue  = *(src--);

		val = 0x00;
		val |= (pix.red >> (8 - fb_info.red.length)) << fb_info.red.offset;
		val |= (pix.green >> (8 - fb_info.green.length)) << fb_info.green.offset;
		val |= (pix.blue >> (8 - fb_info.blue.length)) << fb_info.blue.offset;


		if (fb_info.bpp == 16) {
			*(dst++) = *(p + 0);
			*(dst++) = *(p + 1);
		}
		else if (fb_info.bpp == 24) {
			*(dst++) = *(p + 0);
			*(dst++) = *(p + 1);
			*(dst++) = *(p + 2);
		}
		else if (fb_info.bpp == 32) {
			*(dst++) = *(p + 0);
			*(dst++) = *(p + 1);
			*(dst++) = *(p + 2);
			*(dst++) = *(p + 3);
		}

		/*超过图片长度或显示屏长度认为一行处理完了*/
		img_len--;
		fb_len--;
		if (img_len <= 0 || fb_len <= 0)
			break;
	}
#if 0
	printf("r = %d\n", pix.red);
	printf("g = %d\n", pix.green);
	printf("b = %d\n", pix.blue);
#endif
	return 0;
}

int show_bmp(char *img_name)
{

	FILE *fp;
	int ret = 0;
	BITMAPFILEHEADER FileHead;
	BITMAPINFOHEADER InfoHead;

	if(img_name == NULL) {
		printf("img_name is null\n");
		return -1;
	}

	fp = fopen( img_name, "rb" );
	if(fp == NULL) {
		printf("img[%s] open failed\n", img_name);
		ret = -1;
		goto err_showbmp;
	}

	/* 移位到文件头部 */
	fseek(fp, 0, SEEK_SET);

	ret = fread(&FileHead, sizeof(BITMAPFILEHEADER), 1, fp);
	if ( ret != 1) {
		printf("img read failed\n");
		ret = -1;
		goto err_showbmp;
	}

	//检测是否是bmp图像
	if (memcmp(FileHead.cfType, "BM", 2) != 0) {
		printf("it's not a BMP file[%c%c]\n", FileHead.cfType[0], FileHead.cfType[1]);
		ret = -1;
		goto err_showbmp;
	}

	ret = fread( (char *)&InfoHead, sizeof(BITMAPINFOHEADER),1, fp );
	if ( ret != 1) {
		printf("read infoheader error!\n");
		ret = -1;
		goto err_showbmp;
	}

	img_info.width       = InfoHead.ciWidth;
	img_info.height      = InfoHead.ciHeight;
	img_info.bpp         = InfoHead.ciBitCount;
	img_info.size        = FileHead.cfSize;
	img_info.data_offset = FileHead.cfoffBits;

	printf("img info w[%d] h[%d] bpp[%d] size[%ld] offset[%d]\n", img_info.width, img_info.height, img_info.bpp, img_info.size, img_info.data_offset);

	if (img_info.bpp != 24 && img_info.bpp != 32) {
		printf("img bpp is not 24 or 32\n");
		ret = -1;
		goto err_showbmp;
	}


	/*
	 *一行行处理
	 */
	char *buf_img_one_line;
	char *buf_fb_one_line;
	char *p;
	int fb_height;

	long img_len_one_line = img_info.width * (img_info.bpp / 8);
	long fb_len_one_line = fb_info.line_length;

	printf("img_len_one_line = %d\n", img_len_one_line);
	printf("fb_len_one_line = %d\n", fb_info.line_length);

	buf_img_one_line = (char *)calloc(1, img_len_one_line + 256);
	if(buf_img_one_line == NULL) {
		printf("alloc failed\n");
		ret = -1;
		goto err_showbmp;
	}

	buf_fb_one_line = (char *)calloc(1, fb_len_one_line + 256);
	if(buf_fb_one_line == NULL) {
		printf("alloc failed\n");
		ret = -1;
		goto err_showbmp;
	}


	fseek(fp, img_info.data_offset, SEEK_SET);

	p = fb_info.fbp + fb_info.yoffset * fb_info.line_length; /*进行y轴的偏移*/
	fb_height = fb_info.yres;
	while (1) {
		memset(buf_img_one_line, 0, img_len_one_line);
		memset(buf_fb_one_line, 0, fb_len_one_line);
		ret = fread(buf_img_one_line, 1, img_len_one_line, fp);
		if (ret < img_len_one_line) {
			/*图片读取完成,则图片显示完成*/
			printf("read to end of img file\n");
			cursor_bitmap_format_convert(buf_fb_one_line, buf_img_one_line, img_len_one_line); /*数据转换*/
			memcpy(fb_info.fbp, buf_fb_one_line, fb_len_one_line);
			break;
		}

		cursor_bitmap_format_convert(buf_fb_one_line, buf_img_one_line, img_len_one_line); /*数据转换*/
		memcpy(p, buf_fb_one_line, fb_len_one_line); /*显示一行*/
		p += fb_len_one_line;

		/*超过显示屏宽度认为图片显示完成*/
		fb_height--;
		if (fb_height <= 0)
			break;
	}

	free(buf_img_one_line);
	free(buf_fb_one_line);

	fclose(fp);
	return ret;
err_showbmp:
	if (fp)
		fclose(fp);
	return ret;
}

int show_picture(char *img_name)
{
	struct fb_var_screeninfo vinfo;
	struct fb_fix_screeninfo finfo;

	if (fb_info.fbfd <= -1) {
		printf("fb open fialed\n");
		return -1;
	}

	if (ioctl(fb_info.fbfd, FBIOGET_FSCREENINFO, &finfo)) {
		printf("fb ioctl fialed\n");
		return -1;
	}

	if (ioctl(fb_info.fbfd, FBIOGET_VSCREENINFO, &vinfo)) {
		printf("fb ioctl fialed\n");
		return -1;
	}

	fb_info.xres = vinfo.xres;
	fb_info.yres = vinfo.yres;
	fb_info.xres_virtual = vinfo.xres_virtual;
	fb_info.yres_virtual = vinfo.yres_virtual;
	fb_info.xoffset = vinfo.xoffset;
	fb_info.yoffset = vinfo.yoffset;
	fb_info.bpp  = vinfo.bits_per_pixel;
	fb_info.line_length = finfo.line_length;
	fb_info.size = finfo.smem_len;

	memcpy(&fb_info.red, &vinfo.red, sizeof(struct fb_bitfield));
	memcpy(&fb_info.green, &vinfo.green, sizeof(struct fb_bitfield));
	memcpy(&fb_info.blue, &vinfo.blue, sizeof(struct fb_bitfield));

	printf("fb info x[%d] y[%d] x_v[%d] y_v[%d] xoffset[%d] yoffset[%d] bpp[%d] line_length[%ld] size[%ld]\n", fb_info.xres, fb_info.yres, fb_info.xres_virtual, fb_info.yres_virtual, fb_info.xoffset, fb_info.yoffset, fb_info.bpp, fb_info.line_length, fb_info.size);

	printf("fb info red off[%d] len[%d] msb[%d]\n", fb_info.red.offset, fb_info.red.length, fb_info.red.msb_right);
	printf("fb info green off[%d] len[%d] msb[%d]\n", fb_info.green.offset, fb_info.green.length, fb_info.green.msb_right);
	printf("fb info blue off[%d] len[%d] msb[%d]\n", fb_info.blue.offset, fb_info.blue.length, fb_info.blue.msb_right);

	if (fb_info.bpp != 16 && fb_info.bpp != 24 && fb_info.bpp != 32) {
		printf("fb bpp is not 16,24 or 32\n");
		return -1;
	}

	if (fb_info.red.length > 8 || fb_info.green.length > 8 || fb_info.blue.length > 8) {
		printf("fb red|green|blue length is invalid\n");
		return -1;
	}

	// 内存映射
	fb_info.fbp = (char *)mmap(0, fb_info.size, PROT_READ | PROT_WRITE, MAP_SHARED, fb_info.fbfd, 0);
	if (fb_info.fbp == (char *)-1) {
		printf("mmap fialed\n");
		return -1;
	}

	show_bmp(img_name);

	//删除映射
	munmap(fb_info.fbp, fb_info.size);

	return 0;
}


int main(int argc, char **argv)
{
	char img_name[64];

	if (argc != 2) {
		printf("arg error\n");
		return 0;
	}

	snprintf(img_name, sizeof(img_name), "%s", argv[1]);
	printf("img_name = %s\n", img_name);

	fb_info.fbfd = open("/dev/fb0", O_RDWR);
	if (!fb_info.fbfd) {
		printf("Error: cannot open framebuffer device(/dev/fb0).\n");
		return -1;
	}
	show_picture(img_name);

	close(fb_info.fbfd);
		return 0;
}

运行情况

图号 分辨率 位深度 显示情况
1 658*986 24 灰色半个
2 1024*600 24 正常
3 1024*600 32 正常
4 658*986 32 正常 半个

图片

如果需要,去下面链接下载:
https://download.csdn.net/download/qichongjin/12326281
未完待续… …

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通过fb0显示图片 的相关文章

随机推荐

  • Stable Diffusion 系列教程

    目录 1 模型基本分类 1 1 CheckPoint 大模型 底模型 主模型 1 2 VAE美化模型 变分自编码器 1 3 HyperNetwork 超网络 1 4 embeddings Textual Inversion 嵌入式向量 1
  • 什么是【固件】?

    文章目录 一 软件 硬件 固件 二 BIOS Basic Input output System 三 百度百科的解释 四 固件的工作原理 五 应用 六 参考链接 一 软件 硬件 固件 通常我们会将硬件和软件分开看待 二者协同工作为我们提供计
  • 合流超几何函数_特殊函数之超几何函数

    继上一次更文特殊函数专场还是在去年国庆这篇推文特殊函数专场之贝塞尔函数 八一想了想还是再来一篇特殊函数精讲超几何函数 虽然我也不知道这玩意的实际意义在哪 就给它取名好玩的特殊函数 它可以用来搞积 也可以用来玩代数 同时在数理方程的应用是不可
  • failed with error: Get http://localhost:10248/healthz

    kubelet check It seems like the kubelet isn t running or healthy kubelet check The HTTP call equal to curl sSL http loca
  • Netty 源码分析系列(十八)一行简单的writeAndFlush都做了哪些事?

    系列文章目录 Netty 源码分析系列 一 Netty入门 Netty 源码分析系列 二 Netty 架构设计 Netty 源码分析系列 三 Channel详解 Netty 源码分析系列 四 ChannelHandler介绍 Netty 源
  • lnmp - 线上环境故障排查流程 - 学习/实践

    1 应用场景 主要用于线上环境故障排查 记录整个流程 从而可以按部推进 定位问题 从而解决问题 同时也是为解决问题提供一个流程标准 2 学习 操作 1 文档阅读 TBD 2 整理输出 环境 前端 Web 应用 或者 App 应用 后端 PH
  • SpringCloud最新版环境集成之eureka

    前言 本文依托于SpringCloud最新版环境集成 2021年11月 只介绍eureka环境搭建过程 在SpringCloud的使用过程中我总结为三步曲 引入spring cloud starter相应jar包 properties或ym
  • 多尺度特征的提取

    1 图像金字塔 将图片进行不同尺度的缩放 得到图像金字塔 然后对每层图片提取不同尺度的特征 得到特征图 一幅图像的金字塔是一系列以金字塔形状排列的分辨率逐步降低 且来源于同一张原始图的图像集合 其通过梯次向下采样获得 直到达到某个终止条件才
  • python线性回归模型_Python机器学习/LinearRegression(线性回归模型)(附源码)

    LinearRegression 线性回归 1 线性回归简介 线性回归定义 我个人的理解就是 线性回归算法就是一个使用线性函数作为模型框架 y w x b 并通过优化算法对训练数据进行训练 最终得出最优 全局最优解或局部最优 参数的过程 y
  • MPU6050的原理讲解

    主要讲解 1 加速度 2 陀螺仪 3 磁力计 本博主其实也是从别的资料上看的 然后觉得内容很好理解 于是决定在这分享出来 一 加速度计 标题 加速度计顾名思义 就是测量加速度的那么 我们如何认识这个加速度呢 在此用一个盒子形 状的立方体来做
  • Drools 6.5 :入门程序

    1 概念 2 为什么使用规则 3 入门 学习一样新东西的最好的方法就是尝试使用它 下面编写一个简单的 Drools 应用程序 首先 我们需要创建一个 Maven 工程 然后在其 pom xml 文件添加如下包依赖
  • JavaScript中eval方法的替代方法

    公司开设新的考核标准 着重对代码质量进行考核 用到的代码实时检测工具是sonaLint 用SonarLint进行代码检测的时候 会 出现对显示审查结果严重提示 Review the arguments of this eval to mak
  • 独立事件与非独立事件,条件概率

    1 独立事件与非独立事件 条件概率 1 0 说明例1的A B事件是非独立事件 因为 所以事件A B非独立 如果把木质 蓝 从7改成6 则有 因为 所以事件A B独立 1 1 条件概率 已知事件B发生的条件下事件A发生的概率称为事件A关于事件
  • springmvc项目Aop自定义注解

    springmvc项目Aop自定义注解 今日份敷衍 在mvc项目里写个aop自定义注解 因为没在配置文件里加入扫描跟开启aop搞了一天 简直浪费时间 首先建两个文件如下 一个注解 一个aop 注解是上面那个 里面怎么写呢 如下 packag
  • 说说对jsx的理解

    JSX 可理解成html 经过Bable就是运行在浏览器上的代码了 在原生中 js创建dom用 var a document createElement p a setAtribute class myp a appendChild doc
  • 解决rabbitmq消息队列的顺序及重复消费问题

    五一期间去韩国游玩 顺便去了朋友公司扯淡去了 所谓的扯淡 就是过去听技术分享 有python golang devops docker一些话题 总的来说 技术方面跟国内还是有一些差距的 正题开始 因为业务的各方面的强需求 我们使用了rabb
  • R语言高级数据管理

    文章目录 高级数据管理 标准差 绝对中位差 分位数 quantile 函数 百分位数 数据预处理 中心化 标准化 Standardization 数据中心化和标准化的区别 归一化 Normalization 标准化和归一化 概率函数 协方差
  • VBA中使用SQL

    取出同文件夹下所有表格中相关信息 Dim Cnn As Object MyCat As Object rst As Object sql SheetName f ph r strConn ph ThisWorkbook Path f Dir
  • APP 性能测试工具

    一 APP 自动化测试工具 Appium 官网 http appium io GitHub 地址 https github com appium appium 介绍 Appium 是一个开源的 跨平台的自动化测试工具 支持自动化 iOS A
  • 通过fb0显示图片

    通过fb0显示图片 代码 运行情况 图片 代码 include