求教,StretchDIBits函数结果颜色不正确

dyycdyyc 2013-07-04 04:54:04
做了一个读取和显示DIB的类(边学边抄出来的= =),位图信息全是直接从文件里读取的,最后的图形显示用的是StretchDIBits函数,但是结果是,对于8位以上不需要调色板的图像显示正常,但是对于需要调色板的图形则颜色错误。
拜求高手指出问题所在……

调用环境是MFC应用的CView类下的OnDraw(),调用时对CView的调色板未做改动,调用参数是:
StretchDIBits(pDC->m_hDC, X, Y, Width, Height, 0, 0, m_BMPIH.biWidth, m_BMPIH.biHeight, m_pDibData, (BITMAPINFO*)m_pDibFile, DIB_PAL_COLORS, MODE);
其中m_BMPIH是位图信息头,m_pDibFile是DIB文件除去位图文件头后的数据指针(包括信息头、彩色表、图像数据)。DIB_PAL_COLORS用于测试有调色板的位图。

描述不充分的话,关键代码如下:
//以下是读取BMP文件的函数以及绘图的函数,未注释的部分可略过
bool CDib::OpenBMP(const char* pszFile)
{
CFile fn;
DWORD dwDibSize;
BITMAPFILEHEADER BMPFH;
RGBQUAD *pPalette;
if(!fn.Open(pszFile,CFile::modeRead)) return false;
dwDibSize = fn.GetLength() - sizeof(BITMAPINFOHEADER);
if(!(m_pDibFile = new unsigned char [dwDibSize])) return false;
try
{
if ( fn.Read(&BMPFH, sizeof(BITMAPFILEHEADER)) != sizeof(BITMAPFILEHEADER) ||
BMPFH.bfType != 'MB' || fn.Read(m_pDibFile, dwDibSize) != dwDibSize)
{
delete[] m_pDibFile;
m_pDibFile = NULL;
fn.Close();
return false;
}
}
catch (CFileException *e)
{
e->Delete();
delete[] m_pDibFile;
m_pDibFile = NULL;
fn.Close();
return false;
}
fn.Close();
//位图信息头
m_BMPIH = *(BITMAPINFOHEADER*)m_pDibFile;
//紧接着是彩色表
pPalette = (RGBQUAD*)&m_pDibFile[sizeof(BITMAPINFOHEADER)];
//色板的颜色个数
if(m_BMPIH.biBitCount > 8)
m_nPaletteN = 0;
else if(m_BMPIH.biClrUsed != 0)
m_nPaletteN = m_BMPIH.biClrUsed;
else
m_nPaletteN = 1 << m_BMPIH.biBitCount;
//图像数据
m_pDibData = &m_pDibFile[sizeof(BITMAPINFOHEADER) + m_nPaletteN * sizeof (RGBQUAD)];
if(m_Palette.GetSafeHandle() != NULL)
m_Palette.DeleteObject();
//如果有色板,则用彩色表建立一个对应的CPalette
if(m_nPaletteN)
{
LOGPALETTE* pLogPal = (LOGPALETTE*)new char[sizeof(LOGPALETTE) + m_nPaletteN *sizeof(PALETTEENTRY)];
if(pLogPal == NULL)
{
delete[] m_pDibFile;
m_pDibFile = NULL;
return false;
}
pLogPal->palVersion = 0x300;
pLogPal->palNumEntries = m_nPaletteN;
for (int i = 0; i < m_nPaletteN; i++)
{
pLogPal->palPalEntry[i].peRed = pPalette[i].rgbRed;
pLogPal->palPalEntry[i].peGreen = pPalette[i].rgbGreen;
pLogPal->palPalEntry[i].peBlue = pPalette[i].rgbBlue;
pLogPal->palPalEntry[i].peFlags = 0;
}
m_Palette.CreatePalette(pLogPal);
delete pLogPal;
}
return true;
}

bool CDib::Draw(CDC* pDC, int X, int Y, int Width, int Height, int MODE)
{
if(m_pDibData == NULL) return false;
if(Width == -1) Width = m_BMPIH.biWidth;
if(Height == -1) Height = m_BMPIH.biHeight;
//if(m_pDibFile != NULL)
//目标CDC的色板没有做改动,参数DIB_PAL_COLORS表示BITMAPINFO中已包含调色板
//m_pDibFile为除去文件头后的文件数据,包含信息头与彩色表
StretchDIBits(pDC->m_hDC, X, Y, Width, Height, 0, 0, m_BMPIH.biWidth, m_BMPIH.biHeight, m_pDibData, (BITMAPINFO*)m_pDibFile, DIB_PAL_COLORS, MODE);
return true;
}
...全文
282 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
schlafenhamster 2013-07-07
  • 打赏
  • 举报
回复
参考: 代码中 pBMPinfo->bmiColors[jj].rgbRed=(BYTE)(color_table[jj] & 0x0000FF); pBMPinfo->bmiColors[jj].rgbGreen=(BYTE)((color_table[jj] & 0x00FF00) >> 8); pBMPinfo->bmiColors[jj].rgbBlue=(BYTE)((color_table[jj] & 0xFF0000) >> 16);
schlafenhamster 2013-07-07
  • 打赏
  • 举报
