Skip to content

天楚锐齿

人工智能 云计算 大数据 物联网 IT 通信 嵌入式

天楚锐齿

  • 下载
  • 物联网
  • 云计算
  • 大数据
  • 人工智能
  • Linux&Android
  • 网络
  • 通信
  • 嵌入式
  • 杂七杂八

linux下直接写framebuffer(fb0)的方式显示bmp图像

2019-07-19

linux下的显示设备就是/dev/fb0,往该设备写入的数据会显示在屏幕上,所以我们可以通过直接写frame buffer这个/dev/fb0设备来实现bmp图像的显示,而不用管是在shell文本方式下还是在其他gnome、qt、gtk、wayland等图形模式下,都能显示出来。当前前提是你的linux下必须具有该设备并支持读写(无特殊处理的linux都有该设备)。

代码(支持16位、24位或32位颜色深度的bmp图像,支持24或32位颜色深度的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 <errno.h>
//14byte文件头
typedef struct
{
charcfType[2];//文件类型,”BM”(0x4D42)
int cfSize;//文件大小(字节)
int cfReserved;//保留,值为0
int cfoffBits;//数据区相对于文件头的偏移量(字节)
}__attribute__((packed)) BITMAPFILEHEADER;
//__attribute__((packed))的作用是告诉编译器取消结构在编译过程中的优化对齐
//40byte信息头
typedef struct
{
charciSize[4];//BITMAPFILEHEADER所占的字节数
int ciWidth;//宽度
int ciHeight;//高度
charciPlanes[2];//目标设备的位平面数,值为1
int ciBitCount;//每个像素的位数
charciCompress[4];//压缩说明
charciSizeImage[4];//用字节表示的图像大小,该数据必须是4的倍数
charciXPelsPerMeter[4];//目标设备的水平像素数/米
charciYPelsPerMeter[4];//目标设备的垂直像素数/米
charciClrUsed[4]; //位图使用调色板的颜色数
charciClrImportant[4]; //指定重要的颜色数,当该域的值等于颜色数时(或者等于0时),表示所有颜色都一样重要
}__attribute__((packed)) BITMAPINFOHEADER;
static void FbUpdate(int fbfd, struct fb_var_screeninfo *vi) //将要渲染的图形缓冲区的内容绘制到设备显示屏来
{
vi->yoffset=0; //from 0 to yres will be display.
ioctl(fbfd, FBIOPUT_VSCREENINFO, vi);
}
static int CursorBitmapFormatConvert(char *dst, char *src, int screenXres, int screenYres, int bytes_per_pixel_screen,
intbmpWidth, intbmpHeight, intbytes_per_pixel_bitmap)
{
int i ,j ;
char*psrc = src ;
char*pdst = dst;
char*p = psrc;
int oldi =0;
int left_right = (screenXres-bmpWidth)/2;
int top_bottom = (screenYres-bmpHeight)/2;
printf(“left_right: %d, top_bottom: %d\n”, left_right, top_bottom);
printf(“screenXres: %d, screenYres: %d\n”, screenXres, screenYres);
printf(“bmpWidth: %d, bmpHeight: %d\n”, bmpWidth, bmpHeight);
if(left_right <0&& top_bottom <0){
printf(“error: BMP is too big, screen X: %d, Y: %d, bmp width: %d, height: %d\n”, screenXres, screenYres, bmpWidth, bmpHeight);
return-1;
}
/* 由于bmp存储是从后面往前面,所以需要倒序进行转换 */
pdst += (screenXres * bmpHeight * bytes_per_pixel_screen);
pdst += (screenXres * top_bottom * bytes_per_pixel_screen); //move to middle bmpHeight
for(i=0; i<bmpHeight; i++){
p = psrc + (i+1) * bmpWidth * bytes_per_pixel_bitmap;
if(i ==0)
pdst -= (left_right * bytes_per_pixel_screen); //move to middle bmpWidth
else
pdst -= (left_right * 2 * bytes_per_pixel_screen); //move to middle bmpWidth
for(j=0; j<bmpWidth; j++){
pdst -= bytes_per_pixel_screen;
p -= bytes_per_pixel_bitmap;
int kk =0;
int k;
for(k=0; k<bytes_per_pixel_screen; k++){
if(kk >= bytes_per_pixel_bitmap)
pdst[k] =255; // 3: alpha color
else
pdst[k] =p[kk]; // 0: blue, 1: green, 2: red
kk++;
}
}
}
pdst -= (left_right * bytes_per_pixel_screen); // move to 0 position
return0;
}
int ShowBmp(char *path, int fbfd, struct fb_var_screeninfo *vinfo, char *fbp)
{
int i;
FILE *fp;
int rc;
int line_x, line_y;
longint location =0, BytesPerLine =0;
char*bmp_buf =NULL;
char* buf =NULL;
int flen =0;
int ret =-1;
int total_length =0;
BITMAPFILEHEADER FileHead;
BITMAPINFOHEADER InfoHead;
int width, height;
printf(“into ShowBmp function\n”);
if(path ==NULL) {
printf(“path Error,return\n”);
return-1;
}
printf(“path = %s\n”, path);
fp = fopen( path, “rb” );
if(fp ==NULL){
printf(“load cursor file open failed\n”);
return-1;
}
/* 求解文件长度 */
fseek(fp,0,SEEK_SET);
fseek(fp,0,SEEK_END);
flen = ftell(fp);
printf(“flen is %d\n”,flen);
bmp_buf = (char*)calloc(1,flen – 54);
if(bmp_buf ==NULL){
printf(“load > malloc bmp out of memory!\n”);
return-1;
}
/* 再移位到文件头部 */
fseek(fp,0,SEEK_SET);
rc = fread(&FileHead, sizeof(BITMAPFILEHEADER),1, fp);
if ( rc !=1) {
printf(“read header error!\n”);
fclose( fp );
return( -2 );
}
//检测是否是bmp图像
if (memcmp(FileHead.cfType, “BM”, 2) !=0) {
printf(“it’s not a BMP file\n”);
fclose( fp );
return( -3 );
}
rc = fread( (char *)&InfoHead, sizeof(BITMAPINFOHEADER),1, fp );
if ( rc !=1) {
printf(“read infoheader error!\n”);
fclose( fp );
return( -4 );
}
width = InfoHead.ciWidth;
height = InfoHead.ciHeight;
printf(“FileHead.cfSize =%d byte\n”,FileHead.cfSize);
printf(“flen = %d\n”, flen);
printf(“width = %d, height = %d\n”, width, height);
//跳转的数据区
fseek(fp, FileHead.cfoffBits, SEEK_SET);
printf(” FileHead.cfoffBits = %d\n”, FileHead.cfoffBits);
printf(” InfoHead.ciBitCount = %d\n”, InfoHead.ciBitCount);
int bytes_per_pixel_bitmap =InfoHead.ciBitCount/8;
total_length = width * height * bytes_per_pixel_bitmap;
printf(“total_length = %d\n”, total_length);
//每行字节数
buf = bmp_buf;
while ((ret =fread(buf,1,total_length,fp)) >=0) {
if (ret ==0) {
usleep(100);
continue;
}
printf(“ret = %d\n”, ret);
buf = ((char*) buf) + ret;
total_length = total_length – ret;
if(total_length ==0)
break;
}
CursorBitmapFormatConvert(fbp, bmp_buf, (*vinfo).xres, (*vinfo).yres, (*vinfo).bits_per_pixel/8, width, height, bytes_per_pixel_bitmap);
free(bmp_buf);
fclose(fp);
printf(“show logo return 0\n”);
return0;
}
int ShowPicture(int fbfd, char *path)
{
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
longint screensize =0;
struct fb_bitfield red;
struct fb_bitfield green;
struct fb_bitfield blue;
//打开显示设备
printf(“fbfd = %d\n”, fbfd);
if (fbfd ==-1) {
//printf(“Error opening frame buffer errno=%d (%s)\n”,errno, strerror(errno));
return-1;
}
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) {
//printf(“Error:reading fixed information.\n”);
return-1;
}
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) {
//printf(“Error: reading variable information.\n”);
return-1;
}
//printf(“R:%x ;G:%d ;B:%d \n”, (int)vinfo.red, vinfo.green, vinfo.blue );
printf(“%dx%d, %dbpp\n”, vinfo.xres, vinfo.yres, vinfo.bits_per_pixel );
//计算屏幕的总大小(字节)
screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
printf(“screensize=%ld byte\n”,screensize);
//对象映射
char*fbp = (char*)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
if (fbp == (char*)-1) {
printf(“Error: failed to map framebuffer device to memory.\n”);
return-1;
}
printf(“sizeof file header=%ld\n”, sizeof(BITMAPFILEHEADER));
//显示图像
ShowBmp(path, fbfd, &vinfo, fbp);
FbUpdate(fbfd, &vinfo);
///在屏幕上显示多久
sleep(10);
//删除对象映射
munmap(fbp, screensize);
return0;
}
int main()
{
int fbfd =0;
fbfd = open(“/dev/fb0”, O_RDWR);
if (!fbfd) {
printf(“Error: cannot open framebuffer device.\n”);
return-1;
}
ShowPicture(fbfd, “/tmp/license_ckx.bmp”);
close(fbfd);
return0;
}
2,094次阅读

