【问题标题】:Read bmp file header size读取 bmp 文件头大小
【发布时间】:2017-10-01 07:47:53
【问题描述】:

我正在尝试查找 bmp 文件的文件大小、文件头大小宽度和高度。我研究过bmp文件的格式和文件中的字节排列。 当我尝试此代码时,它显示不同文件的宽度和高度错误。 到目前为止,我已经尝试了三张图片。这张图片的测量结果正确。

这个没有:

我不明白我哪里出错了,但是位深度显示了所有三个图像的正确值。

这是我的代码:

#include<iostream>
#include<fstream>
#include<math.h>

using namespace std;


int main() {
    ifstream inputfile("bmp.bmp",ios::binary);
    char c; int imageheader[1024]; 

    double filesize=0; int width=0; int height=0;int bitCount = 0;

    for(int i=0; i<1024; i++) {
        inputfile.get(c); imageheader[i]=int(c);
    }

    filesize=filesize+(imageheader[2])*pow(2,0)+(imageheader[3])*pow(2,8)+(imageheader[4])*pow(2,16)+(imageheader[5])*pow(2,24);

    cout<<endl<<endl<<"File Size:  "<<(filesize/1024)<<" Kilo Bytes"<<endl;

    width=width+(imageheader[18])*pow(2,0)+(imageheader[19])*pow(2,8)+(imageheader[20])*pow(2,16)+(imageheader[21])*pow(2,24);

    cout<<endl<<"Width: "<<endl<<(width)<<endl;

    height=height+(imageheader[22])*pow(2,0)+(imageheader[23])*pow(2,8)+(imageheader[24])*pow(2,16)+(imageheader[25])*pow(2,24);
    cout<<endl<<"Height: "<<endl<<(height)<<endl;

    bitCount=bitCount+(imageheader[28])*pow(2,0)+(imageheader[29])*pow(2,8);
    cout<<endl<<"Bit Depth: "<<endl<<(bitCount)<<endl;
}

【问题讨论】:

  • 通常在英文句号或逗号后加一个空格。此外,句子中的第一个单词应使用大写字母。最后,格式化您的代码,使其可读,我们不会浪费时间尝试破译它。
  • 很抱歉给您带来不便
  • 代码建议。不要使用doublepow 函数或任何浮点来表示本质上是整数的事物
  • @USERRR5 -- 不使用pow 不仅仅是代码建议,错误甚至可能来自使用它。 See here
  • @USERRR5 - 我为您提供了一个解决方案,但它可能无法解释为什么您没有获得 BMP 的预期值。但是,您发布的图像是 PNG 文件。发送一个指向该史努比图像的原始 BMP 文件的链接,如果下面的代码不能解决问题,我会看看是什么问题。

标签: c++


【解决方案1】:

让我们首先将 BMP 标头读取为一系列字节,而不是整数。为了使这段代码真正可移植,我们将使用&lt;stdint&gt; 类型。

#include <fstream>
#include <stdint.h>

int main()
{

    ifstream inputfile("D:/test.bmp", ios::binary);
    uint8_t headerbytes[54] = {};

    inputfile.read((char*)headerbytes, sizeof(headerbytes));

现在我们已经将内存中的标头作为字节数组获取,我们可以简单地将每个标头字段的内存地址转换回一个整数。为 bmp 和 the layout diagram 引用 wikipedia page

    uint32_t filesize = *(uint32_t*)(headerbytes+2);
    uint32_t dibheadersize = *(uint32_t*)(headerbytes + 14);
    uint32_t width = *(uint32_t*)(headerbytes + 18);
    uint32_t height = *(uint32_t*)(headerbytes + 22);
    uint16_t planes = *(uint16_t*)(headerbytes + 26);
    uint16_t bitcount = *(uint16_t*)(headerbytes + 28);

现在,精明的代码读者会认识到 BMP 标头的各个字段以小端格式存储。并且上面的代码依赖于您拥有一个 x86 处理器或任何其他字节布局为Little Endian 的架构。在大端机器上,您必须应用一种变通方法将上述每个变量从 LE 转换为 BE。

【讨论】:

  • 位图头只有54字节,你可以使用inputfile.read((char*)headerbytes, 54);
  • 谢谢你..我想尽可能少地使用库函数,以便我可以理解 bmp 文件的属性。
  • operator&gt;&gt; 不应用于读取二进制数据。正如您所拥有的,它将跳过在当前编码中被视为空白的字节。您可以使用noskipws,但最好使用read,这对于二进制数据是明确的。
  • @BenjaminLindley - 已修复。
【解决方案2】:

错误正在读入有符号字符。这应该可以解决它:

for(int i = 0; i < 1024; i++)
{
    //inputfile.get(c); imageheader[i] = int(c);

    // This version of get returns int, where -1 means EOF.  Should be checking for errors...
    imageheader[i] = inputfile.get();
}

其他人已经评论了代码的改进,所以我不会打扰。

【讨论】:

  • 我想尽可能少地使用库函数,请您告诉我应该如何更改我的代码..我没有得到关于 unsigned char 的信息。您能帮我解决这个问题吗?跨度>
  • @USERRR5 我向您展示了如何更改您的代码。将数据中现有的 for 循环读取替换为上面的代码。 char 是默认签名的,所以它的值不是 0-255 而是 -128 到 127。使用 int 可以正确地保持 0-255。
猜你喜欢
  • 1970-01-01
  • 2015-05-15
  • 1970-01-01
  • 2014-05-21
  • 1970-01-01
  • 2022-01-15
  • 2018-04-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多