回复
对 啊。对 啊。对 啊。
dyycdyyc 2013-07-07
  • 打赏
  • 举报
回复
引用 8 楼 schlafenhamster 的回复:
“数据应该都是调色板索引吧” 是啊, 问题是数据 有 多少位 DIB_PAL_COLORS 是 16位 DIB_RGB_COLORS 是24位 “source device context”就是“源DC”
还是不知道多少位是指什么…… 好吧刚接触图像显示的东西完全不熟悉= = 那个说明是说: DIB_PAL_COLORS 表示彩色表的内容是对源DC调色板的索引, DIB_RGB_COLORS 表示彩色表的内容是直接的RGB值。 这样吗?
schlafenhamster 2013-07-07
  • 打赏
  • 举报
回复
“数据应该都是调色板索引吧” 是啊, 问题是数据 有 多少位 DIB_PAL_COLORS 是 16位 DIB_RGB_COLORS 是24位 “source device context”就是“源DC”
dyycdyyc 2013-07-07
  • 打赏
  • 举报
回复
引用 6 楼 schlafenhamster 的回复:
还有: Value Meaning DIB_PAL_COLORS The array contains 16-bit indexes into the logical palette of the source device context. DIB_RGB_COLORS The color table contains literal RGB values.(24)
我尝试的是256色及其以下的图像,数据应该都是调色板索引吧…… 好像只有256色以上的图像会直接保存为RGB信息。 话说“source device context”指的是图像文件吗?
schlafenhamster 2013-07-07
  • 打赏
  • 举报
回复
还有: Value Meaning DIB_PAL_COLORS The array contains 16-bit indexes into the logical palette of the source device context. DIB_RGB_COLORS The color table contains literal RGB values.(24)
schlafenhamster 2013-07-07
  • 打赏
  • 举报
回复
#define DIB_RGB_COLORS 0 /* color table in RGBs */ #define DIB_PAL_COLORS 1 /* color table in palette indices */
dyycdyyc 2013-07-07
  • 打赏
  • 举报
回复
引用 3 楼 schlafenhamster 的回复:
参考: //#else // use .dat // void CDrawbmpView::OnDraw(CDC* pDC) { CDrawbmpDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); pDoc->SetTitle("802D Simulator"); // TODO: add draw code for native data here int hei=508; int wid=648; // pal COLORREF color_table[16]={// 0x00bbggrr ! 0x000000, //0 0x000080, //1 0x008000, //2 0x008080, //3 0x800000, //4 0x800080, //5 0x808000, //6 0x808080, //7 0xC0C0C0, //8 0x0000FF, //9 0x00FF00, //10 0x00FFFF, //11 0xFF0000, //12 0xFF00FF, //13 0xFFFF00, //14 0xFFFFFF };//15 // open CFile if_hnd; if(!if_hnd.Open("snapbmp.dat",CFile::modeRead | CFile::shareExclusive)) { AfxMessageBox("Cann't open image file!"); return; } // get mem unsigned fsize; fsize =if_hnd.GetLength();// BYTE *ScreenPtr1=0; ScreenPtr1=(BYTE *)new char[fsize]; // // read all in if_hnd.Read(ScreenPtr1,fsize);// // image data are in buffer if(if_hnd) if_hnd.Close(); #if 1 //def USE_API // fast way ! // make bitmap info LPBITMAPINFO pBMPinfo; pBMPinfo=(LPBITMAPINFO)new BYTE[sizeof(BITMAPINFOHEADER)+16*sizeof(RGBQUAD)]; ZeroMemory(&pBMPinfo->bmiHeader,sizeof(BITMAPINFOHEADER)); pBMPinfo->bmiHeader.biSize=sizeof(BITMAPINFOHEADER); pBMPinfo->bmiHeader.biBitCount=4; pBMPinfo->bmiHeader.biWidth=648; pBMPinfo->bmiHeader.biHeight=508; pBMPinfo->bmiHeader.biPlanes=1; pBMPinfo->bmiHeader.biSizeImage=648*508/2; // copy colors for(int jj=0; jj<16; jj++) {// reversed ! pBMPinfo->bmiColors[jj].rgbReserved=0; pBMPinfo->bmiColors[jj].rgbRed=(BYTE)(color_table[jj] & 0x0000FF); pBMPinfo->bmiColors[jj].rgbGreen=(BYTE)((color_table[jj] & 0x00FF00) >> 8); pBMPinfo->bmiColors[jj].rgbBlue=(BYTE)((color_table[jj] & 0xFF0000) >> 16); } // draw bmp pDC->SetStretchBltMode(COLORONCOLOR); StretchDIBits(pDC->GetSafeHdc(),0,0,wid,hei,0,0,wid,hei, ScreenPtr1, pBMPinfo, DIB_RGB_COLORS,SRCCOPY); // free delete pBMPinfo; delete [] ScreenPtr1; return; #endif }
确实运行正确了。 现在发现我的代码其实是DIB_PAL_COLORS参数写错了,应该改为DIB_RGB_COLORS才能显示正确。 但是DIB_PAL_COLORS不就是表示信息头里包含颜色表吗……为什么不行……
schlafenhamster 2013-07-05
  • 打赏
  • 举报
