Screen capture desktop

Is there any way to get a screenshot of the desktop and create an Image from it? I've been looking around trying to see how it's done with the Windows API and there are a lot of examples of how to do it in Windows, but I don't know anything about the Windows API and it might be hard figuring out how to create a JUCE Image from it. I haven't looked into the other OSs yet, but you have to start somewhere I guess. I'm hoping there's some mechanism in JUCE that can accomplish this though. It would be even cooler to also have the ability to record the screen, but that's probably much harder. 

So on Windows, I can take a screenshot just fine using HBITMAP. I've tested it by copying it to the system clipboard. The problem now is that I can't convert that to a JUCE Image object. Any ideas on how to do this? I've tried using the function 
createImageFromHBITMAP() from juce_win32_Windowing.cpp, but all I get is a white image. 


I have successfully captured some parts of the screen and converted to JPEG in Windows.

Here some code snippets from my project.  Maybe not the best solution, but it works...

Anybody here to have some hints for OS-X ?.  OS-X is a strange world for me.




   int mWidth  = Desktop::getInstance().getDisplays().getMainDisplay().totalArea.getWidth();    
   int mHeight = Desktop::getInstance().getDisplays().getMainDisplay().totalArea.getHeight();

   HDC       hDesktopDC     = GetDC(0);   // Desktop DC
   HDC       mCaptureDC           = CreateCompatibleDC(hDesktopDC);
   HBITMAP   hCaptureBitmap       = CreateCompatibleBitmap(hDesktopDC, width, height);   
   HBITMAP   hBitmap   = (HBITMAP) SelectObject(mCaptureDC, hCaptureBitmap);

    // The BitBlt function performs a bit-block transfer of the color data corresponding
    //  to a rectangle of pixels from the specified source device context into a
    //  destination device context.

    BitBlt( mCaptureDC,             // A handle to the destination device context.
            0, 0,                              // The x,y-coordinate, in logical units, of the upper-left corner of the destination rectangle.
            width, height,              // The width,height in logical units, of the source and destination rectangles.
            hDesktopDC,               // A handle to the source device context.
            x, y,                            // The x,y-coordinate, in logical units, of the upper-left corner of the source rectangle.
            SRCCOPY | CAPTUREBLT );   // A raster-operation code. These codes define how the color data for the source rectangle
                                                       // is to be combined with the color data for the destination rectangle to achieve the final color.

  BITMAP            bitma p;                                           

  BITMAPINFOHEADER  bi;              
  ZeroMemory ((uint8*)&bi, sizeof(BITMAPINFOHEADER));

  bi.biSize        = sizeof(BITMAPINFOHEADER);   
  bi.biWidth       = mWidth;
  bi.biHeight      = mHeight;
  bi.biPlanes      = 1;
  bi.biBitCount    = DAW_RAW_BIT_COUNT;  
  bi.biCompression = BI_RGB;

 uint8  buffer[  MAX   ] ;                                      
  // The GetDIBits function retrieves the bits of the specified compatible bitmap and copies
  // them into a buffer as a DIB using the specified format.

  GetDIBits(hDestinationDC,       // A handle to the device context
            hBitmap,                        // handle to the bitmap. This must be a compatible bitmap (DDB).
            0,                                   // The first scan line to retrieve  
            mHeight,                       // The number of scan lines to retrieve   
            buffer,                          // A pointer to a buffer to receive the bitmap data
            (BITMAPINFO *)&bi,    // A pointer to a BITMAPINFO structure that specifies the desired format for the DIB data.
            DIB_RGB_COLORS);      // he color table should consist of literal red, green, blue (RGB) value                             

 createJpeg( buffer,  bi.biSizeImage);

 void createJpeg(uint8 * pBuffer, uint32 dwLength)
   ScopedPointer<JPEGImageFormat> jpeg = new JPEGImageFormat();
   if ( jpeg )
     Image image = Image (Image::RGB, mWidth,mHeight, true);
     Image::BitmapData imageData (image, Image::BitmapData::writeOnly);

     // Remember th BMP format for 24 Bit: |B|G|R|   |B|G|R|   ....               

     uint8 * p = pBuffer;
     for (int y = mHeight; --y >= 0;)
       memcpy(imageData.getLinePointer(y), p, imageData.lineStride );
       p += imageData.lineStride ;
     MemoryOutputStream out(dwLength);      
     // jpeg->setQuality( ??? );

      jpeg->writeImageToStream(image,out) )




