#pragma once
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned int DWORD;
typedef long LONG;
#pragma pack(1)
//位图文件头定义;
//其中不包含文件类型信息(由于结构体的内存结构决定,
//要是加了的话将不能正确读取文件信息)
typedef struct tagRGBQUAD {
BYTE rgbBlue; //该颜色的蓝色分量
BYTE rgbGreen; //该颜色的绿色分量
BYTE rgbRed; //该颜色的红色分量
BYTE rgbReserved; //保留值
}RGBQUAD;//调色板定义
typedef struct tagBITMAPFILEHEADER {
WORD bfType;//文件类型,必须是0x424D,即字符“BM”
DWORD bfSize;//文件大小
WORD bfReserved1;//保留字
WORD bfReserved2;//保留字
DWORD bfOffBits;//从文件头到实际位图数据的偏移字节数
}BITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER {
DWORD biSize;//信息头大小
LONG biWidth;//图像宽度
LONG biHeight;//图像高度
WORD biPlanes;//位平面数,必须为1
WORD biBitCount;//每像素位数
DWORD biCompression; //压缩类型
DWORD biSizeImage; //压缩图像大小字节数
LONG biXPelsPerMeter; //水平分辨率
LONG biYPelsPerMeter; //垂直分辨率
DWORD biClrUsed; //位图实际用到的色彩数
DWORD biClrImportant; //本位图中重要的色彩数
}BITMAPINFOHEADER; //位图信息头定义
//像素信息
typedef struct tagIMAGEDATA
{
char data[8];
//RGBQUAD strPla[256];//256色调色板
//BYTE green;
//BYTE red;
}IMAGEDATA;
#pragma pack()
//#include <stdio.h>
#include "BmpRot.h"
#include "stdlib.h"
#include "math.h"
#include <iostream>
#pragma warning(disable:4996)
#define _CRT_SECURE_NO_DEPRECATE
#define _CRT_SECURE_NO_WARNINGS
#define PI 3.14159//圆周率宏定义
#define LENGTH_NAME_BMP 30//bmp图片文件名的最大长度
#define WIDTHBYTES(bits) (((bits) + 31) / 32 * 4)
#define RADIAN(angle) ((angle)*PI/180.0)
using namespace std;
//变量定义
//BITMAPFILEHEADER strHead;
//RGBQUAD strPla[256];//256色调色板
//BITMAPINFOHEADER strInfo;
//显示位图文件头信息
void showBmpHead(BITMAPFILEHEADER pBmpHead) {
//cout << "位图文件头:" <<pBmpHead.bfType << endl;
std::cout << "文件大小:" << pBmpHead.bfSize << endl;
std::cout << "保留字_1:" << pBmpHead.bfReserved1 << endl;
std::cout << "保留字_2:" << pBmpHead.bfReserved2 << endl;
std::cout << "实际位图数据的偏移字节数:" << pBmpHead.bfOffBits << endl << endl;
}
void showBmpInforHead(tagBITMAPINFOHEADER pBmpInforHead) {
std::cout << "位图信息头:" << endl;
std::cout << "结构体的长度:" << pBmpInforHead.biSize << endl;
std::cout << "位图宽:" << pBmpInforHead.biWidth << endl;
std::cout << "位图高:" << pBmpInforHead.biHeight << endl;
std::cout << "biPlanes平面数:" << pBmpInforHead.biPlanes << endl;
std::cout << "biBitCount采用颜色位数:" << pBmpInforHead.biBitCount << endl;
std::cout << "压缩方式:" << pBmpInforHead.biCompression << endl;
std::cout << "biSizeImage实际位图数据占用的字节数:" << pBmpInforHead.biSizeImage << endl;
std::cout << "X方向分辨率:" << pBmpInforHead.biXPelsPerMeter << endl;
std::cout << "Y方向分辨率:" << pBmpInforHead.biYPelsPerMeter << endl;
std::cout << "使用的颜色数:" << pBmpInforHead.biClrUsed << endl;
std::cout << "重要颜色数:" << pBmpInforHead.biClrImportant << endl;
}
void saveImg(char * desBuf,int desWidth ,int desHeight,int desBufSize,char* newFilePath) {
//printf("desBufSize=%x\r\n", desBufSize);
//文件头信息
BITMAPFILEHEADER nbmfHeader;
nbmfHeader.bfType = 0x4D42;
nbmfHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)+0x8 + desBufSize;
nbmfHeader.bfReserved1 = 0;
nbmfHeader.bfReserved2 = 0;
nbmfHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)+8;
//printf("nbmfHeader.bfSize=%x \r\n", nbmfHeader.bfSize);
//Bitmap头信息
BITMAPINFOHEADER bmi;
bmi.biSize = sizeof(BITMAPINFOHEADER);
bmi.biWidth = desWidth;
bmi.biHeight = desHeight;
bmi.biPlanes = 1;
bmi.biBitCount = 1;
bmi.biCompression = 0;
bmi.biSizeImage = desBufSize;
bmi.biXPelsPerMeter = 0;
bmi.biYPelsPerMeter = 0;
bmi.biClrUsed = 0;
bmi.biClrImportant = 0;
char* newimg = (char*)calloc(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)+8 + desBufSize, sizeof(char));
if (newimg) {
char rgbquid[] = {0x00,0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff };
memcpy(newimg, &nbmfHeader, sizeof(BITMAPFILEHEADER));
memcpy(newimg + sizeof(BITMAPFILEHEADER), &bmi, sizeof(BITMAPINFOHEADER));
memcpy(newimg + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) , rgbquid, sizeof(rgbquid));
memcpy(newimg + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)+8, desBuf, desBufSize);
FILE* newfp = NULL;
fopen_s(&newfp, newFilePath, "wb+");
fwrite(newimg, nbmfHeader.bfSize, 1, newfp);
/*size_t i = 0;
for (i = 0; i < sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +8+desBufSize; i++)
{
fputc((uint8_t)newimg[i], newfp);
}*/
fclose(newfp);
printf("==>%x\r\n",(uint8_t)*(newimg+2));
}
}
int main(){
char strFile[] = "C:\\Users\\Administrator\\Desktop\\1133.bmp";
char saveFile[] = "C:\\Users\\Administrator\\Desktop\\1133_new.bmp";
int iRotateAngle = 70;
char *imagedata = NULL;//动态分配存储原图片的像素信息的二维数组
char *imagedataRot = NULL;//动态分配存储旋转后的图片的像素信息的二维数组
tagBITMAPFILEHEADER* strHead=(tagBITMAPFILEHEADER*)calloc(1,sizeof(tagBITMAPFILEHEADER));
tagBITMAPINFOHEADER* strInfo=(tagBITMAPINFOHEADER*)calloc(1, sizeof(tagBITMAPINFOHEADER));
RGBQUAD* strPla=(RGBQUAD*)calloc(1,sizeof(RGBQUAD));
int width,height;//图片的宽度和高度
FILE *fpi;
fpi=fopen(strFile,"rb");
if(fpi != NULL){
//先读取文件类型
/*WORD bfType;
fread(&bfType,1,sizeof(WORD),fpi);
if(0x4d42!=bfType)
{
std::cout<<"the file is not a bmp file!"<<endl;
return NULL;
}*/
//读取bmp文件的文件头和信息头
fread(strHead,1,sizeof(tagBITMAPFILEHEADER),fpi);
showBmpHead(*strHead);//显示文件头
fread(strInfo,1,sizeof(tagBITMAPINFOHEADER),fpi);
showBmpInforHead(*strInfo);//显示文件信息头
char* lpDIB = (char*)calloc(strHead->bfSize, sizeof(char));
rewind(fpi);
fread(lpDIB, strHead->bfSize, sizeof(char),fpi);
if (true) {
LONG lWidth, lHeight;// 源图像的宽度和高度
LONG lNewWidth, lNewHeight;// 旋转后图像的宽度和高度
LONG lLineBytes;// 图像每行的字节数
LONG lNewLineBytes;//旋转后图像的宽度(lNewWidth',必须是4的倍数)
char* lpDIBBits; //指向源图像的指针
char* lpNewDIBBits;
char* lpSrc; // 指向源象素的指针
char* lpDst;// 指向旋转图像对应象素的指针
char* hDIB;// 旋转后新DIB句柄
char* lpNewDIB;// 指向旋转图像的指针(源图像指针是参数lpDIB)
tagBITMAPFILEHEADER lpbmi;// 指向BITMAPINFO结构的指针(Win3.0)
tagBITMAPINFOHEADER lpbmc;// 指向BITMAPCOREINFO结构的指针
LONG i, j;// 循环变量(象素在新DIB中的坐标)
LONG i0, j0;// 象素在源DIB中的坐标
float fRotateAngle;// 旋转角度(弧度)
float fSina, fCosa;// 旋转角度的正弦和余弦
// 源图四个角的坐标(以图像中心为坐标系原点)
float fSrcX1, fSrcY1, fSrcX2, fSrcY2, fSrcX3, fSrcY3, fSrcX4, fSrcY4;
float fDstX1, fDstY1, fDstX2, fDstY2, fDstX3, fDstY3, fDstX4, fDstY4;// 旋转后四个角的坐标(以图像中心为坐标系原点)
// 两个中间常量
float f1, f2;
lpDIBBits = lpDIB+strHead->bfOffBits;// 找到源DIB图像象素起始位置
lWidth = strInfo->biWidth; // 获取图像的"宽度"(4的倍数)
lHeight = strInfo->biHeight;// 获取图像的高度
lLineBytes = WIDTHBYTES(lWidth);//计算图像每行的字节数(单色位图)
printf("\r\nlWidth=%d lHeight=%d lLineBytes=%d\r\n", lWidth, lHeight, lLineBytes);
fRotateAngle = (float)RADIAN(iRotateAngle);// 将旋转角度从度转换到弧度
fSina = (float)sin((double)fRotateAngle);// 计算旋转角度的正弦
fCosa = (float)cos((double)fRotateAngle);// 计算旋转角度的余弦
// 计算原图的四个角的坐标(以图像中心为坐标系原点)
fSrcX1 = (float)(-(lWidth - 1) / 2);
fSrcY1 = (float)((lHeight - 1) / 2);
fSrcX2 = (float)((lWidth - 1) / 2);
fSrcY2 = (float)((lHeight - 1) / 2);
fSrcX3 = (float)(-(lWidth - 1) / 2);
fSrcY3 = (float)(-(lHeight - 1) / 2);
fSrcX4 = (float)((lWidth - 1) / 2);
fSrcY4 = (float)(-(lHeight - 1) / 2);
// 计算新图四个角的坐标(以图像中心为坐标系原点)
fDstX1 = fCosa * fSrcX1 + fSina * fSrcY1;
fDstY1 = -fSina * fSrcX1 + fCosa * fSrcY1;
fDstX2 = fCosa * fSrcX2 + fSina * fSrcY2;
fDstY2 = -fSina * fSrcX2 + fCosa * fSrcY2;
fDstX3 = fCosa * fSrcX3 + fSina * fSrcY3;
fDstY3 = -fSina * fSrcX3 + fCosa * fSrcY3;
fDstX4 = fCosa * fSrcX4 + fSina * fSrcY4;
fDstY4 = -fSina * fSrcX4 + fCosa * fSrcY4;
//printf("fDstX1=%f,fDstY1=%f\r\n", fDstX1, fDstY1);
//printf("fDstX4=%f,fDstY4=%f\r\n", fDstX4, fDstY4);
lNewWidth = (LONG)(max(fabs(fDstX4 - fDstX1), fabs(fDstX3 - fDstX2)) + 0.5);// 计算旋转后的图像实际宽度
lNewHeight = (LONG)(max(fabs(fDstY4 - fDstY1), fabs(fDstY3 - fDstY2)) + 0.5);// 计算旋转后的图像高度
lNewLineBytes = WIDTHBYTES(lNewWidth);// 计算新图像每行的字节数(单色图)
size_t newSize = lNewLineBytes * lNewHeight + sizeof(tagBITMAPFILEHEADER) + sizeof(tagBITMAPINFOHEADER) + 8;
printf("lNewWidth=%d lNewHeight=%d lNewLineBytes=%d newSize=%d\r\n", lNewWidth, lNewHeight, lNewLineBytes, newSize);
// 两个常数,这样不用以后每次都计算了
f1 = (float)(-0.5 * (lNewWidth - 1) * fCosa - 0.5 * (lNewHeight - 1) * fSina + 0.5 * (lWidth - 1));
f2 = (float)(0.5 * (lNewWidth - 1) * fSina - 0.5 * (lNewHeight - 1) * fCosa + 0.5 * (lHeight - 1));
printf("f1=%f f2=%f \r\n",f1,f2);
hDIB = (char*)calloc(newSize,sizeof(char));
lpNewDIBBits = hDIB + sizeof(tagBITMAPFILEHEADER) + sizeof(tagBITMAPINFOHEADER) + 8;
lpbmi = *strHead;
lpbmi.bfSize = newSize;
lpbmi.bfOffBits = sizeof(tagBITMAPFILEHEADER) + sizeof(tagBITMAPINFOHEADER) + 8;
lpbmc = *strInfo;
lpbmc.biWidth = (unsigned short)lNewWidth;
lpbmc.biHeight = (unsigned short)lNewHeight;
lpDst = (char*)lpNewDIBBits ;//第i行的数据(DIB是从下向上存储图像的)
int opreate_type =2;
if (1 == opreate_type) {
for (i = 0; i < lNewHeight; i++)// 针对图像每行进行操作
{
// 注意此处宽度和高度是新DIB的宽度和高度
lpDst = (char*)lpNewDIBBits + lNewLineBytes * (lNewHeight - 1 - i);//第i行的数据(DIB是从下向上存储图像的)
for (j = 0; j < lNewWidth; j++)// 针对图像每列进行操作
{
int NewBytes = j / 8;//一行中第几个字节
int NewBits = j % 8;//确定是在该字节中的第几位
BYTE byNewByte = lpDst[NewBytes];//取一个字节,即8个象素
// 计算该象素在源DIB中的坐标
i0 = (LONG)(-((float)j) * fSina + ((float)i) * fCosa + f2 + 0.5);//旋转前的目标行
j0 = (LONG)(((float)j) * fCosa + ((float)i) * fSina + f1 + 0.5);//旋转前的目标列
// 判断是否在源图范围内
if ((j0 >= 0) && (j0 < lWidth) && (i0 >= 0) && (i0 < lHeight))
{
lpSrc = (char*)lpDIBBits + lLineBytes * (lHeight - 1 - i0);//指向源图像中第i0行
//std::cout <<lpSrc << endl;
//printf("%p\r\n",lpSrc);
int SrcBytes = j0 / 8;//该像素在这一行的第几个字节
int SrcBits = j0 % 8;//第几位
BYTE bySrcByte = lpSrc[SrcBytes];//对应源图中的字节
BYTE byTmp = (bySrcByte >> (7 - SrcBits)) & 0x01;//取出源图像中的位,7-0
//注意:最高位代表最左边的象素!
switch (NewBits)
{
case 0:
byNewByte = (byTmp << 7) | byNewByte; //赋值给新DIB中对应的位
break;
case 1:
byNewByte = (byTmp << 6) | byNewByte;
break;
case 2:
byNewByte = (byTmp << 5) | byNewByte;
break;
case 3:
byNewByte = (byTmp << 4) | byNewByte;
break;
case 4:
byNewByte = (byTmp << 3) | byNewByte;
break;
case 5:
byNewByte = (byTmp << 2) | byNewByte;
break;
case 6:
byNewByte = (byTmp << 1) | byNewByte;
break;
case 7:
byNewByte = byTmp | byNewByte;
break;
}
lpDst[NewBytes] = byNewByte;
}
else
{
lpDst[NewBytes] = 255;// 对于源图中没有的象素,直接赋值为255
}
}//列j结束
}//行i结束
}
else if (2== opreate_type) {
memset(lpNewDIBBits, 0xff, lNewLineBytes * lNewHeight);//先将每个像素设为白色
for (i = 0; i < lNewHeight; i++)// 针对图像每行进行操作
{
for (j = 0; j < lNewWidth; j++)// 针对图像每列进行操作
{
// 计算该象素在源DIB中的坐标
i0 = (LONG)(-((float)j) * fSina + ((float)i) * fCosa + f2 + 0.5);//旋转前的目标行
j0 = (LONG)(((float)j) * fCosa + ((float)i) * fSina + f1 + 0.5);//旋转前的目标列
//printf("i=%d, j=%d, i0=%d,j0=%d \r\n",i,j ,i0,j0);
// 判断是否在源图范围内
if ((j0 >= 0) && (j0 < lWidth) && (i0 >= 0) && (i0 < lHeight))
{
BYTE mask = *((char*)lpDIBBits + lLineBytes * i0 + j0 / 8) & (0x80 >> j0 % 8);
if (i == 0 && j == 0) {
printf("i=0 j=0---> i0=%d j0=%d (lLineBytes*i0+j0/8)=0x%x \r\n",i0,j0, lLineBytes * i0 + j0 / 8);
char p = *((char*)lpDIBBits + lLineBytes * i0 + j0 / 8);
printf("p=%x mask=%d \r\n",(uint8_t)p,mask);
}
mask = mask ? (0x80 >> j % 8) : 0;
//lpSrc = (char *)lpDIBBits + lLineBytes * (lHeight - 1 - i0);//指向源图像中第i0行
*((char*)lpNewDIBBits + lNewLineBytes * (i)+(j / 8)) &= ~(0x80 >> j % 8);
*((char*)lpNewDIBBits + lNewLineBytes * (i)+(j / 8)) |= mask;
}
}//列j结束
}//行i结束
}
IMAGEDATA img = { 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff };
saveImg(lpDst, lNewWidth, lNewHeight, newSize, saveFile);
std::cout << "over-----!" << endl;
}
fclose(fpi);
}
else
{
std::cout<<"file open error!"<<endl;
return NULL;
}
//释放内存
delete[] imagedata;
delete[] imagedataRot;
std::cout << "over--!" << endl;
}