2010-04-17 3 views
11

Ich möchte einen rechteckigen Bereich oder ganze Bildschirmpixel lesen. Als ob die Schaltfläche "Screenshot" gedrückt wurde.Wie liest man die Bildschirmpixel?

Wie mache ich das?

Edit: Arbeitscode:

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); 
} 
+1

Vergessen Sie nicht, Antworten zu akzeptieren, wenn sie Ihnen helfen. – Johnsyweb

+0

Ich weiß, ich habe noch nicht funktioniert – Newbie

+0

Vielleicht müssen Sie ein wenig mehr Informationen hinzufügen, wie zum Beispiel was Sie versucht haben und was scheitert. – Johnsyweb

Antwort

7

Beginnend mit Ihrem Code und Weglassen Fehlerprüfung ...

// 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; 
+0

was stelle ich für hCaptureBitmap? – Newbie

+0

Auch, welches Fenster HDC habe ich dort, meinen Desktop oder mein eigenes Programmfenster? – Newbie

+0

Sieh dir meine Änderungen an, ich habe meinen Code aktualisiert, was ist falsch daran? – Newbie

6
+0

Wie kann ich auf den Speicher zugreifen, der in der ersten Beispielfunktion kopiert wurde? Ich habe versucht, den Wert von hCaptureBitmap [0] auszugeben, aber es stürzt ab. – Newbie

+1

@Newbie: Verwenden Sie 'GetDIBits', um die Pixel aus der geräteabhängigen Bitmap in eine geräteunabhängige Bitmap zu übertragen. Sie können dann auf die Pixel zugreifen. Alternativ können Sie eine Bitmap für DIB-Abschnitte erstellen und diese für die Erstaufnahme verwenden. –

+0

die Funktionsdefinition ist total Kauderwelsch für mich. Es gibt Tonnen von Schlüsselwörtern ich habe keine Idee, was sie bedeuten ... ich würde rekursiv von jedem Schlüsselwort zum anderen googeln müssen, um es völlig zu verstehen, das Wochen dauern wird. also ... ich bin jetzt ziemlich beschäftigt mit anderen Problemen, ich habe jetzt keine Zeit dafür. Wenn Sie wollen, können Sie auf diese Frage antworten und ein funktionierendes Stück Code anbieten, dann kann ich es einfach als richtige Antwort akzeptieren und dankbar sein. – Newbie

2

Sie machen einen Screenshot mit BitBlt(). Die Größe der Aufnahme wird mit den Argumenten nWidth und nHeight festgelegt. Die obere linke Ecke wird mit den Argumenten nXSrc und nYSrc gesetzt.

0

HBITMAP ist kein Zeiger oder Array, es ist ein Handle, das von Windows verwaltet wird und nur für Windows Bedeutung hat. Sie müssen Windows bitten, die Pixel irgendwo zur Verwendung zu kopieren.

Um einen individuellen Pixelwert zu erhalten, können Sie GetPixel verwenden, ohne auch nur eine Bitmap zu benötigen. Dies wird langsam, wenn Sie auf viele Pixel zugreifen müssen.

Um eine Bitmap in den Speicher zu kopieren, auf die Sie zugreifen können, verwenden Sie die GetDIBits function.

2

Wenn Sie Ihre Frage erneut lesen, klingt es, als hätten wir eine Tangente mit der Bildschirmaufnahme erhalten. Wenn Sie nur einige Pixel auf dem Bildschirm überprüfen möchten, können Sie GetPixel verwenden.

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

Wenn Sie eine Menge von Pixeln lesen werden, dann bist du mit einem Screen-Capture besser und dann GetDIBits verwenden. Rufen Sie GetPixel Zillionen von Mal wird langsam sein.

+0

Ja, ich möchte ein Rechteck von Pixeln lesen (oder den ganzen Bildschirm auf einmal, wenn es einfacher ist). Ich weiß nicht, wie man diese GetDIBits Funktion benutzt, ich konnte irgendeinen der Ausdrücke für Parameter nicht verstehen, ich habe keine Idee, wie es funktioniert. – Newbie

+0

Ich habe Ihre Funktion zu arbeiten, aber ich möchte effizienter verwenden, um mehr als 1 Pixel zu lesen. Ich kann diese GetDIBits-Funktion nicht ausführen. – Newbie