/src/imagemagick/coders/screenshot.c
Line | Count | Source |
1 | | /* |
2 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
3 | | % % |
4 | | % % |
5 | | % % |
6 | | % SSSSS CCCC RRRR EEEEE EEEEE N N SSSSS H H OOO TTTTT % |
7 | | % SS C R R E E NN N SS H H O O T % |
8 | | % SSS C RRRR EEE EEE N N N SSS HHHHH O O T % |
9 | | % SS C R R E E N NN SS H H O O T % |
10 | | % SSSSS CCCC R R EEEEE EEEEE N N SSSSS H H OOO T % |
11 | | % % |
12 | | % % |
13 | | % Takes a screenshot of the monitor(s). % |
14 | | % % |
15 | | % Software Design % |
16 | | % Dirk Lemstra % |
17 | | % April 2014 % |
18 | | % % |
19 | | % % |
20 | | % Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization % |
21 | | % dedicated to making software imaging solutions freely available. % |
22 | | % % |
23 | | % You may not use this file except in compliance with the License. You may % |
24 | | % obtain a copy of the License at % |
25 | | % % |
26 | | % https://imagemagick.org/license/ % |
27 | | % % |
28 | | % Unless required by applicable law or agreed to in writing, software % |
29 | | % distributed under the License is distributed on an "AS IS" BASIS, % |
30 | | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % |
31 | | % See the License for the specific language governing permissions and % |
32 | | % limitations under the License. % |
33 | | % % |
34 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
35 | | % |
36 | | % |
37 | | */ |
38 | | |
39 | | /* |
40 | | Include declarations. |
41 | | */ |
42 | | #include "MagickCore/studio.h" |
43 | | #if defined(MAGICKCORE_WINGDI32_DELEGATE) |
44 | | # if defined(__CYGWIN__) |
45 | | # include <windows.h> |
46 | | # else |
47 | | /* All MinGW needs ... */ |
48 | | # include "MagickCore/nt-base-private.h" |
49 | | # include <wingdi.h> |
50 | | # ifndef DISPLAY_DEVICE_ACTIVE |
51 | | # define DISPLAY_DEVICE_ACTIVE 0x00000001 |
52 | | # endif |
53 | | # endif |
54 | | #endif |
55 | | #include "MagickCore/blob.h" |
56 | | #include "MagickCore/blob-private.h" |
57 | | #include "MagickCore/cache.h" |
58 | | #include "MagickCore/exception.h" |
59 | | #include "MagickCore/exception-private.h" |
60 | | #include "MagickCore/image.h" |
61 | | #include "MagickCore/image-private.h" |
62 | | #include "MagickCore/list.h" |
63 | | #include "MagickCore/magick.h" |
64 | | #include "MagickCore/memory_.h" |
65 | | #include "MagickCore/module.h" |
66 | | #include "MagickCore/nt-feature.h" |
67 | | #include "MagickCore/option.h" |
68 | | #include "MagickCore/pixel-accessor.h" |
69 | | #include "MagickCore/quantum-private.h" |
70 | | #include "MagickCore/static.h" |
71 | | #include "MagickCore/string_.h" |
72 | | #include "MagickCore/token.h" |
73 | | #include "MagickCore/transform.h" |
74 | | #include "MagickCore/utility.h" |
75 | | #include "MagickCore/xwindow.h" |
76 | | #include "MagickCore/xwindow-private.h" |
77 | | |
78 | | /* |
79 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
80 | | % % |
81 | | % % |
82 | | % % |
83 | | % R e a d S C R E E N S H O T I m a g e % |
84 | | % % |
85 | | % % |
86 | | % % |
87 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
88 | | % |
89 | | % ReadSCREENSHOTImage() Takes a screenshot from the monitor(s). |
90 | | % |
91 | | % The format of the ReadSCREENSHOTImage method is: |
92 | | % |
93 | | % Image *ReadXImage(const ImageInfo *image_info,ExceptionInfo *exception) |
94 | | % |
95 | | % A description of each parameter follows: |
96 | | % |
97 | | % o image_info: the image info. |
98 | | % |
99 | | % o exception: return any errors or warnings in this structure. |
100 | | % |
101 | | */ |
102 | | static Image *ReadSCREENSHOTImage(const ImageInfo *image_info, |
103 | | ExceptionInfo *exception) |
104 | 0 | { |
105 | 0 | Image |
106 | 0 | *image; |
107 | |
|
108 | 0 | assert(image_info->signature == MagickCoreSignature); |
109 | 0 | assert(exception != (ExceptionInfo *) NULL); |
110 | 0 | assert(exception->signature == MagickCoreSignature); |
111 | 0 | if (IsEventLogging() != MagickFalse) |
112 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", |
113 | 0 | image_info->filename); |
114 | 0 | image=(Image *) NULL; |
115 | | #if defined(MAGICKCORE_WINGDI32_DELEGATE) |
116 | | { |
117 | | BITMAPINFO |
118 | | bmi; |
119 | | |
120 | | DISPLAY_DEVICE |
121 | | device; |
122 | | |
123 | | HBITMAP |
124 | | bitmap, |
125 | | bitmapOld; |
126 | | |
127 | | HDC |
128 | | bitmapDC, |
129 | | hDC; |
130 | | |
131 | | Image |
132 | | *screen; |
133 | | |
134 | | int |
135 | | i; |
136 | | |
137 | | MagickBooleanType |
138 | | status; |
139 | | |
140 | | RectangleInfo |
141 | | geometry; |
142 | | |
143 | | Quantum |
144 | | *q; |
145 | | |
146 | | ssize_t |
147 | | x; |
148 | | |
149 | | RGBQUAD |
150 | | *p; |
151 | | |
152 | | ssize_t |
153 | | y; |
154 | | |
155 | | assert(image_info != (const ImageInfo *) NULL); |
156 | | i=0; |
157 | | device.cb = sizeof(device); |
158 | | image=(Image *) NULL; |
159 | | while(EnumDisplayDevices(NULL,i,&device,0) && ++i) |
160 | | { |
161 | | if ((device.StateFlags & DISPLAY_DEVICE_ACTIVE) != DISPLAY_DEVICE_ACTIVE) |
162 | | continue; |
163 | | |
164 | | hDC=CreateDC(device.DeviceName,device.DeviceName,NULL,NULL); |
165 | | if (hDC == (HDC) NULL) |
166 | | ThrowReaderException(CoderError,"UnableToCreateDC"); |
167 | | |
168 | | screen=AcquireImage(image_info,exception); |
169 | | geometry.x=0; |
170 | | geometry.y=0; |
171 | | geometry.width=(size_t) GetDeviceCaps(hDC,DESKTOPHORZRES); |
172 | | geometry.height=(size_t) GetDeviceCaps(hDC,DESKTOPVERTRES); |
173 | | if (image_info->extract != (char *) NULL) |
174 | | { |
175 | | geometry.x=MagickMin(screen->extract_info.x,(ssize_t) geometry.width); |
176 | | if (geometry.x < 0) |
177 | | { |
178 | | geometry.width=(size_t ) MagickMin(0,(ssize_t) geometry.width+ |
179 | | geometry.x); |
180 | | geometry.x=0; |
181 | | } |
182 | | geometry.width=geometry.width-geometry.x; |
183 | | if (screen->columns > 0) |
184 | | geometry.width=MagickMin(geometry.width,screen->columns); |
185 | | geometry.y=MagickMin(screen->extract_info.y,(ssize_t) geometry.height); |
186 | | if (geometry.y < 0) |
187 | | { |
188 | | geometry.width=(size_t ) MagickMin(0,(ssize_t) geometry.width+ |
189 | | geometry.y); |
190 | | geometry.y=0; |
191 | | } |
192 | | geometry.height=geometry.height-geometry.y; |
193 | | if (screen->rows > 0) |
194 | | geometry.height=MagickMin(geometry.height,screen->rows); |
195 | | /* Reset extract to prevent cropping */ |
196 | | *image_info->extract='\0'; |
197 | | screen->extract_info.x=0; |
198 | | screen->extract_info.y=0; |
199 | | } |
200 | | if ((geometry.width == 0) || (geometry.height == 0)) |
201 | | ThrowReaderException(OptionError,"InvalidGeometry"); |
202 | | screen->columns=geometry.width; |
203 | | screen->rows=geometry.height; |
204 | | screen->storage_class=DirectClass; |
205 | | if (image == (Image *) NULL) |
206 | | image=screen; |
207 | | else |
208 | | AppendImageToList(&image,screen); |
209 | | status=SetImageExtent(screen,screen->columns,screen->rows,exception); |
210 | | if (status == MagickFalse) |
211 | | return(DestroyImageList(image)); |
212 | | |
213 | | bitmapDC=CreateCompatibleDC(hDC); |
214 | | if (bitmapDC == (HDC) NULL) |
215 | | { |
216 | | DeleteDC(hDC); |
217 | | ThrowReaderException(CoderError,"UnableToCreateDC"); |
218 | | } |
219 | | (void) memset(&bmi,0,sizeof(BITMAPINFO)); |
220 | | bmi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); |
221 | | bmi.bmiHeader.biWidth=(LONG) screen->columns; |
222 | | bmi.bmiHeader.biHeight=(-1)*(LONG) screen->rows; |
223 | | bmi.bmiHeader.biPlanes=1; |
224 | | bmi.bmiHeader.biBitCount=32; |
225 | | bmi.bmiHeader.biCompression=BI_RGB; |
226 | | bitmap=CreateDIBSection(hDC,&bmi,DIB_RGB_COLORS,(void **) &p,NULL,0); |
227 | | if (bitmap == (HBITMAP) NULL) |
228 | | { |
229 | | DeleteDC(hDC); |
230 | | DeleteDC(bitmapDC); |
231 | | ThrowReaderException(CoderError,"UnableToCreateBitmap"); |
232 | | } |
233 | | bitmapOld=(HBITMAP) SelectObject(bitmapDC,bitmap); |
234 | | if (bitmapOld == (HBITMAP) NULL) |
235 | | { |
236 | | DeleteDC(hDC); |
237 | | DeleteDC(bitmapDC); |
238 | | DeleteObject(bitmap); |
239 | | ThrowReaderException(CoderError,"UnableToCreateBitmap"); |
240 | | } |
241 | | BitBlt(bitmapDC,0,0,(int) screen->columns,(int) screen->rows,hDC, |
242 | | (int) geometry.x,(int) geometry.y,SRCCOPY); |
243 | | (void) SelectObject(bitmapDC,bitmapOld); |
244 | | |
245 | | for (y=0; y < (ssize_t) screen->rows; y++) |
246 | | { |
247 | | q=QueueAuthenticPixels(screen,0,y,screen->columns,1,exception); |
248 | | if (q == (Quantum *) NULL) |
249 | | break; |
250 | | for (x=0; x < (ssize_t) screen->columns; x++) |
251 | | { |
252 | | SetPixelRed(screen,ScaleCharToQuantum(p->rgbRed),q); |
253 | | SetPixelGreen(screen,ScaleCharToQuantum(p->rgbGreen),q); |
254 | | SetPixelBlue(screen,ScaleCharToQuantum(p->rgbBlue),q); |
255 | | SetPixelAlpha(screen,OpaqueAlpha,q); |
256 | | p++; |
257 | | q+=(ptrdiff_t) GetPixelChannels(screen); |
258 | | } |
259 | | if (SyncAuthenticPixels(screen,exception) == MagickFalse) |
260 | | break; |
261 | | } |
262 | | |
263 | | DeleteDC(hDC); |
264 | | DeleteDC(bitmapDC); |
265 | | DeleteObject(bitmap); |
266 | | } |
267 | | } |
268 | | #elif defined(MAGICKCORE_X11_DELEGATE) |
269 | | { |
270 | | const char |
271 | | *option; |
272 | | |
273 | | XImportInfo |
274 | | ximage_info; |
275 | | |
276 | | XGetImportInfo(&ximage_info); |
277 | | option=GetImageOption(image_info,"x:screen"); |
278 | | if (option != (const char *) NULL) |
279 | | ximage_info.screen=IsStringTrue(option); |
280 | | option=GetImageOption(image_info,"x:silent"); |
281 | | if (option != (const char *) NULL) |
282 | | ximage_info.silent=IsStringTrue(option); |
283 | | image=XImportImage(image_info,&ximage_info,exception); |
284 | | if ((image != (Image *) NULL) && (image_info->extract != (char *) NULL)) |
285 | | { |
286 | | Image |
287 | | *crop_image; |
288 | | |
289 | | RectangleInfo |
290 | | crop_info; |
291 | | |
292 | | /* |
293 | | Crop image as defined by the extract rectangle. |
294 | | */ |
295 | | (void) ParsePageGeometry(image,image_info->extract,&crop_info, |
296 | | exception); |
297 | | crop_image=CropImage(image,&crop_info,exception); |
298 | | if (crop_image != (Image *) NULL) |
299 | | { |
300 | | image=DestroyImage(image); |
301 | | image=crop_image; |
302 | | } |
303 | | } |
304 | | } |
305 | | #endif |
306 | 0 | return(image); |
307 | 0 | } |
308 | | |
309 | | /* |
310 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
311 | | % % |
312 | | % % |
313 | | % % |
314 | | % R e g i s t e r S C R E E N S H O T I m a g e % |
315 | | % % |
316 | | % % |
317 | | % % |
318 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
319 | | % |
320 | | % RegisterSCREENSHOTImage() adds attributes for the screen shot format to |
321 | | % the list of supported formats. The attributes include the image format |
322 | | % tag, a method to read and/or write the format, whether the format |
323 | | % supports the saving of more than one frame to the same file or blob, |
324 | | % whether the format supports native in-memory I/O, and a brief |
325 | | % description of the format. |
326 | | % |
327 | | % The format of the RegisterScreenShotImage method is: |
328 | | % |
329 | | % size_t RegisterScreenShotImage(void) |
330 | | % |
331 | | */ |
332 | | ModuleExport size_t RegisterSCREENSHOTImage(void) |
333 | 7 | { |
334 | 7 | MagickInfo |
335 | 7 | *entry; |
336 | | |
337 | 7 | entry=AcquireMagickInfo("SCREENSHOT","SCREENSHOT","Screen shot"); |
338 | 7 | entry->decoder=(DecodeImageHandler *) ReadSCREENSHOTImage; |
339 | 7 | entry->format_type=ImplicitFormatType; |
340 | 7 | (void) RegisterMagickInfo(entry); |
341 | 7 | return(MagickImageCoderSignature); |
342 | 7 | } |
343 | | |
344 | | /* |
345 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
346 | | % % |
347 | | % % |
348 | | % % |
349 | | % U n r e g i s t e r S C R E E N S H O T I m a g e % |
350 | | % % |
351 | | % % |
352 | | % % |
353 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
354 | | % |
355 | | % UnregisterScreenShotImage() removes format registrations made by the |
356 | | % screen shot module from the list of supported formats. |
357 | | % |
358 | | % The format of the UnregisterSCREENSHOTImage method is: |
359 | | % |
360 | | % UnregisterSCREENSHOTImage(void) |
361 | | % |
362 | | */ |
363 | | ModuleExport void UnregisterSCREENSHOTImage(void) |
364 | 0 | { |
365 | 0 | (void) UnregisterMagickInfo("SCREENSHOT"); |
366 | 0 | } |