#include
#include
//因为在 BITMAPFILEHEADER 结构体中 bfType 为2字节,为防止字节对齐为4字节,故强制使用2字节对齐。
//详情请搜索 内存对齐
#pragma pack (2)//C编译器将按照2个字节对齐
typedef unsigned long DWORD;
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef long LONG;
typedef struct tagBITMAPFILEHEADER {
WORD bfType; //必须为'BM'
DWORD bfSize; //文件大小
WORD bfReserved1; //必须为0
WORD bfReserved2; //必须为0
DWORD bfOffBits;//从ITMAPFILEHEADER到存放bmp数据的偏移量
}BITMAPFILEHEADER, *PBITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER {
DWORD biSize; //此结构的大小,可用sizeof(BITMAPINFOHEAER)得到
LONG biWidth; //位图宽度,以象素为单位
LONG biHeight; //位图高度,以象素为单位
WORD biPlanes; //必须为1
WORD biBitCount;//位图象素位数,可为0,1,4,8,24,32
DWORD biCompression;
DWORD biSizeImage; //(仅用于压缩)
LONG biXPelsPerMeter; //一米横向象素数
LONG biYPelsPerMeter; //一米纵向象素数
DWORD biClrUsed;// (非零用语短颜色表)
DWORD biClrImportant;
}BITMAPINFOHEADER, *PBITMAPINFOHEADER;
void RoateBitmap(char *srcFileName, char *dstFileName);
void RoateData(LONG width, LONG height, unsigned char * srcData, unsigned char * dstData, int Bpp);
int main()
{
printf("DWORD: %d, BYTE: %d, WORD: %d, LONG: %d.\n", sizeof(DWORD),
sizeof(BYTE), sizeof(WORD), sizeof(LONG));
char *srcFileName = "0.bmp";
char *dstFileName = "dst.bmp";
RoateBitmap(srcFileName, dstFileName);
return 0;
}
//把位图结构分为两部分, 位图数据域(真正保存位图像素信息的) 和 非数据域(保存位图结构信息)
void RoateBitmap(char *srcFileName, char *dstFileName)
{
FILE* fp = NULL;
DWORD fileLen, dataLen;
int bmpHeight, bmpWidth, bmpBpp;
if ((fp = fopen(srcFileName, "rb")) == NULL)
{
printf("can't open file");
exit(-1);
}
printf("open file %s successed.\n", srcFileName);
//获取文件长度
fseek(fp, 0, SEEK_END);//fp指向文件尾0个字节处
fileLen = ftell(fp);//fp当前位置相对于文件首的偏移字节数
fseek(fp, 0, SEEK_SET);
BITMAPFILEHEADER bfhHeader;//bmp文件头
BITMAPINFOHEADER bmiHeader; //bmp格式头
fread(&bfhHeader, sizeof(BITMAPFILEHEADER), 1, fp);
if (bfhHeader.bfType != ((WORD)('M' << 8) | 'B')) //判断是否是"BM"
{
printf("the file is not a bitmap! exit...\n");
exit(-1);
}
if (bfhHeader.bfSize != fileLen)
{
printf("fileLen = %ld, headerInfo's length = %ld\n", fileLen, bfhHeader.bfSize);
printf("the file length contained by the bitmap file head info is not correct! exit...\n");
exit(-1);
}
fread(&bmiHeader, sizeof(BITMAPINFOHEADER), 1, fp);
bmpHeight = bmiHeader.biHeight; //得到高度和宽度
bmpWidth = bmiHeader.biWidth;
bmpBpp = bmiHeader.biBitCount; //得到每个像素占用多少字节
dataLen = bmiHeader.biSizeImage; //得到位图数据域长度
unsigned char* srcBmpData = (unsigned char *)malloc(dataLen); //位图数据域
unsigned char* fileHead = (unsigned char *)malloc(bfhHeader.bfOffBits); //非位图数据域信息
fseek(fp, 0, SEEK_SET);
fread(fileHead, bfhHeader.bfOffBits, 1, fp); //读取非数据域的信息
fread(srcBmpData, dataLen, 1, fp); //读取图像数据
fclose(fp);
printf("complete read data from %s, close it.\n", srcFileName);
//交换位图的宽高
unsigned char* tmp;
tmp = fileHead;
tmp += 0x12; //是十六进制的0x12
*((LONG*)tmp) = bmpHeight;
tmp += 4;
*((LONG*)tmp) = bmpWidth;
unsigned char * dstBmpData = (unsigned char *)malloc(dataLen); //保存旋转后的位图数据
printf("beginning roate bitmap.\n");
RoateData(bmpWidth, bmpHeight, srcBmpData, dstBmpData, bmpBpp / 8);
printf("completed roate bitmap.\n");
printf("begining write roated data to file(%s)\n", dstFileName);
if ((fp = fopen(dstFileName, "wb")) == NULL)
{
printf("can't open file");
exit(-1);
}
fwrite(fileHead, bfhHeader.bfOffBits, 1, fp);
fwrite(dstBmpData, dataLen, 1, fp);
fclose(fp);
printf("write data successed!\n");
free(srcBmpData);
free(fileHead);
free(dstBmpData);
return;
}
void RoateData(LONG width, LONG height, unsigned char * srcData, unsigned char * dstData, int Bpp)
{
//Bpp byte per pixel
printf("current roating bitmap's byte per pixel is %d\n", Bpp);
int i, j;
int k;
unsigned char *tmpSrc = srcData;
unsigned char *tmpDst = dstData;
width *= Bpp; //每像素占三字节
/*
假如bmp格式src图像为2*2大小,内存中的存储顺序和逆转90度之后的存储顺序为:
2 3 3 1
------>
0 1 2 0
注:bmp格式的图像在内存中的存储顺序为:从下至上,从左至右
*/
for (i = 0; i < width; i += Bpp)
{
for (j = height - 1; j >= 0; j--)
{
for (k = 0; k < Bpp; k++)
{
*tmpDst = *(tmpSrc + j * width + i + k);
tmpDst++;
}
}
}
}