24位图转1位位图

网络上较多的是24为转8位的,因为24位转8位正好是将一个RGB值转为一个字节进行存储,所以比较好转。

24位转一位位图,与其逻辑相似,但是有一定区别。

1、取得24位图的3个字节的RGB值,按照一定方式转为1位二进制值。转换的方式有很多

			/*
			这里共有三种灰度的计算方法,这个可以随机取
			1、每个颜色值按比例取值组为新的灰度值
			2、计算点之间的距离,取较近的一个
			3、除了纯白的(全是255的),其余全部认为是黑色点(0)
			*/
			//gray=(299*r+587*g+114*b)/1000;
			//gray = (BYTE)( ( 256 * r) >> 8 ); // 24位转8位核心算法
			//int iTo0 = (r-0)*(r-0)+(g-0)*(g-0)+(b-0)*(b-0);
			//int iTo1 = (r-255)*(r-255)+(g-255)*(g-255)+(b-255)*(b-255);
			//gray = iTo1 > iTo0 ? 0x00 : 0xFF;

			if(255 == b && 255 == g && 255 == r)
			{
				gray = 0xff;
			}
			else
			{
				gray = 0x00;
			}

这三种都是可以的。我的代码中采取第三种

2、补零的问题,bmp图像要求,每一行的字节数为4的整数倍,所以不管24位图还是1位图,都要注意。尤其是读取24位图的RGB数据时,要区分哪些是有效数据,哪些是为了字节对齐要求补足的无效数据,不然转换出来的图像会出现扭曲的情况。网络上有的绝大部分代码都没有注意到这种情况,所以一旦当图片的中存在补足的数据后就会出现图像转换后扭曲的情况。


将转换的代码封装成了一个函数,如下所示

void change(char *file)
{	
	FILE *opfile;
	int iLineByte = 0;
	int iSize = 0;
	int iWidth = 0;
	int iHeight = 0;
	int iBitCount = 0;
	BYTE bByte = 0;
	int iOffset = 0;
	int iOffsetBytes = 0;
	unsigned char* pNewBuff = NULL;

	if((opfile = fopen(file,"rb")) == NULL)
	{
		printf("File can not open!\n");
		exit(1);
	}
	FILE *wrfile;
	char sFileName[256] = {0};
	sprintf(sFileName, "%s/data/%s", OSL_GetAppPath(), "QRCode.bmp");
	if((wrfile = fopen(sFileName,"wb")) == NULL)
	{
		printf("File can not open!\n");
		exit(1);
	}

	BITMAPFILEHEADER fileHead;
	fread(&fileHead, sizeof(BITMAPFILEHEADER), 1, opfile);	
	BITMAPINFOHEADER bitmapinfoHead;
	fread(&bitmapinfoHead, sizeof(BITMAPINFOHEADER), 1, opfile);
	
	//计算1位图所占的总字节空间
	iWidth = bitmapinfoHead.biWidth ;
	iHeight = bitmapinfoHead.biHeight ;
	iBitCount = bitmapinfoHead.biBitCount ;
	iLineByte = (iWidth *iBitCount/8+3)/4*4;
	iSize = (iLineByte*iHeight)/3;
	iOffset = fileHead.bfOffBits ;
	iOffsetBytes = iLineByte - (iWidth*iBitCount/8);

	if(0 != ((iLineByte*iHeight)%3))
	{
		iSize = iSize + 1;
	}
	pNewBuff = new unsigned char[iSize];

	COLORREF rgb;
	UINT pitchcount;
	BYTE r, g, b;
	BYTE gray;
	BYTE writein = 0;
	int k;
	bitmapinfoHead.biBitCount = 1;
	bitmapinfoHead.biClrUsed = 0;
	fileHead.bfOffBits = 54 + 2*sizeof(RGBQUAD);
	bitmapinfoHead.biSizeImage = (((bitmapinfoHead.biWidth*bitmapinfoHead.biBitCount)+31)/32)*abs(bitmapinfoHead.biHeight)*4;
	fileHead.bfSize = fileHead.bfOffBits + bitmapinfoHead.biSizeImage;
	fwrite(&fileHead, sizeof(BITMAPFILEHEADER), 1, wrfile);
	fwrite(&bitmapinfoHead, sizeof(BITMAPINFOHEADER), 1, wrfile);
	wrfile = SetRGBQUAD(wrfile);
	
	fseek(opfile,iOffset,0);
	for(int i = 0; i < abs(bitmapinfoHead.biHeight); i++)
	{
		pitchcount = 0;
		k = 0;

		for (int j = 0; j < bitmapinfoHead.biWidth; j++)
		{
			fread(&rgb, 3, 1, opfile);
			if(feof(opfile)) 
			{
				break;
			}
			// rgb: 0x00bbggrr
			b = GetBValue(rgb);
			g = GetGValue(rgb);
			r = GetRValue(rgb);
			/*
			这里共有三种灰度的计算方法,这个可以随机取
			1、每个颜色值按比例取值组为新的灰度值
			2、计算点之间的距离,取较近的一个
			3、除了纯白的(全是255的),其余全部认为是黑色点(0)
			*/
			//gray=(299*r+587*g+114*b)/1000;
			//gray = (BYTE)( ( 256 * r) >> 8 ); // 24位转8位核心算法
			//int iTo0 = (r-0)*(r-0)+(g-0)*(g-0)+(b-0)*(b-0);
			//int iTo1 = (r-255)*(r-255)+(g-255)*(g-255)+(b-255)*(b-255);
			//gray = iTo1 > iTo0 ? 0x00 : 0xFF;

			if(255 == b && 255 == g && 255 == r)
			{
				gray = 0xff;
			}
			else
			{
				gray = 0x00;
			}
			/*
			note by wangwei 20141029
			24位转一位的比例是1:24,每三个字节组成一位,每24个字节组成一个新图的字节
			*/
			bByte = (bByte<<1)| (gray>>7);
			k++;
			if(8 == k)
			{
				fwrite(&bByte, sizeof(char), 1, wrfile);
				bByte = 0;
				k = 0;
				pitchcount++;
			}
		}

		/*
		add by wangwei 20141029
		这句代码很重要,如果没有的话,如果缩放0.25这类的比例,会出现图像走样的情况
		因为原图也是存在补足字节的情况的,也是要求每行的字节数是4的整数倍数的,而上面一个循环结束,就是实际像素的结束,
		这时候如果不补足的话,是另起一行的,实际为了补足为4的倍数,会补足一堆无意义字节,而这类补足的字节是不能作为新图的像素依据的,
		所以需要调过这类无意义字节
		*/
		fseek(opfile,iOffsetBytes,SEEK_CUR);
		if(0 != k)
		{
			bByte = bByte <<(8-k);
			fwrite(&bByte,sizeof(char),1,wrfile);
			k = 0;
			bByte = 0;
			pitchcount++;
		}
		if(0 != (pitchcount%4))
		{
			k = pitchcount%4;
			for(int iIndex = 0;iIndex<(4-k);iIndex++)
			{
				fwrite(&bByte,sizeof(char),1,wrfile);
				pitchcount = pitchcount + 1;
			}
		}
	}
	fclose(opfile);
	fclose(wrfile);
	memset(pNewBuff,0x00,sizeof(pNewBuff));
	delete []pNewBuff;
	pNewBuff = NULL;
}

