Capture the Screen into a Bitmap

Capture the Screen into a Bitmap

If using the .NET 2.0 (or later) framework you can use the CopyFromScreen() method detailed here:

http://www.geekpedia.com/tutorial181_Capturing-screenshots-using-Csharp.html

//Create a new bitmap.
var bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
Screen.PrimaryScreen.Bounds.Height,
PixelFormat.Format32bppArgb);

// Create a graphics object from the bitmap.
var gfxScreenshot = Graphics.FromImage(bmpScreenshot);

// Take the screenshot from the upper left corner to the right bottom corner.
gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
Screen.PrimaryScreen.Bounds.Y,
0,
0,
Screen.PrimaryScreen.Bounds.Size,
CopyPixelOperation.SourceCopy);

// Save the screenshot to the specified path that the user has chosen.
bmpScreenshot.Save("Screenshot.png", ImageFormat.Png);

c# - Trying to capture screen using bitmap

You must capture the screen before getting color. Try this:

public static string Getcolor()
{
Bitmap screen = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
Graphics captureGraphics = Graphics.FromImage(screen);
captureGraphics.CopyFromScreen(0, 0, 0, 0, new Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height));
Color getcolor = screen.GetPixel(GetMousePositionWindowsForms().X-1, GetMousePositionWindowsForms().Y-1);
return Convert.ToString(getcolor);
}

C++ screen capture - how to read the bitmap?

You are forcing the compression to be BI_RGB, you might as well set the first 6 values and call GetDIBits only once. And since the bitmap height starts from bottom to top you have to supply negative height for BITMAPINFOHEADER otherwise read from bottom to top.

Make sure the process is DPI aware. Easiest way (but not the preferred way) is to call SetProcessDPIAware(). For each hBitmap allocation call DeleteObject(hBitmap)

int main()
{
SetProcessDPIAware();
int width = GetSystemMetrics(SM_CXSCREEN);
int height = GetSystemMetrics(SM_CYSCREEN);
while(!GetAsyncKeyState(VK_SPACE))
{
HDC hdc = GetDC(0);
POINT p;
GetCursorPos(&p);

HDC memdc = CreateCompatibleDC(hdc);
HBITMAP hbitmap = CreateCompatibleBitmap(hdc, width, height);
HGDIOBJ oldbmp = SelectObject(memdc, hbitmap);
BitBlt(memdc, 0, 0, width, height, hdc, 0, 0, SRCCOPY | CAPTUREBLT);
SelectObject(memdc, oldbmp);
DeleteDC(memdc);

//use GetPixel for testing
COLORREF c = GetPixel(hdc, p.x, p.y);
printf("%02X%02X%02X\n", GetRValue(c), GetGValue(c), GetBValue(c));

BITMAPINFO bi = { 0 };
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
bi.bmiHeader.biWidth = width;
bi.bmiHeader.biHeight = -height;
bi.bmiHeader.biBitCount = 32; //32-bit bitmap
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biCompression = BI_RGB;

//allocate 4 bytes per pixel for 32-bit
BYTE* lpPixels = new BYTE[height * width * 4];
if(0 != GetDIBits(hdc, hbitmap, 0, height, lpPixels,
&bi, DIB_RGB_COLORS))
{
int i = (p.y * width + p.x) * 4;
printf("%02X%02X%02X\n\n",
lpPixels[i + 2], lpPixels[i + 1], lpPixels[i + 0]);
}
DeleteObject(hbitmap);
ReleaseDC(NULL, hdc);
delete[] lpPixels;
Sleep(1000);
}
return 0;
}

How to take screenshot of complete desktop Windows c#

This should work fine for you, duplicate question here

Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, 
Screen.PrimaryScreen.Bounds.Height);
Graphics graphics = Graphics.FromImage(bitmap as Image);
graphics.CopyFromScreen(0, 0, 0, 0, bitmap.Size);

Take screenshot and show it in form

