如題,先有基于MFC渲染的一個OpenGL場景,需要保存成圖片,需要做成想平時各種軟體狗保存時那樣,可以在保存時彈出檔案對話框,自主選擇路徑和檔案名和格式等,求有好心的大神提供一份完整的代碼,小弟感激不盡!!
uj5u.com熱心網友回復:
求好心的大神給一個代碼,最近都要崩潰了,網上各種零零亂亂的說的挺多的,不太懂 現在時間來不及了,只好求一個完整的代碼,我的郵箱[email protected]uj5u.com熱心網友回復:
參考保存為 bmp 的
//
bool ScreenShot(const char* filename)
{
GLenum lastBuffer;
GLbyte* pBits = 0; // data
unsigned long lImageSize;
GLint iViewport[4]; // view
glGetIntegerv(GL_VIEWPORT, iViewport);
lImageSize = iViewport[2] * iViewport[3] * 3;
pBits = (GLbyte*)new unsigned char[lImageSize];
if (!pBits) return false;
// 從color buffer中讀取資料
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glPixelStorei(GL_PACK_SKIP_ROWS, 0);
glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
//
glGetIntegerv(GL_READ_BUFFER, (GLint*)&lastBuffer);
glReadBuffer(GL_FRONT);
glReadPixels(0, 0, iViewport[2], iViewport[3], GL_BGR_EXT, GL_UNSIGNED_BYTE, pBits);
glReadBuffer(lastBuffer);
if (writeBMP(filename,(unsigned char*)pBits,iViewport[2],iViewport[3])) return true;
return false;
}
///////////////////////////////////////////////////
// save
void CxxxxDlg::OnButton2()
{
// TODO: Add your control notification handler code here
if(ScreenShot("Gl.bmp")) AfxMessageBox("Gl.bmp saved");
}
uj5u.com熱心網友回復:
學習了!
uj5u.com熱心網友回復:
writeBMP是什么東東
uj5u.com熱心網友回復:
bool writeBMP(const char filename[], unsigned char* data, unsigned int w, unsigned int h)
{
/** 創建位圖檔案資訊和位圖檔案頭結構 */
BITMAPFILEHEADER header;
BITMAPINFOHEADER bitmapInfoHeader;
/** 填充BITMAPFILEHEADER */
header.bfType = 0x4d42;// 'BM'
header.bfSize = w*h*3 + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
header.bfReserved1 = 0;
header.bfReserved2 = 0;
header.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
/** 寫入位圖檔案頭資訊 */
CFile out_file;
out_file.Open(filename,CFile::modeCreate | CFile::modeWrite);
out_file.Write((char*)&header, sizeof(BITMAPFILEHEADER));
/** 填充BITMAPINFOHEADER */
bitmapInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapInfoHeader.biWidth = w;
bitmapInfoHeader.biHeight = h;
bitmapInfoHeader.biPlanes = 1;
bitmapInfoHeader.biBitCount = 24;
bitmapInfoHeader.biCompression = BI_RGB; // BI_RLE4 BI_RLE8
bitmapInfoHeader.biSizeImage = w * h * 3; // 當壓縮型別為BI_RGB是也可以設定為0
bitmapInfoHeader.biXPelsPerMeter = 0;
bitmapInfoHeader.biYPelsPerMeter = 0;
bitmapInfoHeader.biClrUsed = 0;
bitmapInfoHeader.biClrImportant = 0;
/** 寫入位圖檔案資訊 */
out_file.Write((char*)&bitmapInfoHeader, sizeof(BITMAPINFOHEADER));
/** 將指標移到資料開始位置 */
out_file.Seek(header.bfOffBits,CFile::begin);
/** 寫入影像資料 */
out_file.Write((char*)data, bitmapInfoHeader.biSizeImage);
out_file.Close();
delete [] data;
return true;
}
uj5u.com熱心網友回復:
不太懂你這個函式 out_file.Open(filename,CFile::modeCreate | CFile::modeWrite); 第一個引數報錯,我強制轉換后 程式可以運行,但是不知道保存在哪的,而且我想要想GDI里面呼叫DoModal那樣保存的時候彈出對話框,選擇路徑和檔案名, 還請您費費心,謝謝了
uj5u.com熱心網友回復:
///////////////////////////////////////////////////// save
void CxxxxDlg::OnButton2()
{
// TODO: Add your control notification handler code here
if(ScreenShot("Gl.bmp")) AfxMessageBox("Gl.bmp saved");
}
uj5u.com熱心網友回復:
filename 就是 save 后 檔案名。如果 是 Unicode 版本,要 使用
ScreenShot(L"Gl.bmp");
uj5u.com熱心網友回復:
我的代碼,前面一個加了有錯,后面不加有錯,我用的是VC2010旗艦版,一般情況雙引號的字串都是要加L的,但是這個加了有錯。
if(ScreenShot("Gl.bmp")) AfxMessageBox(L"Gl.bmp saved");
這個是后面函式的錯誤:
error C2664: “BOOL CFile::Open(LPCTSTR,UINT,CFileException *)”: 不能將引數 1 從“const char []”轉換為“LPCTSTR”,代碼什么都沒改。
uj5u.com熱心網友回復:
writeBMP(const char filename[], 這里 要 改 WCHARuj5u.com熱心網友回復:
我都不好意思再問了,又出問題了,保存后的圖片打開顯示圖片錯誤,這是為什么?又給你添麻煩了
uj5u.com熱心網友回復:
"保存后的圖片打開顯示圖片錯誤"用 “畫圖” 打開看看。
用通用的方法(與 GL 無關) 截圖 是
//
HBITMAP CopyScreenToBitmap(CRect &Rect,HWND hwnd)
{
HDC hScrDC, hMemDC;
HBITMAP hOldBitmap,hBitmap;
int xScrn, yScrn;
// to screen coordinates.
MapWindowPoints(hwnd,NULL,(POINT *)&Rect,2);
hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL);
hMemDC = CreateCompatibleDC(hScrDC);
//
xScrn = GetDeviceCaps(hScrDC, HORZRES);
yScrn = GetDeviceCaps(hScrDC, VERTRES);
//
if (Rect.left < 0) Rect.left = 0;
if (Rect.top < 0) Rect.top = 0;
if (Rect.right > xScrn) Rect.right = xScrn;
if (Rect.bottom > yScrn) Rect.bottom = yScrn;
//
hBitmap = CreateCompatibleBitmap(hScrDC, Rect.Width(),Rect.Height());
hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);
BitBlt(hMemDC,0,0,Rect.Width(),Rect.Height(),hScrDC,Rect.left,Rect.top,SRCCOPY);
hBitmap =(HBITMAP)SelectObject(hMemDC,hOldBitmap);
//
DeleteDC(hScrDC);
DeleteDC(hMemDC);
//
return hBitmap;
}
///////
BOOL SaveBitmapToFile(HBITMAP hBitmap, LPCSTR lpszFileName)
{
HDC hDC; //設備描述表
int iBits; //當前顯示解析度下每個像素所占位元組數
WORD wBitCount; //位圖中每個像素所占位元組數
//定義調色板大小, 位圖中像素位元組大小 , 位圖檔案大小 , 寫入檔案位元組數
DWORD dwPaletteSize=0,dwBmBitsSize,dwDIBSize, dwWritten;
BITMAP Bitmap; //位圖屬性結構
BITMAPFILEHEADER bmfHdr; //位圖檔案頭結構
BITMAPINFOHEADER bi;//位圖資訊頭結構
LPBITMAPINFOHEADER lpbi; //指向位圖資訊頭結構
HANDLE fh, hDib, hPal;
HPALETTE hOldPal=NULL;//定義檔案,分配記憶體句柄,調色板句柄
//計算位圖檔案每個像素所占位元組數
hDC = CreateDC("DISPLAY",NULL,NULL,NULL);
iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES); //?
DeleteDC(hDC);
if (iBits <= 1) wBitCount = 1;
else if (iBits <= 4) wBitCount = 4;
else if (iBits <= 8) wBitCount = 8;
else if (iBits <= 24) wBitCount = 24;
else wBitCount = 32;
//計算調色板大小
if (wBitCount <= 8) dwPaletteSize=(1 << wBitCount)*sizeof(RGBQUAD);
//設定位圖資訊頭結構
GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap);
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = Bitmap.bmWidth;
bi.biHeight = Bitmap.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = wBitCount;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
dwBmBitsSize = ((Bitmap.bmWidth*wBitCount+31)/32)*4*Bitmap.bmHeight;
//為位圖內容分配記憶體
hDib = GlobalAlloc(GHND,dwBmBitsSize+dwPaletteSize+sizeof(BITMAPINFOHEADER));
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
*lpbi = bi;
// 處理調色板
hPal = GetStockObject(DEFAULT_PALETTE);
if (hPal)
{
hDC = ::GetDC(NULL);
hOldPal=SelectPalette(hDC,(HPALETTE)hPal,FALSE);
RealizePalette(hDC);
}
// 獲取該調色板下新的像素值
GetDIBits(hDC,hBitmap,0,(UINT)Bitmap.bmHeight,(LPSTR)lpbi+sizeof(BITMAPINFOHEADER)+dwPaletteSize, (BITMAPINFO *)lpbi,DIB_RGB_COLORS);
//恢復調色板
if (hOldPal)
{
SelectPalette(hDC, hOldPal, TRUE);
RealizePalette(hDC);
::ReleaseDC(NULL, hDC);
}
//創建位圖檔案
fh=CreateFile(lpszFileName, GENERIC_WRITE,0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (fh==INVALID_HANDLE_VALUE) return FALSE;
// 設定位圖檔案頭
bmfHdr.bfType = 0x4D42; // "BM"
dwDIBSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+dwPaletteSize+dwBmBitsSize;
bmfHdr.bfSize = dwDIBSize;
bmfHdr.bfReserved1 = 0;
bmfHdr.bfReserved2 = 0;
bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER)+(DWORD)sizeof(BITMAPINFOHEADER)+dwPaletteSize;
// 寫入位圖檔案頭
WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);
// 寫入位圖檔案其余內容
WriteFile(fh, (LPSTR)lpbi, sizeof(BITMAPINFOHEADER)+dwPaletteSize+dwBmBitsSize , &dwWritten, NULL);
//清除
GlobalUnlock(hDib);
GlobalFree(hDib);
CloseHandle(fh);
return TRUE;
}
呼叫
void CxxxxDlg::OnButton2()
{
// TODO: Add your control notification handler code here
CRect rc;
GetClientRect(rc);
if(SaveBitmapToFile(CopyScreenToBitmap(rc,m_hWnd),"tmpGl.bmp"))
AfxMessageBox("tmpGl.bmp saved");
}
uj5u.com熱心網友回復:
這個函式和我要的差距有點大,他會把覆寫在這個區域上的圖形也截進去,之前那個函式我發現所保存的圖片不能一般的圖片瀏覽器或者畫圖打開,但是可以用VC打開,圖形是沒有錯的,估計就是格式有錯。
uj5u.com熱心網友回復:
前一個方法 在 vc6 win7 上 的 “畫圖“ 打開是沒問題的 !uj5u.com熱心網友回復:
據說bmp每行像素資料的位元組數必須是4的倍數,不足需要補1到3個0:bool writeBMP(const char filename[], unsigned char* data, unsigned int w, unsigned int h) {
/** 創建位圖檔案資訊和位圖檔案頭結構 */
BITMAPFILEHEADER header;
BITMAPINFOHEADER bitmapInfoHeader;
/** 填充BITMAPFILEHEADER */
header.bfType = 0x4d42;// 'BM'
int alinepixelsbytescount=(w*3+31)/32*4;
header.bfSize = alinepixelsbytescount*h + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
header.bfReserved1 = 0;
header.bfReserved2 = 0;
header.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
/** 寫入位圖檔案頭資訊 */
CFile out_file;
out_file.Open(filename,CFile::modeCreate | CFile::modeWrite);
out_file.Write((char*)&header, sizeof(BITMAPFILEHEADER));
/** 填充BITMAPINFOHEADER */
bitmapInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapInfoHeader.biWidth = w;
bitmapInfoHeader.biHeight = h;
bitmapInfoHeader.biPlanes = 1;
bitmapInfoHeader.biBitCount = 24;
bitmapInfoHeader.biCompression = BI_RGB; // BI_RLE4 BI_RLE8
bitmapInfoHeader.biSizeImage = alinepixelsbytescount*h ; // 當壓縮型別為BI_RGB是也可以設定為0
bitmapInfoHeader.biXPelsPerMeter = 0;
bitmapInfoHeader.biYPelsPerMeter = 0;
bitmapInfoHeader.biClrUsed = 0;
bitmapInfoHeader.biClrImportant = 0;
/** 寫入位圖檔案資訊 */
out_file.Write((char*)&bitmapInfoHeader, sizeof(BITMAPINFOHEADER));
/** 將指標移到資料開始位置 */
out_file.Seek(header.bfOffBits,CFile::begin);
/** 寫入影像資料 */
int y;
unsigned char *alinepixels=new unsigned char[alinepixelsbytescount];
memset(alinepixels+alinepixelsbytescount-4,0,4);
for (y=0;y<h;y++) {
memcpy(alinepixels,data+y*w);
out_file.Write((char*)alinepixels, alinepixelsbytescount);
}
out_file.Close();
delete [] alinepixels;
delete [] data;
return true;
}
uj5u.com熱心網友回復:
有一句dwBmBitsSize = ((Bitmap.bmWidth*wBitCount+31)/32)*4*Bitmap.bmHeight;
uj5u.com熱心網友回復:
前一種header.bfSize = h*(w*3+31)/32*4 + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
// header.bfSize = w*h*3 + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
uj5u.com熱心網友回復:
糾正15樓代碼第7行int alinepixelsbytescount=(w*3+31)/32*4;
應改為
int alinepixelsbytescount=(w*3+3)/4*4;
uj5u.com熱心網友回復:
還是不太對啊 保存的圖片使得原來的圖的左邊有一小塊變到右邊去了就像“12345”變成了“”23451這樣的,圖形還有一點形變。。。
uj5u.com熱心網友回復:
1.看看lImageSize = iViewport[2] * iViewport[3] * 3;// = w*h*3
這句有沒有問題
2. 把視窗 w 設定為 4的倍數
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/156104.html
標籤:界面
上一篇:關于windows media player 控制元件的用法
下一篇:畫貝塞爾曲線和曲面問題
