Skip to content

Commit 5fe9b3f

Browse files
committed
Add screenshot grabber from mozilla
1 parent e30c272 commit 5fe9b3f

File tree

1 file changed

+205
-0
lines changed

1 file changed

+205
-0
lines changed

screenshot.cpp

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
/*
2+
* Copyright (c) 2009, The Mozilla Foundation
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions are met:
7+
* * Redistributions of source code must retain the above copyright
8+
* notice, this list of conditions and the following disclaimer.
9+
* * Redistributions in binary form must reproduce the above copyright
10+
* notice, this list of conditions and the following disclaimer in the
11+
* documentation and/or other materials provided with the distribution.
12+
* * Neither the name of the Mozilla Foundation nor the
13+
* names of its contributors may be used to endorse or promote products
14+
* derived from this software without specific prior written permission.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY The Mozilla Foundation ''AS IS'' AND ANY
17+
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19+
* DISCLAIMED. IN NO EVENT SHALL The Mozilla Foundation BE LIABLE FOR ANY
20+
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23+
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26+
*
27+
* Contributors:
28+
* Ted Mielczarek <[email protected]>
29+
* Bartosz Wiklak <[email protected]>
30+
*/
31+
/*
32+
* NAME:
33+
* screenshot - Save a screenshot of the Windows desktop or window in .png format.
34+
*
35+
* SYNOPSIS:
36+
* screenshot [-wt WINDOW_TITLE | -rc LEFT TOP RIGHT BOTTOM | -o FILENAME | -h]
37+
*
38+
* OPTIONS:
39+
* -wt WINDOW_TITLE
40+
* Select window with this title. Title must not contain space (" ").
41+
* -rc LEFT TOP RIGHT BOTTOM
42+
* Crop source. If no WINDOW_TITLE is provided
43+
* (0,0) is left top corner of desktop,
44+
* else if WINDOW_TITLE maches a desktop window
45+
* (0,0) is it's top left corner.
46+
* -o FILENAME
47+
* Output file name, if none, the image will be saved
48+
* as "screenshot.png" in the current working directory.
49+
* -h
50+
* Shows this help info.
51+
*
52+
*
53+
*
54+
* Requires GDI+. All linker dependencies are specified explicitly in this
55+
* file, so you can compile screenshot.exe by simply running:
56+
* cl screenshot.cpp
57+
*
58+
* http://blog.mozilla.com/ted/2009/02/05/command-line-screenshot-tool-for-windows/
59+
*/
60+
61+
#include <windows.h>
62+
#include <gdiplus.h>
63+
#include <string.h>
64+
#include <stdio.h>
65+
66+
#pragma comment(lib, "user32.lib")
67+
#pragma comment(lib, "gdi32.lib")
68+
#pragma comment(lib, "gdiplus.lib")
69+
70+
using namespace Gdiplus;
71+
72+
// From http://msdn.microsoft.com/en-us/library/ms533843%28VS.85%29.aspx
73+
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
74+
{
75+
UINT num = 0; // number of image encoders
76+
UINT size = 0; // size of the image encoder array in bytes
77+
78+
ImageCodecInfo* pImageCodecInfo = NULL;
79+
80+
GetImageEncodersSize(&num, &size);
81+
if(size == 0)
82+
return -1; // Failure
83+
84+
pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
85+
if(pImageCodecInfo == NULL)
86+
return -1; // Failure
87+
88+
GetImageEncoders(num, size, pImageCodecInfo);
89+
90+
for(UINT j = 0; j < num; ++j)
91+
{
92+
if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
93+
{
94+
*pClsid = pImageCodecInfo[j].Clsid;
95+
free(pImageCodecInfo);
96+
return j; // Success
97+
}
98+
}
99+
100+
free(pImageCodecInfo);
101+
return -1; // Failure
102+
}
103+
104+
int wmain(int argc, wchar_t** argv)
105+
{
106+
HWND windowSearched = NULL;
107+
RECT rect = {0};
108+
wchar_t filename[MAX_PATH] = {0};
109+
110+
bool rectProvided = false;
111+
112+
if( argc>1 && wcscmp( argv[1], L"-h" )==0 ){
113+
printf( "\nNAME:\n"
114+
"\tscreenshot -\tSave a screenshot of the Windows desktop\n\t\t\tor window in .png format.\n\n"
115+
"SYNOPSIS:\n"
116+
"\tscreenshot [ -wt WINDOW_TITLE |\n\t\t -wh WINDOW_HANDLE |\n\t\t -rc LEFT TOP RIGHT BOTTOM |\n\t\t -o FILENAME |\n\t\t -h ]\n\n"
117+
"OPTIONS:\n"
118+
"\t-wt WINDOW_TITLE\n"
119+
"\t\t\tSelect window with this title.\n\t\t\tTitle must not contain space (\" \").\n"
120+
"\t-wh WINDOW_HANDLE\n"
121+
"\t\t\tSelect window by it's handle\n\t\t\t(representad as hex string - f.e. \"0012079E\") \n"
122+
"\t-rc LEFT TOP RIGHT BOTTOM\n"
123+
"\t\t\tCrop source. If no WINDOW_TITLE is provided\n"
124+
"\t\t\t(0,0) is left top corner of desktop,\n"
125+
"\t\t\telse if WINDOW_TITLE maches a desktop window\n"
126+
"\t\t\t(0,0) is it's top left corner.\n"
127+
"\t-o FILENAME\n"
128+
"\t\t\tOutput file name, if none, the image will be saved\n"
129+
"\t\t\tas \"screenshot.png\" in the current working directory.\n"
130+
"\t-h\n"
131+
"\t\t\tShows this help info.\n" );
132+
return 1;
133+
}
134+
135+
for(short i=1; i < argc; i++ ) {
136+
if( wcscmp( argv[i], L"-wt" )==0 && i+1<argc ){
137+
windowSearched = FindWindowW( NULL, argv[i+1] );
138+
if(windowSearched){
139+
SetWindowPos( windowSearched, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW );
140+
Sleep(200); //TODO: Arbitrary waiting time for window to become topmost
141+
if(!rectProvided) GetWindowRect(windowSearched, &rect);
142+
}
143+
}else if( wcscmp( argv[i], L"-wh" )==0 && i+1<argc ){
144+
windowSearched = (HWND)wcstoul( argv[i+1],NULL,16); //TODO: How does it work on 64bit enviroment?
145+
if(windowSearched){
146+
SetWindowPos( windowSearched, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW );
147+
Sleep(200); //TODO: Arbitrary waiting time for window to become topmost
148+
if(!rectProvided) GetWindowRect(windowSearched, &rect);
149+
}
150+
}else if( wcscmp( argv[i], L"-rc" )==0 && i+4<argc ){
151+
rect.left = _wtoi( argv[i+1] );
152+
rect.top = _wtoi( argv[i+2] );
153+
rect.right = _wtoi( argv[i+3] );
154+
rect.bottom = _wtoi( argv[i+4] );
155+
156+
rectProvided = true;
157+
}else if( wcscmp( argv[i], L"-o" )==0 && i+1<argc ){
158+
wcscpy( filename, argv[i+1] );
159+
}
160+
}
161+
162+
GdiplusStartupInput gdiplusStartupInput;
163+
ULONG_PTR gdiplusToken;
164+
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
165+
166+
/* If windowSearched and rectangle was provided we should recalculate rectangle to the windowSearched coordinates */
167+
if(windowSearched && rectProvided){
168+
RECT wrect;
169+
GetWindowRect(windowSearched, &wrect);
170+
OffsetRect( &rect, wrect.left, wrect.top );
171+
}
172+
173+
if( wcslen(filename)==0 ) wcscpy( filename, L"screenshot.png" );
174+
175+
HWND desktop = GetDesktopWindow();
176+
HDC desktopdc = GetDC(desktop);
177+
HDC mydc = CreateCompatibleDC(desktopdc);
178+
179+
int width = (rect.right-rect.left==0) ? GetSystemMetrics(SM_CXSCREEN) : rect.right-rect.left;
180+
int height = (rect.bottom-rect.top==0) ? GetSystemMetrics(SM_CYSCREEN) : rect.bottom-rect.top;
181+
182+
HBITMAP mybmp = CreateCompatibleBitmap(desktopdc, width, height);
183+
HBITMAP oldbmp = (HBITMAP)SelectObject(mydc, mybmp);
184+
BitBlt(mydc,0,0,width,height,desktopdc,rect.left,rect.top, SRCCOPY|CAPTUREBLT);
185+
SelectObject(mydc, oldbmp);
186+
187+
if(windowSearched) SetWindowPos( windowSearched, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW );
188+
189+
Bitmap* b = Bitmap::FromHBITMAP(mybmp, NULL);
190+
CLSID encoderClsid;
191+
Status stat = GenericError;
192+
if (b && GetEncoderClsid(L"image/png", &encoderClsid) != -1) {
193+
stat = b->Save(filename, &encoderClsid, NULL);
194+
}
195+
if (b)
196+
delete b;
197+
198+
// cleanup
199+
GdiplusShutdown(gdiplusToken);
200+
ReleaseDC(desktop, desktopdc);
201+
DeleteObject(mybmp);
202+
DeleteDC(mydc);
203+
return stat != Ok; // return 0 on success, (Issue 2)
204+
// thanks to [email protected] for reporting this bug.
205+
}

0 commit comments

Comments
 (0)