如题,先有基于MFC渲染的一个OpenGL场景,需要保存成图片,需要做成想平时各种软件狗保存时那样,可以在保存时弹出文件对话框,自主选择路径和文件名和格式等,求有好心的大神提供一份完整的代码,小弟感激不尽!!

解决方案 »

  1.   

    参考
    保存为 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");
    }
      

  2.   


    writeBMP是什么东东
      

  3.   


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

  4.   

    不太懂你这个函数   out_file.Open(filename,CFile::modeCreate | CFile::modeWrite); 第一个参数报错,我强制转换后 程序可以运行,但是不知道保存在哪的,而且我想要想GDI里面调用DoModal那样保存的时候弹出对话框,选择路径和文件名, 还请您费费心,谢谢了
      

  5.   

    ///////////////////////////////////////////////////
    // save
    void CxxxxDlg::OnButton2() 
    {
    // TODO: Add your control notification handler code here
    if(ScreenShot("Gl.bmp")) AfxMessageBox("Gl.bmp saved");
    }
      

  6.   

    filename 就是 save 后 文件名。
    如果 是 Unicode 版本,要 使用 
    ScreenShot(L"Gl.bmp");
      

  7.   

    我的代码,前面一个加了有错,后面不加有错,我用的是VC2010旗舰版,一般情况双引号的字符串都是要加L的,但是这个加了有错。
    if(ScreenShot("Gl.bmp")) AfxMessageBox(L"Gl.bmp saved");
    这个是后面函数的错误:
    error C2664: “BOOL CFile::Open(LPCTSTR,UINT,CFileException *)”: 不能将参数 1 从“const char []”转换为“LPCTSTR”,代码什么都没改。
      

  8.   

    writeBMP(const char filename[], 这里 要 改 WCHAR 
      

  9.   

    "保存后的图片打开显示图片错误"
    用 “画图” 打开看看。用通用的方法(与 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");
    }
      

  10.   

    前一个方法 在 vc6 win7 上 的 “画图“ 打开是没问题的 !
      

  11.   

    据说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;
    }
      

  12.   

    有一句
    dwBmBitsSize = ((Bitmap.bmWidth*wBitCount+31)/32)*4*Bitmap.bmHeight; 
      

  13.   

    前一种
    header.bfSize = h*(w*3+31)/32*4 + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); 
    // header.bfSize = w*h*3 + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
      

  14.   

    纠正15楼代码第7行
     int alinepixelsbytescount=(w*3+31)/32*4;
    应改为
     int alinepixelsbytescount=(w*3+3)/4*4;
      

  15.   

    1.看看
    lImageSize = iViewport[2] * iViewport[3] * 3;// = w*h*3
    这句有没有问题
    2. 把窗口 w 设置为 4的倍数