A Graphics object is a sort of wrapper around an image that lets you draw on the image. They are usually temporary, and don't actually own the pixels that you're drawing.

In your case, gfxScreenshot is just providing the ability to draw onto bmpScreenshot, which is where the image actually lives in memory.

You should throw away the Graphics and return the Bitmap:

private Bitmap TakeScreenshot()
{
//Create a new bitmap.
var bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
Screen.PrimaryScreen.Bounds.Height,
System.Drawing.Imaging.PixelFormat.Format32bppArgb);

// Create a graphics object from the bitmap.
using (var gfxScreenshot = Graphics.FromImage(bmpScreenshot))
{
// Take the screenshot from the upper left corner to the right bottom corner.
gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
Screen.PrimaryScreen.Bounds.Y,
0,
0,
Screen.PrimaryScreen.Bounds.Size,
CopyPixelOperation.SourceCopy);
}

return bmpScreenshot;
}

Then you can assign the bitmap to a PictureBox:

Bitmap screenshot = TakeScreenshot();
pictureBox1.Image = screenshot;

How to get screenshot of a window as bitmap object in C++?

you should call the PrintWindow API:

void CScreenShotDlg::OnPaint()
{
// device context for painting
CPaintDC dc(this);

// Get the window handle of calculator application.
HWND hWnd = ::FindWindow( 0, _T( "Calculator" ));

// Take screenshot.
PrintWindow( hWnd,
dc.GetSafeHdc(),
0 );
}

see this question: getting window screenshot windows API

if you are not using MFC, here the pure PrintWindow signature:

BOOL PrintWindow(
HWND hwnd,
HDC hdcBlt,
UINT nFlags
);

see MSDN for more details: http://msdn.microsoft.com/en-us/library/dd162869(v=vs.85).aspx

about how to save it as bitmap asMatteo said depends on the actual framework you are using...

EDIT:

here full example in raw C++

#define _WIN32_WINNT    0x0501        //xp
#include <windows.h>

int main()
{
RECT rc;
HWND hwnd = FindWindow(TEXT("Notepad"), NULL); //the window can't be min
if (hwnd == NULL)
{
cout << "it can't find any 'note' window" << endl;
return 0;
}
GetClientRect(hwnd, &rc);

//create
HDC hdcScreen = GetDC(NULL);
HDC hdc = CreateCompatibleDC(hdcScreen);
HBITMAP hbmp = CreateCompatibleBitmap(hdcScreen,
rc.right - rc.left, rc.bottom - rc.top);
SelectObject(hdc, hbmp);

//Print to memory hdc
PrintWindow(hwnd, hdc, PW_CLIENTONLY);

//copy to clipboard
OpenClipboard(NULL);
EmptyClipboard();
SetClipboardData(CF_BITMAP, hbmp);
CloseClipboard();

//release
DeleteDC(hdc);
DeleteObject(hbmp);
ReleaseDC(NULL, hdcScreen);

cout << "success copy to clipboard, please paste it to the 'mspaint'" << endl;

return 0;
}

Screen capture to Direct2D compatible bitmap

Direct2D doesn't provide such functionality.

A possible way to go is if you first capture the screen via GDI (1) and then create a ID2D1Bitmap from the returned bitmap handle (2).

  1. Getting a HBITMAP - Check this answer: https://stackoverflow.com/a/5164267/3962893. You need the part till the HBITMAP hbDesktop = CreateCompatibleBitmap( hdc, width, height); The hbDesktop variable will contain a handle to the screen captured bitmap.

  2. Creating an ID2D1Bitmap from a HBITMAP - check this answer: https://stackoverflow.com/a/27500938/3962893. It copies an icon to a ID2D1Bitmap, but the workflow is identical. Except:

    hIcon := SendMessage(Handle, WM_GETICON, ICON_BIG, 0);
    ....
    wicFactory.CreateBitmapFromHICON(hIcon, wicBitmap);

    that you have to change to:

    wicFactory.CreateBitmapFromHBITMAP(hbDesktop, wicBitmap);

