C++ 无法创建某些大小的BMP文件
我正在为我的应用程序创建小型BMP文件,其中一些文件(取决于像素数)会使我的应用程序崩溃,Windows会看到它们已损坏。工作尺寸的示例为60 x 60px,但即61 x 61不是m_宽度和m_高度的变量 pragma pack使用的结构适用于BMP相关结构:C++ 无法创建某些大小的BMP文件,c++,bmp,C++,Bmp,我正在为我的应用程序创建小型BMP文件,其中一些文件(取决于像素数)会使我的应用程序崩溃,Windows会看到它们已损坏。工作尺寸的示例为60 x 60px,但即61 x 61不是m_宽度和m_高度的变量 pragma pack使用的结构适用于BMP相关结构: struct Rgb /// vector's content { uint8_t r; uint8_t g; uint8_t b; }; #pragma pack(push, 1) struct FileHea
struct Rgb /// vector's content
{
uint8_t r;
uint8_t g;
uint8_t b;
};
#pragma pack(push, 1)
struct FileHeader
{
int16_t bfType;
int32_t bfSize;
int16_t bfReserved1;
int16_t bfReserved2;
int32_t bfOffBits;
};
struct BitMapInfoHeader
{
int32_t biSize;
int32_t biWidth;
int32_t biHeight;
int16_t biPlanes;
int16_t biBitCount;
int32_t biCompression;
int32_t biSizeImage;
int32_t biXPelsPerMeter;
int32_t biYPelsPerMeter;
int32_t biClrUsed;
int8_t biClrImportant;
int8_t biClrRotation;
int16_t biReserved;
};
struct RGBQuad
{
int8_t rgbBlue;
int8_t rgbGreen;
int8_t rgbRed;
int8_t rgbReserved;
};
#pragma pack(pop)
我为整个BMP文件分配内存,为每个文件区域分配指针,填充结构,从其他数组复制像素数据并保存文件。代码:
int m_width = 60, m_height = 60;
uint8_t* data = new uint8_t[ m_width * m_height ];
memset( data, 0, m_width * m_height );
data[ 2 ] = 1; /// one pixel differs
std::vector< Rgb > RGBVec = { { 223, 223, 123 }, { 230, 0, 12 } };
int numberOfSymbols = RGBVec.size();
FileHeader* fileHeader;
BitMapInfoHeader* infoHeader;
RGBQuad* colorTable;
uint8_t* m_pBMPFile; /// pointer to bitmap in memory
uint8_t* m_BMPData; /// begin of pixel data
int m_BMPFileLength = sizeof( FileHeader ) + sizeof( BitMapInfoHeader )
+ numberOfSymbols * sizeof( RGBQuad ) + m_width * m_height;
/// assign pointers to specific parts of bitmap:
m_pBMPFile = new uint8_t[ m_BMPFileLength ];
memset( m_pBMPFile, 0, m_BMPFileLength );
fileHeader = reinterpret_cast< FileHeader* >( m_pBMPFile );
infoHeader = reinterpret_cast< BitMapInfoHeader* >( m_pBMPFile + sizeof( FileHeader ) );
colorTable =
reinterpret_cast< RGBQuad* >( m_pBMPFile + sizeof( FileHeader ) + sizeof( BitMapInfoHeader ) );
m_BMPData = reinterpret_cast< uint8_t* >( m_pBMPFile + sizeof( FileHeader ) + sizeof( BitMapInfoHeader )
+ numberOfSymbols * sizeof( RGBQuad ) );
///////////
/// FileHeader:
fileHeader->bfType = 0x4d42; /// magic number
fileHeader->bfSize = m_BMPFileLength;
fileHeader->bfOffBits = int( m_BMPData - m_pBMPFile );
/// BitMapInfoHeader:
infoHeader->biSize = 40;
infoHeader->biWidth = m_width;
infoHeader->biHeight = -m_height; /// multiplied by -1 so pixels are displayed top-down
infoHeader->biPlanes = 1;
infoHeader->biBitCount = 8;
infoHeader->biCompression = 0;
infoHeader->biSizeImage = 0;
infoHeader->biXPelsPerMeter = 2835;
infoHeader->biYPelsPerMeter = 2835;
infoHeader->biClrUsed = numberOfSymbols;
infoHeader->biClrImportant = 0;
infoHeader->biClrRotation = 0;
/// palette:
int i = 0;
for( auto& s : RGBVec )
{
( &colorTable[ i ] )->rgbRed = s.r;
( &colorTable[ i ] )->rgbGreen = s.g;
( &colorTable[ i ] )->rgbBlue = s.b;
++i;
}
/// apply pixel data:
memcpy( m_BMPData, data, m_width * m_height );
/// save:
std::ofstream file2( "out.bmp", std::ios::binary | std::ios::trunc );
file2.write( ( char* )m_pBMPFile, m_BMPFileLength );
file2.close();
delete[] m_pBMPFile;
在VS2015上编译,64位。主要问题是m_width应该被填充,以字节为单位的宽度可以被4整除。您可以使用以下公式计算宽度(单位:字节),这可以保证。在本例中,它将宽度从61更改为64。多余的字节可以忽略
此外,您可以通过避免过度使用指针来简化代码。将头声明为局部变量就足够了。使用std::vector分配数据,而不是新建/删除数据。并使用单个RGBQ头来管理数据。例如:
struct RGBQ { uint8_t rgbBlue, rgbGreen, rgbRed, rgbReserved; };
int m_width = 61, m_height = 61;
int bitcount = 8;
int width_in_bytes = ((m_width * bitcount + 31) / 32) * 4;
int imagesize = width_in_bytes * m_height;
std::vector<RGBQ> color_table{ { 223, 223, 123 }, { 230, 0, 12 } };
std::vector<uint8_t> data(imagesize);
data[2] = 1;
FileHeader fileHeader = { 0 };
BitMapInfoHeader infoHeader = { 0 };
fileHeader.bfType = 0x4d42;
fileHeader.bfSize = sizeof(fileHeader) + sizeof(infoHeader) + color_table.size()
* sizeof(RGBQ) + data.size();
fileHeader.bfOffBits = sizeof(fileHeader) + sizeof(infoHeader);
infoHeader.biSize = 40;
infoHeader.biWidth = m_width;
infoHeader.biHeight = -m_height;
infoHeader.biPlanes = 1;
infoHeader.biBitCount = bitcount;
infoHeader.biClrUsed = color_table.size();
std::ofstream file2("out.bmp", std::ios::binary | std::ios::trunc);
file2.write((char*)&fileHeader, sizeof(fileHeader));
file2.write((char*)&infoHeader, sizeof(infoHeader));
file2.write((char*)color_table.data(), color_table.size() * sizeof(RGBQ));
file2.write((char*)data.data(), data.size());
file2.close();
您记得吗?您是否通过调试器运行代码以确定崩溃的原因?同意Lightness。图像的每个扫描行都需要填充在4字节的边界上。即使你的程序没有崩溃,你的BMP文件在查看时很可能会产生阶梯效果,显示扫描线关闭。你在上面的代码中有主要的错误。。首先,将数据分配为[宽度*高度]。。但每个像素的大小可以是3字节或4字节..+您没有包括填充..+您没有删除[]数据。。哦,天哪。。