【问题标题】:Bitmap file image data offset producing different image位图文件图像数据偏移产生不同的图像
【发布时间】:2017-01-14 18:11:54
【问题描述】:

我刚开始创建位图图像文件加载器,只是从 wiki 中得出结论,从文件开头到图像数据的偏移量是 50 字节。因此,我将数据设置为 50。这是原始图像:

现在当我使用以下代码加载图像时:

   std::fstream file;
file.open(fileName, std::fstream::binary | std::fstream::in);

if (file.fail()) std::cout << "Couldn't open: `" << fileName << "`\n";
GLchar * data;

file.seekg(0, file.end);
int length = file.tellg();
file.seekg(0, file.beg);

data = new GLchar[length];


file.read(data, length);


if(file)
    std::cout << "all characters read successfully.\n";
else
    std::cout << "error: only " << file.gcount() << " could be read";

GLchar sec = data[1];

std::cout << data[0] << data[1] << "= ";

switch (sec) {
case 'M':std::cout << "Windows 3.1x"; break;
case 'A':std::cout << "OS/2 struct bitmap array"; break;
case 'I':std::cout << "OS/2 struct color icon"; break;
case 'P':std::cout << "OS/2 const color pointer"; break;
case 'C':std::cout << "OS/2 struct icon"; break;
}

int headerOffset = 50;
std::cout << "\n\n~~ "<< *(GLuint *)&data[10];
width = *(GLuint *)&data[18];
height = *(GLuint *)&data[22];

int bpp = *(int *)&data[28];

int compressionMethod = *(int *)&data[30];

std::cout << "\nDimensions: " << width << "x" << height << "\n";
std::cout << "Bits per pixel: " << bpp;
std::cout << "\nCompression Method: " << compressionMethod << "\n";
//start of pixel array - 50
unsigned char *pixels = new unsigned char[width*height * 3];
file.seekg(headerOffset + 40);
file.read((char *)pixels, width*height*3);

unsigned char tmpRGB = 0; // Swap buffer
for (unsigned long i = 0; i < width * height * 3; i += 3)
{
    tmpRGB = pixels[i];
    pixels[i] = pixels[i + 2];
    pixels[i + 2] = tmpRGB;
}

glGenTextures(1, &texture);             // Generate a texture
glBindTexture(GL_TEXTURE_2D, texture); // Bind that texture temporarily

GLint mode = GL_RGB;                   // Set the mode

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

glTexImage2D(GL_TEXTURE_2D, 0, mode, width, height, 0, mode, GL_UNSIGNED_BYTE, pixels);


delete[] pixels;
delete[] data;
file.close();
std::cout << "\n\n\n";

此代码假设图像数组的偏移量为 50

有了这个假设:这就是图像产生的结果-

现在,经过一些研究,我了解到 The offset, i.e. starting address, of the byte where the bitmap image data (pixel array) can be found. 在文件中的偏移量为 10。于是,我决定改变

       GLuint offset = 50;

到下面

       GLuint offset = *(GLuint *)&data[10];

但是,当我这样做时,颜色会切换到错误的顺序。这是一张图片:

这是对问题的解释:原始图像从上到下是蓝-绿-红-白-灰。我渲染的第一张图片遵循了这一点。第二个(从代码中找到偏移量的那个)没有。谁能解释为什么会这样?

【问题讨论】:

    标签: c++ opengl


    【解决方案1】:

    没有看太多代码,好像没有考虑到图片是存储在Little Endian中的:

    对于 24 位像素,内存中的像素如下所示:0xBBGGRR,也就是说,错误可能是您编写的代码假设一个像素 是用大端写的,像这样:0xRRGGBB

    这意味着,即使我们将一个像素视为 3 个字节的 RGB 值(红色 1B,绿色 1B 和蓝色 1B),字节也会在内存中交换。

    编辑: 这就解释了为什么只有蓝色与红色交换,而绿色和其他颜色保持不变;因为未交换的颜色在 Big endian 和 Little endian 表示法中都有一个对称的十六进制值。

    【讨论】:

      【解决方案2】:

      这是我编写位图加载器时的示例 cpp文件

       #include "BMP.h"
      
      void LoadBMP(const std::string fn, std::vector<Color>& image, unsigned int &width, unsigned int &height)
      {
          std::ifstream fin(fn.c_str(), std::ios::binary);
              char signature[2];
              fin.read(signature, sizeof(signature));
              if (signature[0] == 'B' && signature[1] == 'M') {
                  BMPFileHeader fileheader;
                  BMPInfoHeader infoheader;
                  fin.read((char*)&fileheader, sizeof(fileheader));
                  fin.read((char*)&infoheader, sizeof(infoheader));
      
                  width = infoheader.width;
                  height = infoheader.height;
      
                  fin.seekg(fileheader.offset, fin.beg);
                  int PaddingBytesPerRow = (4 - ((infoheader.width * 3) % 4)) % 4;
                  Pixels pxl;
                  int cc = 0;
                  image.resize(infoheader.width*infoheader.height);
                  for (unsigned int y = 0; y < infoheader.height; y++) {
                      for (unsigned int x = 0; x < infoheader.width; x++) {
                          fin.read((char*)&pxl, sizeof(pxl));
                          cc = x + ((infoheader.height - 1) - y) * infoheader.width;
                          image[cc].SetR(pxl.r);
                          image[cc].SetG(pxl.g);
                          image[cc].SetB(pxl.b);
                      }
                      fin.seekg(PaddingBytesPerRow, fin.cur);
                  }
              }
              fin.close();
      
      }
      

      h 文件

      #pragma once
      #include <string>
      #include "Graphics.h" // color array
      #include <fstream>
      #include <vector>
      
      
      struct BMPFileHeader
      {
          unsigned int size;
          unsigned short reserved1, reserved2;
          unsigned int offset;
      };
      
      struct BMPInfoHeader
      {
          unsigned int HeaderSize;
          unsigned int width, height;
          unsigned short planes;
          unsigned short bits;
          unsigned int compression;
          unsigned int imagesize;
          int xResolution, yResolution;
          unsigned int nColors;
          unsigned int importantColors;
      };
      
      struct Pixels {
          unsigned char b, g, r;
      };
      
      void LoadBMP(const std::string fn,std::vector<Color>& image, unsigned int &width,unsigned int &height);
      

      我将结构用于位图,因此不会有任何魔法值,所有内容都将从文件加载到结构中,然后使用这些值计算填充并将像素推入矢量,我已经测试了这段代码及其工作正常

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-06-12
        • 2018-10-01
        • 2013-03-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多