-
-
Save prashanthrajagopal/05f8ad157ece964d8c4d to your computer and use it in GitHub Desktop.
| #include <stdio.h> | |
| #include <windows.h> | |
| #include <gdiplus.h> | |
| #include <time.h> | |
| int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) { | |
| using namespace Gdiplus; | |
| UINT num = 0; | |
| UINT size = 0; | |
| ImageCodecInfo* pImageCodecInfo = NULL; | |
| GetImageEncodersSize(&num, &size); | |
| if(size == 0) | |
| return -1; | |
| pImageCodecInfo = (ImageCodecInfo*)(malloc(size)); | |
| if(pImageCodecInfo == NULL) | |
| return -1; | |
| GetImageEncoders(num, size, pImageCodecInfo); | |
| for(UINT j = 0; j < num; ++j) | |
| { | |
| if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 ) | |
| { | |
| *pClsid = pImageCodecInfo[j].Clsid; | |
| free(pImageCodecInfo); | |
| return j; | |
| } | |
| } | |
| free(pImageCodecInfo); | |
| return 0; | |
| } | |
| void gdiscreen() { | |
| using namespace Gdiplus; | |
| IStream* istream; | |
| HRESULT res = CreateStreamOnHGlobal(NULL, true, &istream); | |
| GdiplusStartupInput gdiplusStartupInput; | |
| ULONG_PTR gdiplusToken; | |
| GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); | |
| { | |
| HDC scrdc, memdc; | |
| HBITMAP membit; | |
| scrdc = ::GetDC(0); | |
| int Height = GetSystemMetrics(SM_CYSCREEN); | |
| int Width = GetSystemMetrics(SM_CXSCREEN); | |
| memdc = CreateCompatibleDC(scrdc); | |
| membit = CreateCompatibleBitmap(scrdc, Width, Height); | |
| HBITMAP hOldBitmap =(HBITMAP) SelectObject(memdc, membit); | |
| BitBlt(memdc, 0, 0, Width, Height, scrdc, 0, 0, SRCCOPY); | |
| Gdiplus::Bitmap bitmap(membit, NULL); | |
| CLSID clsid; | |
| GetEncoderClsid(L"image/jpeg", &clsid); | |
| // bitmap.Save(L"screen.jpeg", &clsid, NULL); // To save the jpeg to a file | |
| bitmap.Save(istream, &clsid, NULL); | |
| // Create a bitmap from the stream and save it to make sure the stream has the image | |
| // Gdiplus::Bitmap bmp(istream, NULL); | |
| // bmp.Save(L"t1est.jpeg", &clsid, NULL); | |
| // END | |
| delete &clsid; | |
| DeleteObject(memdc); | |
| DeleteObject(membit); | |
| ::ReleaseDC(0,scrdc); | |
| } | |
| GdiplusShutdown(gdiplusToken); | |
| } | |
| int main() | |
| { | |
| clock_t t1 = clock(); | |
| int i; | |
| int iterations = 10; | |
| for(i=0;i<iterations;i++){ | |
| gdiscreen(); | |
| } | |
| clock_t t2 = clock(); | |
| printf("%d iterations: %0.0f fps\n", iterations, iterations/((double)(t2 - t1) / CLOCKS_PER_SEC)); | |
| return 0; | |
| } |
Remove
delete &clsid;
Can you please help me ?
I'm getting ERROR
undefined reference to __imp_CreateStreamOnHGlobal
This is the only ERROR I'm getting right
@prashanthrajagopal @haephrati @dbdeadka
Can you please help me ?
I'm getting ERROR
undefined reference to __imp_CreateStreamOnHGlobal
This is the only ERROR I'm getting right
@prashanthrajagopal @haephrati @dbdeadka
yes i am gettin the same error C:\Users\USER\AppData\Local\Temp\ccTLI53G.o:screenshot.cpp:(.text+0x158): undefined reference to CreateStreamOnHGlobal@12'` ;(
Mr-0-neti,
Add -lgdiplus to your linker options.
Mr-0-neti,
Add -lgdiplus to your linker options.
@dbdeadka
I'm using -lgdiplus but not working.
Without linking GDI library you will get plenty of errors not one.
So, it's supports only 1 display screenshot?
So, it's supports only 1 display screenshot?
@conspiracynomad
Who said that ??
Can you please help me ?
I'm getting ERROR
undefined reference to __imp_CreateStreamOnHGlobal
This is the only ERROR I'm getting right
@prashanthrajagopal @haephrati @dbdeadkayes i am gettin the same error
C:\Users\USER\AppData\Local\Temp\ccTLI53G.o:screenshot.cpp:(.text+0x158): undefined reference toCreateStreamOnHGlobal@12'` ;(
Add -mwindows -lgdiplus -lole32 to linker options.
One should import gdiplus.lib in their project before compiling. If you are on windows/Visual-studio, you should include this in your source file
#pragma comment (lib, "gdiplus.lib")
OR
You could add the above lib in the VS Project like below
Project Properties > Linker > input > Additional Dependencies
Plus as stated by haephrati; remove delete &clsid;
In order to write the jpeg file; you had to uncomment the below line to save the jpeg image in the appropriate location i.e.
bitmap.Save(path/to/jpeg, &clsid, NULL);
i spent time to find out how to start it working. so i did. on windows 7. to right code is:
#include <stdio.h>
#include <windows.h>
#include <gdiplus.h>
#include <time.h>
#include <cstdio>
#pragma comment (lib, "gdiplus.lib")
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) {
using namespace Gdiplus;
UINT num = 0;
UINT size = 0;
ImageCodecInfo* pImageCodecInfo = NULL;
GetImageEncodersSize(&num, &size);
if(size == 0)
return -1;
pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
if(pImageCodecInfo == NULL)
return -1;
GetImageEncoders(num, size, pImageCodecInfo);
for(UINT j = 0; j < num; ++j)
{
if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
{
*pClsid = pImageCodecInfo[j].Clsid;
free(pImageCodecInfo);
return j;
}
}
free(pImageCodecInfo);
return 0;
}
void gdiscreen() {
using namespace Gdiplus;
IStream* istream;
HRESULT res = CreateStreamOnHGlobal(NULL, true, &istream);
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
{
HDC scrdc, memdc;
HBITMAP membit;
scrdc = ::GetDC(0);
int Height = GetSystemMetrics(SM_CYSCREEN);
int Width = GetSystemMetrics(SM_CXSCREEN);
memdc = CreateCompatibleDC(scrdc);
membit = CreateCompatibleBitmap(scrdc, Width, Height);
HBITMAP hOldBitmap =(HBITMAP) SelectObject(memdc, membit);
BitBlt(memdc, 0, 0, Width, Height, scrdc, 0, 0, SRCCOPY);
Gdiplus::Bitmap bitmap(membit, NULL);
CLSID clsid;
GetEncoderClsid(L"image/jpeg", &clsid);
bitmap.Save(L"screen.jpeg", &clsid, NULL); // To save the jpeg to a file
bitmap.Save(istream, &clsid, NULL);
// Create a bitmap from the stream and save it to make sure the stream has the image
// Gdiplus::Bitmap bmp(istream, NULL);
// bmp.Save(L"t1est.jpeg", &clsid, NULL);
// END
//delete &clsid;
DeleteObject(memdc);
DeleteObject(membit);
::ReleaseDC(0,scrdc);
}
GdiplusShutdown(gdiplusToken);
}
int main()
{
clock_t t1 = clock();
int i;
int iterations = 10;
for(i=0;i<iterations;i++){
gdiscreen();
}
clock_t t2 = clock();
printf("%d iterations: %0.0f fps\n", iterations, iterations/((double)(t2 - t1) / CLOCKS_PER_SEC));
return 0;
}
but if you compile it with :
gcc screenshot.cpp -o out.exe -lgdiplus -mwindows -lole32
it gives error:
undefined reference to __gxx_personality_v0' ...
so the right command to compile it is :
gcc screenshot.cpp -o out.exe -lgdiplus -mwindows -lole32 -static-libgcc -Wl,-Bstatic -lstdc++
have a nice day!
Saving screenshot into a byte array:
std::vector<unsigned char> GetScreenshot() {
IStream* istream;
HRESULT res = CreateStreamOnHGlobal(NULL, true, &istream);
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
HDC scrdc, memdc;
HBITMAP membit;
scrdc = ::GetDC(0);
int Height = GetSystemMetrics(SM_CYSCREEN);
int Width = GetSystemMetrics(SM_CXSCREEN);
memdc = CreateCompatibleDC(scrdc);
membit = CreateCompatibleBitmap(scrdc, Width, Height);
HBITMAP hOldBitmap = (HBITMAP)SelectObject(memdc, membit);
BitBlt(memdc, 0, 0, Width, Height, scrdc, 0, 0, SRCCOPY);
Gdiplus::Bitmap bitmap(membit, NULL);
CLSID clsid;
GetEncoderClsid(L"image/jpeg", &clsid);
bitmap.Save(istream, &clsid, NULL);
STATSTG statstg;
istream->Stat(&statstg, STATFLAG_NONAME);
ULARGE_INTEGER uliSize = statstg.cbSize;
// Allocate buffer and read the stream into it
std::vector<unsigned char> buffer(uliSize.LowPart);
LARGE_INTEGER liZero = {};
istream->Seek(liZero, STREAM_SEEK_SET, NULL);
ULONG bytesRead;
istream->Read(buffer.data(), uliSize.LowPart, &bytesRead);
return buffer;
}
Thank you so much for a good script.
But I've to notice that it's necessary to add
istream->Release();
string
after
Gdiplus::GdiplusShutdown(gdiplusToken);
(to avoid mem leaks)