How to capture part of the screen and save it to a BMP?

It took a while, but I have now finally ended up with a functioning script.

Requirements:

#include <iostream>
#include <ole2.h>
#include <olectl.h>

Also you might(?) have to add ole32, oleaut32 and uuid to your linker.

screenCapturePart:

bool screenCapturePart(int x, int y, int w, int h, LPCSTR fname){
HDC hdcSource = GetDC(NULL);
HDC hdcMemory = CreateCompatibleDC(hdcSource);

int capX = GetDeviceCaps(hdcSource, HORZRES);
int capY = GetDeviceCaps(hdcSource, VERTRES);

HBITMAP hBitmap = CreateCompatibleBitmap(hdcSource, w, h);
HBITMAP hBitmapOld = (HBITMAP)SelectObject(hdcMemory, hBitmap);

BitBlt(hdcMemory, 0, 0, w, h, hdcSource, x, y, SRCCOPY);
hBitmap = (HBITMAP)SelectObject(hdcMemory, hBitmapOld);

DeleteDC(hdcSource);
DeleteDC(hdcMemory);

HPALETTE hpal = NULL;
if(saveBitmap(fname, hBitmap, hpal)) return true;
return false;
}

saveBitmap:

bool saveBitmap(LPCSTR filename, HBITMAP bmp, HPALETTE pal)
{
bool result = false;
PICTDESC pd;

pd.cbSizeofstruct = sizeof(PICTDESC);
pd.picType = PICTYPE_BITMAP;
pd.bmp.hbitmap = bmp;
pd.bmp.hpal = pal;

LPPICTURE picture;
HRESULT res = OleCreatePictureIndirect(&pd, IID_IPicture, false,
reinterpret_cast<void**>(&picture));

if (!SUCCEEDED(res))
return false;

LPSTREAM stream;
res = CreateStreamOnHGlobal(0, true, &stream);

if (!SUCCEEDED(res))
{
picture->Release();
return false;
}

LONG bytes_streamed;
res = picture->SaveAsFile(stream, true, &bytes_streamed);

HANDLE file = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, 0,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);

if (!SUCCEEDED(res) || !file)
{
stream->Release();
picture->Release();
return false;
}

HGLOBAL mem = 0;
GetHGlobalFromStream(stream, &mem);
LPVOID data = GlobalLock(mem);

DWORD bytes_written;

result = !!WriteFile(file, data, bytes_streamed, &bytes_written, 0);
result &= (bytes_written == static_cast<DWORD>(bytes_streamed));

GlobalUnlock(mem);
CloseHandle(file);

stream->Release();
picture->Release();

return result;
}

can't capture Full Screen image ?? (with taskbar and any other open windows)

Your display settings are set to 125% (or higher) zoom.

Your application isn't DPI aware. You can correct that by updating your application's manifest.

If that doesn't work for you (or you'd rather not use the manifest), you can pinvoke GetDeviceCaps API to get the correct width and height for CopyFromScreen.

Here are your native definitions:

private static class Win32Native
{
public const int DESKTOPVERTRES = 0x75;
public const int DESKTOPHORZRES = 0x76;

[DllImport("gdi32.dll")]
public static extern int GetDeviceCaps(IntPtr hDC, int index);
}

And you'd call it as so:

int width, height;
using(var g = Graphics.FromHwnd(IntPtr.Zero))
{
var hDC = g.GetHdc();
width = Win32Native.GetDeviceCaps(hDC, Win32Native.DESKTOPHORZRES);
height = Win32Native.GetDeviceCaps(hDC, Win32Native.DESKTOPVERTRES);
g.ReleaseHdc(hDC);
}

using (var img = new Bitmap(width, height))
{
using (var g = Graphics.FromImage(img))
{
g.CopyFromScreen(0, 0, 0, 0, img.Size);
}
img.Save(@"C:\users\andy\desktop\test.jpg", ImageFormat.Jpeg);
}


Related Topics



Leave a reply



Submit