Post navigation

前一篇:

Linux下使用curl库做HTTP GET、POST请求

后一篇:

杰发或MTK芯片下使用/sys/cli/commands文件来操作内核

发表评论 取消回复

邮箱地址不会被公开。 必填项已用*标注

个人介绍

需要么,有事情这里找联系方式:关于天楚锐齿

=== 美女同欣赏,好酒共品尝 ===

微信扫描二维码赞赏该文章:

扫描二维码分享该文章:

分类目录

  • Linux&Android (79)
  • Uncategorized (1)
  • 下载 (28)
  • 云计算 (37)
  • 人工智能 (8)
  • 大数据 (24)
  • 嵌入式 (34)
  • 杂七杂八 (34)
  • 物联网 (59)
  • 网络 (23)
  • 通信 (21)

文章归档

近期文章

  • 使用Python渲染OpenGL的.obj和.mtl文件
  • 用LVGL图形库绘制二维码
  • Android使用Messenger和SharedMemory实现跨app的海量数据传输
  • CAN信号的c语言解析代码
  • QT qml下DBus的使用例子

近期评论

  • 硕发表在《使用Android的HIDL+AIDL方式编写从HAL层到APP层的程序》
  • maxshu发表在《使用Android的HIDL+AIDL方式编写从HAL层到APP层的程序》
  • Ambition发表在《使用Android的HIDL+AIDL方式编写从HAL层到APP层的程序》
  • Ambition发表在《使用Android的HIDL+AIDL方式编写从HAL层到APP层的程序》
  • maxshu发表在《Android9下用ethernet 的Tether模式来做路由器功能》