1 Like

bro, use the Code style tag when you post that stuff lol

Actually, the createImageFromHBITMAP() function from juce_win32_Windowing.cpp does actually work! I just had to make sure that I deleted and released the DC before I actualy called createImageFromHBITMAP(). Maybe because it creates it's own our something. I should try just passing it to that function and handle cleanup from there.

Thanks for your reply elli! I really appreciate you posting your code. I'm going to have to try your way and see which one performs better.

Does anyone have any idea about what I could use in Linux for doing this? On Windows, I can just use the Windows API. I'm not sure what to use for Linux though. I don't want add any extra dependencies that JUCE doesn't already use. 

I'd really appreciate any help from you guys. If I can figure out how to do it on all of the desktop platforms, I'll be sure to share it with the community so anyone else in the future can use it if they need. I think this would be a good feature to add to JUCE too. It seems like most of the other popular graphics frameworks/libraries have a facility for taking screenshots. 

It seems like most of the other popular graphics frameworks/libraries have a facility for taking screenshots. 

Do they? Sounds to me like quite a rare thing for people to want to do in their app! (And surely modern OSes have security restrictions that would stop apps from snapshotting other windows?)

But just to be clear, are you really trying to take an image of the OS desktop, or just your own app's window? Because if it's your own window then the Component class has methods to capture it to an Image.


Yeah, I'm sure it is a rare thing to want. Surprisingly, it seems that they do. The ones I remember seeing mentioned were libraries like Qt, SDL, Cinder, etc. 

Really, it's not a big deal if I figure this out or not. I'm just trying to experiment and make myself a "snipping tool" that lets you take an image of part of the screen. Yeah I know you can capture a component as an image (which is awesome by the way). I just realized that when I was looking into this. 

I’m working in the same direction (purpose: streamlining user manual content creation for my VSTi). GUI libraries often have such capability not because its popularity but because, on the lowest level, rendering a component to a image memory container (later encoded to an image format, e.g. JPEG) or to screen - is ~same thing. I’ll dig around juce::LowLevelGraphicsContext, juce::Drawable … ang generally in juce::gui_basics & juce::graphics namespaces. It shouldn’t be that hard to make a screenshot utility class. I’ll post here any progress.

While the API wasn’t mentioned directly, are you aware of:

 Image Component::createComponentSnapshot(Rectangle< int > areaToGrab, bool clipImageToComponentBounds=true, float scaleFactor=1.0f)

OS X and Windows both have a really easy way to take screenshots of app windows. Why can’t you just use that? on OS X it’s Cmd-Shift-3 to do the whole desktop, and CMD-shift-4 + Spacebar to take a screenshot of whatever app window is under the cursor. you can also do Cmd-Shift-4 and then click-drag to take a screenshot of an area on screen.

Your reply is real answer to the question.
Something like this would be implementation:

	auto editor = synthProcessor->getActiveEditor();
	auto editorRectangle = editor->getBounds();
	auto image = editor->createComponentSnapshot(editorRectangle, true);
	String filePath = File::getCurrentWorkingDirectory().getFullPathName();
	File outFile(filePath + "temp.jpg");

	JPEGImageFormat jpegFormat = JPEGImageFormat();
	juce::FileOutputStream * s = outFile.createOutputStream(500000);

	jpegFormat.writeImageToStream(image, *s);

Edit: just tested - WORKS :slight_smile:
Edit 2: implemented @Achder’s memory leak warrning. Read his reply below for other important comments.

1 Like

That’s a memory leak right there.
Just use:

File outFile(filePath + “temp.jpg”);

And with regards to this line:

It says in the documentation:

Note that this is an old method, and actually it’s usually best to avoid it and instead use an RAII pattern with an FileOutputStream directly, e.g.

1 Like

Oh! I’m coming from C# - that “new” wasn’t meant as C++ new :slight_smile: Thanks for tip, I’ll update my answer with your suggestion. THANKS!

1 Like
1 Like