回复
参考: //#else // use .dat // void CDrawbmpView::OnDraw(CDC* pDC) { CDrawbmpDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); pDoc->SetTitle("802D Simulator"); // TODO: add draw code for native data here int hei=508; int wid=648; // pal COLORREF color_table[16]={// 0x00bbggrr ! 0x000000, //0 0x000080, //1 0x008000, //2 0x008080, //3 0x800000, //4 0x800080, //5 0x808000, //6 0x808080, //7 0xC0C0C0, //8 0x0000FF, //9 0x00FF00, //10 0x00FFFF, //11 0xFF0000, //12 0xFF00FF, //13 0xFFFF00, //14 0xFFFFFF };//15 // open CFile if_hnd; if(!if_hnd.Open("snapbmp.dat",CFile::modeRead | CFile::shareExclusive)) { AfxMessageBox("Cann't open image file!"); return; } // get mem unsigned fsize; fsize =if_hnd.GetLength();// BYTE *ScreenPtr1=0; ScreenPtr1=(BYTE *)new char[fsize]; // // read all in if_hnd.Read(ScreenPtr1,fsize);// // image data are in buffer if(if_hnd) if_hnd.Close(); #if 1 //def USE_API // fast way ! // make bitmap info LPBITMAPINFO pBMPinfo; pBMPinfo=(LPBITMAPINFO)new BYTE[sizeof(BITMAPINFOHEADER)+16*sizeof(RGBQUAD)]; ZeroMemory(&pBMPinfo->bmiHeader,sizeof(BITMAPINFOHEADER)); pBMPinfo->bmiHeader.biSize=sizeof(BITMAPINFOHEADER); pBMPinfo->bmiHeader.biBitCount=4; pBMPinfo->bmiHeader.biWidth=648; pBMPinfo->bmiHeader.biHeight=508; pBMPinfo->bmiHeader.biPlanes=1; pBMPinfo->bmiHeader.biSizeImage=648*508/2; // copy colors for(int jj=0; jj<16; jj++) {// reversed ! pBMPinfo->bmiColors[jj].rgbReserved=0; pBMPinfo->bmiColors[jj].rgbRed=(BYTE)(color_table[jj] & 0x0000FF); pBMPinfo->bmiColors[jj].rgbGreen=(BYTE)((color_table[jj] & 0x00FF00) >> 8); pBMPinfo->bmiColors[jj].rgbBlue=(BYTE)((color_table[jj] & 0xFF0000) >> 16); } // draw bmp pDC->SetStretchBltMode(COLORONCOLOR); StretchDIBits(pDC->GetSafeHdc(),0,0,wid,hei,0,0,wid,hei, ScreenPtr1, pBMPinfo, DIB_RGB_COLORS,SRCCOPY); // free delete pBMPinfo; delete [] ScreenPtr1; return; #endif }
dyycdyyc 2013-07-05
  • 打赏
  • 举报
回复
引用 1 楼 zongran 的回复:
bool CDib::Draw(CDC* pDC, int X, int Y, int Width, int Height, int MODE) { if(m_pDibData == NULL) return false; if(Width == -1) Width = m_BMPIH.biWidth; if(Height == -1) Height = m_BMPIH.biHeight; //if(m_pDibFile != NULL) //目标CDC的色板没有做改动,参数DIB_PAL_COLORS表示BITMAPINFO中已包含调色板 //m_pDibFile为除去文件头后的文件数据,包含信息头与彩色表 pDC->SetStretchBltMode(COLORONCOLOR); StretchDIBits(pDC->m_hDC, X, Y, Width, Height, 0, 0, m_BMPIH.biWidth, m_BMPIH.biHeight, m_pDibData, (BITMAPINFO*)m_pDibFile, DIB_PAL_COLORS, MODE); return true; }
加了这一行也没有用,运行结果是一样的。 这……我用的函数是StretchDIBits不是StretchBlt,后者我不会用,我只有像素矩阵没有对应的CDC类……
zongran 2013-07-04
  • 打赏
  • 举报
回复
bool CDib::Draw(CDC* pDC, int X, int Y, int Width, int Height, int MODE) { if(m_pDibData == NULL) return false; if(Width == -1) Width = m_BMPIH.biWidth; if(Height == -1) Height = m_BMPIH.biHeight; //if(m_pDibFile != NULL) //目标CDC的色板没有做改动,参数DIB_PAL_COLORS表示BITMAPINFO中已包含调色板 //m_pDibFile为除去文件头后的文件数据,包含信息头与彩色表 pDC->SetStretchBltMode(COLORONCOLOR); StretchDIBits(pDC->m_hDC, X, Y, Width, Height, 0, 0, m_BMPIH.biWidth, m_BMPIH.biHeight, m_pDibData, (BITMAPINFO*)m_pDibFile, DIB_PAL_COLORS, MODE); return true; }

19,468

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