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

    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;

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,198评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,663评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,985评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,673评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,994评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,399评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,717评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,407评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,112评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,371评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,891评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,255评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,881评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,010评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,764评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,412评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,299评论 2 260

推荐阅读更多精彩内容