How to snap an OpenGL client and send it to the clipboard

This article demonstrates how to snap an OpenGL client and send it to ClipBoard.
We suppose your screen configuration is set to true color.
We could send the same buffer in a .bmp file in a few lines too....

// Snap OpenGL client and send it to ClipBoard
// so that you can insert it in your favorite
// image editor, Powerpoint, etc...
// Replace CRenderView by your own CView-derived class
void CRenderView::SnapClient()
{
 BeginWaitCursor();

 // Get client geometry
 CRect rect;
 GetClientRect(&rect);
 CSize size(rect.Width(),rect.Height());
 TRACE("  client zone : (%d;%d)\n",size.cx,size.cy);
 // Lines have to be 32 bytes aligned, suppose 24 bits per pixel
 // I just cropped it
 size.cx -= size.cx % 4;
 TRACE("  final client zone : (%d;%d)\n",size.cx,size.cy);

 // Create a bitmap and select it in the device context
 // Note that this will never be used ;-) but no matter
 CBitmap bitmap;
 CDC *pDC = GetDC();
 CDC MemDC;
 ASSERT(MemDC.CreateCompatibleDC(NULL));
 ASSERT(bitmap.CreateCompatibleBitmap(pDC,size.cx,size.cy));
 MemDC.SelectObject(&bitmap);

 // Alloc pixel bytes
 int NbBytes = 3 * size.cx * size.cy;
 unsigned char *pPixelData = new unsigned char[NbBytes];

 // Copy from OpenGL
 ::glReadPixels(0,0,size.cx,size.cy,GL_RGB,GL_UNSIGNED_BYTE,pPixelData);

 // Fill header
 BITMAPINFOHEADER header;
 header.biWidth = size.cx;
 header.biHeight = size.cy;
 header.biSizeImage = NbBytes;
 header.biSize = 40;
 header.biPlanes = 1;
 header.biBitCount =  3 * 8; // RGB
 header.biCompression = 0;
 header.biXPelsPerMeter = 0;
 header.biYPelsPerMeter = 0;
 header.biClrUsed = 0;
 header.biClrImportant = 0;

 // Generate handle
 HANDLE handle = (HANDLE)::GlobalAlloc (GHND,sizeof(BITMAPINFOHEADER) + NbBytes);
 if(handle != NULL)
 {
  // Lock handle
  char *pData = (char *) ::GlobalLock((HGLOBAL)handle);
  // Copy header and data
  memcpy(pData,&header,sizeof(BITMAPINFOHEADER));
  memcpy(pData+sizeof(BITMAPINFOHEADER),pPixelData,NbBytes);
  // Unlock
  ::GlobalUnlock((HGLOBAL)handle);

  // Push DIB in clipboard
  OpenClipboard();
  EmptyClipboard();
  SetClipboardData(CF_DIB,handle);
  CloseClipboard();
 }

 // Cleanup
 MemDC.DeleteDC();
 bitmap.DeleteObject();
 delete [] pPixelData;

 EndWaitCursor();
}
 
 