代码中部分变量是为了测试用才定义的,并不是代码完全不能更改的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是将MFC 24位图换为1位图的源代码: // 获取24位图像素数据 CImage image; image.Load(_T("24bit.bmp")); BYTE* pSrc = (BYTE*)image.GetBits(); int nWidth = image.GetWidth(); int nHeight = image.GetHeight(); // 创建1位图 CBitmap bitmap; bitmap.CreateBitmap(nWidth, nHeight, 1, 1, NULL); // 获取1位图像素数据 BYTE* pDst = new BYTE[nWidth * nHeight / 8]; memset(pDst, 0, nWidth * nHeight / 8); BITMAPINFOHEADER bih; bih.biSize = sizeof(BITMAPINFOHEADER); bih.biWidth = nWidth; bih.biHeight = nHeight; bih.biPlanes = 1; bih.biBitCount = 1; bih.biCompression = BI_RGB; bih.biSizeImage = 0; bih.biXPelsPerMeter = 0; bih.biYPelsPerMeter = 0; bih.biClrUsed = 0; bih.biClrImportant = 0; BITMAPINFO bi; bi.bmiHeader = bih; bi.bmiColors[0] = RGB(0, 0, 0); bi.bmiColors[1] = RGB(255, 255, 255); // 将24位图换为1位图 for (int i = 0; i < nHeight; i++) { for (int j = 0; j < nWidth; j++) { int nIndex = i * nWidth + j; BYTE r = pSrc[nIndex * 3]; BYTE g = pSrc[nIndex * 3 + 1]; BYTE b = pSrc[nIndex * 3 + 2]; BYTE nGray = (r * 30 + g * 59 + b * 11) / 100; if (nGray < 128) { pDst[i * ((nWidth + 31) / 32) + j / 8] |= (BYTE)(0x80 >> (j % 8)); } } } // 将1位图像素数据写入位图对象 CBitmap* pOldBitmap = dc.SelectObject(&bitmap); SetDIBits(dc.GetSafeHdc(), (HBITMAP)bitmap.GetSafeHandle(), 0, nHeight, pDst, &bi, DIB_RGB_COLORS); dc.SelectObject(pOldBitmap); delete[] pDst; 注意:上述代码仅支持24RGB格式的位图,如果需要支持其他格式的位图,需要根据实际情况进行修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值