基于Qt的.bmp图片转C语言数组或.bin二进制文件方法

  BMP是英文Bitmap(位图)的简写,它是Windows操作系统中的标准图像文件格式,能够被多种Windows应用程序所支持。关于BMP文件的格式网上有很多资料,这里不再赘述,直接说怎么用Qt读取BMP文件并转换。
  首先写一个结构体用来存BMP文件头的信息,文件头包括文件大小、图片宽度、高度、每个像素的位数等信息。这里注意,结构体要用宏定义#pragma pack(1)#pragma pack()括起来,#pragma pack(1)表示以下结构体按1字节对齐,#pragma pack()则是恢复系统的对齐方式。下面的代码里除了BMP文件头的结构体外还有一个共用体RGB565,这个共用体便于将一个short型(16字节)变量转为两个char型(8字节)变量。

#pragma pack(1)
typedef struct
{
    unsigned short bfType;      
    unsigned int bfSize;       
    unsigned short bfReserved1; 
    unsigned short bfReserved2; 
    unsigned int bfOffBits;    
    unsigned int biSize;      
    int biWidth;                
    int biHeight;               
    unsigned short biPlanes;    
    unsigned short biBitCount;  
    unsigned int biCompression; 
    unsigned int biSizeImages;  
    unsigned int biXPelsPerMeter;   
    unsigned int biYPelsPerMeter;   
    unsigned int biClrUsed;     
    unsigned int biClrImportant;    
}BmpHeader;

typedef union
{
    unsigned short rgb16[WIDTH*HEIGHT];
    unsigned char rgb8[WIDTH*HEIGHT*2];
}RGB565;
#pragma pack()

  接下来编写代码读取BMP文件并转换成RGB565的格式。这个代码是针对我用的240×240大小RGB888存储的BMP图片写的,其实可以根据文件头的信息写得更普适一些。

void Widget::ReadBmp(QString file_name)
{//BMP图片像素的存储顺序为从左到右,从下到上存,转为从左到右,从上到下
    QFile file(file_name);
    BmpHeader header;
    unsigned char rgb888[240*3];

    if(!file.exists())
    {
        return;
    }
    file.open(QFileDevice::ReadOnly);
    file.read((char*)&header, sizeof(BmpHeader));//先把文件头读进来看看信息对不对

    for(int i = 0; i < HEIGHT; i++)
    {
        file.seek(header.bfOffBits + 3*240*(HEIGHT-1-i));//文件读写指针定位到某一行,行数是从后往前索引的
        file.read((char*)&rgb888, sizeof(rgb888));		 //读进一行的RGB888数据
        for(int j = 0; j < WIDTH; j++)
        {
            unsigned short rgb_temp = 0x0000;
            //BMP文件中RGB存储的顺序是由低地址到高地址存B、G、R
            rgb_temp = RGB888toRGB565(rgb888[j * 3 + 2], rgb888[j * 3 + 1], rgb888[j * 3]);
            int index = i * WIDTH + j;
            //我用的屏幕需要用SPI将RGB565的数据逐个字节的写入,并且是高位在前,按照R、G、B的顺序写入,这里涉及到大小端的问题
            //把RGB565的高8位和低8位转一下,这样R和部分G就能存在低地址的字节,部分G和B就能存在高地址字节
            rgb565.rgb16[index] = rgb_temp >> 8;
            rgb565.rgb16[index] |= rgb_temp << 8;
        }
    }
    file.close();
}

unsigned short Widget::RGB888toRGB565(unsigned char red, unsigned char green, unsigned char blue)
{//RGB888转RGB565,都是保留高几位
    unsigned short B = (blue >> 3) & 0x001F;
    unsigned short G = ((green >> 2) << 5) & 0x07E0;
    unsigned short R = ((red >> 3) << 11) & 0xF800;
    return (unsigned short) (R | G | B);
}

  上面的代码已经把最复杂的部分实现了,下面是输出C数组到源文件,还有输出二进制文件。

void Widget::GenerateSrcFile(QString file_name, int cnt)
{
    QFile file(file_name);
    file.open(QFileDevice::WriteOnly);
    QString var_name = "trans" + file_name.mid(file_name.lastIndexOf("\\")+1).replace(".c", "");
    QTextStream out(&file);	//写源文件用文本流输出
    out << QString("const unsigned char ").toUtf8()	//加上.toUtf8(),否则可能出现乱码
        << var_name.toUtf8()
        << "[]"
        << QString("__attribute__((at(0x00000000 + 115200*").toUtf8()
        << QString::number(cnt).toUtf8() + QString(")))").toUtf8()
        //上面两行__attribute__是为了定位变量存储地址用的,不用可以不写
        << " = {\n";
    for(int i = 0; i < (int)sizeof(RGB565)/16; i++)
    {
        for(int j = 0; j < 16; j++)
        {
            out << "0x" + QString::number(rgb565.rgb8[i*16 + j], 16) + ", ";//以16进制将数值转换成字符串
        }
        out << "\n";
    }
    out << "};\n";
    file.close();
}

void Widget::GenerateBinFile(QString file_name)
{
    QFile file(file_name);
    file.open(QFileDevice::WriteOnly);
    QDataStream out(&file);	//写二进制文件用数据流输出
    for(int i = 0; i < (int)sizeof(RGB565); i++)
    {
        out << rgb565.rgb8[i];	//这里比较简单,数据流会直接将变量的二进制值写到文件里
    }
    file.close();
}

void Widget::GenerateMergedBinFile(QString file_name)
{//好几张图片的RGB565数据合并成一个二进制文件输出
    QFile file(file_name);
    if(!file.exists())
    {//第一次写不存在的文件会自动创建文件
        file.open(QFileDevice::WriteOnly);
        QDataStream out(&file);	//写二进制文件用数据流输出
        for(int i = 0; i < (int)sizeof(RGB565); i++)
        {
            out << rgb565.rgb8[i];
        }
        file.close();
        return;
    }
    file.open(QFileDevice::Append);//后面再写注意用Append追加数据
    QDataStream out(&file);
    for(int i = 0; i < (int)sizeof(RGB565); i++)
    {
        out << rgb565.rgb8[i];
    }
    file.close();
}
  • 2
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值