views:

178

answers:

5

I want to read a rectangular area, or whole screen pixels. As if screenshot button was pressed.

How i do this?

Edit: Working code:

void CaptureScreen(char *filename)
{
    int nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
    int nScreenHeight = GetSystemMetrics(SM_CYSCREEN);
    HWND hDesktopWnd = GetDesktopWindow();
    HDC hDesktopDC = GetDC(hDesktopWnd);
    HDC hCaptureDC = CreateCompatibleDC(hDesktopDC);
    HBITMAP hCaptureBitmap = CreateCompatibleBitmap(hDesktopDC, nScreenWidth, nScreenHeight);
    SelectObject(hCaptureDC, hCaptureBitmap); 

    BitBlt(hCaptureDC, 0, 0, nScreenWidth, nScreenHeight, hDesktopDC, 0,0, SRCCOPY|CAPTUREBLT); 

    BITMAPINFO bmi = {0}; 
    bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); 
    bmi.bmiHeader.biWidth = nScreenWidth; 
    bmi.bmiHeader.biHeight = nScreenHeight; 
    bmi.bmiHeader.biPlanes = 1; 
    bmi.bmiHeader.biBitCount = 32; 
    bmi.bmiHeader.biCompression = BI_RGB; 

    RGBQUAD *pPixels = new RGBQUAD[nScreenWidth * nScreenHeight]; 

    GetDIBits(
        hCaptureDC, 
        hCaptureBitmap, 
        0,  
        nScreenHeight,  
        pPixels, 
        &bmi,  
        DIB_RGB_COLORS
    );  

    // write:
    int p;
    int x, y;
    FILE *fp = fopen(filename, "wb");
    for(y = 0; y < nScreenHeight; y++){
        for(x = 0; x < nScreenWidth; x++){
            p = (nScreenHeight-y-1)*nScreenWidth+x; // upside down
            unsigned char r = pPixels[p].rgbRed;
            unsigned char g = pPixels[p].rgbGreen;
            unsigned char b = pPixels[p].rgbBlue;
            fwrite(fp, &r, 1);
            fwrite(fp, &g, 1);
            fwrite(fp, &b, 1);
        }
    }
    fclose(fp);

    delete [] pPixels; 

    ReleaseDC(hDesktopWnd, hDesktopDC);
    DeleteDC(hCaptureDC);
    DeleteObject(hCaptureBitmap);
}
+3  A: 

Start here Various methods for capturing the screen

Martin Beckett
How do i access the memory it copied in the first example function? i tried to output the value of hCaptureBitmap[0] but it crashes.
Newbie
@Newbie: Use `GetDIBits` to get the pixels from the device-dependent bitmap into a device-independent bitmap. You can then access the pixels from that. Alternatively, you can create a DIB section bitmap and use that for the initial capture.
Adrian McCarthy
the function definition is total gibberish to me. theres tons of keywords i have no idea what they mean... i would have to google recursively from each keyword to another to understand it completely, that will take weeks. so... i am kinda busy now with other problems, i dont have time for that now. If you want, you can answer to this question and offer a working piece of code, then i can just accept it as correct answer and be thankful.
Newbie
+2  A: 

You make a screenshot with BitBlt(). The size of the shot is set with the nWidth and nHeight arguments. The upper left corner is set with the nXSrc and nYSrc arguments.

Hans Passant
A: 

HBITMAP is not a pointer or an array, it is a handle that is managed by Windows and has meaning only to Windows. You must ask Windows to copy the pixels somewhere for use.

To get an individual pixel value, you can use GetPixel without even needing a bitmap. This will be slow if you need to access many pixels.

To copy a bitmap to memory you can access, use the GetDIBits function.

Mark Ransom
A: 

Rereading your question, it sounds like we may have gotten off on a tangent with the screen capture. If you just want to check some pixels on the screen, you can use GetPixel.

HDC hdcScreen = ::GetDC(NULL);
COLORREF pixel = ::GetPixel(hdcScreen, x, y);
ReleaseDC(NULL, hdcScreen);
if (pixel != CLR_INVALID) {
  int red = GetRValue(pixel);
  int green = GetGValue(pixel);
  int blue = GetBValue(pixel);
  ...
} else {
  // Error, x and y were outside the clipping region.
}

If you're going to read a lot of pixels, then you're better off with a screen capture and then using GetDIBits. Calling GetPixel zillions of times will be slow.

Adrian McCarthy
yeah i want to read a rectangle of pixels (or whole screen at once if its any easier). I dont know how to use that GetDIBits function, i couldnt understand any of the terms for parameters, i have no idea how it works.
Newbie
I got your function to work, but i would like to use more efficient way for reading more than 1 pixel. I cant get to work this GetDIBits function.
Newbie
A: 

Starting with your code and omitted error checking ...

// Create a BITMAPINFO specifying the format you want the pixels in.
// To keep this simple, we'll use 32-bits per pixel (the high byte isn't
// used).
BITMAPINFO bmi = {0};
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
bmi.bmiHeader.biWidth = nScreenWidth;
bmi.bmiHeader.biHeight = nScreenHeight;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;

// Allocate a buffer to receive the pixel data.
RGBQUAD *pPixels = new RGBQUAD[nScreenWidth * nScreenHeight];

// Call GetDIBits to copy the bits from the device dependent bitmap
// into the buffer allocated above, using the pixel format you
// chose in the BITMAPINFO.
::GetDIBits(hCaptureDC,
            hCaptureBitmap,
            0,  // starting scanline
            nScreenHeight,  // scanlines to copy
            pPixels,  // buffer for your copy of the pixels
            &bmi,  // format you want the data in
            DIB_RGB_COLORS);  // actual pixels, not palette references

// You can now access the raw pixel data in pPixels.  Note that they are
// stored from the bottom scanline to the top, so pPixels[0] is the lower
// left pixel, pPixels[1] is the next pixel to the right,
// pPixels[nScreenWidth] is the first pixel on the second row from the
// bottom, etc.

// Don't forget to free the pixel buffer.
delete [] pPixels;
Adrian McCarthy
what i put for hCaptureBitmap ?
Newbie
Also, what window HDC i put there, my desktop or my program own window?
Newbie
Look at my edits, i updated my code, what is wrong with it?
Newbie
Why did you delete the capture code you had originally? What I posted was supposed to be _added_ to what you had, not replaced it. That's why I used your variable names for `hCaptureBitmap` and `hCaptureDC`.
Adrian McCarthy
oh shit. lol. takes a while to search the code again >_>
Newbie
Found the code, now i updated, and STILL its returning black image
Newbie
Your missing the BitBlt from the original code.
Adrian McCarthy
ah, thanks, it works now!
Newbie