eefocus_4023189 发表于 2024-11-23 11:48:22

飞凌嵌入式ElfBoard ELF1板卡-显示bmp图片代码

注意:学习资料可在ElfBoard官方网站“资料”专区获取。
本节用到的源码路径:ELF 1开发板资料包\03-例程源码\03-1 命令行例程源码\07_elf1_cmd_bmp
bmp.c
#include "bmp.h"

/*
* @description   : 图片显示函数
* @param - *fbp    : 映射内存起始地址
* @param - *scrinfo: 屏幕信息结构体
* @param - *bmpname: .bmp位图文件名
* @return                  : 执行结果
*/
int show_photo(const char *fbp, struct fb_var_screeninfo *scrinfo, const char *bmpname, char mode)
{
    if (NULL == fbp || NULL == scrinfo || NULL == bmpname)
      return -1;

    int line_x = 0, line_y = 0;
    unsigned long tmp32 = 0;
    unsigned int tmp = 0;
    int xres = scrinfo->xres_virtual;             //屏幕宽(虚拟)
    int bits_per_pixel = scrinfo->bits_per_pixel; //屏幕位数
    BitMapFileHeader FileHead;
    BitMapInfoHeader InfoHead;
    RgbQuad rgb;

    unsigned long location = 0;

    //打开.bmp文件
    FILE *fb = fopen(bmpname, "rb");
    if (fb == NULL)
    {
      printf("fopen bmp error\r\n");
      return -1;
    }

    //读文件信息
    if (1 != fread(&FileHead, sizeof(BitMapFileHeader), 1, fb))
    {
      printf("read BitMapFileHeader error!\n");
      fclose(fb);
      return -1;
    }
    if (memcmp(FileHead.bfType, "BM", 2) != 0)
    {
      printf("it's not a BMP file\n");
      fclose(fb);
      return -1;
    }

    //读位图信息
    if (1 != fread((char *)&InfoHead, sizeof(BitMapInfoHeader), 1, fb))
    {
      printf("read BitMapInfoHeader error!\n");
      fclose(fb);
      return -1;
    }

    //跳转至数据区
    fseek(fb, FileHead.bfOffBits, SEEK_SET);

    int len = InfoHead.biBitCount / 8; //原图一个像素占几字节
    int bits_len = bits_per_pixel / 8; //屏幕一个像素占几字节//循环显示

    while (!feof(fb))
    {
      tmp = 0;
      tmp32 = 0;
      rgb.Reserved = 0xFF;

      if (len != fread((char *)&rgb, 1, len, fb))
            break;

      //计算该像素在映射内存起始地址的偏移量
      location = line_x * bits_len + (InfoHead.biHeight - line_y - 1) * xres * bits_len;

      if (BIT32 == mode)
      {
            tmp32 |= rgb.Reserved << 24 | rgb.Red << 16 | rgb.Green << 8 | rgb.Blue; // RGB888
            *((unsigned long *)(fbp + location)) = tmp32;
      }
      else if (BIT16 == mode)
      {
            tmp |= (rgb.Red >> 3) << 11 | (rgb.Green >> 2) << 5 | rgb.Blue >> 3; // RGB565
            *((unsigned short *)(fbp + location)) = tmp;
      }
        else
                break;

      line_x++;
      if (line_x == InfoHead.biWidth)
      {
            line_x = 0;
            line_y++;
            if (line_y == InfoHead.biHeight)
                break;
      }
    }

    fclose(fb);

    return 0;
}
bmp.h
#ifndef __BMP_H__
#define __BMP_H__

#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>

#define BIT16 0
#define BIT32 1

//文件头结构体
typedef struct
{
    unsigned char bfType;                //文件类型
    unsigned long bfSize;                   //位图大小
    unsigned short bfReserved1;             //位0
    unsigned short bfReserved2;             //位0
    unsigned long bfOffBits;                //到数据偏移量
} __attribute__((packed)) BitMapFileHeader; //使编译器不优化,其大小为14字节

//信息头结构体
typedef struct
{
    unsigned long biSize;         // BitMapFileHeader 字节数
    long biWidth;               //位图宽度
    long biHeight;                //位图高度,正位正向,反之为倒图
    unsigned short biPlanes;      //为目标设备说明位面数,其值将总是被设为1
    unsigned short biBitCount;    //说明比特数/象素,为1、4、8、16、24、或32。
    unsigned long biCompression;//图象数据压缩的类型没有压缩的类型:BI_RGB
    unsigned long biSizeImage;    //说明图象的大小,以字节为单位
    long biXPelsPerMeter;         //说明水平分辨率
    long biYPelsPerMeter;         //说明垂直分辨率
    unsigned long biClrUsed;      //说明位图实际使用的彩色表中的颜色索引数
    unsigned long biClrImportant; //对图象显示有重要影响的索引数,0都重要。
} __attribute__((packed)) BitMapInfoHeader;