Comments

  • Gray box, still.

    Posted by Legacy on 10/20/2003 12:00am

    Originally posted by: Russ Lewis

    Here's my copy of this solution, however I still
    get the Gray box on the paste operation to mspaint. Any ideas/suggestions?

    wglMakeCurrent() returns FALSE but the extended error
    message returns "The operation completed successfully."

    according to Platform SDK: OpenGL --
    When the wglMakeCurrent function succeeds, the return value is TRUE; otherwise the return value is FALSE.

    what's up with this?

    thanks for any help.

    void CSimpleSDIGLView::SnapClient()
    {
    BeginWaitCursor();

    // Get client geometry
    CRect rect;
    GetClientRect(&rect);
    CSize size(rect.Width(),rect.Height());
    TRACE(" client zone : (%d;%d)\n",size.cx,size.cy);
    // Lines have to be 32 bytes aligned, suppose 24 bits per pixel
    // I just cropped it
    size.cx -= size.cx % 4;
    TRACE(" final client zone : (%d;%d)\n",size.cx,size.cy);

    // Create a bitmap and select it in the device context
    // Note that this will never be used ;-) but no matter
    CBitmap bitmap;
    CDC *pDC = GetDC();
    CDC MemDC;
    VERIFY(MemDC.CreateCompatibleDC(NULL));
    VERIFY(bitmap.CreateCompatibleBitmap(pDC,size.cx,size.cy));
    MemDC.SelectObject(&bitmap);

    // Alloc pixel bytes
    int NbBytes = 3 * size.cx * size.cy;
    unsigned char *pPixelData = new unsigned char[NbBytes];
    if( FALSE == wglMakeCurrent(m_OpenGLCtrl.getDC(), m_OpenGLCtrl.getRC()))
    {
    AfxMessageBox("FALSE from wglMakeCurrent");
    LPVOID lpMsgBuf;
    FormatMessage(
    FORMAT_MESSAGE_ALLOCATE_BUFFER |
    FORMAT_MESSAGE_FROM_SYSTEM |
    FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL,
    GetLastError(),
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
    (LPTSTR) &lpMsgBuf,
    0,
    NULL
    );
    // Process any inserts in lpMsgBuf.
    // ...
    // Display the string.
    AfxMessageBox( (LPCTSTR)lpMsgBuf);
    // Free the buffer.
    LocalFree( lpMsgBuf );
    }


    // Copy from OpenGL
    ::glReadPixels(0,0,size.cx,size.cy,GL_BGR_EXT,GL_UNSIGNED_BYTE,pPixelData);

    // Fill header
    BITMAPINFOHEADER header;
    header.biWidth = size.cx;
    header.biHeight = size.cy;
    header.biSizeImage = NbBytes;
    header.biSize = 40;
    header.biPlanes = 1;
    header.biBitCount = 3 * 8; // RGB
    header.biCompression = 0;
    header.biXPelsPerMeter = 0;
    header.biYPelsPerMeter = 0;
    header.biClrUsed = 0;
    header.biClrImportant = 0;

    // Generate handle
    HANDLE handle = (HANDLE)::GlobalAlloc (GHND,sizeof(BITMAPINFOHEADER) + NbBytes);
    if(handle != NULL)
    {
    // Lock handle
    char *pData = (char *) ::GlobalLock((HGLOBAL)handle);
    // Copy header and data
    memcpy(pData,&header,sizeof(BITMAPINFOHEADER));
    memcpy(pData+sizeof(BITMAPINFOHEADER),pPixelData,NbBytes);
    // Unlock
    ::GlobalUnlock((HGLOBAL)handle);

    // Push DIB in clipboard
    OpenClipboard();
    EmptyClipboard();
    SetClipboardData(CF_DIB,handle);
    CloseClipboard();
    }

    // Cleanup
    MemDC.DeleteDC();
    bitmap.DeleteObject();
    delete [] pPixelData;

    EndWaitCursor();
    }

    • Mr

      Posted by Phil O on 06/06/2014 05:59am

      If you're getting the grey box, the glReadPixels isn't working and that may be because you've not loaded a valid context using wglMakeCurrent().

      Reply
    Reply
  • How can I save a graphic as a JPG file?

    Posted by Legacy on 10/17/2002 12:00am

    Originally posted by: Shujie

    I use VC++ and OpenGL. I want to save a graphic as a JPG file. How can I do it?
    Thanks!

    Reply
  • How can I capture screen into OpenGL?

    Posted by Legacy on 02/21/2002 12:00am

    Originally posted by: Miguel

    Can you help me in the following thing.?
    I need to capture the total screen, without having to use the BitBlt(...) function because this it takes a long time 450 mseg approximately. Does exists some method in OpenGL to make it. Or otherwise, witch library I should to use?.
    Thank you.

    Miguel

    Reply
  • I want download thisfile

    Posted by Legacy on 11/12/2001 12:00am

    Originally posted by: lee


    Please send to me thisfile(facedrawing)

    Reply
  • 10x for the article + a question

    Posted by Legacy on 08/01/2001 12:00am

    Originally posted by: Eyal Ron

    How can I get the from the clipboard
    
    and print it?

    Here is what I've tried:
    OpenClipboard();
    HGLOBAL global = (HGLOBAL)GetClipboardData(CF_DIB);
    BITMAPINFOHEADER* bmpHeader = (LPBITMAPINFOHEADER)global;
    BITMAPINFO* bmpInfo = (LPBITMAPINFO)global;
    EmptyClipboard();
    CloseClipboard();

    int nColors = bmpHeader->biClrUsed ? bmpHeader->biClrUsed : 1 << bmpHeader->biBitCount;

    LPVOID lpDIBBits;
    if (bmpInfo->bmiHeader.biBitCount>8)
    lpDIBBits = (LPVOID)((LPDWORD)(bmpInfo->bmiColors + bmpInfo->bmiHeader.biClrUsed) + ((bmpInfo->bmiHeader.biCompression==BI_BITFIELDS) ? 3 : 0));
    else
    lpDIBBits = (LPVOID)(bmpInfo->bmiColors + nColors);

    CDC bmpDC;
    bmpDC.CreateCompatibleDC(dc);
    HBITMAP hBitmap = CreateDIBitmap(bmpDC.m_hDC, bmpHeader, CBM_INIT, lpDIBBits, bmpInfo, DIB_RGB_COLORS);
    if (hBitmap==NULL) return;

    dc->StartDoc(&docinfo);
    dc->StartPage();
    dc->BitBlt(0, 0, 500, 500, &bmpDC, 0, 0, SRCCOPY);
    dc->EndPage();
    dc->EndDoc();

    ::GlobalFree(global);
    // bmpDC.SelectObject(pOldBmp);
    bmpDC.DeleteDC();
    dc->SelectObject(pOldFont);
    delete printDlg;
    DeleteDC(hDc);
    dc->Detach();
    dc->DeleteDC();

    |Nothing is printed. What am I doing wrong?

    Reply
  • Not Work On Win'98

    Posted by Legacy on 06/07/2001 12:00am

    Originally posted by: Sanjay S. Bora

    Very Good Article. It helped me lot.
    
    But it doesnt work on Win'98.

    Regds & Thanks

    Sanjay


    Reply
  • Thanks for fine article and one question !

    Posted by Legacy on 04/27/2001 12:00am

    Originally posted by: Armen

    I am admirer of your great articles both in CodeGuru and
    CodeProject sites.
    How can i get this sourse code with workspace ?

    Reply
  • How can I Pick/Select control points from mesh on drawing

    Posted by Legacy on 12/28/2000 12:00am

    Originally posted by: Wu Peng

    
    

    Thank you for your article demonstrations, it is very helpful to everyone who interest in OpenGL programming,I think.
    I have not good idea on how to pick some control points of polygon meshes on MFC+OpenGL environment. Would you like to
    give some suggestion if you have time? It will be very thankful if I can get a demo project about this problem?
    Regards,Thanks!

    Reply
  • Shall get I this source code with workspace?

    Posted by Legacy on 10/17/2000 12:00am

    Originally posted by: Anbumani

    Hello, the image file diplayed in this article shoing that it not just as saving into jpg. In left side ofthe splliter window..i am seeing a sphere in 3D..I dont thing so that as an image..what i am feling is, it's a 3D object, may be that window also itself an openGL window..how ot make it? and how to place it?

    Thankx in advance.
    anbumani@india.com

    Reply
  • How can I save to BMP file directly from opengl buffer ?

    Posted by Legacy on 10/19/1999 12:00am

    Originally posted by: guaguo

    How can I save to BMP file directly from opengl buffer ?
    thank you!

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
  • The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
  • Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date