优秀的编程知识分享平台

网站首页 > 技术文章 正文

Windows API操作BMP图像(2)BMP文件读取

nanyue 2024-08-16 19:59:32 技术文章 8 ℃


读取BMP文件流程图如上图所示。主要分为文件头读取、信息头读取、调色板读取和像素值读取等几个步骤。特别需要注意的是,BMP文件的像素值是按行存储的,每行字节数一般是4的倍数,如果不是4的倍数,则要在每行末尾补0。在BMP文件中,信息头和调色板一起封装在BITMAPINFO结构体中,在显示图像中需要用到这个结构体,如下所示:

typedef struct tagBITMAPINFO {
     BITMAPINFOHEADER bmiHeader; //位图信息头
     RGBQUAD bmiColors[1]; //调色板
}BITMAPINFO;

从二进制文件中读取BMP图像的函数ReadBMPFromFile如代码1-1所示。这里文件信息头是固定14个字节,而位图信息头和调色板捆绑在一起,其大小由bmfHeader.bfOffBits - sizeof(BITMAPFILEHEADER)决定,其中bmfHeader是文件信息头对象。由于调色板大小和位图大小都是不确定的,因此函数中传入的二维指针,其所占用内存在ReadBMPFromFile函数内部进行分配并返回。

读取BMP图像的函数

//功能:从BMP文件读取图像
//输入:szFileName,输入文件名
//输出:ppBmpInfo,包含信息头和调色板;ppBmpBits,图像像素数据
//返回值:如果读取成功,则返回true,否则返回false
#define DIB_HEADER_MARKER ((WORD) ('M' << 8) | 'B')
bool ReadBMPFromFile(char *szFileName, BITMAPINFO **ppBmpInfo, 
unsigned char **ppBmpBits)
{
  FILE *pFile = NULL;
  if (fopen_s(&pFile, szFileName, "rb") != 0) {
    std::cout << "打开文件失败" << std::endl;
    return false;
  }
  BITMAPFILEHEADER bmpFileHdr; //文件头对象
  //读取文件头
  if (fread_s(&bmpFileHdr, sizeof(BITMAPFILEHEADER), \
  sizeof(BITMAPFILEHEADER), 1, pFile) != 1) {
    std::cout << "读取位图文件头失败" << std::endl;
    fclose(pFile);
    return false;
  }
  //检查读取的文件格式是否正确,即起始两字节应是’BM’
  if (bmpFileHdr.bfType != DIB_HEADER_MARKER) {
    fclose(pFile);
    std::cout << "读取的不是位图文件" << std::endl;
    return false;
  }
  //读取信息头和调色板
  int nLen = bmpFileHdr.bfOffBits - sizeof(BITMAPFILEHEADER);
  *ppBmpInfo = (BITMAPINFO *)new unsigned char[nLen];
  if (fread_s(*ppBmpInfo, nLen, nLen, 1, pFile) != 1) {
    fclose(pFile);
    std::cout << "读取位图信息头和调色板信息失败" << std::endl;
    return false;
  }
  //位图数据长度由bmpFileHdr.bfSize - bmpFileHdr.bfOffBits指定
  DWORD dwBmpLen = bmpFileHdr.bfSize - bmpFileHdr.bfOffBits;
  *ppBmpBits = new unsigned char[dwBmpLen];
  if (NULL == *ppBmpBits) {
    delete[] *ppBmpInfo;
    fclose(pFile);
    std::cout << "分配内存失败" << std::endl;
    return false;
  }
  //读取位图数据
  if (fread_s(*ppBmpBits, dwBmpLen, dwBmpLen, 1, pFile) != 1) {
    delete[] *ppBmpInfo;
    delete[] *ppBmpBits;
    fclose(pFile);
    std::cout << "读取图像像素失败" << std::endl;
    return false;
  }
  fclose(pFile); //关闭位图文件
  return true;
}

Tags:

最近发表
标签列表