//像素点结构体
typedef struct
{
    unsigned char Blue;   //该颜色的蓝色分量
    unsigned char Green;    //该颜色的绿色分量
    unsigned char Red;      //该颜色的红色分量
    unsigned char Reserved; //保留值(亮度)
} __attribute__((packed)) RgbQuad;

int show_photo(const char *fbp, struct fb_var_screeninfo *scrinfo, const char *bmpname, char mode);

#endif //__BMP_H__main.c
#include "bmp.h"

char ver = {"ver01.001"};

int dev_fd;
char dev;

char rgb_mode = BIT16; // BIT16-16位屏幕BIT32-32位屏幕
char bmpname = {0};

/*
* @description: 打印参数设置格式
* @param - pname: 函数名
* @return               : 无
*/
static void print_usage(const char *pname)
{
    printf("Usage: %s device [-b bits] [-n bmpname] [-v]"
         "\n\t'-b bits' for 16 bits_per_pixel or 32 bits_per_pixel"
         "\n\t'-n bmpname' for the bmp file name containing the path "
         "\n\t'-v' show version"
         "\n\texample :--> ./elf1_cmd_lcd_bmp fb0 -b 16 -n /home/root/test1.bmp\n ",
         pname);
}

/*
* @description   : 解析函数带入参数
* @param - numb: 参数个数
* @param - *param: 带入参数数组指针
* @return                  : 无
*/
void get_param(int numb, char *param[])
{
    int i = 0;
    int temp = 0;

    if (numb <= 2)
      return;

    for (i = 2; i < numb; i++)
    {
      if (!strcmp(param, "-b"))
      {
            i++;

            temp = atoi(param);
            if (16 == temp)
            {
                rgb_mode = BIT16;
            }
            else if (32 == temp)
            {
                rgb_mode = BIT32;
            }
            continue;
      }
      if (!strcmp(param, "-n"))
      {
            i++;
            strcpy(bmpname, param);
            printf("%s", bmpname);
            continue;
      }
      if (!strcmp(param, "-v"))
      {
            printf("tty_demo ver:%s\n", ver);
            continue;
      }
    }
}

/*
* @description: 主函数
* @param - argc : 参数个数
* @param - *argv: 带入参数数组指针
* @return               : 执行结果
*/
int main(int argc, char *argv[])
{
    struct fb_var_screeninfo scrinfo;
    unsigned long screensize;
    char *fbp;

    //检测是否有参数
    if (argc < 2)
    {
      print_usage(argv);
      exit(1);
    }

    //检测是否有--h或--help
    if ((!strcmp(argv, "--h")) || (!strcmp(argv, "--help")))
    {
      print_usage(argv);
      exit(1);
    }

    strcpy(dev, "/dev/");
    strcat(dev, argv);

    //从main函数带入的参数解析
    get_param(argc, argv);

    //当知道设备名称时可以直接赋值dev,例strcpy(dev, "/dev/fb0");
    //打开屏幕外设
    dev_fd = open(dev, O_RDWR);
    if (!dev_fd)
    {
      printf("dev_fd open error!\r\n");
      return -1;
    }
    // printf("dev_fd open OK! %d\r\n", dev_fd);

    //获取屏幕信息
    //若屏幕显示区域大小不合适,可用ioctl(dev_fd, FBIOPUT_VSCREENINFO, &scrinfo)设置
    if (ioctl(dev_fd, FBIOGET_VSCREENINFO, &scrinfo))
    {
      printf("get screen infomation error!\r\n");
      return -1;
    }

    //打印屏幕信息
    printf(".xres=%d, .yres=%d, .bit=%d\r\n", scrinfo.xres, scrinfo.yres, scrinfo.bits_per_pixel);
    printf(".xres_virtual=%d, .yres_virtual=%d\r\n", scrinfo.xres_virtual, scrinfo.yres_virtual);

    if (((16 != scrinfo.bits_per_pixel) && (BIT16 == rgb_mode)) ||
      ((32 != scrinfo.bits_per_pixel) && (BIT32 == rgb_mode)))
    {
      printf("screen infomation.bits error!\r\n");
      return -1;
    }

    //计算需要的映射内存大小
    screensize = scrinfo.xres_virtual * scrinfo.yres_virtual * scrinfo.bits_per_pixel / 8;
    // printf("screensize=%lu!\r\n", screensize);

    //内存映射
    fbp = (char *)mmap(NULL, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd, 0);
    if (-1 == (int)fbp)
    {
      printf("mmap error!\r\n");
      return -1;
    }

    //显示图片
    show_photo(fbp, &scrinfo, bmpname, rgb_mode);

    //取消映射,关闭文件
    munmap(fbp, screensize);
    close(dev_fd);

    return 0;
}
进程名:elf1_cmd_lcd_bmp
使用方法:./elf1_cmd_lcd_bmp 设备名 [参数选项]… …


页: [1]
查看完整版本: 飞凌嵌入式ElfBoard ELF1板卡-显示bmp图片代码

Baidu
map