1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % X X W W DDDD %
7 % X X W W D D %
8 % X W W D D %
9 % X X W W W D D %
10 % X X W W DDDD %
11 % %
12 % %
13 % Read/Write X Windows System Window Dump Format %
14 % %
15 % Software Design %
16 % Cristy %
17 % July 1992 %
18 % %
19 % %
20 % Copyright 1999-2021 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/script/license.php %
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 #include "MagickCore/attribute.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/color-private.h"
48 #include "MagickCore/colormap.h"
49 #include "MagickCore/colormap-private.h"
50 #include "MagickCore/colorspace.h"
51 #include "MagickCore/colorspace-private.h"
52 #include "MagickCore/exception.h"
53 #include "MagickCore/exception-private.h"
54 #include "MagickCore/image.h"
55 #include "MagickCore/image-private.h"
56 #include "MagickCore/list.h"
57 #include "MagickCore/magick.h"
58 #include "MagickCore/memory_.h"
59 #include "MagickCore/monitor.h"
60 #include "MagickCore/monitor-private.h"
61 #include "MagickCore/pixel-accessor.h"
62 #include "MagickCore/property.h"
63 #include "MagickCore/quantum-private.h"
64 #include "MagickCore/static.h"
65 #include "MagickCore/string_.h"
66 #include "MagickCore/module.h"
67 #if defined(MAGICKCORE_X11_DELEGATE)
68 #include "MagickCore/xwindow-private.h"
69 #if !defined(vms)
70 #include <X11/XWDFile.h>
71 #else
72 #include "XWDFile.h"
73 #endif
74 #endif
75
76 /*
77 Forward declarations.
78 */
79 #if defined(MAGICKCORE_X11_DELEGATE)
80 static MagickBooleanType
81 WriteXWDImage(const ImageInfo *,Image *,ExceptionInfo *);
82 #endif
83
84 /*
85 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
86 % %
87 % %
88 % %
89 % I s X W D %
90 % %
91 % %
92 % %
93 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
94 %
95 % IsXWD() returns MagickTrue if the image format type, identified by the
96 % magick string, is XWD.
97 %
98 % The format of the IsXWD method is:
99 %
100 % MagickBooleanType IsXWD(const unsigned char *magick,const size_t length)
101 %
102 % A description of each parameter follows:
103 %
104 % o magick: compare image format pattern against these bytes.
105 %
106 % o length: Specifies the length of the magick string.
107 %
108 */
IsXWD(const unsigned char * magick,const size_t length)109 static MagickBooleanType IsXWD(const unsigned char *magick,const size_t length)
110 {
111 if (length < 8)
112 return(MagickFalse);
113 if (memcmp(magick+1,"\000\000",2) == 0)
114 {
115 if (memcmp(magick+4,"\007\000\000",3) == 0)
116 return(MagickTrue);
117 if (memcmp(magick+5,"\000\000\007",3) == 0)
118 return(MagickTrue);
119 }
120 return(MagickFalse);
121 }
122
123 #if defined(MAGICKCORE_X11_DELEGATE)
124 /*
125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
126 % %
127 % %
128 % %
129 % R e a d X W D I m a g e %
130 % %
131 % %
132 % %
133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
134 %
135 % ReadXWDImage() reads an X Window System window dump image file and
136 % returns it. It allocates the memory necessary for the new Image structure
137 % and returns a pointer to the new image.
138 %
139 % The format of the ReadXWDImage method is:
140 %
141 % Image *ReadXWDImage(const ImageInfo *image_info,ExceptionInfo *exception)
142 %
143 % A description of each parameter follows:
144 %
145 % o image_info: the image info.
146 %
147 % o exception: return any errors or warnings in this structure.
148 %
149 */
150
ReadXWDImage(const ImageInfo * image_info,ExceptionInfo * exception)151 static Image *ReadXWDImage(const ImageInfo *image_info,ExceptionInfo *exception)
152 {
153 #define CheckOverflowException(length,width,height) \
154 (((height) != 0) && ((length)/((size_t) height) != ((size_t) width)))
155
156 char
157 *comment;
158
159 Image
160 *image;
161
162 int
163 x_status;
164
165 MagickBooleanType
166 authentic_colormap;
167
168 MagickStatusType
169 status;
170
171 Quantum
172 index;
173
174 ssize_t
175 x;
176
177 Quantum
178 *q;
179
180 ssize_t
181 i;
182
183 size_t
184 pixel;
185
186 size_t
187 length;
188
189 ssize_t
190 count,
191 y;
192
193 unsigned long
194 lsb_first;
195
196 XColor
197 *colors;
198
199 XImage
200 *ximage;
201
202 XWDFileHeader
203 header;
204
205 /*
206 Open image file.
207 */
208 assert(image_info != (const ImageInfo *) NULL);
209 assert(image_info->signature == MagickCoreSignature);
210 if (image_info->debug != MagickFalse)
211 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
212 image_info->filename);
213 assert(exception != (ExceptionInfo *) NULL);
214 assert(exception->signature == MagickCoreSignature);
215 image=AcquireImage(image_info,exception);
216 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
217 if (status == MagickFalse)
218 {
219 image=DestroyImageList(image);
220 return((Image *) NULL);
221 }
222 /*
223 Read in header information.
224 */
225 count=ReadBlob(image,sz_XWDheader,(unsigned char *) &header);
226 if (count != sz_XWDheader)
227 ThrowReaderException(CorruptImageError,"UnableToReadImageHeader");
228 /*
229 Ensure the header byte-order is most-significant byte first.
230 */
231 lsb_first=1;
232 if ((int) (*(char *) &lsb_first) != 0)
233 MSBOrderLong((unsigned char *) &header,sz_XWDheader);
234 /*
235 Check to see if the dump file is in the proper format.
236 */
237 if (header.file_version != XWD_FILE_VERSION)
238 ThrowReaderException(CorruptImageError,"FileFormatVersionMismatch");
239 if (header.header_size < sz_XWDheader)
240 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
241 if (header.xoffset >= header.pixmap_width)
242 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
243 switch (header.visual_class)
244 {
245 case StaticGray:
246 case GrayScale:
247 {
248 if (header.bits_per_pixel != 1)
249 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
250 break;
251 }
252 case StaticColor:
253 case PseudoColor:
254 {
255 if ((header.bits_per_pixel < 1) || (header.bits_per_pixel > 15) ||
256 (header.colormap_entries == 0))
257 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
258 break;
259 }
260 case TrueColor:
261 case DirectColor:
262 {
263 if ((header.bits_per_pixel != 16) && (header.bits_per_pixel != 24) &&
264 (header.bits_per_pixel != 32))
265 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
266 break;
267 }
268 default:
269 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
270 }
271 switch (header.pixmap_format)
272 {
273 case XYBitmap:
274 {
275 if (header.pixmap_depth != 1)
276 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
277 break;
278 }
279 case XYPixmap:
280 case ZPixmap:
281 {
282 if ((header.pixmap_depth < 1) || (header.pixmap_depth > 32))
283 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
284 switch (header.bitmap_pad)
285 {
286 case 8:
287 case 16:
288 case 32:
289 break;
290 default:
291 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
292 }
293 break;
294 }
295 default:
296 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
297 }
298 switch (header.bitmap_unit)
299 {
300 case 8:
301 case 16:
302 case 32:
303 break;
304 default:
305 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
306 }
307 switch (header.byte_order)
308 {
309 case LSBFirst:
310 case MSBFirst:
311 break;
312 default:
313 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
314 }
315 switch (header.bitmap_bit_order)
316 {
317 case LSBFirst:
318 case MSBFirst:
319 break;
320 default:
321 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
322 }
323 if (((header.bitmap_pad % 8) != 0) || (header.bitmap_pad > 32))
324 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
325 length=(size_t) (header.header_size-sz_XWDheader);
326 comment=(char *) AcquireQuantumMemory(length+1,sizeof(*comment));
327 if (comment == (char *) NULL)
328 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
329 count=ReadBlob(image,length,(unsigned char *) comment);
330 comment[length]='\0';
331 (void) SetImageProperty(image,"comment",comment,exception);
332 comment=DestroyString(comment);
333 if (count != (ssize_t) length)
334 ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
335 /*
336 Initialize the X image.
337 */
338 ximage=(XImage *) AcquireMagickMemory(sizeof(*ximage));
339 if (ximage == (XImage *) NULL)
340 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
341 ximage->depth=(int) header.pixmap_depth;
342 ximage->format=(int) header.pixmap_format;
343 ximage->xoffset=(int) header.xoffset;
344 ximage->data=(char *) NULL;
345 ximage->width=(int) header.pixmap_width;
346 ximage->height=(int) header.pixmap_height;
347 ximage->bitmap_pad=(int) header.bitmap_pad;
348 ximage->bytes_per_line=(int) header.bytes_per_line;
349 ximage->byte_order=(int) header.byte_order;
350 ximage->bitmap_unit=(int) header.bitmap_unit;
351 ximage->bitmap_bit_order=(int) header.bitmap_bit_order;
352 ximage->bits_per_pixel=(int) header.bits_per_pixel;
353 ximage->red_mask=header.red_mask;
354 ximage->green_mask=header.green_mask;
355 ximage->blue_mask=header.blue_mask;
356 if ((ximage->depth < 0) || (ximage->format < 0) || (ximage->xoffset < 0) ||
357 (ximage->width < 0) || (ximage->height < 0) || (ximage->bitmap_pad < 0) ||
358 (ximage->bytes_per_line < 0) || (ximage->byte_order < 0) ||
359 (ximage->bitmap_unit < 0) || (ximage->bitmap_bit_order < 0) ||
360 (ximage->bits_per_pixel < 0))
361 {
362 ximage=(XImage *) RelinquishMagickMemory(ximage);
363 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
364 }
365 if ((ximage->width > 65535) || (ximage->height > 65535))
366 {
367 ximage=(XImage *) RelinquishMagickMemory(ximage);
368 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
369 }
370 if ((ximage->bits_per_pixel > 32) || (ximage->bitmap_unit > 32))
371 {
372 ximage=(XImage *) RelinquishMagickMemory(ximage);
373 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
374 }
375 x_status=XInitImage(ximage);
376 if (x_status == 0)
377 {
378 ximage=(XImage *) RelinquishMagickMemory(ximage);
379 ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
380 }
381 /*
382 Read colormap.
383 */
384 authentic_colormap=MagickFalse;
385 colors=(XColor *) NULL;
386 if (header.ncolors != 0)
387 {
388 XWDColor
389 color;
390
391 length=(size_t) header.ncolors;
392 if (length > ((~0UL)/sizeof(*colors)))
393 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
394 colors=(XColor *) AcquireQuantumMemory(length,sizeof(*colors));
395 if (colors == (XColor *) NULL)
396 {
397 ximage=(XImage *) RelinquishMagickMemory(ximage);
398 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
399 }
400 for (i=0; i < (ssize_t) header.ncolors; i++)
401 {
402 count=ReadBlob(image,sz_XWDColor,(unsigned char *) &color);
403 if (count != sz_XWDColor)
404 {
405 colors=(XColor *) RelinquishMagickMemory(colors);
406 ximage=(XImage *) RelinquishMagickMemory(ximage);
407 ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
408 }
409 colors[i].pixel=color.pixel;
410 colors[i].red=color.red;
411 colors[i].green=color.green;
412 colors[i].blue=color.blue;
413 colors[i].flags=(char) color.flags;
414 if (color.flags != 0)
415 authentic_colormap=MagickTrue;
416 }
417 /*
418 Ensure the header byte-order is most-significant byte first.
419 */
420 lsb_first=1;
421 if ((int) (*(char *) &lsb_first) != 0)
422 for (i=0; i < (ssize_t) header.ncolors; i++)
423 {
424 MSBOrderLong((unsigned char *) &colors[i].pixel,
425 sizeof(colors[i].pixel));
426 MSBOrderShort((unsigned char *) &colors[i].red,3*
427 sizeof(colors[i].red));
428 }
429 }
430 /*
431 Allocate the pixel buffer.
432 */
433 length=(size_t) ximage->bytes_per_line*ximage->height;
434 if (CheckOverflowException(length,ximage->bytes_per_line,ximage->height))
435 {
436 if (header.ncolors != 0)
437 colors=(XColor *) RelinquishMagickMemory(colors);
438 ximage=(XImage *) RelinquishMagickMemory(ximage);
439 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
440 }
441 if (ximage->format != ZPixmap)
442 {
443 size_t
444 extent;
445
446 extent=length;
447 length*=ximage->depth;
448 if (CheckOverflowException(length,extent,ximage->depth))
449 {
450 if (header.ncolors != 0)
451 colors=(XColor *) RelinquishMagickMemory(colors);
452 ximage=(XImage *) RelinquishMagickMemory(ximage);
453 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
454 }
455 }
456 ximage->data=(char *) AcquireQuantumMemory(length,sizeof(*ximage->data));
457 if (ximage->data == (char *) NULL)
458 {
459 if (header.ncolors != 0)
460 colors=(XColor *) RelinquishMagickMemory(colors);
461 ximage=(XImage *) RelinquishMagickMemory(ximage);
462 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
463 }
464 count=ReadBlob(image,length,(unsigned char *) ximage->data);
465 if (count != (ssize_t) length)
466 {
467 if (header.ncolors != 0)
468 colors=(XColor *) RelinquishMagickMemory(colors);
469 ximage->data=DestroyString(ximage->data);
470 ximage=(XImage *) RelinquishMagickMemory(ximage);
471 ThrowReaderException(CorruptImageError,"UnableToReadImageData");
472 }
473 /*
474 Convert image to MIFF format.
475 */
476 image->columns=(size_t) ximage->width;
477 image->rows=(size_t) ximage->height;
478 image->depth=8;
479 status=SetImageExtent(image,image->columns,image->rows,exception);
480 if (status == MagickFalse)
481 {
482 if (header.ncolors != 0)
483 colors=(XColor *) RelinquishMagickMemory(colors);
484 ximage->data=DestroyString(ximage->data);
485 ximage=(XImage *) RelinquishMagickMemory(ximage);
486 return(DestroyImageList(image));
487 }
488 if ((header.ncolors == 0U) || (ximage->red_mask != 0) ||
489 (ximage->green_mask != 0) || (ximage->blue_mask != 0))
490 image->storage_class=DirectClass;
491 else
492 image->storage_class=PseudoClass;
493 image->colors=header.ncolors;
494 if (image_info->ping == MagickFalse)
495 switch (image->storage_class)
496 {
497 case DirectClass:
498 default:
499 {
500 size_t
501 color;
502
503 size_t
504 blue_mask,
505 blue_shift,
506 green_mask,
507 green_shift,
508 red_mask,
509 red_shift;
510
511 /*
512 Determine shift and mask for red, green, and blue.
513 */
514 red_mask=ximage->red_mask;
515 red_shift=0;
516 while ((red_mask != 0) && ((red_mask & 0x01) == 0))
517 {
518 red_mask>>=1;
519 red_shift++;
520 }
521 green_mask=ximage->green_mask;
522 green_shift=0;
523 while ((green_mask != 0) && ((green_mask & 0x01) == 0))
524 {
525 green_mask>>=1;
526 green_shift++;
527 }
528 blue_mask=ximage->blue_mask;
529 blue_shift=0;
530 while ((blue_mask != 0) && ((blue_mask & 0x01) == 0))
531 {
532 blue_mask>>=1;
533 blue_shift++;
534 }
535 /*
536 Convert X image to DirectClass packets.
537 */
538 if ((image->colors != 0) && (authentic_colormap != MagickFalse))
539 for (y=0; y < (ssize_t) image->rows; y++)
540 {
541 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
542 if (q == (Quantum *) NULL)
543 break;
544 for (x=0; x < (ssize_t) image->columns; x++)
545 {
546 pixel=XGetPixel(ximage,(int) x,(int) y);
547 index=(Quantum) ConstrainColormapIndex(image,(ssize_t) (pixel >>
548 red_shift) & red_mask,exception);
549 SetPixelRed(image,ScaleShortToQuantum(
550 colors[(ssize_t) index].red),q);
551 index=(Quantum) ConstrainColormapIndex(image,(ssize_t) (pixel >>
552 green_shift) & green_mask,exception);
553 SetPixelGreen(image,ScaleShortToQuantum(
554 colors[(ssize_t) index].green),q);
555 index=(Quantum) ConstrainColormapIndex(image,(ssize_t) (pixel >>
556 blue_shift) & blue_mask,exception);
557 SetPixelBlue(image,ScaleShortToQuantum(
558 colors[(ssize_t) index].blue),q);
559 q+=GetPixelChannels(image);
560 }
561 if (SyncAuthenticPixels(image,exception) == MagickFalse)
562 break;
563 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
564 image->rows);
565 if (status == MagickFalse)
566 break;
567 }
568 else
569 for (y=0; y < (ssize_t) image->rows; y++)
570 {
571 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
572 if (q == (Quantum *) NULL)
573 break;
574 for (x=0; x < (ssize_t) image->columns; x++)
575 {
576 pixel=XGetPixel(ximage,(int) x,(int) y);
577 color=(pixel >> red_shift) & red_mask;
578 if (red_mask != 0)
579 color=(color*65535UL)/red_mask;
580 SetPixelRed(image,ScaleShortToQuantum((unsigned short) color),q);
581 color=(pixel >> green_shift) & green_mask;
582 if (green_mask != 0)
583 color=(color*65535UL)/green_mask;
584 SetPixelGreen(image,ScaleShortToQuantum((unsigned short) color),
585 q);
586 color=(pixel >> blue_shift) & blue_mask;
587 if (blue_mask != 0)
588 color=(color*65535UL)/blue_mask;
589 SetPixelBlue(image,ScaleShortToQuantum((unsigned short) color),q);
590 q+=GetPixelChannels(image);
591 }
592 if (SyncAuthenticPixels(image,exception) == MagickFalse)
593 break;
594 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
595 image->rows);
596 if (status == MagickFalse)
597 break;
598 }
599 break;
600 }
601 case PseudoClass:
602 {
603 /*
604 Convert X image to PseudoClass packets.
605 */
606 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
607 {
608 if (header.ncolors != 0)
609 colors=(XColor *) RelinquishMagickMemory(colors);
610 ximage->data=DestroyString(ximage->data);
611 ximage=(XImage *) RelinquishMagickMemory(ximage);
612 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
613 }
614 for (i=0; i < (ssize_t) image->colors; i++)
615 {
616 image->colormap[i].red=(MagickRealType) ScaleShortToQuantum(
617 colors[i].red);
618 image->colormap[i].green=(MagickRealType) ScaleShortToQuantum(
619 colors[i].green);
620 image->colormap[i].blue=(MagickRealType) ScaleShortToQuantum(
621 colors[i].blue);
622 }
623 for (y=0; y < (ssize_t) image->rows; y++)
624 {
625 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
626 if (q == (Quantum *) NULL)
627 break;
628 for (x=0; x < (ssize_t) image->columns; x++)
629 {
630 index=(Quantum) ConstrainColormapIndex(image,(ssize_t)
631 XGetPixel(ximage,(int) x,(int) y),exception);
632 SetPixelIndex(image,index,q);
633 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
634 q+=GetPixelChannels(image);
635 }
636 if (SyncAuthenticPixels(image,exception) == MagickFalse)
637 break;
638 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
639 image->rows);
640 if (status == MagickFalse)
641 break;
642 }
643 break;
644 }
645 }
646 /*
647 Free image and colormap.
648 */
649 if (header.ncolors != 0)
650 colors=(XColor *) RelinquishMagickMemory(colors);
651 ximage->data=DestroyString(ximage->data);
652 ximage=(XImage *) RelinquishMagickMemory(ximage);
653 if (EOFBlob(image) != MagickFalse)
654 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
655 image->filename);
656 (void) CloseBlob(image);
657 return(GetFirstImageInList(image));
658 }
659 #endif
660
661 /*
662 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
663 % %
664 % %
665 % %
666 % R e g i s t e r X W D I m a g e %
667 % %
668 % %
669 % %
670 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
671 %
672 % RegisterXWDImage() adds properties for the XWD image format to
673 % the list of supported formats. The properties include the image format
674 % tag, a method to read and/or write the format, whether the format
675 % supports the saving of more than one frame to the same file or blob,
676 % whether the format supports native in-memory I/O, and a brief
677 % description of the format.
678 %
679 % The format of the RegisterXWDImage method is:
680 %
681 % size_t RegisterXWDImage(void)
682 %
683 */
RegisterXWDImage(void)684 ModuleExport size_t RegisterXWDImage(void)
685 {
686 MagickInfo
687 *entry;
688
689 entry=AcquireMagickInfo("XWD","XWD","X Windows system window dump (color)");
690 #if defined(MAGICKCORE_X11_DELEGATE)
691 entry->decoder=(DecodeImageHandler *) ReadXWDImage;
692 entry->encoder=(EncodeImageHandler *) WriteXWDImage;
693 #endif
694 entry->magick=(IsImageFormatHandler *) IsXWD;
695 entry->flags^=CoderAdjoinFlag;
696 (void) RegisterMagickInfo(entry);
697 return(MagickImageCoderSignature);
698 }
699
700 /*
701 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
702 % %
703 % %
704 % %
705 % U n r e g i s t e r X W D I m a g e %
706 % %
707 % %
708 % %
709 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
710 %
711 % UnregisterXWDImage() removes format registrations made by the
712 % XWD module from the list of supported formats.
713 %
714 % The format of the UnregisterXWDImage method is:
715 %
716 % UnregisterXWDImage(void)
717 %
718 */
UnregisterXWDImage(void)719 ModuleExport void UnregisterXWDImage(void)
720 {
721 (void) UnregisterMagickInfo("XWD");
722 }
723
724 #if defined(MAGICKCORE_X11_DELEGATE)
725 /*
726 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
727 % %
728 % %
729 % %
730 % W r i t e X W D I m a g e %
731 % %
732 % %
733 % %
734 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
735 %
736 % WriteXWDImage() writes an image to a file in X window dump
737 % rasterfile format.
738 %
739 % The format of the WriteXWDImage method is:
740 %
741 % MagickBooleanType WriteXWDImage(const ImageInfo *image_info,
742 % Image *image,ExceptionInfo *exception)
743 %
744 % A description of each parameter follows.
745 %
746 % o image_info: the image info.
747 %
748 % o image: The image.
749 %
750 % o exception: return any errors or warnings in this structure.
751 %
752 */
WriteXWDImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)753 static MagickBooleanType WriteXWDImage(const ImageInfo *image_info,Image *image,
754 ExceptionInfo *exception)
755 {
756 const char
757 *value;
758
759 MagickBooleanType
760 status;
761
762 const Quantum
763 *p;
764
765 ssize_t
766 x;
767
768 unsigned char
769 *q;
770
771 size_t
772 bits_per_pixel,
773 bytes_per_line,
774 length,
775 scanline_pad;
776
777 ssize_t
778 count,
779 y;
780
781 unsigned char
782 *pixels;
783
784 unsigned long
785 lsb_first;
786
787 XWDFileHeader
788 xwd_info;
789
790 /*
791 Open output image file.
792 */
793 assert(image_info != (const ImageInfo *) NULL);
794 assert(image_info->signature == MagickCoreSignature);
795 assert(image != (Image *) NULL);
796 assert(image->signature == MagickCoreSignature);
797 if (image->debug != MagickFalse)
798 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
799 assert(exception != (ExceptionInfo *) NULL);
800 assert(exception->signature == MagickCoreSignature);
801 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
802 if (status == MagickFalse)
803 return(status);
804 if ((image->columns != (CARD32) image->columns) ||
805 (image->rows != (CARD32) image->rows))
806 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
807 if ((image->storage_class == PseudoClass) && (image->colors > 256))
808 (void) SetImageType(image,TrueColorType,exception);
809 (void) TransformImageColorspace(image,sRGBColorspace,exception);
810 /*
811 Initialize XWD file header.
812 */
813 (void) memset(&xwd_info,0,sizeof(xwd_info));
814 xwd_info.header_size=(CARD32) sz_XWDheader;
815 value=GetImageProperty(image,"comment",exception);
816 if (value != (const char *) NULL)
817 xwd_info.header_size+=(CARD32) strlen(value);
818 xwd_info.header_size++;
819 xwd_info.file_version=(CARD32) XWD_FILE_VERSION;
820 xwd_info.pixmap_format=(CARD32) ZPixmap;
821 xwd_info.pixmap_depth=(CARD32) (image->storage_class == DirectClass ? 24 : 8);
822 xwd_info.pixmap_width=(CARD32) image->columns;
823 xwd_info.pixmap_height=(CARD32) image->rows;
824 xwd_info.xoffset=(CARD32) 0;
825 xwd_info.byte_order=(CARD32) MSBFirst;
826 xwd_info.bitmap_unit=(CARD32) (image->storage_class == DirectClass ? 32 : 8);
827 xwd_info.bitmap_bit_order=(CARD32) MSBFirst;
828 xwd_info.bitmap_pad=(CARD32) (image->storage_class == DirectClass ? 32 : 8);
829 bits_per_pixel=(size_t) (image->storage_class == DirectClass ? 24 : 8);
830 xwd_info.bits_per_pixel=(CARD32) bits_per_pixel;
831 bytes_per_line=(CARD32) ((((xwd_info.bits_per_pixel*
832 xwd_info.pixmap_width)+((xwd_info.bitmap_pad)-1))/
833 (xwd_info.bitmap_pad))*((xwd_info.bitmap_pad) >> 3));
834 xwd_info.bytes_per_line=(CARD32) bytes_per_line;
835 xwd_info.visual_class=(CARD32)
836 (image->storage_class == DirectClass ? DirectColor : PseudoColor);
837 xwd_info.red_mask=(CARD32)
838 (image->storage_class == DirectClass ? 0xff0000 : 0);
839 xwd_info.green_mask=(CARD32)
840 (image->storage_class == DirectClass ? 0xff00 : 0);
841 xwd_info.blue_mask=(CARD32) (image->storage_class == DirectClass ? 0xff : 0);
842 xwd_info.bits_per_rgb=(CARD32) (image->storage_class == DirectClass ? 24 : 8);
843 xwd_info.colormap_entries=(CARD32)
844 (image->storage_class == DirectClass ? 256 : image->colors);
845 xwd_info.ncolors=(unsigned int)
846 (image->storage_class == DirectClass ? 0 : image->colors);
847 xwd_info.window_width=(CARD32) image->columns;
848 xwd_info.window_height=(CARD32) image->rows;
849 xwd_info.window_x=0;
850 xwd_info.window_y=0;
851 xwd_info.window_bdrwidth=(CARD32) 0;
852 /*
853 Write XWD header.
854 */
855 lsb_first=1;
856 if ((int) (*(char *) &lsb_first) != 0)
857 MSBOrderLong((unsigned char *) &xwd_info,sizeof(xwd_info));
858 (void) WriteBlob(image,sz_XWDheader,(unsigned char *) &xwd_info);
859 if (value != (const char *) NULL)
860 (void) WriteBlob(image,strlen(value),(unsigned char *) value);
861 (void) WriteBlob(image,1,(const unsigned char *) "\0");
862 if (image->storage_class == PseudoClass)
863 {
864 ssize_t
865 i;
866
867 XColor
868 *colors;
869
870 XWDColor
871 color;
872
873 /*
874 Dump colormap to file.
875 */
876 (void) memset(&color,0,sizeof(color));
877 colors=(XColor *) AcquireQuantumMemory((size_t) image->colors,
878 sizeof(*colors));
879 if (colors == (XColor *) NULL)
880 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
881 for (i=0; i < (ssize_t) image->colors; i++)
882 {
883 colors[i].pixel=(unsigned long) i;
884 colors[i].red=ScaleQuantumToShort(ClampToQuantum(
885 image->colormap[i].red));
886 colors[i].green=ScaleQuantumToShort(ClampToQuantum(
887 image->colormap[i].green));
888 colors[i].blue=ScaleQuantumToShort(ClampToQuantum(
889 image->colormap[i].blue));
890 colors[i].flags=(char) (DoRed | DoGreen | DoBlue);
891 colors[i].pad='\0';
892 if ((int) (*(char *) &lsb_first) != 0)
893 {
894 MSBOrderLong((unsigned char *) &colors[i].pixel,
895 sizeof(colors[i].pixel));
896 MSBOrderShort((unsigned char *) &colors[i].red,3*
897 sizeof(colors[i].red));
898 }
899 }
900 for (i=0; i < (ssize_t) image->colors; i++)
901 {
902 color.pixel=(CARD32) colors[i].pixel;
903 color.red=colors[i].red;
904 color.green=colors[i].green;
905 color.blue=colors[i].blue;
906 color.flags=(CARD8) colors[i].flags;
907 count=WriteBlob(image,sz_XWDColor,(unsigned char *) &color);
908 if (count != (ssize_t) sz_XWDColor)
909 break;
910 }
911 colors=(XColor *) RelinquishMagickMemory(colors);
912 }
913 /*
914 Allocate memory for pixels.
915 */
916 length=3*bytes_per_line;
917 if (image->storage_class == PseudoClass)
918 length=bytes_per_line;
919 pixels=(unsigned char *) AcquireQuantumMemory(length,sizeof(*pixels));
920 if (pixels == (unsigned char *) NULL)
921 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
922 (void) memset(pixels,0,length);
923 /*
924 Convert MIFF to XWD raster pixels.
925 */
926 scanline_pad=(bytes_per_line-((image->columns*bits_per_pixel) >> 3));
927 for (y=0; y < (ssize_t) image->rows; y++)
928 {
929 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
930 if (p == (const Quantum *) NULL)
931 break;
932 q=pixels;
933 if (image->storage_class == PseudoClass)
934 {
935 for (x=0; x < (ssize_t) image->columns; x++)
936 {
937 *q++=(unsigned char) ((ssize_t) GetPixelIndex(image,p));
938 p+=GetPixelChannels(image);
939 }
940 }
941 else
942 for (x=0; x < (ssize_t) image->columns; x++)
943 {
944 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
945 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
946 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
947 p+=GetPixelChannels(image);
948 }
949 for (x=0; x < (ssize_t) scanline_pad; x++)
950 *q++='\0';
951 length=(size_t) (q-pixels);
952 count=WriteBlob(image,length,pixels);
953 if (count != (ssize_t) length)
954 break;
955 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
956 image->rows);
957 if (status == MagickFalse)
958 break;
959 }
960 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
961 (void) CloseBlob(image);
962 return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
963 }
964 #endif
965