Last active
October 23, 2024 13:14
-
-
Save prashanthrajagopal/05f8ad157ece964d8c4d to your computer and use it in GitHub Desktop.
Take a screenshot and save as jpeg in c++
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
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;
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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);