soft

soft

BMP rotate 2

#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;
}


发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

联系我 331434376    15629529961