使用GDI+保存图像为8bpp的灰度图像
2013-05-10 10:43
429 查看
使用GDI+保存图像为8bpp的灰度图像,GDI+真的有些特殊。。。。。
// Greyscale conversion #define GREY(r, g, b) (BYTE)(((WORD)r * 77 + (WORD)g * 150 + (WORD)b * 29) >> 8) // .299R + .587G + .114B //#define GREY(r, g, b) (BYTE)(((WORD)r * 169 + (WORD)g * 256 + (WORD)b * 87) >> 9) // .33R + 0.5G + .17B
// BOOL GDIPlusImage::SaveToFileWith8pp(TCHAR *pszPath) // 功能:保存图片为8位的灰度图像 // 参数: pszPath要保存的文件名 BOOL GDIPlusImage::SaveToFileWith8pp(TCHAR *pszPath) { Bitmap *ima = this->m_pBitmap; // GDIPlusImage的Bitmap对象 if (!ima || !pszPath || !*pszPath) { return FALSE; } int width = m_pBitmap->GetWidth(); int height = m_pBitmap->GetHeight(); int bitcount = 8; //1, 4, 8, 24, 32 ////////////////////////////////////////////////////////////////////////// //Build bitmap header BITMAPFILEHEADER bitmapFileHeader; BITMAPINFOHEADER bitmapInfoHeader; BYTE rgbquad[4]; // RGBQUAD int index = 0; DWORD stride = ((bitcount*width + 31)/32)*4; //每行都是4的倍数,或者说是DWORD大小的倍数 switch(bitcount) { case 1: index = 2; bitmapFileHeader.bfOffBits = (DWORD)(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 2*4); break; case 4: index = 16; bitmapFileHeader.bfOffBits = (DWORD)(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16*4); break; case 8: index = 256; bitmapFileHeader.bfOffBits = (DWORD)(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD)); break; case 24: case 32: index = 0; bitmapFileHeader.bfOffBits = (DWORD)(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)); break; default: break; } //构造Bitmap文件头BITMAPFILEHEADER bitmapFileHeader.bfType = 0x4d42; // 很重要的标志位 BM 标识 bitmapFileHeader.bfSize = (DWORD)(bitmapFileHeader.bfOffBits + height * stride); //bmp文件长度 bitmapFileHeader.bfReserved1 = 0; bitmapFileHeader.bfReserved2 = 0; //构造Bitmap文件信息头BITMAPINFOHEADER bitmapInfoHeader.biSize = sizeof(BITMAPINFOHEADER); bitmapInfoHeader.biWidth = width; bitmapInfoHeader.biHeight = height; bitmapInfoHeader.biPlanes = 1; bitmapInfoHeader.biBitCount = bitcount; bitmapInfoHeader.biCompression = BI_RGB; // 未压缩 bitmapInfoHeader.biSizeImage = height * stride; bitmapInfoHeader.biXPelsPerMeter = 3780; bitmapInfoHeader.biYPelsPerMeter = 3780; bitmapInfoHeader.biClrUsed = 0; bitmapInfoHeader.biClrImportant = 0; //创建BMP内存映像,写入位图头部 BYTE *pMyBmp = new BYTE[bitmapFileHeader.bfSize]; // 我的位图pMyBmp BYTE *curr = pMyBmp; // curr指针指示pMyBmp的位置 memset(curr, 0, bitmapFileHeader.bfSize); //写入头信息 memcpy(curr, &bitmapFileHeader,sizeof(BITMAPFILEHEADER)); curr = pMyBmp + sizeof(BITMAPFILEHEADER); memcpy(curr, &bitmapInfoHeader,sizeof(BITMAPINFOHEADER)); curr += sizeof(BITMAPINFOHEADER); //构造调色板 if(8 == bitcount) { rgbquad[3] = 0; //rgbReserved for(int i = 0; i < 256; i++) { rgbquad[0] = rgbquad[1] = rgbquad[2] = i; memcpy(curr, rgbquad, sizeof(RGBQUAD)); curr += sizeof(RGBQUAD); } }else if (4 == bitcount) { rgbquad[3] = 0; for (int i = 0; i < 16; i++) { rgbquad[0] = rgbquad[1] = rgbquad[2] = i; memcpy(curr, rgbquad, sizeof(RGBQUAD)); curr += sizeof(RGBQUAD); } } else if(1 == bitcount) { rgbquad[3] = 0; //rgbReserved for(int i = 0; i < 2; i++) { rgbquad[0] = rgbquad[1] = rgbquad[2] = (256 - i)%256; memcpy(curr, rgbquad, sizeof(RGBQUAD)); curr += sizeof(RGBQUAD); } } //用GDI+加载数据源,也可以是其他的,写入文件数据 Rect rect(0,0,width,height); // Gdiplus+ BitmapData bmData; Status iSucess = ima->LockBits( &rect, ImageLockModeRead, ima->GetPixelFormat() , &bmData); BYTE *_pixels = (BYTE*)bmData.Scan0; //原图rect区域内存位置的起始指针,以BYTE作为单元类型 BYTE *_pRow; int _strideoff8 = stride - width; //前面计算的索引图像的stride BYTE _grey; // build pixles, GDI+ (windows)的图像数据的原点在左下角,参考一下OpenCV的IplImage结构体 switch(ima->GetPixelFormat()) { case PixelFormat24bppRGB: { int _strideoff24 = stride - 3*width; //前面计算的索引图像的stride // 灰度化 for (int i=height-1; i >= 0; i--) { _pRow = _pixels + i*bmData.Stride; // 当前的行 for (int j=width-1; j >= 0; j--) { BYTE* _pixels_b; //b BYTE* _pixels_g; //g BYTE* _pixels_r; //r _pixels_b = _pRow++; //blue _pixels_g = _pRow++; //green _pixels_r = _pRow++; //red _grey = GREY(*_pixels_r, *_pixels_g, *_pixels_b); *curr = _grey; //根据红绿蓝求出此像素的灰度值 curr++; } curr += _strideoff8; } } break; case PixelFormat32bppARGB: { // 灰度化 for (int i=height-1;i>=0;i--) { _pRow = _pixels + i*bmData.Stride; for (int j=width-1;j>=0;j--) { BYTE* _pixels_b; BYTE* _pixels_g; BYTE* _pixels_r; _pixels_b = _pRow++; //blue _pixels_g = _pRow++; //green _pixels_r = _pRow++; //red _pRow++; _grey = GREY(*_pixels_r, *_pixels_g, *_pixels_b); *curr = _grey; curr++; } curr += _strideoff8; } } break; case PixelFormat8bppIndexed: // Gdi+只能保存成24位真彩色的图像 { // 不能直接用memcpy复制,需要水平镜像,memcpy(curr, _pixels, height * stride); for (int i=height-1; i >= 0; i--) { _pRow = _pixels + i*bmData.Stride; // for (int j=width-1;j >= 0;j--) // { // _grey = *_pRow++; // *curr = _grey; // curr++; // } memcpy(curr, _pRow, width); curr += stride; } } break; default: break; } // 保存图像 pMyBmp 到文件 try { CFile f(pszPath, CFile::modeCreate | CFile::modeWrite ); f.Write(pMyBmp, bitmapFileHeader.bfSize); f.Close(); } catch( CFileException* e ) { TCHAR szCause[255]; e->GetErrorMessage(szCause, 255); CString msg; msg.Format(_T("file error: %s, m_cause:%d\n"),szCause, e->m_cause); TRACE1("%s",msg); AfxMessageBox(msg); e->Delete(); } //clean: ima->UnlockBits(&bmData); delete[] pMyBmp; return TRUE; }
相关文章推荐
- 使用GDI+保存带Alpha通道的图像(续)
- 使用GDI+保存带Alpha通道的图像
- 使用GDI+将24位真彩色图像转换为8位灰度图像
- 使用GDI+将24位真彩色图像转换为8位灰度图像
- 猎豹MFC--使用GDI+打开保存图片--把bmp格式图像 保存为了 jpeg格式
- 六.使用OpenCv将图像转化为灰度图像
- vc6.0使用gdi+在内存中绘图并将其保存为bmp,jpg,gif,png等格式的图片
- VC下如何使用GDI+进行图像程序设计
- 使用GDI+保存用户的绘图数据.
- 《炼数成金》第八课 保存和载入模型,使用Google的图像识别网络inception-v3进行图像识别。
- 最近在做的图形图像处理项目,使用GDI+(贴图)
- GDI+将CDC中画好的图像,保存到文件中
- 使用开源jpeg库保存jpg图像
- 使用 Video4Linux 采集USB摄像头的图像,并保存到一张 jpg图像文件中的程序
- opencv2 使用鼠标绘制矩形并截取和保存矩形区域图像
- [WIN32]VB6.0用GDI+保存图像为BMP\JPG\PNG\GIF格式终结版。
- opencv2 使用鼠标绘制矩形并截取和保存矩形区域图像
- 使用GDI+处理数字图像
- GDI+ 摘要: 保存图像文件
- 总结:C# Bitmap保存的问题,eg:GDI+中发生一般性错误 .jpg 正由另一个进程使用 ,该进程无法访问文件