阅读量

  • 使用Android的HIDL+AIDL方式编写从HAL层到APP层的程序 - 16,806次阅读
  • 卸载深信服Ingress、SecurityDesktop客户端 - 12,078次阅读
  • 车机技术之Android Automotive - 6,661次阅读
  • 车机技术之车规级Linux-Automotive Grade Linux(AGL) - 5,862次阅读
  • Linux策略路由及iptables mangle、ip rule、ip route关系及一种Network is unreachable错误 - 5,711次阅读
  • 在Android9下用ndk编译vSomeIP和CommonAPI以及使用例子 - 5,658次阅读
  • linux下的unbound DNS服务器设置详解 - 5,601次阅读
  • linux的tee命令导致ssh客户端下的shell卡住不动 - 4,998次阅读
  • 车机技术之360°全景影像(环视)系统 - 4,897次阅读
  • libwebp(处理webp图像)的安装和使用 - 4,749次阅读

功能

  • 文章RSS
  • 评论RSS

联系方式

地址
深圳市科技园

时间
周一至周五:  9:00~12:00,14:00~18:00
周六和周日:10:00~12:00

标签

android AT命令 centos Hadoop hdfs ip ipv6 kickstart linux mapreduce mini6410 modem OAuth openstack os python socket ssh uboot 内核 协议 安装 嵌入式 性能 报表 授权 操作系统 数据 数据库 月报 模型 汽车 测试 深信服 深度学习 源代码 神经网络 统计 编译 网络 脚本 虚拟机 调制解调器 车机 金融
© 2023 天楚锐齿