One student reported a bug caused by in-memory data alignment, when reading a bitmap file,
it is said that image size and with are always wrong. The fix solution is quite much simple:
You can just simply and temperalily disable data in-memory alignment by calling:
#pragma pack(push, 1)
After that BitmapFileheader and BMPheader information could be written faithfully.
#pragma pack(push, 1)
typedef struct tagBITMAPFILEHEADER
{
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
#pragma pack(pop) //back to whatever the previous packing mode was
==========================================================
// Source code appended, quite much in C style
// There is memory leak issue, haha, just let it be la
#include < string.h >
#include < math.h >
#include < stdio.h >
#include < stdlib.h >
#include < malloc.h >
#define bool char
#define ture 1
#define false 0
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;
typedef long LONG;
// zxg, 临时不允许4字节对齐
#pragma pack(push, 1) // exact fit - no padding
typedef struct tagBITMAPFILEHEADER
{
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
#pragma pack(pop) //back to whatever the previous packing mode was
// zxg, 临时不允许4字节对齐
#pragma pack(push, 1) // exact fit - no padding
typedef struct tagBITMAPINFOHEADER
{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount ;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
}BITMAPINFOHEADER;
#pragma pack(pop) //back to whatever the previous packing mode was
typedef struct tagRGBQUAD
{
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbReserved;
}RGBQUAD;
unsigned char *pBmpBuf = NULL; //pointer that reads the image's data
int bmpWidth; //image' wide
int bmpheight;
RGBQUAD *pColorTable;
int biBitCount;
bool readBmp(char *bmpName)
{
FILE *fp;
fp =fopen(bmpName,"rb");
if(fp==0)
return 0;
int size1 = sizeof(BITMAPFILEHEADER);
//fseek(fp,sizeof(BITMAPFILEHEADER),SEEK_SET);
BITMAPFILEHEADER h1;
fread(&h1,size1,1,fp);
BITMAPINFOHEADER head;
fread(&head, sizeof(BITMAPINFOHEADER),1,fp);
bmpWidth = head.biWidth ;
bmpheight = head.biHeight ;
biBitCount = head.biBitCount ;
int lineByte = (bmpWidth *biBitCount/8+3)/4*4;
if(biBitCount != 24 ) // by zxg
{
// by zxg
int color_table_size = 1;
for(int __k = 0; __k < biBitCount; __k++)
{
color_table_size *= 2;
}
// end by zxg
pColorTable=new RGBQUAD[color_table_size];
fread(pColorTable,sizeof(RGBQUAD),color_table_size,fp);
}
pBmpBuf = new unsigned char[lineByte*bmpheight];
fread(pBmpBuf,1,lineByte*bmpheight,fp);
fclose(fp);
return 1;
}
bool saveBmp(char *bmpName, unsigned char *imgBuf, int width,int height,int biBitCount,RGBQUAD *pColorTable)
{
if(!imgBuf)
return 0;
int colorTablesize=0;
if(biBitCount==8)
colorTablesize=1024;
int lineByte=(width*biBitCount/8+3)/4*4;
FILE *fp=fopen(bmpName,"wb");
if(fp==0)
return 0;
BITMAPFILEHEADER fileHead;
fileHead.bfType = 0x4D42;
fileHead.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + colorTablesize + lineByte*height;
fileHead.bfReserved1 = 0;
fileHead.bfReserved2 = 0;
fileHead.bfOffBits=54+colorTablesize;
fwrite(&fileHead,sizeof(BITMAPFILEHEADER),1,fp);
BITMAPINFOHEADER head;
head.biBitCount = biBitCount;
head.biClrImportant =0;
head.biClrUsed =0;
head.biCompression=0;
head.biHeight=height;
head.biPlanes=1;
head.biSize=40;
head.biSizeImage=lineByte*height;
head.biWidth=width;
head.biXPelsPerMeter=0;
head.biYPelsPerMeter=0;
fwrite(&head,sizeof(BITMAPINFOHEADER),1,fp);
// by zxg, start
//if(biBitCount==8) // commented out by zxg
if(biBitCount != 24 )
{
// by zxg
int color_table_size = 1;
for(int __k = 0; __k < biBitCount; __k++)
{
color_table_size *= 2;
}
fwrite(pColorTable,sizeof(RGBQUAD),color_table_size,fp);
}
// end by zxg
fwrite(imgBuf, height*lineByte, 1, fp);
fclose(fp);
return 1;
}
void main_24bits()
{
char readPath[]="f:\\lele_24_bits.BMP";
readBmp(readPath);
printf("width=%d,height=%d,biBitCount=%d\n",bmpWidth,bmpheight,biBitCount);
char writePath[]="f:\\lele_24_bits_copy.BMP";
saveBmp(writePath,pBmpBuf,bmpWidth,bmpheight,biBitCount,pColorTable);
delete[]pBmpBuf;
if(biBitCount==8)
delete[]pColorTable;
}
void main_8bits()
{
char readPath[]="f:\\lele_8_bits.BMP";
readBmp(readPath);
printf("width=%d,height=%d,biBitCount=%d\n",bmpWidth,bmpheight,biBitCount);
char writePath[]="f:\\lele_8_bits_copy.BMP";
saveBmp(writePath,pBmpBuf,bmpWidth,bmpheight,biBitCount,pColorTable);
delete[]pBmpBuf;
if(biBitCount==8)
delete[]pColorTable;
}
void main_4bits()
{
char readPath[]="f:\\lele_4_bits.BMP";
readBmp(readPath);
printf("width=%d,height=%d,biBitCount=%d\n",bmpWidth,bmpheight,biBitCount);
char writePath[]="f:\\lele_4_bits_copy.BMP";
saveBmp(writePath,pBmpBuf,bmpWidth,bmpheight,biBitCount,pColorTable);
delete[]pBmpBuf;
if(biBitCount==8)
delete[]pColorTable;
}
int main()
{
main_24bits();
main_8bits();
main_4bits();
}