1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % DDDD IIIII SSSSS PPPP L AAA Y Y %
7 % D D I SS P P L A A Y Y %
8 % D D I SSS PPPP L AAAAA Y %
9 % D D I SS P L A A Y %
10 % DDDD IIIII SSSSS P LLLLL A A Y %
11 % %
12 % %
13 % MagickCore Methods to Interactively Display and Edit an Image %
14 % %
15 % Software Design %
16 % Cristy %
17 % July 1992 %
18 % %
19 % %
20 % Copyright 1999-2016 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 % http://www.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/artifact.h"
44 #include "MagickCore/attribute.h"
45 #include "MagickCore/blob.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/cache-private.h"
48 #include "MagickCore/channel.h"
49 #include "MagickCore/client.h"
50 #include "MagickCore/color.h"
51 #include "MagickCore/colorspace.h"
52 #include "MagickCore/composite.h"
53 #include "MagickCore/constitute.h"
54 #include "MagickCore/decorate.h"
55 #include "MagickCore/delegate.h"
56 #include "MagickCore/display.h"
57 #include "MagickCore/display-private.h"
58 #include "MagickCore/distort.h"
59 #include "MagickCore/draw.h"
60 #include "MagickCore/effect.h"
61 #include "MagickCore/enhance.h"
62 #include "MagickCore/exception.h"
63 #include "MagickCore/exception-private.h"
64 #include "MagickCore/fx.h"
65 #include "MagickCore/geometry.h"
66 #include "MagickCore/image.h"
67 #include "MagickCore/image-private.h"
68 #include "MagickCore/list.h"
69 #include "MagickCore/log.h"
70 #include "MagickCore/magick.h"
71 #include "MagickCore/memory_.h"
72 #include "MagickCore/monitor.h"
73 #include "MagickCore/monitor-private.h"
74 #include "MagickCore/montage.h"
75 #include "MagickCore/nt-base-private.h"
76 #include "MagickCore/option.h"
77 #include "MagickCore/paint.h"
78 #include "MagickCore/pixel.h"
79 #include "MagickCore/pixel-accessor.h"
80 #include "MagickCore/property.h"
81 #include "MagickCore/quantum.h"
82 #include "MagickCore/quantum-private.h"
83 #include "MagickCore/resize.h"
84 #include "MagickCore/resource_.h"
85 #include "MagickCore/shear.h"
86 #include "MagickCore/segment.h"
87 #include "MagickCore/statistic.h"
88 #include "MagickCore/string_.h"
89 #include "MagickCore/string-private.h"
90 #include "MagickCore/transform.h"
91 #include "MagickCore/transform-private.h"
92 #include "MagickCore/threshold.h"
93 #include "MagickCore/utility.h"
94 #include "MagickCore/utility-private.h"
95 #include "MagickCore/version.h"
96 #include "MagickCore/widget.h"
97 #include "MagickCore/widget-private.h"
98 #include "MagickCore/xwindow.h"
99 #include "MagickCore/xwindow-private.h"
100
101 #if defined(MAGICKCORE_X11_DELEGATE)
102 /*
103 Define declarations.
104 */
105 #define MaxColors MagickMin((ssize_t) windows->visual_info->colormap_size,256L)
106
107 /*
108 Constant declarations.
109 */
110 static const unsigned char
111 HighlightBitmap[8] =
112 {
113 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55
114 },
115 OpaqueBitmap[8] =
116 {
117 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
118 },
119 ShadowBitmap[8] =
120 {
121 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
122 };
123
124 static const char
125 *PageSizes[] =
126 {
127 "Letter",
128 "Tabloid",
129 "Ledger",
130 "Legal",
131 "Statement",
132 "Executive",
133 "A3",
134 "A4",
135 "A5",
136 "B4",
137 "B5",
138 "Folio",
139 "Quarto",
140 "10x14",
141 (char *) NULL
142 };
143
144 /*
145 Help widget declarations.
146 */
147 static const char
148 *ImageAnnotateHelp[] =
149 {
150 "In annotate mode, the Command widget has these options:",
151 "",
152 " Font Name",
153 " fixed",
154 " variable",
155 " 5x8",
156 " 6x10",
157 " 7x13bold",
158 " 8x13bold",
159 " 9x15bold",
160 " 10x20",
161 " 12x24",
162 " Browser...",
163 " Font Color",
164 " black",
165 " blue",
166 " cyan",
167 " green",
168 " gray",
169 " red",
170 " magenta",
171 " yellow",
172 " white",
173 " transparent",
174 " Browser...",
175 " Font Color",
176 " black",
177 " blue",
178 " cyan",
179 " green",
180 " gray",
181 " red",
182 " magenta",
183 " yellow",
184 " white",
185 " transparent",
186 " Browser...",
187 " Rotate Text",
188 " -90",
189 " -45",
190 " -30",
191 " 0",
192 " 30",
193 " 45",
194 " 90",
195 " 180",
196 " Dialog...",
197 " Help",
198 " Dismiss",
199 "",
200 "Choose a font name from the Font Name sub-menu. Additional",
201 "font names can be specified with the font browser. You can",
202 "change the menu names by setting the X resources font1",
203 "through font9.",
204 "",
205 "Choose a font color from the Font Color sub-menu.",
206 "Additional font colors can be specified with the color",
207 "browser. You can change the menu colors by setting the X",
208 "resources pen1 through pen9.",
209 "",
210 "If you select the color browser and press Grab, you can",
211 "choose the font color by moving the pointer to the desired",
212 "color on the screen and press any button.",
213 "",
214 "If you choose to rotate the text, choose Rotate Text from the",
215 "menu and select an angle. Typically you will only want to",
216 "rotate one line of text at a time. Depending on the angle you",
217 "choose, subsequent lines may end up overwriting each other.",
218 "",
219 "Choosing a font and its color is optional. The default font",
220 "is fixed and the default color is black. However, you must",
221 "choose a location to begin entering text and press button 1.",
222 "An underscore character will appear at the location of the",
223 "pointer. The cursor changes to a pencil to indicate you are",
224 "in text mode. To exit immediately, press Dismiss.",
225 "",
226 "In text mode, any key presses will display the character at",
227 "the location of the underscore and advance the underscore",
228 "cursor. Enter your text and once completed press Apply to",
229 "finish your image annotation. To correct errors press BACK",
230 "SPACE. To delete an entire line of text, press DELETE. Any",
231 "text that exceeds the boundaries of the image window is",
232 "automagically continued onto the next line.",
233 "",
234 "The actual color you request for the font is saved in the",
235 "image. However, the color that appears in your image window",
236 "may be different. For example, on a monochrome screen the",
237 "text will appear black or white even if you choose the color",
238 "red as the font color. However, the image saved to a file",
239 "with -write is written with red lettering. To assure the",
240 "correct color text in the final image, any PseudoClass image",
241 "is promoted to DirectClass (see miff(5)). To force a",
242 "PseudoClass image to remain PseudoClass, use -colors.",
243 (char *) NULL,
244 },
245 *ImageChopHelp[] =
246 {
247 "In chop mode, the Command widget has these options:",
248 "",
249 " Direction",
250 " horizontal",
251 " vertical",
252 " Help",
253 " Dismiss",
254 "",
255 "If the you choose the horizontal direction (this the",
256 "default), the area of the image between the two horizontal",
257 "endpoints of the chop line is removed. Otherwise, the area",
258 "of the image between the two vertical endpoints of the chop",
259 "line is removed.",
260 "",
261 "Select a location within the image window to begin your chop,",
262 "press and hold any button. Next, move the pointer to",
263 "another location in the image. As you move a line will",
264 "connect the initial location and the pointer. When you",
265 "release the button, the area within the image to chop is",
266 "determined by which direction you choose from the Command",
267 "widget.",
268 "",
269 "To cancel the image chopping, move the pointer back to the",
270 "starting point of the line and release the button.",
271 (char *) NULL,
272 },
273 *ImageColorEditHelp[] =
274 {
275 "In color edit mode, the Command widget has these options:",
276 "",
277 " Method",
278 " point",
279 " replace",
280 " floodfill",
281 " filltoborder",
282 " reset",
283 " Pixel Color",
284 " black",
285 " blue",
286 " cyan",
287 " green",
288 " gray",
289 " red",
290 " magenta",
291 " yellow",
292 " white",
293 " Browser...",
294 " Border Color",
295 " black",
296 " blue",
297 " cyan",
298 " green",
299 " gray",
300 " red",
301 " magenta",
302 " yellow",
303 " white",
304 " Browser...",
305 " Fuzz",
306 " 0%",
307 " 2%",
308 " 5%",
309 " 10%",
310 " 15%",
311 " Dialog...",
312 " Undo",
313 " Help",
314 " Dismiss",
315 "",
316 "Choose a color editing method from the Method sub-menu",
317 "of the Command widget. The point method recolors any pixel",
318 "selected with the pointer until the button is released. The",
319 "replace method recolors any pixel that matches the color of",
320 "the pixel you select with a button press. Floodfill recolors",
321 "any pixel that matches the color of the pixel you select with",
322 "a button press and is a neighbor. Whereas filltoborder recolors",
323 "any neighbor pixel that is not the border color. Finally reset",
324 "changes the entire image to the designated color.",
325 "",
326 "Next, choose a pixel color from the Pixel Color sub-menu.",
327 "Additional pixel colors can be specified with the color",
328 "browser. You can change the menu colors by setting the X",
329 "resources pen1 through pen9.",
330 "",
331 "Now press button 1 to select a pixel within the image window",
332 "to change its color. Additional pixels may be recolored as",
333 "prescribed by the method you choose.",
334 "",
335 "If the Magnify widget is mapped, it can be helpful in positioning",
336 "your pointer within the image (refer to button 2).",
337 "",
338 "The actual color you request for the pixels is saved in the",
339 "image. However, the color that appears in your image window",
340 "may be different. For example, on a monochrome screen the",
341 "pixel will appear black or white even if you choose the",
342 "color red as the pixel color. However, the image saved to a",
343 "file with -write is written with red pixels. To assure the",
344 "correct color text in the final image, any PseudoClass image",
345 "is promoted to DirectClass (see miff(5)). To force a",
346 "PseudoClass image to remain PseudoClass, use -colors.",
347 (char *) NULL,
348 },
349 *ImageCompositeHelp[] =
350 {
351 "First a widget window is displayed requesting you to enter an",
352 "image name. Press Composite, Grab or type a file name.",
353 "Press Cancel if you choose not to create a composite image.",
354 "When you choose Grab, move the pointer to the desired window",
355 "and press any button.",
356 "",
357 "If the Composite image does not have any matte information,",
358 "you are informed and the file browser is displayed again.",
359 "Enter the name of a mask image. The image is typically",
360 "grayscale and the same size as the composite image. If the",
361 "image is not grayscale, it is converted to grayscale and the",
362 "resulting intensities are used as matte information.",
363 "",
364 "A small window appears showing the location of the cursor in",
365 "the image window. You are now in composite mode. To exit",
366 "immediately, press Dismiss. In composite mode, the Command",
367 "widget has these options:",
368 "",
369 " Operators",
370 " Over",
371 " In",
372 " Out",
373 " Atop",
374 " Xor",
375 " Plus",
376 " Minus",
377 " Add",
378 " Subtract",
379 " Difference",
380 " Multiply",
381 " Bumpmap",
382 " Copy",
383 " CopyRed",
384 " CopyGreen",
385 " CopyBlue",
386 " CopyOpacity",
387 " Clear",
388 " Dissolve",
389 " Displace",
390 " Help",
391 " Dismiss",
392 "",
393 "Choose a composite operation from the Operators sub-menu of",
394 "the Command widget. How each operator behaves is described",
395 "below. Image window is the image currently displayed on",
396 "your X server and image is the image obtained with the File",
397 "Browser widget.",
398 "",
399 "Over The result is the union of the two image shapes,",
400 " with image obscuring image window in the region of",
401 " overlap.",
402 "",
403 "In The result is simply image cut by the shape of",
404 " image window. None of the image data of image",
405 " window is in the result.",
406 "",
407 "Out The resulting image is image with the shape of",
408 " image window cut out.",
409 "",
410 "Atop The result is the same shape as image image window,",
411 " with image obscuring image window where the image",
412 " shapes overlap. Note this differs from over",
413 " because the portion of image outside image window's",
414 " shape does not appear in the result.",
415 "",
416 "Xor The result is the image data from both image and",
417 " image window that is outside the overlap region.",
418 " The overlap region is blank.",
419 "",
420 "Plus The result is just the sum of the image data.",
421 " Output values are cropped to QuantumRange (no overflow).",
422 "",
423 "Minus The result of image - image window, with underflow",
424 " cropped to zero.",
425 "",
426 "Add The result of image + image window, with overflow",
427 " wrapping around (mod 256).",
428 "",
429 "Subtract The result of image - image window, with underflow",
430 " wrapping around (mod 256). The add and subtract",
431 " operators can be used to perform reversible",
432 " transformations.",
433 "",
434 "Difference",
435 " The result of abs(image - image window). This",
436 " useful for comparing two very similar images.",
437 "",
438 "Multiply",
439 " The result of image * image window. This",
440 " useful for the creation of drop-shadows.",
441 "",
442 "Bumpmap The result of surface normals from image * image",
443 " window.",
444 "",
445 "Copy The resulting image is image window replaced with",
446 " image. Here the matte information is ignored.",
447 "",
448 "CopyRed The red layer of the image window is replace with",
449 " the red layer of the image. The other layers are",
450 " untouched.",
451 "",
452 "CopyGreen",
453 " The green layer of the image window is replace with",
454 " the green layer of the image. The other layers are",
455 " untouched.",
456 "",
457 "CopyBlue The blue layer of the image window is replace with",
458 " the blue layer of the image. The other layers are",
459 " untouched.",
460 "",
461 "CopyOpacity",
462 " The matte layer of the image window is replace with",
463 " the matte layer of the image. The other layers are",
464 " untouched.",
465 "",
466 "The image compositor requires a matte, or alpha channel in",
467 "the image for some operations. This extra channel usually",
468 "defines a mask which represents a sort of a cookie-cutter",
469 "for the image. This the case when matte is opaque (full",
470 "coverage) for pixels inside the shape, zero outside, and",
471 "between 0 and QuantumRange on the boundary. If image does not",
472 "have a matte channel, it is initialized with 0 for any pixel",
473 "matching in color to pixel location (0,0), otherwise QuantumRange.",
474 "",
475 "If you choose Dissolve, the composite operator becomes Over. The",
476 "image matte channel percent transparency is initialized to factor.",
477 "The image window is initialized to (100-factor). Where factor is the",
478 "value you specify in the Dialog widget.",
479 "",
480 "Displace shifts the image pixels as defined by a displacement",
481 "map. With this option, image is used as a displacement map.",
482 "Black, within the displacement map, is a maximum positive",
483 "displacement. White is a maximum negative displacement and",
484 "middle gray is neutral. The displacement is scaled to determine",
485 "the pixel shift. By default, the displacement applies in both the",
486 "horizontal and vertical directions. However, if you specify a mask,",
487 "image is the horizontal X displacement and mask the vertical Y",
488 "displacement.",
489 "",
490 "Note that matte information for image window is not retained",
491 "for colormapped X server visuals (e.g. StaticColor,",
492 "StaticColor, GrayScale, PseudoColor). Correct compositing",
493 "behavior may require a TrueColor or DirectColor visual or a",
494 "Standard Colormap.",
495 "",
496 "Choosing a composite operator is optional. The default",
497 "operator is replace. However, you must choose a location to",
498 "composite your image and press button 1. Press and hold the",
499 "button before releasing and an outline of the image will",
500 "appear to help you identify your location.",
501 "",
502 "The actual colors of the composite image is saved. However,",
503 "the color that appears in image window may be different.",
504 "For example, on a monochrome screen image window will appear",
505 "black or white even though your composited image may have",
506 "many colors. If the image is saved to a file it is written",
507 "with the correct colors. To assure the correct colors are",
508 "saved in the final image, any PseudoClass image is promoted",
509 "to DirectClass (see miff(5)). To force a PseudoClass image",
510 "to remain PseudoClass, use -colors.",
511 (char *) NULL,
512 },
513 *ImageCutHelp[] =
514 {
515 "In cut mode, the Command widget has these options:",
516 "",
517 " Help",
518 " Dismiss",
519 "",
520 "To define a cut region, press button 1 and drag. The",
521 "cut region is defined by a highlighted rectangle that",
522 "expands or contracts as it follows the pointer. Once you",
523 "are satisfied with the cut region, release the button.",
524 "You are now in rectify mode. In rectify mode, the Command",
525 "widget has these options:",
526 "",
527 " Cut",
528 " Help",
529 " Dismiss",
530 "",
531 "You can make adjustments by moving the pointer to one of the",
532 "cut rectangle corners, pressing a button, and dragging.",
533 "Finally, press Cut to commit your copy region. To",
534 "exit without cutting the image, press Dismiss.",
535 (char *) NULL,
536 },
537 *ImageCopyHelp[] =
538 {
539 "In copy mode, the Command widget has these options:",
540 "",
541 " Help",
542 " Dismiss",
543 "",
544 "To define a copy region, press button 1 and drag. The",
545 "copy region is defined by a highlighted rectangle that",
546 "expands or contracts as it follows the pointer. Once you",
547 "are satisfied with the copy region, release the button.",
548 "You are now in rectify mode. In rectify mode, the Command",
549 "widget has these options:",
550 "",
551 " Copy",
552 " Help",
553 " Dismiss",
554 "",
555 "You can make adjustments by moving the pointer to one of the",
556 "copy rectangle corners, pressing a button, and dragging.",
557 "Finally, press Copy to commit your copy region. To",
558 "exit without copying the image, press Dismiss.",
559 (char *) NULL,
560 },
561 *ImageCropHelp[] =
562 {
563 "In crop mode, the Command widget has these options:",
564 "",
565 " Help",
566 " Dismiss",
567 "",
568 "To define a cropping region, press button 1 and drag. The",
569 "cropping region is defined by a highlighted rectangle that",
570 "expands or contracts as it follows the pointer. Once you",
571 "are satisfied with the cropping region, release the button.",
572 "You are now in rectify mode. In rectify mode, the Command",
573 "widget has these options:",
574 "",
575 " Crop",
576 " Help",
577 " Dismiss",
578 "",
579 "You can make adjustments by moving the pointer to one of the",
580 "cropping rectangle corners, pressing a button, and dragging.",
581 "Finally, press Crop to commit your cropping region. To",
582 "exit without cropping the image, press Dismiss.",
583 (char *) NULL,
584 },
585 *ImageDrawHelp[] =
586 {
587 "The cursor changes to a crosshair to indicate you are in",
588 "draw mode. To exit immediately, press Dismiss. In draw mode,",
589 "the Command widget has these options:",
590 "",
591 " Element",
592 " point",
593 " line",
594 " rectangle",
595 " fill rectangle",
596 " circle",
597 " fill circle",
598 " ellipse",
599 " fill ellipse",
600 " polygon",
601 " fill polygon",
602 " Color",
603 " black",
604 " blue",
605 " cyan",
606 " green",
607 " gray",
608 " red",
609 " magenta",
610 " yellow",
611 " white",
612 " transparent",
613 " Browser...",
614 " Stipple",
615 " Brick",
616 " Diagonal",
617 " Scales",
618 " Vertical",
619 " Wavy",
620 " Translucent",
621 " Opaque",
622 " Open...",
623 " Width",
624 " 1",
625 " 2",
626 " 4",
627 " 8",
628 " 16",
629 " Dialog...",
630 " Undo",
631 " Help",
632 " Dismiss",
633 "",
634 "Choose a drawing primitive from the Element sub-menu.",
635 "",
636 "Choose a color from the Color sub-menu. Additional",
637 "colors can be specified with the color browser.",
638 "",
639 "If you choose the color browser and press Grab, you can",
640 "select the color by moving the pointer to the desired",
641 "color on the screen and press any button. The transparent",
642 "color updates the image matte channel and is useful for",
643 "image compositing.",
644 "",
645 "Choose a stipple, if appropriate, from the Stipple sub-menu.",
646 "Additional stipples can be specified with the file browser.",
647 "Stipples obtained from the file browser must be on disk in the",
648 "X11 bitmap format.",
649 "",
650 "Choose a width, if appropriate, from the Width sub-menu. To",
651 "choose a specific width select the Dialog widget.",
652 "",
653 "Choose a point in the Image window and press button 1 and",
654 "hold. Next, move the pointer to another location in the",
655 "image. As you move, a line connects the initial location and",
656 "the pointer. When you release the button, the image is",
657 "updated with the primitive you just drew. For polygons, the",
658 "image is updated when you press and release the button without",
659 "moving the pointer.",
660 "",
661 "To cancel image drawing, move the pointer back to the",
662 "starting point of the line and release the button.",
663 (char *) NULL,
664 },
665 *DisplayHelp[] =
666 {
667 "BUTTONS",
668 " The effects of each button press is described below. Three",
669 " buttons are required. If you have a two button mouse,",
670 " button 1 and 3 are returned. Press ALT and button 3 to",
671 " simulate button 2.",
672 "",
673 " 1 Press this button to map or unmap the Command widget.",
674 "",
675 " 2 Press and drag to define a region of the image to",
676 " magnify.",
677 "",
678 " 3 Press and drag to choose from a select set of commands.",
679 " This button behaves differently if the image being",
680 " displayed is a visual image directory. Here, choose a",
681 " particular tile of the directory and press this button and",
682 " drag to select a command from a pop-up menu. Choose from",
683 " these menu items:",
684 "",
685 " Open",
686 " Next",
687 " Former",
688 " Delete",
689 " Update",
690 "",
691 " If you choose Open, the image represented by the tile is",
692 " displayed. To return to the visual image directory, choose",
693 " Next from the Command widget. Next and Former moves to the",
694 " next or former image respectively. Choose Delete to delete",
695 " a particular image tile. Finally, choose Update to",
696 " synchronize all the image tiles with their respective",
697 " images.",
698 "",
699 "COMMAND WIDGET",
700 " The Command widget lists a number of sub-menus and commands.",
701 " They are",
702 "",
703 " File",
704 " Open...",
705 " Next",
706 " Former",
707 " Select...",
708 " Save...",
709 " Print...",
710 " Delete...",
711 " New...",
712 " Visual Directory...",
713 " Quit",
714 " Edit",
715 " Undo",
716 " Redo",
717 " Cut",
718 " Copy",
719 " Paste",
720 " View",
721 " Half Size",
722 " Original Size",
723 " Double Size",
724 " Resize...",
725 " Apply",
726 " Refresh",
727 " Restore",
728 " Transform",
729 " Crop",
730 " Chop",
731 " Flop",
732 " Flip",
733 " Rotate Right",
734 " Rotate Left",
735 " Rotate...",
736 " Shear...",
737 " Roll...",
738 " Trim Edges",
739 " Enhance",
740 " Brightness...",
741 " Saturation...",
742 " Hue...",
743 " Gamma...",
744 " Sharpen...",
745 " Dull",
746 " Contrast Stretch...",
747 " Sigmoidal Contrast...",
748 " Normalize",
749 " Equalize",
750 " Negate",
751 " Grayscale",
752 " Map...",
753 " Quantize...",
754 " Effects",
755 " Despeckle",
756 " Emboss",
757 " Reduce Noise",
758 " Add Noise",
759 " Sharpen...",
760 " Blur...",
761 " Threshold...",
762 " Edge Detect...",
763 " Spread...",
764 " Shade...",
765 " Painting...",
766 " Segment...",
767 " F/X",
768 " Solarize...",
769 " Sepia Tone...",
770 " Swirl...",
771 " Implode...",
772 " Vignette...",
773 " Wave...",
774 " Oil Painting...",
775 " Charcoal Drawing...",
776 " Image Edit",
777 " Annotate...",
778 " Draw...",
779 " Color...",
780 " Matte...",
781 " Composite...",
782 " Add Border...",
783 " Add Frame...",
784 " Comment...",
785 " Launch...",
786 " Region of Interest...",
787 " Miscellany",
788 " Image Info",
789 " Zoom Image",
790 " Show Preview...",
791 " Show Histogram",
792 " Show Matte",
793 " Background...",
794 " Slide Show",
795 " Preferences...",
796 " Help",
797 " Overview",
798 " Browse Documentation",
799 " About Display",
800 "",
801 " Menu items with a indented triangle have a sub-menu. They",
802 " are represented above as the indented items. To access a",
803 " sub-menu item, move the pointer to the appropriate menu and",
804 " press a button and drag. When you find the desired sub-menu",
805 " item, release the button and the command is executed. Move",
806 " the pointer away from the sub-menu if you decide not to",
807 " execute a particular command.",
808 "",
809 "KEYBOARD ACCELERATORS",
810 " Accelerators are one or two key presses that effect a",
811 " particular command. The keyboard accelerators that",
812 " display(1) understands is:",
813 "",
814 " Ctl+O Press to open an image from a file.",
815 "",
816 " space Press to display the next image.",
817 "",
818 " If the image is a multi-paged document such as a Postscript",
819 " document, you can skip ahead several pages by preceding",
820 " this command with a number. For example to display the",
821 " third page beyond the current page, press 3<space>.",
822 "",
823 " backspace Press to display the former image.",
824 "",
825 " If the image is a multi-paged document such as a Postscript",
826 " document, you can skip behind several pages by preceding",
827 " this command with a number. For example to display the",
828 " third page preceding the current page, press 3<backspace>.",
829 "",
830 " Ctl+S Press to write the image to a file.",
831 "",
832 " Ctl+P Press to print the image to a Postscript printer.",
833 "",
834 " Ctl+D Press to delete an image file.",
835 "",
836 " Ctl+N Press to create a blank canvas.",
837 "",
838 " Ctl+Q Press to discard all images and exit program.",
839 "",
840 " Ctl+Z Press to undo last image transformation.",
841 "",
842 " Ctl+R Press to redo last image transformation.",
843 "",
844 " Ctl+X Press to cut a region of the image.",
845 "",
846 " Ctl+C Press to copy a region of the image.",
847 "",
848 " Ctl+V Press to paste a region to the image.",
849 "",
850 " < Press to half the image size.",
851 "",
852 " - Press to return to the original image size.",
853 "",
854 " > Press to double the image size.",
855 "",
856 " % Press to resize the image to a width and height you",
857 " specify.",
858 "",
859 "Cmd-A Press to make any image transformations permanent."
860 "",
861 " By default, any image size transformations are applied",
862 " to the original image to create the image displayed on",
863 " the X server. However, the transformations are not",
864 " permanent (i.e. the original image does not change",
865 " size only the X image does). For example, if you",
866 " press > the X image will appear to double in size,",
867 " but the original image will in fact remain the same size.",
868 " To force the original image to double in size, press >",
869 " followed by Cmd-A.",
870 "",
871 " @ Press to refresh the image window.",
872 "",
873 " C Press to cut out a rectangular region of the image.",
874 "",
875 " [ Press to chop the image.",
876 "",
877 " H Press to flop image in the horizontal direction.",
878 "",
879 " V Press to flip image in the vertical direction.",
880 "",
881 " / Press to rotate the image 90 degrees clockwise.",
882 "",
883 " \\ Press to rotate the image 90 degrees counter-clockwise.",
884 "",
885 " * Press to rotate the image the number of degrees you",
886 " specify.",
887 "",
888 " S Press to shear the image the number of degrees you",
889 " specify.",
890 "",
891 " R Press to roll the image.",
892 "",
893 " T Press to trim the image edges.",
894 "",
895 " Shft-H Press to vary the image hue.",
896 "",
897 " Shft-S Press to vary the color saturation.",
898 "",
899 " Shft-L Press to vary the color brightness.",
900 "",
901 " Shft-G Press to gamma correct the image.",
902 "",
903 " Shft-C Press to sharpen the image contrast.",
904 "",
905 " Shft-Z Press to dull the image contrast.",
906 "",
907 " = Press to perform histogram equalization on the image.",
908 "",
909 " Shft-N Press to perform histogram normalization on the image.",
910 "",
911 " Shft-~ Press to negate the colors of the image.",
912 "",
913 " . Press to convert the image colors to gray.",
914 "",
915 " Shft-# Press to set the maximum number of unique colors in the",
916 " image.",
917 "",
918 " F2 Press to reduce the speckles in an image.",
919 "",
920 " F3 Press to eliminate peak noise from an image.",
921 "",
922 " F4 Press to add noise to an image.",
923 "",
924 " F5 Press to sharpen an image.",
925 "",
926 " F6 Press to delete an image file.",
927 "",
928 " F7 Press to threshold the image.",
929 "",
930 " F8 Press to detect edges within an image.",
931 "",
932 " F9 Press to emboss an image.",
933 "",
934 " F10 Press to displace pixels by a random amount.",
935 "",
936 " F11 Press to negate all pixels above the threshold level.",
937 "",
938 " F12 Press to shade the image using a distant light source.",
939 "",
940 " F13 Press to lighten or darken image edges to create a 3-D effect.",
941 "",
942 " F14 Press to segment the image by color.",
943 "",
944 " Meta-S Press to swirl image pixels about the center.",
945 "",
946 " Meta-I Press to implode image pixels about the center.",
947 "",
948 " Meta-W Press to alter an image along a sine wave.",
949 "",
950 " Meta-P Press to simulate an oil painting.",
951 "",
952 " Meta-C Press to simulate a charcoal drawing.",
953 "",
954 " Alt-A Press to annotate the image with text.",
955 "",
956 " Alt-D Press to draw on an image.",
957 "",
958 " Alt-P Press to edit an image pixel color.",
959 "",
960 " Alt-M Press to edit the image matte information.",
961 "",
962 " Alt-V Press to composite the image with another.",
963 "",
964 " Alt-B Press to add a border to the image.",
965 "",
966 " Alt-F Press to add an ornamental border to the image.",
967 "",
968 " Alt-Shft-!",
969 " Press to add an image comment.",
970 "",
971 " Ctl-A Press to apply image processing techniques to a region",
972 " of interest.",
973 "",
974 " Shft-? Press to display information about the image.",
975 "",
976 " Shft-+ Press to map the zoom image window.",
977 "",
978 " Shft-P Press to preview an image enhancement, effect, or f/x.",
979 "",
980 " F1 Press to display helpful information about display(1).",
981 "",
982 " Find Press to browse documentation about ImageMagick.",
983 "",
984 " 1-9 Press to change the level of magnification.",
985 "",
986 " Use the arrow keys to move the image one pixel up, down,",
987 " left, or right within the magnify window. Be sure to first",
988 " map the magnify window by pressing button 2.",
989 "",
990 " Press ALT and one of the arrow keys to trim off one pixel",
991 " from any side of the image.",
992 (char *) NULL,
993 },
994 *ImageMatteEditHelp[] =
995 {
996 "Matte information within an image is useful for some",
997 "operations such as image compositing (See IMAGE",
998 "COMPOSITING). This extra channel usually defines a mask",
999 "which represents a sort of a cookie-cutter for the image.",
1000 "This the case when matte is opaque (full coverage) for",
1001 "pixels inside the shape, zero outside, and between 0 and",
1002 "QuantumRange on the boundary.",
1003 "",
1004 "A small window appears showing the location of the cursor in",
1005 "the image window. You are now in matte edit mode. To exit",
1006 "immediately, press Dismiss. In matte edit mode, the Command",
1007 "widget has these options:",
1008 "",
1009 " Method",
1010 " point",
1011 " replace",
1012 " floodfill",
1013 " filltoborder",
1014 " reset",
1015 " Border Color",
1016 " black",
1017 " blue",
1018 " cyan",
1019 " green",
1020 " gray",
1021 " red",
1022 " magenta",
1023 " yellow",
1024 " white",
1025 " Browser...",
1026 " Fuzz",
1027 " 0%",
1028 " 2%",
1029 " 5%",
1030 " 10%",
1031 " 15%",
1032 " Dialog...",
1033 " Matte",
1034 " Opaque",
1035 " Transparent",
1036 " Dialog...",
1037 " Undo",
1038 " Help",
1039 " Dismiss",
1040 "",
1041 "Choose a matte editing method from the Method sub-menu of",
1042 "the Command widget. The point method changes the matte value",
1043 "of any pixel selected with the pointer until the button is",
1044 "is released. The replace method changes the matte value of",
1045 "any pixel that matches the color of the pixel you select with",
1046 "a button press. Floodfill changes the matte value of any pixel",
1047 "that matches the color of the pixel you select with a button",
1048 "press and is a neighbor. Whereas filltoborder changes the matte",
1049 "value any neighbor pixel that is not the border color. Finally",
1050 "reset changes the entire image to the designated matte value.",
1051 "",
1052 "Choose Matte Value and pick Opaque or Transarent. For other values",
1053 "select the Dialog entry. Here a dialog appears requesting a matte",
1054 "value. The value you select is assigned as the opacity value of the",
1055 "selected pixel or pixels.",
1056 "",
1057 "Now, press any button to select a pixel within the image",
1058 "window to change its matte value.",
1059 "",
1060 "If the Magnify widget is mapped, it can be helpful in positioning",
1061 "your pointer within the image (refer to button 2).",
1062 "",
1063 "Matte information is only valid in a DirectClass image.",
1064 "Therefore, any PseudoClass image is promoted to DirectClass",
1065 "(see miff(5)). Note that matte information for PseudoClass",
1066 "is not retained for colormapped X server visuals (e.g.",
1067 "StaticColor, StaticColor, GrayScale, PseudoColor) unless you",
1068 "immediately save your image to a file (refer to Write).",
1069 "Correct matte editing behavior may require a TrueColor or",
1070 "DirectColor visual or a Standard Colormap.",
1071 (char *) NULL,
1072 },
1073 *ImagePanHelp[] =
1074 {
1075 "When an image exceeds the width or height of the X server",
1076 "screen, display maps a small panning icon. The rectangle",
1077 "within the panning icon shows the area that is currently",
1078 "displayed in the image window. To pan about the image,",
1079 "press any button and drag the pointer within the panning",
1080 "icon. The pan rectangle moves with the pointer and the",
1081 "image window is updated to reflect the location of the",
1082 "rectangle within the panning icon. When you have selected",
1083 "the area of the image you wish to view, release the button.",
1084 "",
1085 "Use the arrow keys to pan the image one pixel up, down,",
1086 "left, or right within the image window.",
1087 "",
1088 "The panning icon is withdrawn if the image becomes smaller",
1089 "than the dimensions of the X server screen.",
1090 (char *) NULL,
1091 },
1092 *ImagePasteHelp[] =
1093 {
1094 "A small window appears showing the location of the cursor in",
1095 "the image window. You are now in paste mode. To exit",
1096 "immediately, press Dismiss. In paste mode, the Command",
1097 "widget has these options:",
1098 "",
1099 " Operators",
1100 " over",
1101 " in",
1102 " out",
1103 " atop",
1104 " xor",
1105 " plus",
1106 " minus",
1107 " add",
1108 " subtract",
1109 " difference",
1110 " replace",
1111 " Help",
1112 " Dismiss",
1113 "",
1114 "Choose a composite operation from the Operators sub-menu of",
1115 "the Command widget. How each operator behaves is described",
1116 "below. Image window is the image currently displayed on",
1117 "your X server and image is the image obtained with the File",
1118 "Browser widget.",
1119 "",
1120 "Over The result is the union of the two image shapes,",
1121 " with image obscuring image window in the region of",
1122 " overlap.",
1123 "",
1124 "In The result is simply image cut by the shape of",
1125 " image window. None of the image data of image",
1126 " window is in the result.",
1127 "",
1128 "Out The resulting image is image with the shape of",
1129 " image window cut out.",
1130 "",
1131 "Atop The result is the same shape as image image window,",
1132 " with image obscuring image window where the image",
1133 " shapes overlap. Note this differs from over",
1134 " because the portion of image outside image window's",
1135 " shape does not appear in the result.",
1136 "",
1137 "Xor The result is the image data from both image and",
1138 " image window that is outside the overlap region.",
1139 " The overlap region is blank.",
1140 "",
1141 "Plus The result is just the sum of the image data.",
1142 " Output values are cropped to QuantumRange (no overflow).",
1143 " This operation is independent of the matte",
1144 " channels.",
1145 "",
1146 "Minus The result of image - image window, with underflow",
1147 " cropped to zero.",
1148 "",
1149 "Add The result of image + image window, with overflow",
1150 " wrapping around (mod 256).",
1151 "",
1152 "Subtract The result of image - image window, with underflow",
1153 " wrapping around (mod 256). The add and subtract",
1154 " operators can be used to perform reversible",
1155 " transformations.",
1156 "",
1157 "Difference",
1158 " The result of abs(image - image window). This",
1159 " useful for comparing two very similar images.",
1160 "",
1161 "Copy The resulting image is image window replaced with",
1162 " image. Here the matte information is ignored.",
1163 "",
1164 "CopyRed The red layer of the image window is replace with",
1165 " the red layer of the image. The other layers are",
1166 " untouched.",
1167 "",
1168 "CopyGreen",
1169 " The green layer of the image window is replace with",
1170 " the green layer of the image. The other layers are",
1171 " untouched.",
1172 "",
1173 "CopyBlue The blue layer of the image window is replace with",
1174 " the blue layer of the image. The other layers are",
1175 " untouched.",
1176 "",
1177 "CopyOpacity",
1178 " The matte layer of the image window is replace with",
1179 " the matte layer of the image. The other layers are",
1180 " untouched.",
1181 "",
1182 "The image compositor requires a matte, or alpha channel in",
1183 "the image for some operations. This extra channel usually",
1184 "defines a mask which represents a sort of a cookie-cutter",
1185 "for the image. This the case when matte is opaque (full",
1186 "coverage) for pixels inside the shape, zero outside, and",
1187 "between 0 and QuantumRange on the boundary. If image does not",
1188 "have a matte channel, it is initialized with 0 for any pixel",
1189 "matching in color to pixel location (0,0), otherwise QuantumRange.",
1190 "",
1191 "Note that matte information for image window is not retained",
1192 "for colormapped X server visuals (e.g. StaticColor,",
1193 "StaticColor, GrayScale, PseudoColor). Correct compositing",
1194 "behavior may require a TrueColor or DirectColor visual or a",
1195 "Standard Colormap.",
1196 "",
1197 "Choosing a composite operator is optional. The default",
1198 "operator is replace. However, you must choose a location to",
1199 "paste your image and press button 1. Press and hold the",
1200 "button before releasing and an outline of the image will",
1201 "appear to help you identify your location.",
1202 "",
1203 "The actual colors of the pasted image is saved. However,",
1204 "the color that appears in image window may be different.",
1205 "For example, on a monochrome screen image window will appear",
1206 "black or white even though your pasted image may have",
1207 "many colors. If the image is saved to a file it is written",
1208 "with the correct colors. To assure the correct colors are",
1209 "saved in the final image, any PseudoClass image is promoted",
1210 "to DirectClass (see miff(5)). To force a PseudoClass image",
1211 "to remain PseudoClass, use -colors.",
1212 (char *) NULL,
1213 },
1214 *ImageROIHelp[] =
1215 {
1216 "In region of interest mode, the Command widget has these",
1217 "options:",
1218 "",
1219 " Help",
1220 " Dismiss",
1221 "",
1222 "To define a region of interest, press button 1 and drag.",
1223 "The region of interest is defined by a highlighted rectangle",
1224 "that expands or contracts as it follows the pointer. Once",
1225 "you are satisfied with the region of interest, release the",
1226 "button. You are now in apply mode. In apply mode the",
1227 "Command widget has these options:",
1228 "",
1229 " File",
1230 " Save...",
1231 " Print...",
1232 " Edit",
1233 " Undo",
1234 " Redo",
1235 " Transform",
1236 " Flop",
1237 " Flip",
1238 " Rotate Right",
1239 " Rotate Left",
1240 " Enhance",
1241 " Hue...",
1242 " Saturation...",
1243 " Brightness...",
1244 " Gamma...",
1245 " Spiff",
1246 " Dull",
1247 " Contrast Stretch",
1248 " Sigmoidal Contrast...",
1249 " Normalize",
1250 " Equalize",
1251 " Negate",
1252 " Grayscale",
1253 " Map...",
1254 " Quantize...",
1255 " Effects",
1256 " Despeckle",
1257 " Emboss",
1258 " Reduce Noise",
1259 " Sharpen...",
1260 " Blur...",
1261 " Threshold...",
1262 " Edge Detect...",
1263 " Spread...",
1264 " Shade...",
1265 " Raise...",
1266 " Segment...",
1267 " F/X",
1268 " Solarize...",
1269 " Sepia Tone...",
1270 " Swirl...",
1271 " Implode...",
1272 " Vignette...",
1273 " Wave...",
1274 " Oil Painting...",
1275 " Charcoal Drawing...",
1276 " Miscellany",
1277 " Image Info",
1278 " Zoom Image",
1279 " Show Preview...",
1280 " Show Histogram",
1281 " Show Matte",
1282 " Help",
1283 " Dismiss",
1284 "",
1285 "You can make adjustments to the region of interest by moving",
1286 "the pointer to one of the rectangle corners, pressing a",
1287 "button, and dragging. Finally, choose an image processing",
1288 "technique from the Command widget. You can choose more than",
1289 "one image processing technique to apply to an area.",
1290 "Alternatively, you can move the region of interest before",
1291 "applying another image processing technique. To exit, press",
1292 "Dismiss.",
1293 (char *) NULL,
1294 },
1295 *ImageRotateHelp[] =
1296 {
1297 "In rotate mode, the Command widget has these options:",
1298 "",
1299 " Pixel Color",
1300 " black",
1301 " blue",
1302 " cyan",
1303 " green",
1304 " gray",
1305 " red",
1306 " magenta",
1307 " yellow",
1308 " white",
1309 " Browser...",
1310 " Direction",
1311 " horizontal",
1312 " vertical",
1313 " Help",
1314 " Dismiss",
1315 "",
1316 "Choose a background color from the Pixel Color sub-menu.",
1317 "Additional background colors can be specified with the color",
1318 "browser. You can change the menu colors by setting the X",
1319 "resources pen1 through pen9.",
1320 "",
1321 "If you choose the color browser and press Grab, you can",
1322 "select the background color by moving the pointer to the",
1323 "desired color on the screen and press any button.",
1324 "",
1325 "Choose a point in the image window and press this button and",
1326 "hold. Next, move the pointer to another location in the",
1327 "image. As you move a line connects the initial location and",
1328 "the pointer. When you release the button, the degree of",
1329 "image rotation is determined by the slope of the line you",
1330 "just drew. The slope is relative to the direction you",
1331 "choose from the Direction sub-menu of the Command widget.",
1332 "",
1333 "To cancel the image rotation, move the pointer back to the",
1334 "starting point of the line and release the button.",
1335 (char *) NULL,
1336 };
1337
1338 /*
1339 Enumeration declarations.
1340 */
1341 typedef enum
1342 {
1343 CopyMode,
1344 CropMode,
1345 CutMode
1346 } ClipboardMode;
1347
1348 typedef enum
1349 {
1350 OpenCommand,
1351 NextCommand,
1352 FormerCommand,
1353 SelectCommand,
1354 SaveCommand,
1355 PrintCommand,
1356 DeleteCommand,
1357 NewCommand,
1358 VisualDirectoryCommand,
1359 QuitCommand,
1360 UndoCommand,
1361 RedoCommand,
1362 CutCommand,
1363 CopyCommand,
1364 PasteCommand,
1365 HalfSizeCommand,
1366 OriginalSizeCommand,
1367 DoubleSizeCommand,
1368 ResizeCommand,
1369 ApplyCommand,
1370 RefreshCommand,
1371 RestoreCommand,
1372 CropCommand,
1373 ChopCommand,
1374 FlopCommand,
1375 FlipCommand,
1376 RotateRightCommand,
1377 RotateLeftCommand,
1378 RotateCommand,
1379 ShearCommand,
1380 RollCommand,
1381 TrimCommand,
1382 HueCommand,
1383 SaturationCommand,
1384 BrightnessCommand,
1385 GammaCommand,
1386 SpiffCommand,
1387 DullCommand,
1388 ContrastStretchCommand,
1389 SigmoidalContrastCommand,
1390 NormalizeCommand,
1391 EqualizeCommand,
1392 NegateCommand,
1393 GrayscaleCommand,
1394 MapCommand,
1395 QuantizeCommand,
1396 DespeckleCommand,
1397 EmbossCommand,
1398 ReduceNoiseCommand,
1399 AddNoiseCommand,
1400 SharpenCommand,
1401 BlurCommand,
1402 ThresholdCommand,
1403 EdgeDetectCommand,
1404 SpreadCommand,
1405 ShadeCommand,
1406 RaiseCommand,
1407 SegmentCommand,
1408 SolarizeCommand,
1409 SepiaToneCommand,
1410 SwirlCommand,
1411 ImplodeCommand,
1412 VignetteCommand,
1413 WaveCommand,
1414 OilPaintCommand,
1415 CharcoalDrawCommand,
1416 AnnotateCommand,
1417 DrawCommand,
1418 ColorCommand,
1419 MatteCommand,
1420 CompositeCommand,
1421 AddBorderCommand,
1422 AddFrameCommand,
1423 CommentCommand,
1424 LaunchCommand,
1425 RegionofInterestCommand,
1426 ROIHelpCommand,
1427 ROIDismissCommand,
1428 InfoCommand,
1429 ZoomCommand,
1430 ShowPreviewCommand,
1431 ShowHistogramCommand,
1432 ShowMatteCommand,
1433 BackgroundCommand,
1434 SlideShowCommand,
1435 PreferencesCommand,
1436 HelpCommand,
1437 BrowseDocumentationCommand,
1438 VersionCommand,
1439 SaveToUndoBufferCommand,
1440 FreeBuffersCommand,
1441 NullCommand
1442 } CommandType;
1443
1444 typedef enum
1445 {
1446 AnnotateNameCommand,
1447 AnnotateFontColorCommand,
1448 AnnotateBackgroundColorCommand,
1449 AnnotateRotateCommand,
1450 AnnotateHelpCommand,
1451 AnnotateDismissCommand,
1452 TextHelpCommand,
1453 TextApplyCommand,
1454 ChopDirectionCommand,
1455 ChopHelpCommand,
1456 ChopDismissCommand,
1457 HorizontalChopCommand,
1458 VerticalChopCommand,
1459 ColorEditMethodCommand,
1460 ColorEditColorCommand,
1461 ColorEditBorderCommand,
1462 ColorEditFuzzCommand,
1463 ColorEditUndoCommand,
1464 ColorEditHelpCommand,
1465 ColorEditDismissCommand,
1466 CompositeOperatorsCommand,
1467 CompositeDissolveCommand,
1468 CompositeDisplaceCommand,
1469 CompositeHelpCommand,
1470 CompositeDismissCommand,
1471 CropHelpCommand,
1472 CropDismissCommand,
1473 RectifyCopyCommand,
1474 RectifyHelpCommand,
1475 RectifyDismissCommand,
1476 DrawElementCommand,
1477 DrawColorCommand,
1478 DrawStippleCommand,
1479 DrawWidthCommand,
1480 DrawUndoCommand,
1481 DrawHelpCommand,
1482 DrawDismissCommand,
1483 MatteEditMethod,
1484 MatteEditBorderCommand,
1485 MatteEditFuzzCommand,
1486 MatteEditValueCommand,
1487 MatteEditUndoCommand,
1488 MatteEditHelpCommand,
1489 MatteEditDismissCommand,
1490 PasteOperatorsCommand,
1491 PasteHelpCommand,
1492 PasteDismissCommand,
1493 RotateColorCommand,
1494 RotateDirectionCommand,
1495 RotateCropCommand,
1496 RotateSharpenCommand,
1497 RotateHelpCommand,
1498 RotateDismissCommand,
1499 HorizontalRotateCommand,
1500 VerticalRotateCommand,
1501 TileLoadCommand,
1502 TileNextCommand,
1503 TileFormerCommand,
1504 TileDeleteCommand,
1505 TileUpdateCommand
1506 } ModeType;
1507
1508 /*
1509 Stipples.
1510 */
1511 #define BricksWidth 20
1512 #define BricksHeight 20
1513 #define DiagonalWidth 16
1514 #define DiagonalHeight 16
1515 #define HighlightWidth 8
1516 #define HighlightHeight 8
1517 #define OpaqueWidth 8
1518 #define OpaqueHeight 8
1519 #define ScalesWidth 16
1520 #define ScalesHeight 16
1521 #define ShadowWidth 8
1522 #define ShadowHeight 8
1523 #define VerticalWidth 16
1524 #define VerticalHeight 16
1525 #define WavyWidth 16
1526 #define WavyHeight 16
1527
1528 /*
1529 Constant declaration.
1530 */
1531 static const int
1532 RoiDelta = 8;
1533
1534 static const unsigned char
1535 BricksBitmap[] =
1536 {
1537 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00,
1538 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01,
1539 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00,
1540 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f,
1541 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01
1542 },
1543 DiagonalBitmap[] =
1544 {
1545 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88,
1546 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22,
1547 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22
1548 },
1549 ScalesBitmap[] =
1550 {
1551 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80,
1552 0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3,
1553 0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e
1554 },
1555 VerticalBitmap[] =
1556 {
1557 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
1558 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
1559 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11
1560 },
1561 WavyBitmap[] =
1562 {
1563 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff,
1564 0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf,
1565 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f
1566 };
1567
1568 /*
1569 Function prototypes.
1570 */
1571 static CommandType
1572 XImageWindowCommand(Display *,XResourceInfo *,XWindows *,
1573 const MagickStatusType,KeySym,Image **,ExceptionInfo *);
1574
1575 static Image
1576 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType,
1577 Image **,ExceptionInfo *),
1578 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType),
1579 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *,
1580 ExceptionInfo *),
1581 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *,
1582 ExceptionInfo *);
1583
1584 static MagickBooleanType
1585 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *,
1586 ExceptionInfo *),
1587 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **,
1588 ExceptionInfo *),
1589 XChopImage(Display *,XResourceInfo *,XWindows *,Image **,
1590 ExceptionInfo *),
1591 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode,
1592 ExceptionInfo *),
1593 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **,
1594 ExceptionInfo *),
1595 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *,
1596 ExceptionInfo *),
1597 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1598 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **,
1599 ExceptionInfo *),
1600 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **,
1601 ExceptionInfo *),
1602 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1603 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1604 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **,
1605 ExceptionInfo *),
1606 XROIImage(Display *,XResourceInfo *,XWindows *,Image **,ExceptionInfo *),
1607 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1608 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *);
1609
1610 static void
1611 XDrawPanRectangle(Display *,XWindows *),
1612 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **,
1613 ExceptionInfo *),
1614 XMagnifyImage(Display *,XWindows *,XEvent *,ExceptionInfo *),
1615 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1616 XPanImage(Display *,XWindows *,XEvent *,ExceptionInfo *),
1617 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType,
1618 const KeySym,ExceptionInfo *),
1619 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *),
1620 XScreenEvent(Display *,XWindows *,XEvent *,ExceptionInfo *),
1621 XTranslateImage(Display *,XWindows *,Image *,const KeySym);
1622
1623 /*
1624 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1625 % %
1626 % %
1627 % %
1628 % D i s p l a y I m a g e s %
1629 % %
1630 % %
1631 % %
1632 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1633 %
1634 % DisplayImages() displays an image sequence to any X window screen. It
1635 % returns a value other than 0 if successful. Check the exception member
1636 % of image to determine the reason for any failure.
1637 %
1638 % The format of the DisplayImages method is:
1639 %
1640 % MagickBooleanType DisplayImages(const ImageInfo *image_info,
1641 % Image *images,ExceptionInfo *exception)
1642 %
1643 % A description of each parameter follows:
1644 %
1645 % o image_info: the image info.
1646 %
1647 % o image: the image.
1648 %
1649 % o exception: return any errors or warnings in this structure.
1650 %
1651 */
DisplayImages(const ImageInfo * image_info,Image * images,ExceptionInfo * exception)1652 MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
1653 Image *images,ExceptionInfo *exception)
1654 {
1655 char
1656 *argv[1];
1657
1658 Display
1659 *display;
1660
1661 Image
1662 *image;
1663
1664 register ssize_t
1665 i;
1666
1667 size_t
1668 state;
1669
1670 XrmDatabase
1671 resource_database;
1672
1673 XResourceInfo
1674 resource_info;
1675
1676 assert(image_info != (const ImageInfo *) NULL);
1677 assert(image_info->signature == MagickCoreSignature);
1678 assert(images != (Image *) NULL);
1679 assert(images->signature == MagickCoreSignature);
1680 if (images->debug != MagickFalse )
1681 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
1682 display=XOpenDisplay(image_info->server_name);
1683 if (display == (Display *) NULL)
1684 {
1685 (void) ThrowMagickException(exception,GetMagickModule(),XServerError,
1686 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name));
1687 return(MagickFalse);
1688 }
1689 if (exception->severity != UndefinedException)
1690 CatchException(exception);
1691 (void) XSetErrorHandler(XError);
1692 resource_database=XGetResourceDatabase(display,GetClientName());
1693 (void) ResetMagickMemory(&resource_info,0,sizeof(resource_info));
1694 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info);
1695 if (image_info->page != (char *) NULL)
1696 resource_info.image_geometry=AcquireString(image_info->page);
1697 resource_info.immutable=MagickTrue;
1698 argv[0]=AcquireString(GetClientName());
1699 state=DefaultState;
1700 for (i=0; (state & ExitState) == 0; i++)
1701 {
1702 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations))
1703 break;
1704 image=GetImageFromList(images,i % GetImageListLength(images));
1705 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state,exception);
1706 }
1707 (void) SetErrorHandler((ErrorHandler) NULL);
1708 (void) SetWarningHandler((WarningHandler) NULL);
1709 argv[0]=DestroyString(argv[0]);
1710 (void) XCloseDisplay(display);
1711 XDestroyResourceInfo(&resource_info);
1712 if (exception->severity != UndefinedException)
1713 return(MagickFalse);
1714 return(MagickTrue);
1715 }
1716
1717 /*
1718 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1719 % %
1720 % %
1721 % %
1722 % R e m o t e D i s p l a y C o m m a n d %
1723 % %
1724 % %
1725 % %
1726 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1727 %
1728 % RemoteDisplayCommand() encourages a remote display program to display the
1729 % specified image filename.
1730 %
1731 % The format of the RemoteDisplayCommand method is:
1732 %
1733 % MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
1734 % const char *window,const char *filename,ExceptionInfo *exception)
1735 %
1736 % A description of each parameter follows:
1737 %
1738 % o image_info: the image info.
1739 %
1740 % o window: Specifies the name or id of an X window.
1741 %
1742 % o filename: the name of the image filename to display.
1743 %
1744 % o exception: return any errors or warnings in this structure.
1745 %
1746 */
RemoteDisplayCommand(const ImageInfo * image_info,const char * window,const char * filename,ExceptionInfo * exception)1747 MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
1748 const char *window,const char *filename,ExceptionInfo *exception)
1749 {
1750 Display
1751 *display;
1752
1753 MagickStatusType
1754 status;
1755
1756 assert(image_info != (const ImageInfo *) NULL);
1757 assert(image_info->signature == MagickCoreSignature);
1758 assert(filename != (char *) NULL);
1759 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
1760 display=XOpenDisplay(image_info->server_name);
1761 if (display == (Display *) NULL)
1762 {
1763 (void) ThrowMagickException(exception,GetMagickModule(),XServerError,
1764 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name));
1765 return(MagickFalse);
1766 }
1767 (void) XSetErrorHandler(XError);
1768 status=XRemoteCommand(display,window,filename);
1769 (void) XCloseDisplay(display);
1770 return(status != 0 ? MagickTrue : MagickFalse);
1771 }
1772
1773 /*
1774 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1775 % %
1776 % %
1777 % %
1778 + X A n n o t a t e E d i t I m a g e %
1779 % %
1780 % %
1781 % %
1782 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1783 %
1784 % XAnnotateEditImage() annotates the image with text.
1785 %
1786 % The format of the XAnnotateEditImage method is:
1787 %
1788 % MagickBooleanType XAnnotateEditImage(Display *display,
1789 % XResourceInfo *resource_info,XWindows *windows,Image *image,
1790 % ExceptionInfo *exception)
1791 %
1792 % A description of each parameter follows:
1793 %
1794 % o display: Specifies a connection to an X server; returned from
1795 % XOpenDisplay.
1796 %
1797 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
1798 %
1799 % o windows: Specifies a pointer to a XWindows structure.
1800 %
1801 % o image: the image; returned from ReadImage.
1802 %
1803 */
1804
XAnnotateEditImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,ExceptionInfo * exception)1805 static MagickBooleanType XAnnotateEditImage(Display *display,
1806 XResourceInfo *resource_info,XWindows *windows,Image *image,
1807 ExceptionInfo *exception)
1808 {
1809 static const char
1810 *AnnotateMenu[] =
1811 {
1812 "Font Name",
1813 "Font Color",
1814 "Box Color",
1815 "Rotate Text",
1816 "Help",
1817 "Dismiss",
1818 (char *) NULL
1819 },
1820 *TextMenu[] =
1821 {
1822 "Help",
1823 "Apply",
1824 (char *) NULL
1825 };
1826
1827 static const ModeType
1828 AnnotateCommands[] =
1829 {
1830 AnnotateNameCommand,
1831 AnnotateFontColorCommand,
1832 AnnotateBackgroundColorCommand,
1833 AnnotateRotateCommand,
1834 AnnotateHelpCommand,
1835 AnnotateDismissCommand
1836 },
1837 TextCommands[] =
1838 {
1839 TextHelpCommand,
1840 TextApplyCommand
1841 };
1842
1843 static MagickBooleanType
1844 transparent_box = MagickTrue,
1845 transparent_pen = MagickFalse;
1846
1847 static double
1848 degrees = 0.0;
1849
1850 static unsigned int
1851 box_id = MaxNumberPens-2,
1852 font_id = 0,
1853 pen_id = 0;
1854
1855 char
1856 command[MagickPathExtent],
1857 text[MagickPathExtent];
1858
1859 const char
1860 *ColorMenu[MaxNumberPens+1];
1861
1862 Cursor
1863 cursor;
1864
1865 GC
1866 annotate_context;
1867
1868 int
1869 id,
1870 pen_number,
1871 status,
1872 x,
1873 y;
1874
1875 KeySym
1876 key_symbol;
1877
1878 register char
1879 *p;
1880
1881 register ssize_t
1882 i;
1883
1884 unsigned int
1885 height,
1886 width;
1887
1888 size_t
1889 state;
1890
1891 XAnnotateInfo
1892 *annotate_info,
1893 *previous_info;
1894
1895 XColor
1896 color;
1897
1898 XFontStruct
1899 *font_info;
1900
1901 XEvent
1902 event,
1903 text_event;
1904
1905 /*
1906 Map Command widget.
1907 */
1908 (void) CloneString(&windows->command.name,"Annotate");
1909 windows->command.data=4;
1910 (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL);
1911 (void) XMapRaised(display,windows->command.id);
1912 XClientMessage(display,windows->image.id,windows->im_protocols,
1913 windows->im_update_widget,CurrentTime);
1914 /*
1915 Track pointer until button 1 is pressed.
1916 */
1917 XQueryPosition(display,windows->image.id,&x,&y);
1918 (void) XSelectInput(display,windows->image.id,
1919 windows->image.attributes.event_mask | PointerMotionMask);
1920 cursor=XCreateFontCursor(display,XC_left_side);
1921 (void) XCheckDefineCursor(display,windows->image.id,cursor);
1922 state=DefaultState;
1923 do
1924 {
1925 if (windows->info.mapped != MagickFalse )
1926 {
1927 /*
1928 Display pointer position.
1929 */
1930 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ",
1931 x+windows->image.x,y+windows->image.y);
1932 XInfoWidget(display,windows,text);
1933 }
1934 /*
1935 Wait for next event.
1936 */
1937 XScreenEvent(display,windows,&event,exception);
1938 if (event.xany.window == windows->command.id)
1939 {
1940 /*
1941 Select a command from the Command widget.
1942 */
1943 id=XCommandWidget(display,windows,AnnotateMenu,&event);
1944 (void) XCheckDefineCursor(display,windows->image.id,cursor);
1945 if (id < 0)
1946 continue;
1947 switch (AnnotateCommands[id])
1948 {
1949 case AnnotateNameCommand:
1950 {
1951 const char
1952 *FontMenu[MaxNumberFonts];
1953
1954 int
1955 font_number;
1956
1957 /*
1958 Initialize menu selections.
1959 */
1960 for (i=0; i < MaxNumberFonts; i++)
1961 FontMenu[i]=resource_info->font_name[i];
1962 FontMenu[MaxNumberFonts-2]="Browser...";
1963 FontMenu[MaxNumberFonts-1]=(const char *) NULL;
1964 /*
1965 Select a font name from the pop-up menu.
1966 */
1967 font_number=XMenuWidget(display,windows,AnnotateMenu[id],
1968 (const char **) FontMenu,command);
1969 if (font_number < 0)
1970 break;
1971 if (font_number == (MaxNumberFonts-2))
1972 {
1973 static char
1974 font_name[MagickPathExtent] = "fixed";
1975
1976 /*
1977 Select a font name from a browser.
1978 */
1979 resource_info->font_name[font_number]=font_name;
1980 XFontBrowserWidget(display,windows,"Select",font_name);
1981 if (*font_name == '\0')
1982 break;
1983 }
1984 /*
1985 Initialize font info.
1986 */
1987 font_info=XLoadQueryFont(display,resource_info->font_name[
1988 font_number]);
1989 if (font_info == (XFontStruct *) NULL)
1990 {
1991 XNoticeWidget(display,windows,"Unable to load font:",
1992 resource_info->font_name[font_number]);
1993 break;
1994 }
1995 font_id=(unsigned int) font_number;
1996 (void) XFreeFont(display,font_info);
1997 break;
1998 }
1999 case AnnotateFontColorCommand:
2000 {
2001 /*
2002 Initialize menu selections.
2003 */
2004 for (i=0; i < (int) (MaxNumberPens-2); i++)
2005 ColorMenu[i]=resource_info->pen_colors[i];
2006 ColorMenu[MaxNumberPens-2]="transparent";
2007 ColorMenu[MaxNumberPens-1]="Browser...";
2008 ColorMenu[MaxNumberPens]=(const char *) NULL;
2009 /*
2010 Select a pen color from the pop-up menu.
2011 */
2012 pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
2013 (const char **) ColorMenu,command);
2014 if (pen_number < 0)
2015 break;
2016 transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue :
2017 MagickFalse;
2018 if (transparent_pen != MagickFalse )
2019 break;
2020 if (pen_number == (MaxNumberPens-1))
2021 {
2022 static char
2023 color_name[MagickPathExtent] = "gray";
2024
2025 /*
2026 Select a pen color from a dialog.
2027 */
2028 resource_info->pen_colors[pen_number]=color_name;
2029 XColorBrowserWidget(display,windows,"Select",color_name);
2030 if (*color_name == '\0')
2031 break;
2032 }
2033 /*
2034 Set pen color.
2035 */
2036 (void) XParseColor(display,windows->map_info->colormap,
2037 resource_info->pen_colors[pen_number],&color);
2038 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
2039 (unsigned int) MaxColors,&color);
2040 windows->pixel_info->pen_colors[pen_number]=color;
2041 pen_id=(unsigned int) pen_number;
2042 break;
2043 }
2044 case AnnotateBackgroundColorCommand:
2045 {
2046 /*
2047 Initialize menu selections.
2048 */
2049 for (i=0; i < (int) (MaxNumberPens-2); i++)
2050 ColorMenu[i]=resource_info->pen_colors[i];
2051 ColorMenu[MaxNumberPens-2]="transparent";
2052 ColorMenu[MaxNumberPens-1]="Browser...";
2053 ColorMenu[MaxNumberPens]=(const char *) NULL;
2054 /*
2055 Select a pen color from the pop-up menu.
2056 */
2057 pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
2058 (const char **) ColorMenu,command);
2059 if (pen_number < 0)
2060 break;
2061 transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue :
2062 MagickFalse;
2063 if (transparent_box != MagickFalse )
2064 break;
2065 if (pen_number == (MaxNumberPens-1))
2066 {
2067 static char
2068 color_name[MagickPathExtent] = "gray";
2069
2070 /*
2071 Select a pen color from a dialog.
2072 */
2073 resource_info->pen_colors[pen_number]=color_name;
2074 XColorBrowserWidget(display,windows,"Select",color_name);
2075 if (*color_name == '\0')
2076 break;
2077 }
2078 /*
2079 Set pen color.
2080 */
2081 (void) XParseColor(display,windows->map_info->colormap,
2082 resource_info->pen_colors[pen_number],&color);
2083 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
2084 (unsigned int) MaxColors,&color);
2085 windows->pixel_info->pen_colors[pen_number]=color;
2086 box_id=(unsigned int) pen_number;
2087 break;
2088 }
2089 case AnnotateRotateCommand:
2090 {
2091 int
2092 entry;
2093
2094 static char
2095 angle[MagickPathExtent] = "30.0";
2096
2097 static const char
2098 *RotateMenu[] =
2099 {
2100 "-90",
2101 "-45",
2102 "-30",
2103 "0",
2104 "30",
2105 "45",
2106 "90",
2107 "180",
2108 "Dialog...",
2109 (char *) NULL,
2110 };
2111
2112 /*
2113 Select a command from the pop-up menu.
2114 */
2115 entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu,
2116 command);
2117 if (entry < 0)
2118 break;
2119 if (entry != 8)
2120 {
2121 degrees=StringToDouble(RotateMenu[entry],(char **) NULL);
2122 break;
2123 }
2124 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:",
2125 angle);
2126 if (*angle == '\0')
2127 break;
2128 degrees=StringToDouble(angle,(char **) NULL);
2129 break;
2130 }
2131 case AnnotateHelpCommand:
2132 {
2133 XTextViewWidget(display,resource_info,windows,MagickFalse,
2134 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2135 break;
2136 }
2137 case AnnotateDismissCommand:
2138 {
2139 /*
2140 Prematurely exit.
2141 */
2142 state|=EscapeState;
2143 state|=ExitState;
2144 break;
2145 }
2146 default:
2147 break;
2148 }
2149 continue;
2150 }
2151 switch (event.type)
2152 {
2153 case ButtonPress:
2154 {
2155 if (event.xbutton.button != Button1)
2156 break;
2157 if (event.xbutton.window != windows->image.id)
2158 break;
2159 /*
2160 Change to text entering mode.
2161 */
2162 x=event.xbutton.x;
2163 y=event.xbutton.y;
2164 state|=ExitState;
2165 break;
2166 }
2167 case ButtonRelease:
2168 break;
2169 case Expose:
2170 break;
2171 case KeyPress:
2172 {
2173 if (event.xkey.window != windows->image.id)
2174 break;
2175 /*
2176 Respond to a user key press.
2177 */
2178 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2179 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2180 switch ((int) key_symbol)
2181 {
2182 case XK_Escape:
2183 case XK_F20:
2184 {
2185 /*
2186 Prematurely exit.
2187 */
2188 state|=EscapeState;
2189 state|=ExitState;
2190 break;
2191 }
2192 case XK_F1:
2193 case XK_Help:
2194 {
2195 XTextViewWidget(display,resource_info,windows,MagickFalse,
2196 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2197 break;
2198 }
2199 default:
2200 {
2201 (void) XBell(display,0);
2202 break;
2203 }
2204 }
2205 break;
2206 }
2207 case MotionNotify:
2208 {
2209 /*
2210 Map and unmap Info widget as cursor crosses its boundaries.
2211 */
2212 x=event.xmotion.x;
2213 y=event.xmotion.y;
2214 if (windows->info.mapped != MagickFalse )
2215 {
2216 if ((x < (int) (windows->info.x+windows->info.width)) &&
2217 (y < (int) (windows->info.y+windows->info.height)))
2218 (void) XWithdrawWindow(display,windows->info.id,
2219 windows->info.screen);
2220 }
2221 else
2222 if ((x > (int) (windows->info.x+windows->info.width)) ||
2223 (y > (int) (windows->info.y+windows->info.height)))
2224 (void) XMapWindow(display,windows->info.id);
2225 break;
2226 }
2227 default:
2228 break;
2229 }
2230 } while ((state & ExitState) == 0);
2231 (void) XSelectInput(display,windows->image.id,
2232 windows->image.attributes.event_mask);
2233 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
2234 if ((state & EscapeState) != 0)
2235 return(MagickTrue);
2236 /*
2237 Set font info and check boundary conditions.
2238 */
2239 font_info=XLoadQueryFont(display,resource_info->font_name[font_id]);
2240 if (font_info == (XFontStruct *) NULL)
2241 {
2242 XNoticeWidget(display,windows,"Unable to load font:",
2243 resource_info->font_name[font_id]);
2244 font_info=windows->font_info;
2245 }
2246 if ((x+font_info->max_bounds.width) >= (int) windows->image.width)
2247 x=(int) windows->image.width-font_info->max_bounds.width;
2248 if (y < (int) (font_info->ascent+font_info->descent))
2249 y=(int) font_info->ascent+font_info->descent;
2250 if (((int) font_info->max_bounds.width > (int) windows->image.width) ||
2251 ((font_info->ascent+font_info->descent) >= (int) windows->image.height))
2252 return(MagickFalse);
2253 /*
2254 Initialize annotate structure.
2255 */
2256 annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info));
2257 if (annotate_info == (XAnnotateInfo *) NULL)
2258 return(MagickFalse);
2259 XGetAnnotateInfo(annotate_info);
2260 annotate_info->x=x;
2261 annotate_info->y=y;
2262 if ((transparent_box == MagickFalse) && (transparent_pen == MagickFalse))
2263 annotate_info->stencil=OpaqueStencil;
2264 else
2265 if (transparent_box == MagickFalse)
2266 annotate_info->stencil=BackgroundStencil;
2267 else
2268 annotate_info->stencil=ForegroundStencil;
2269 annotate_info->height=(unsigned int) font_info->ascent+font_info->descent;
2270 annotate_info->degrees=degrees;
2271 annotate_info->font_info=font_info;
2272 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
2273 windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL,
2274 sizeof(*annotate_info->text));
2275 if (annotate_info->text == (char *) NULL)
2276 return(MagickFalse);
2277 /*
2278 Create cursor and set graphic context.
2279 */
2280 cursor=XCreateFontCursor(display,XC_pencil);
2281 (void) XCheckDefineCursor(display,windows->image.id,cursor);
2282 annotate_context=windows->image.annotate_context;
2283 (void) XSetFont(display,annotate_context,font_info->fid);
2284 (void) XSetBackground(display,annotate_context,
2285 windows->pixel_info->pen_colors[box_id].pixel);
2286 (void) XSetForeground(display,annotate_context,
2287 windows->pixel_info->pen_colors[pen_id].pixel);
2288 /*
2289 Begin annotating the image with text.
2290 */
2291 (void) CloneString(&windows->command.name,"Text");
2292 windows->command.data=0;
2293 (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL);
2294 state=DefaultState;
2295 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
2296 text_event.xexpose.width=(int) font_info->max_bounds.width;
2297 text_event.xexpose.height=font_info->max_bounds.ascent+
2298 font_info->max_bounds.descent;
2299 p=annotate_info->text;
2300 do
2301 {
2302 /*
2303 Display text cursor.
2304 */
2305 *p='\0';
2306 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
2307 /*
2308 Wait for next event.
2309 */
2310 XScreenEvent(display,windows,&event,exception);
2311 if (event.xany.window == windows->command.id)
2312 {
2313 /*
2314 Select a command from the Command widget.
2315 */
2316 (void) XSetBackground(display,annotate_context,
2317 windows->pixel_info->background_color.pixel);
2318 (void) XSetForeground(display,annotate_context,
2319 windows->pixel_info->foreground_color.pixel);
2320 id=XCommandWidget(display,windows,AnnotateMenu,&event);
2321 (void) XSetBackground(display,annotate_context,
2322 windows->pixel_info->pen_colors[box_id].pixel);
2323 (void) XSetForeground(display,annotate_context,
2324 windows->pixel_info->pen_colors[pen_id].pixel);
2325 if (id < 0)
2326 continue;
2327 switch (TextCommands[id])
2328 {
2329 case TextHelpCommand:
2330 {
2331 XTextViewWidget(display,resource_info,windows,MagickFalse,
2332 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2333 (void) XCheckDefineCursor(display,windows->image.id,cursor);
2334 break;
2335 }
2336 case TextApplyCommand:
2337 {
2338 /*
2339 Finished annotating.
2340 */
2341 annotate_info->width=(unsigned int) XTextWidth(font_info,
2342 annotate_info->text,(int) strlen(annotate_info->text));
2343 XRefreshWindow(display,&windows->image,&text_event);
2344 state|=ExitState;
2345 break;
2346 }
2347 default:
2348 break;
2349 }
2350 continue;
2351 }
2352 /*
2353 Erase text cursor.
2354 */
2355 text_event.xexpose.x=x;
2356 text_event.xexpose.y=y-font_info->max_bounds.ascent;
2357 (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y,
2358 (unsigned int) text_event.xexpose.width,(unsigned int)
2359 text_event.xexpose.height,MagickFalse);
2360 XRefreshWindow(display,&windows->image,&text_event);
2361 switch (event.type)
2362 {
2363 case ButtonPress:
2364 {
2365 if (event.xbutton.window != windows->image.id)
2366 break;
2367 if (event.xbutton.button == Button2)
2368 {
2369 /*
2370 Request primary selection.
2371 */
2372 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
2373 windows->image.id,CurrentTime);
2374 break;
2375 }
2376 break;
2377 }
2378 case Expose:
2379 {
2380 if (event.xexpose.count == 0)
2381 {
2382 XAnnotateInfo
2383 *text_info;
2384
2385 /*
2386 Refresh Image window.
2387 */
2388 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
2389 text_info=annotate_info;
2390 while (text_info != (XAnnotateInfo *) NULL)
2391 {
2392 if (annotate_info->stencil == ForegroundStencil)
2393 (void) XDrawString(display,windows->image.id,annotate_context,
2394 text_info->x,text_info->y,text_info->text,
2395 (int) strlen(text_info->text));
2396 else
2397 (void) XDrawImageString(display,windows->image.id,
2398 annotate_context,text_info->x,text_info->y,text_info->text,
2399 (int) strlen(text_info->text));
2400 text_info=text_info->previous;
2401 }
2402 (void) XDrawString(display,windows->image.id,annotate_context,
2403 x,y,"_",1);
2404 }
2405 break;
2406 }
2407 case KeyPress:
2408 {
2409 int
2410 length;
2411
2412 if (event.xkey.window != windows->image.id)
2413 break;
2414 /*
2415 Respond to a user key press.
2416 */
2417 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
2418 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2419 *(command+length)='\0';
2420 if (((event.xkey.state & ControlMask) != 0) ||
2421 ((event.xkey.state & Mod1Mask) != 0))
2422 state|=ModifierState;
2423 if ((state & ModifierState) != 0)
2424 switch ((int) key_symbol)
2425 {
2426 case XK_u:
2427 case XK_U:
2428 {
2429 key_symbol=DeleteCommand;
2430 break;
2431 }
2432 default:
2433 break;
2434 }
2435 switch ((int) key_symbol)
2436 {
2437 case XK_BackSpace:
2438 {
2439 /*
2440 Erase one character.
2441 */
2442 if (p == annotate_info->text)
2443 {
2444 if (annotate_info->previous == (XAnnotateInfo *) NULL)
2445 break;
2446 else
2447 {
2448 /*
2449 Go to end of the previous line of text.
2450 */
2451 annotate_info=annotate_info->previous;
2452 p=annotate_info->text;
2453 x=annotate_info->x+annotate_info->width;
2454 y=annotate_info->y;
2455 if (annotate_info->width != 0)
2456 p+=strlen(annotate_info->text);
2457 break;
2458 }
2459 }
2460 p--;
2461 x-=XTextWidth(font_info,p,1);
2462 text_event.xexpose.x=x;
2463 text_event.xexpose.y=y-font_info->max_bounds.ascent;
2464 XRefreshWindow(display,&windows->image,&text_event);
2465 break;
2466 }
2467 case XK_bracketleft:
2468 {
2469 key_symbol=XK_Escape;
2470 break;
2471 }
2472 case DeleteCommand:
2473 {
2474 /*
2475 Erase the entire line of text.
2476 */
2477 while (p != annotate_info->text)
2478 {
2479 p--;
2480 x-=XTextWidth(font_info,p,1);
2481 text_event.xexpose.x=x;
2482 XRefreshWindow(display,&windows->image,&text_event);
2483 }
2484 break;
2485 }
2486 case XK_Escape:
2487 case XK_F20:
2488 {
2489 /*
2490 Finished annotating.
2491 */
2492 annotate_info->width=(unsigned int) XTextWidth(font_info,
2493 annotate_info->text,(int) strlen(annotate_info->text));
2494 XRefreshWindow(display,&windows->image,&text_event);
2495 state|=ExitState;
2496 break;
2497 }
2498 default:
2499 {
2500 /*
2501 Draw a single character on the Image window.
2502 */
2503 if ((state & ModifierState) != 0)
2504 break;
2505 if (*command == '\0')
2506 break;
2507 *p=(*command);
2508 if (annotate_info->stencil == ForegroundStencil)
2509 (void) XDrawString(display,windows->image.id,annotate_context,
2510 x,y,p,1);
2511 else
2512 (void) XDrawImageString(display,windows->image.id,
2513 annotate_context,x,y,p,1);
2514 x+=XTextWidth(font_info,p,1);
2515 p++;
2516 if ((x+font_info->max_bounds.width) < (int) windows->image.width)
2517 break;
2518 }
2519 case XK_Return:
2520 case XK_KP_Enter:
2521 {
2522 /*
2523 Advance to the next line of text.
2524 */
2525 *p='\0';
2526 annotate_info->width=(unsigned int) XTextWidth(font_info,
2527 annotate_info->text,(int) strlen(annotate_info->text));
2528 if (annotate_info->next != (XAnnotateInfo *) NULL)
2529 {
2530 /*
2531 Line of text already exists.
2532 */
2533 annotate_info=annotate_info->next;
2534 x=annotate_info->x;
2535 y=annotate_info->y;
2536 p=annotate_info->text;
2537 break;
2538 }
2539 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory(
2540 sizeof(*annotate_info->next));
2541 if (annotate_info->next == (XAnnotateInfo *) NULL)
2542 return(MagickFalse);
2543 *annotate_info->next=(*annotate_info);
2544 annotate_info->next->previous=annotate_info;
2545 annotate_info=annotate_info->next;
2546 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
2547 windows->image.width/MagickMax((ssize_t)
2548 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text));
2549 if (annotate_info->text == (char *) NULL)
2550 return(MagickFalse);
2551 annotate_info->y+=annotate_info->height;
2552 if (annotate_info->y > (int) windows->image.height)
2553 annotate_info->y=(int) annotate_info->height;
2554 annotate_info->next=(XAnnotateInfo *) NULL;
2555 x=annotate_info->x;
2556 y=annotate_info->y;
2557 p=annotate_info->text;
2558 break;
2559 }
2560 }
2561 break;
2562 }
2563 case KeyRelease:
2564 {
2565 /*
2566 Respond to a user key release.
2567 */
2568 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2569 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2570 state&=(~ModifierState);
2571 break;
2572 }
2573 case SelectionNotify:
2574 {
2575 Atom
2576 type;
2577
2578 int
2579 format;
2580
2581 unsigned char
2582 *data;
2583
2584 unsigned long
2585 after,
2586 length;
2587
2588 /*
2589 Obtain response from primary selection.
2590 */
2591 if (event.xselection.property == (Atom) None)
2592 break;
2593 status=XGetWindowProperty(display,event.xselection.requestor,
2594 event.xselection.property,0L,(long) MagickPathExtent,True,XA_STRING,
2595 &type,&format,&length,&after,&data);
2596 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
2597 (length == 0))
2598 break;
2599 /*
2600 Annotate Image window with primary selection.
2601 */
2602 for (i=0; i < (ssize_t) length; i++)
2603 {
2604 if ((char) data[i] != '\n')
2605 {
2606 /*
2607 Draw a single character on the Image window.
2608 */
2609 *p=(char) data[i];
2610 (void) XDrawString(display,windows->image.id,annotate_context,
2611 x,y,p,1);
2612 x+=XTextWidth(font_info,p,1);
2613 p++;
2614 if ((x+font_info->max_bounds.width) < (int) windows->image.width)
2615 continue;
2616 }
2617 /*
2618 Advance to the next line of text.
2619 */
2620 *p='\0';
2621 annotate_info->width=(unsigned int) XTextWidth(font_info,
2622 annotate_info->text,(int) strlen(annotate_info->text));
2623 if (annotate_info->next != (XAnnotateInfo *) NULL)
2624 {
2625 /*
2626 Line of text already exists.
2627 */
2628 annotate_info=annotate_info->next;
2629 x=annotate_info->x;
2630 y=annotate_info->y;
2631 p=annotate_info->text;
2632 continue;
2633 }
2634 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory(
2635 sizeof(*annotate_info->next));
2636 if (annotate_info->next == (XAnnotateInfo *) NULL)
2637 return(MagickFalse);
2638 *annotate_info->next=(*annotate_info);
2639 annotate_info->next->previous=annotate_info;
2640 annotate_info=annotate_info->next;
2641 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
2642 windows->image.width/MagickMax((ssize_t)
2643 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text));
2644 if (annotate_info->text == (char *) NULL)
2645 return(MagickFalse);
2646 annotate_info->y+=annotate_info->height;
2647 if (annotate_info->y > (int) windows->image.height)
2648 annotate_info->y=(int) annotate_info->height;
2649 annotate_info->next=(XAnnotateInfo *) NULL;
2650 x=annotate_info->x;
2651 y=annotate_info->y;
2652 p=annotate_info->text;
2653 }
2654 (void) XFree((void *) data);
2655 break;
2656 }
2657 default:
2658 break;
2659 }
2660 } while ((state & ExitState) == 0);
2661 (void) XFreeCursor(display,cursor);
2662 /*
2663 Annotation is relative to image configuration.
2664 */
2665 width=(unsigned int) image->columns;
2666 height=(unsigned int) image->rows;
2667 x=0;
2668 y=0;
2669 if (windows->image.crop_geometry != (char *) NULL)
2670 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
2671 /*
2672 Initialize annotated image.
2673 */
2674 XSetCursorState(display,windows,MagickTrue);
2675 XCheckRefreshWindows(display,windows);
2676 while (annotate_info != (XAnnotateInfo *) NULL)
2677 {
2678 if (annotate_info->width == 0)
2679 {
2680 /*
2681 No text on this line-- go to the next line of text.
2682 */
2683 previous_info=annotate_info->previous;
2684 annotate_info->text=(char *)
2685 RelinquishMagickMemory(annotate_info->text);
2686 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
2687 annotate_info=previous_info;
2688 continue;
2689 }
2690 /*
2691 Determine pixel index for box and pen color.
2692 */
2693 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id];
2694 if (windows->pixel_info->colors != 0)
2695 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
2696 if (windows->pixel_info->pixels[i] ==
2697 windows->pixel_info->pen_colors[box_id].pixel)
2698 {
2699 windows->pixel_info->box_index=(unsigned short) i;
2700 break;
2701 }
2702 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
2703 if (windows->pixel_info->colors != 0)
2704 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
2705 if (windows->pixel_info->pixels[i] ==
2706 windows->pixel_info->pen_colors[pen_id].pixel)
2707 {
2708 windows->pixel_info->pen_index=(unsigned short) i;
2709 break;
2710 }
2711 /*
2712 Define the annotate geometry string.
2713 */
2714 annotate_info->x=(int)
2715 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width;
2716 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+
2717 windows->image.y)/windows->image.ximage->height;
2718 (void) FormatLocaleString(annotate_info->geometry,MagickPathExtent,
2719 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width,
2720 height*annotate_info->height/windows->image.ximage->height,
2721 annotate_info->x+x,annotate_info->y+y);
2722 /*
2723 Annotate image with text.
2724 */
2725 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image,
2726 exception);
2727 if (status == 0)
2728 return(MagickFalse);
2729 /*
2730 Free up memory.
2731 */
2732 previous_info=annotate_info->previous;
2733 annotate_info->text=DestroyString(annotate_info->text);
2734 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
2735 annotate_info=previous_info;
2736 }
2737 (void) XSetForeground(display,annotate_context,
2738 windows->pixel_info->foreground_color.pixel);
2739 (void) XSetBackground(display,annotate_context,
2740 windows->pixel_info->background_color.pixel);
2741 (void) XSetFont(display,annotate_context,windows->font_info->fid);
2742 XSetCursorState(display,windows,MagickFalse);
2743 (void) XFreeFont(display,font_info);
2744 /*
2745 Update image configuration.
2746 */
2747 XConfigureImageColormap(display,resource_info,windows,image,exception);
2748 (void) XConfigureImage(display,resource_info,windows,image,exception);
2749 return(MagickTrue);
2750 }
2751
2752 /*
2753 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2754 % %
2755 % %
2756 % %
2757 + X B a c k g r o u n d I m a g e %
2758 % %
2759 % %
2760 % %
2761 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2762 %
2763 % XBackgroundImage() displays the image in the background of a window.
2764 %
2765 % The format of the XBackgroundImage method is:
2766 %
2767 % MagickBooleanType XBackgroundImage(Display *display,
2768 % XResourceInfo *resource_info,XWindows *windows,Image **image,
2769 % ExceptionInfo *exception)
2770 %
2771 % A description of each parameter follows:
2772 %
2773 % o display: Specifies a connection to an X server; returned from
2774 % XOpenDisplay.
2775 %
2776 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2777 %
2778 % o windows: Specifies a pointer to a XWindows structure.
2779 %
2780 % o image: the image.
2781 %
2782 % o exception: return any errors or warnings in this structure.
2783 %
2784 */
XBackgroundImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image ** image,ExceptionInfo * exception)2785 static MagickBooleanType XBackgroundImage(Display *display,
2786 XResourceInfo *resource_info,XWindows *windows,Image **image,
2787 ExceptionInfo *exception)
2788 {
2789 #define BackgroundImageTag "Background/Image"
2790
2791 int
2792 status;
2793
2794 static char
2795 window_id[MagickPathExtent] = "root";
2796
2797 XResourceInfo
2798 background_resources;
2799
2800 /*
2801 Put image in background.
2802 */
2803 status=XDialogWidget(display,windows,"Background",
2804 "Enter window id (id 0x00 selects window with pointer):",window_id);
2805 if (*window_id == '\0')
2806 return(MagickFalse);
2807 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
2808 exception);
2809 XInfoWidget(display,windows,BackgroundImageTag);
2810 XSetCursorState(display,windows,MagickTrue);
2811 XCheckRefreshWindows(display,windows);
2812 background_resources=(*resource_info);
2813 background_resources.window_id=window_id;
2814 background_resources.backdrop=status != 0 ? MagickTrue : MagickFalse;
2815 status=XDisplayBackgroundImage(display,&background_resources,*image,
2816 exception);
2817 if (status != MagickFalse)
2818 XClientMessage(display,windows->image.id,windows->im_protocols,
2819 windows->im_retain_colors,CurrentTime);
2820 XSetCursorState(display,windows,MagickFalse);
2821 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image,
2822 exception);
2823 return(MagickTrue);
2824 }
2825
2826 /*
2827 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2828 % %
2829 % %
2830 % %
2831 + X C h o p I m a g e %
2832 % %
2833 % %
2834 % %
2835 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2836 %
2837 % XChopImage() chops the X image.
2838 %
2839 % The format of the XChopImage method is:
2840 %
2841 % MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info,
2842 % XWindows *windows,Image **image,ExceptionInfo *exception)
2843 %
2844 % A description of each parameter follows:
2845 %
2846 % o display: Specifies a connection to an X server; returned from
2847 % XOpenDisplay.
2848 %
2849 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2850 %
2851 % o windows: Specifies a pointer to a XWindows structure.
2852 %
2853 % o image: the image.
2854 %
2855 % o exception: return any errors or warnings in this structure.
2856 %
2857 */
XChopImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image ** image,ExceptionInfo * exception)2858 static MagickBooleanType XChopImage(Display *display,
2859 XResourceInfo *resource_info,XWindows *windows,Image **image,
2860 ExceptionInfo *exception)
2861 {
2862 static const char
2863 *ChopMenu[] =
2864 {
2865 "Direction",
2866 "Help",
2867 "Dismiss",
2868 (char *) NULL
2869 };
2870
2871 static ModeType
2872 direction = HorizontalChopCommand;
2873
2874 static const ModeType
2875 ChopCommands[] =
2876 {
2877 ChopDirectionCommand,
2878 ChopHelpCommand,
2879 ChopDismissCommand
2880 },
2881 DirectionCommands[] =
2882 {
2883 HorizontalChopCommand,
2884 VerticalChopCommand
2885 };
2886
2887 char
2888 text[MagickPathExtent];
2889
2890 Image
2891 *chop_image;
2892
2893 int
2894 id,
2895 x,
2896 y;
2897
2898 double
2899 scale_factor;
2900
2901 RectangleInfo
2902 chop_info;
2903
2904 unsigned int
2905 distance,
2906 height,
2907 width;
2908
2909 size_t
2910 state;
2911
2912 XEvent
2913 event;
2914
2915 XSegment
2916 segment_info;
2917
2918 /*
2919 Map Command widget.
2920 */
2921 (void) CloneString(&windows->command.name,"Chop");
2922 windows->command.data=1;
2923 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL);
2924 (void) XMapRaised(display,windows->command.id);
2925 XClientMessage(display,windows->image.id,windows->im_protocols,
2926 windows->im_update_widget,CurrentTime);
2927 /*
2928 Track pointer until button 1 is pressed.
2929 */
2930 XQueryPosition(display,windows->image.id,&x,&y);
2931 (void) XSelectInput(display,windows->image.id,
2932 windows->image.attributes.event_mask | PointerMotionMask);
2933 state=DefaultState;
2934 (void) ResetMagickMemory(&segment_info,0,sizeof(segment_info));
2935 do
2936 {
2937 if (windows->info.mapped != MagickFalse )
2938 {
2939 /*
2940 Display pointer position.
2941 */
2942 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ",
2943 x+windows->image.x,y+windows->image.y);
2944 XInfoWidget(display,windows,text);
2945 }
2946 /*
2947 Wait for next event.
2948 */
2949 XScreenEvent(display,windows,&event,exception);
2950 if (event.xany.window == windows->command.id)
2951 {
2952 /*
2953 Select a command from the Command widget.
2954 */
2955 id=XCommandWidget(display,windows,ChopMenu,&event);
2956 if (id < 0)
2957 continue;
2958 switch (ChopCommands[id])
2959 {
2960 case ChopDirectionCommand:
2961 {
2962 char
2963 command[MagickPathExtent];
2964
2965 static const char
2966 *Directions[] =
2967 {
2968 "horizontal",
2969 "vertical",
2970 (char *) NULL,
2971 };
2972
2973 /*
2974 Select a command from the pop-up menu.
2975 */
2976 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command);
2977 if (id >= 0)
2978 direction=DirectionCommands[id];
2979 break;
2980 }
2981 case ChopHelpCommand:
2982 {
2983 XTextViewWidget(display,resource_info,windows,MagickFalse,
2984 "Help Viewer - Image Chop",ImageChopHelp);
2985 break;
2986 }
2987 case ChopDismissCommand:
2988 {
2989 /*
2990 Prematurely exit.
2991 */
2992 state|=EscapeState;
2993 state|=ExitState;
2994 break;
2995 }
2996 default:
2997 break;
2998 }
2999 continue;
3000 }
3001 switch (event.type)
3002 {
3003 case ButtonPress:
3004 {
3005 if (event.xbutton.button != Button1)
3006 break;
3007 if (event.xbutton.window != windows->image.id)
3008 break;
3009 /*
3010 User has committed to start point of chopping line.
3011 */
3012 segment_info.x1=(short int) event.xbutton.x;
3013 segment_info.x2=(short int) event.xbutton.x;
3014 segment_info.y1=(short int) event.xbutton.y;
3015 segment_info.y2=(short int) event.xbutton.y;
3016 state|=ExitState;
3017 break;
3018 }
3019 case ButtonRelease:
3020 break;
3021 case Expose:
3022 break;
3023 case KeyPress:
3024 {
3025 char
3026 command[MagickPathExtent];
3027
3028 KeySym
3029 key_symbol;
3030
3031 if (event.xkey.window != windows->image.id)
3032 break;
3033 /*
3034 Respond to a user key press.
3035 */
3036 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
3037 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
3038 switch ((int) key_symbol)
3039 {
3040 case XK_Escape:
3041 case XK_F20:
3042 {
3043 /*
3044 Prematurely exit.
3045 */
3046 state|=EscapeState;
3047 state|=ExitState;
3048 break;
3049 }
3050 case XK_F1:
3051 case XK_Help:
3052 {
3053 (void) XSetFunction(display,windows->image.highlight_context,
3054 GXcopy);
3055 XTextViewWidget(display,resource_info,windows,MagickFalse,
3056 "Help Viewer - Image Chop",ImageChopHelp);
3057 (void) XSetFunction(display,windows->image.highlight_context,
3058 GXinvert);
3059 break;
3060 }
3061 default:
3062 {
3063 (void) XBell(display,0);
3064 break;
3065 }
3066 }
3067 break;
3068 }
3069 case MotionNotify:
3070 {
3071 /*
3072 Map and unmap Info widget as text cursor crosses its boundaries.
3073 */
3074 x=event.xmotion.x;
3075 y=event.xmotion.y;
3076 if (windows->info.mapped != MagickFalse )
3077 {
3078 if ((x < (int) (windows->info.x+windows->info.width)) &&
3079 (y < (int) (windows->info.y+windows->info.height)))
3080 (void) XWithdrawWindow(display,windows->info.id,
3081 windows->info.screen);
3082 }
3083 else
3084 if ((x > (int) (windows->info.x+windows->info.width)) ||
3085 (y > (int) (windows->info.y+windows->info.height)))
3086 (void) XMapWindow(display,windows->info.id);
3087 }
3088 }
3089 } while ((state & ExitState) == 0);
3090 (void) XSelectInput(display,windows->image.id,
3091 windows->image.attributes.event_mask);
3092 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3093 if ((state & EscapeState) != 0)
3094 return(MagickTrue);
3095 /*
3096 Draw line as pointer moves until the mouse button is released.
3097 */
3098 chop_info.width=0;
3099 chop_info.height=0;
3100 chop_info.x=0;
3101 chop_info.y=0;
3102 distance=0;
3103 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
3104 state=DefaultState;
3105 do
3106 {
3107 if (distance > 9)
3108 {
3109 /*
3110 Display info and draw chopping line.
3111 */
3112 if (windows->info.mapped == MagickFalse)
3113 (void) XMapWindow(display,windows->info.id);
3114 (void) FormatLocaleString(text,MagickPathExtent,
3115 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double)
3116 chop_info.height,(double) chop_info.x,(double) chop_info.y);
3117 XInfoWidget(display,windows,text);
3118 XHighlightLine(display,windows->image.id,
3119 windows->image.highlight_context,&segment_info);
3120 }
3121 else
3122 if (windows->info.mapped != MagickFalse )
3123 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3124 /*
3125 Wait for next event.
3126 */
3127 XScreenEvent(display,windows,&event,exception);
3128 if (distance > 9)
3129 XHighlightLine(display,windows->image.id,
3130 windows->image.highlight_context,&segment_info);
3131 switch (event.type)
3132 {
3133 case ButtonPress:
3134 {
3135 segment_info.x2=(short int) event.xmotion.x;
3136 segment_info.y2=(short int) event.xmotion.y;
3137 break;
3138 }
3139 case ButtonRelease:
3140 {
3141 /*
3142 User has committed to chopping line.
3143 */
3144 segment_info.x2=(short int) event.xbutton.x;
3145 segment_info.y2=(short int) event.xbutton.y;
3146 state|=ExitState;
3147 break;
3148 }
3149 case Expose:
3150 break;
3151 case MotionNotify:
3152 {
3153 segment_info.x2=(short int) event.xmotion.x;
3154 segment_info.y2=(short int) event.xmotion.y;
3155 }
3156 default:
3157 break;
3158 }
3159 /*
3160 Check boundary conditions.
3161 */
3162 if (segment_info.x2 < 0)
3163 segment_info.x2=0;
3164 else
3165 if (segment_info.x2 > windows->image.ximage->width)
3166 segment_info.x2=windows->image.ximage->width;
3167 if (segment_info.y2 < 0)
3168 segment_info.y2=0;
3169 else
3170 if (segment_info.y2 > windows->image.ximage->height)
3171 segment_info.y2=windows->image.ximage->height;
3172 distance=(unsigned int)
3173 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+
3174 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1)));
3175 /*
3176 Compute chopping geometry.
3177 */
3178 if (direction == HorizontalChopCommand)
3179 {
3180 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1);
3181 chop_info.x=(ssize_t) windows->image.x+segment_info.x1;
3182 chop_info.height=0;
3183 chop_info.y=0;
3184 if (segment_info.x1 > (int) segment_info.x2)
3185 {
3186 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1);
3187 chop_info.x=(ssize_t) windows->image.x+segment_info.x2;
3188 }
3189 }
3190 else
3191 {
3192 chop_info.width=0;
3193 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1);
3194 chop_info.x=0;
3195 chop_info.y=(ssize_t) windows->image.y+segment_info.y1;
3196 if (segment_info.y1 > segment_info.y2)
3197 {
3198 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1);
3199 chop_info.y=(ssize_t) windows->image.y+segment_info.y2;
3200 }
3201 }
3202 } while ((state & ExitState) == 0);
3203 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
3204 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3205 if (distance <= 9)
3206 return(MagickTrue);
3207 /*
3208 Image chopping is relative to image configuration.
3209 */
3210 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
3211 exception);
3212 XSetCursorState(display,windows,MagickTrue);
3213 XCheckRefreshWindows(display,windows);
3214 windows->image.window_changes.width=windows->image.ximage->width-
3215 (unsigned int) chop_info.width;
3216 windows->image.window_changes.height=windows->image.ximage->height-
3217 (unsigned int) chop_info.height;
3218 width=(unsigned int) (*image)->columns;
3219 height=(unsigned int) (*image)->rows;
3220 x=0;
3221 y=0;
3222 if (windows->image.crop_geometry != (char *) NULL)
3223 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
3224 scale_factor=(double) width/windows->image.ximage->width;
3225 chop_info.x+=x;
3226 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5);
3227 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5);
3228 scale_factor=(double) height/windows->image.ximage->height;
3229 chop_info.y+=y;
3230 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5);
3231 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5);
3232 /*
3233 Chop image.
3234 */
3235 chop_image=ChopImage(*image,&chop_info,exception);
3236 XSetCursorState(display,windows,MagickFalse);
3237 if (chop_image == (Image *) NULL)
3238 return(MagickFalse);
3239 *image=DestroyImage(*image);
3240 *image=chop_image;
3241 /*
3242 Update image configuration.
3243 */
3244 XConfigureImageColormap(display,resource_info,windows,*image,exception);
3245 (void) XConfigureImage(display,resource_info,windows,*image,exception);
3246 return(MagickTrue);
3247 }
3248
3249 /*
3250 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3251 % %
3252 % %
3253 % %
3254 + X C o l o r E d i t I m a g e %
3255 % %
3256 % %
3257 % %
3258 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3259 %
3260 % XColorEditImage() allows the user to interactively change the color of one
3261 % pixel for a DirectColor image or one colormap entry for a PseudoClass image.
3262 %
3263 % The format of the XColorEditImage method is:
3264 %
3265 % MagickBooleanType XColorEditImage(Display *display,
3266 % XResourceInfo *resource_info,XWindows *windows,Image **image,
3267 % ExceptionInfo *exception)
3268 %
3269 % A description of each parameter follows:
3270 %
3271 % o display: Specifies a connection to an X server; returned from
3272 % XOpenDisplay.
3273 %
3274 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
3275 %
3276 % o windows: Specifies a pointer to a XWindows structure.
3277 %
3278 % o image: the image; returned from ReadImage.
3279 %
3280 % o exception: return any errors or warnings in this structure.
3281 %
3282 */
XColorEditImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image ** image,ExceptionInfo * exception)3283 static MagickBooleanType XColorEditImage(Display *display,
3284 XResourceInfo *resource_info,XWindows *windows,Image **image,
3285 ExceptionInfo *exception)
3286 {
3287 static const char
3288 *ColorEditMenu[] =
3289 {
3290 "Method",
3291 "Pixel Color",
3292 "Border Color",
3293 "Fuzz",
3294 "Undo",
3295 "Help",
3296 "Dismiss",
3297 (char *) NULL
3298 };
3299
3300 static const ModeType
3301 ColorEditCommands[] =
3302 {
3303 ColorEditMethodCommand,
3304 ColorEditColorCommand,
3305 ColorEditBorderCommand,
3306 ColorEditFuzzCommand,
3307 ColorEditUndoCommand,
3308 ColorEditHelpCommand,
3309 ColorEditDismissCommand
3310 };
3311
3312 static PaintMethod
3313 method = PointMethod;
3314
3315 static unsigned int
3316 pen_id = 0;
3317
3318 static XColor
3319 border_color = { 0, 0, 0, 0, 0, 0 };
3320
3321 char
3322 command[MagickPathExtent],
3323 text[MagickPathExtent];
3324
3325 Cursor
3326 cursor;
3327
3328 int
3329 entry,
3330 id,
3331 x,
3332 x_offset,
3333 y,
3334 y_offset;
3335
3336 register Quantum
3337 *q;
3338
3339 register ssize_t
3340 i;
3341
3342 unsigned int
3343 height,
3344 width;
3345
3346 size_t
3347 state;
3348
3349 XColor
3350 color;
3351
3352 XEvent
3353 event;
3354
3355 /*
3356 Map Command widget.
3357 */
3358 (void) CloneString(&windows->command.name,"Color Edit");
3359 windows->command.data=4;
3360 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL);
3361 (void) XMapRaised(display,windows->command.id);
3362 XClientMessage(display,windows->image.id,windows->im_protocols,
3363 windows->im_update_widget,CurrentTime);
3364 /*
3365 Make cursor.
3366 */
3367 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
3368 resource_info->background_color,resource_info->foreground_color);
3369 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3370 /*
3371 Track pointer until button 1 is pressed.
3372 */
3373 XQueryPosition(display,windows->image.id,&x,&y);
3374 (void) XSelectInput(display,windows->image.id,
3375 windows->image.attributes.event_mask | PointerMotionMask);
3376 state=DefaultState;
3377 do
3378 {
3379 if (windows->info.mapped != MagickFalse )
3380 {
3381 /*
3382 Display pointer position.
3383 */
3384 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ",
3385 x+windows->image.x,y+windows->image.y);
3386 XInfoWidget(display,windows,text);
3387 }
3388 /*
3389 Wait for next event.
3390 */
3391 XScreenEvent(display,windows,&event,exception);
3392 if (event.xany.window == windows->command.id)
3393 {
3394 /*
3395 Select a command from the Command widget.
3396 */
3397 id=XCommandWidget(display,windows,ColorEditMenu,&event);
3398 if (id < 0)
3399 {
3400 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3401 continue;
3402 }
3403 switch (ColorEditCommands[id])
3404 {
3405 case ColorEditMethodCommand:
3406 {
3407 char
3408 **methods;
3409
3410 /*
3411 Select a method from the pop-up menu.
3412 */
3413 methods=(char **) GetCommandOptions(MagickMethodOptions);
3414 if (methods == (char **) NULL)
3415 break;
3416 entry=XMenuWidget(display,windows,ColorEditMenu[id],
3417 (const char **) methods,command);
3418 if (entry >= 0)
3419 method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
3420 MagickFalse,methods[entry]);
3421 methods=DestroyStringList(methods);
3422 break;
3423 }
3424 case ColorEditColorCommand:
3425 {
3426 const char
3427 *ColorMenu[MaxNumberPens];
3428
3429 int
3430 pen_number;
3431
3432 /*
3433 Initialize menu selections.
3434 */
3435 for (i=0; i < (int) (MaxNumberPens-2); i++)
3436 ColorMenu[i]=resource_info->pen_colors[i];
3437 ColorMenu[MaxNumberPens-2]="Browser...";
3438 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
3439 /*
3440 Select a pen color from the pop-up menu.
3441 */
3442 pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
3443 (const char **) ColorMenu,command);
3444 if (pen_number < 0)
3445 break;
3446 if (pen_number == (MaxNumberPens-2))
3447 {
3448 static char
3449 color_name[MagickPathExtent] = "gray";
3450
3451 /*
3452 Select a pen color from a dialog.
3453 */
3454 resource_info->pen_colors[pen_number]=color_name;
3455 XColorBrowserWidget(display,windows,"Select",color_name);
3456 if (*color_name == '\0')
3457 break;
3458 }
3459 /*
3460 Set pen color.
3461 */
3462 (void) XParseColor(display,windows->map_info->colormap,
3463 resource_info->pen_colors[pen_number],&color);
3464 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
3465 (unsigned int) MaxColors,&color);
3466 windows->pixel_info->pen_colors[pen_number]=color;
3467 pen_id=(unsigned int) pen_number;
3468 break;
3469 }
3470 case ColorEditBorderCommand:
3471 {
3472 const char
3473 *ColorMenu[MaxNumberPens];
3474
3475 int
3476 pen_number;
3477
3478 /*
3479 Initialize menu selections.
3480 */
3481 for (i=0; i < (int) (MaxNumberPens-2); i++)
3482 ColorMenu[i]=resource_info->pen_colors[i];
3483 ColorMenu[MaxNumberPens-2]="Browser...";
3484 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
3485 /*
3486 Select a pen color from the pop-up menu.
3487 */
3488 pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
3489 (const char **) ColorMenu,command);
3490 if (pen_number < 0)
3491 break;
3492 if (pen_number == (MaxNumberPens-2))
3493 {
3494 static char
3495 color_name[MagickPathExtent] = "gray";
3496
3497 /*
3498 Select a pen color from a dialog.
3499 */
3500 resource_info->pen_colors[pen_number]=color_name;
3501 XColorBrowserWidget(display,windows,"Select",color_name);
3502 if (*color_name == '\0')
3503 break;
3504 }
3505 /*
3506 Set border color.
3507 */
3508 (void) XParseColor(display,windows->map_info->colormap,
3509 resource_info->pen_colors[pen_number],&border_color);
3510 break;
3511 }
3512 case ColorEditFuzzCommand:
3513 {
3514 static char
3515 fuzz[MagickPathExtent];
3516
3517 static const char
3518 *FuzzMenu[] =
3519 {
3520 "0%",
3521 "2%",
3522 "5%",
3523 "10%",
3524 "15%",
3525 "Dialog...",
3526 (char *) NULL,
3527 };
3528
3529 /*
3530 Select a command from the pop-up menu.
3531 */
3532 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu,
3533 command);
3534 if (entry < 0)
3535 break;
3536 if (entry != 5)
3537 {
3538 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double)
3539 QuantumRange+1.0);
3540 break;
3541 }
3542 (void) (void) CopyMagickString(fuzz,"20%",MagickPathExtent);
3543 (void) XDialogWidget(display,windows,"Ok",
3544 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
3545 if (*fuzz == '\0')
3546 break;
3547 (void) ConcatenateMagickString(fuzz,"%",MagickPathExtent);
3548 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+
3549 1.0);
3550 break;
3551 }
3552 case ColorEditUndoCommand:
3553 {
3554 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
3555 image,exception);
3556 break;
3557 }
3558 case ColorEditHelpCommand:
3559 default:
3560 {
3561 XTextViewWidget(display,resource_info,windows,MagickFalse,
3562 "Help Viewer - Image Annotation",ImageColorEditHelp);
3563 break;
3564 }
3565 case ColorEditDismissCommand:
3566 {
3567 /*
3568 Prematurely exit.
3569 */
3570 state|=EscapeState;
3571 state|=ExitState;
3572 break;
3573 }
3574 }
3575 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3576 continue;
3577 }
3578 switch (event.type)
3579 {
3580 case ButtonPress:
3581 {
3582 if (event.xbutton.button != Button1)
3583 break;
3584 if ((event.xbutton.window != windows->image.id) &&
3585 (event.xbutton.window != windows->magnify.id))
3586 break;
3587 /*
3588 exit loop.
3589 */
3590 x=event.xbutton.x;
3591 y=event.xbutton.y;
3592 (void) XMagickCommand(display,resource_info,windows,
3593 SaveToUndoBufferCommand,image,exception);
3594 state|=UpdateConfigurationState;
3595 break;
3596 }
3597 case ButtonRelease:
3598 {
3599 if (event.xbutton.button != Button1)
3600 break;
3601 if ((event.xbutton.window != windows->image.id) &&
3602 (event.xbutton.window != windows->magnify.id))
3603 break;
3604 /*
3605 Update colormap information.
3606 */
3607 x=event.xbutton.x;
3608 y=event.xbutton.y;
3609 XConfigureImageColormap(display,resource_info,windows,*image,exception);
3610 (void) XConfigureImage(display,resource_info,windows,*image,exception);
3611 XInfoWidget(display,windows,text);
3612 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3613 state&=(~UpdateConfigurationState);
3614 break;
3615 }
3616 case Expose:
3617 break;
3618 case KeyPress:
3619 {
3620 KeySym
3621 key_symbol;
3622
3623 if (event.xkey.window == windows->magnify.id)
3624 {
3625 Window
3626 window;
3627
3628 window=windows->magnify.id;
3629 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
3630 }
3631 if (event.xkey.window != windows->image.id)
3632 break;
3633 /*
3634 Respond to a user key press.
3635 */
3636 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
3637 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
3638 switch ((int) key_symbol)
3639 {
3640 case XK_Escape:
3641 case XK_F20:
3642 {
3643 /*
3644 Prematurely exit.
3645 */
3646 state|=ExitState;
3647 break;
3648 }
3649 case XK_F1:
3650 case XK_Help:
3651 {
3652 XTextViewWidget(display,resource_info,windows,MagickFalse,
3653 "Help Viewer - Image Annotation",ImageColorEditHelp);
3654 break;
3655 }
3656 default:
3657 {
3658 (void) XBell(display,0);
3659 break;
3660 }
3661 }
3662 break;
3663 }
3664 case MotionNotify:
3665 {
3666 /*
3667 Map and unmap Info widget as cursor crosses its boundaries.
3668 */
3669 x=event.xmotion.x;
3670 y=event.xmotion.y;
3671 if (windows->info.mapped != MagickFalse )
3672 {
3673 if ((x < (int) (windows->info.x+windows->info.width)) &&
3674 (y < (int) (windows->info.y+windows->info.height)))
3675 (void) XWithdrawWindow(display,windows->info.id,
3676 windows->info.screen);
3677 }
3678 else
3679 if ((x > (int) (windows->info.x+windows->info.width)) ||
3680 (y > (int) (windows->info.y+windows->info.height)))
3681 (void) XMapWindow(display,windows->info.id);
3682 break;
3683 }
3684 default:
3685 break;
3686 }
3687 if (event.xany.window == windows->magnify.id)
3688 {
3689 x=windows->magnify.x-windows->image.x;
3690 y=windows->magnify.y-windows->image.y;
3691 }
3692 x_offset=x;
3693 y_offset=y;
3694 if ((state & UpdateConfigurationState) != 0)
3695 {
3696 CacheView
3697 *image_view;
3698
3699 int
3700 x,
3701 y;
3702
3703 /*
3704 Pixel edit is relative to image configuration.
3705 */
3706 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
3707 MagickTrue);
3708 color=windows->pixel_info->pen_colors[pen_id];
3709 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel);
3710 width=(unsigned int) (*image)->columns;
3711 height=(unsigned int) (*image)->rows;
3712 x=0;
3713 y=0;
3714 if (windows->image.crop_geometry != (char *) NULL)
3715 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
3716 &width,&height);
3717 x_offset=(int)
3718 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x);
3719 y_offset=(int)
3720 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y);
3721 if ((x_offset < 0) || (y_offset < 0))
3722 continue;
3723 if ((x_offset >= (int) (*image)->columns) ||
3724 (y_offset >= (int) (*image)->rows))
3725 continue;
3726 image_view=AcquireAuthenticCacheView(*image,exception);
3727 switch (method)
3728 {
3729 case PointMethod:
3730 default:
3731 {
3732 /*
3733 Update color information using point algorithm.
3734 */
3735 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
3736 return(MagickFalse);
3737 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset,
3738 (ssize_t) y_offset,1,1,exception);
3739 if (q == (Quantum *) NULL)
3740 break;
3741 SetPixelRed(*image,ScaleShortToQuantum(color.red),q);
3742 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q);
3743 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q);
3744 (void) SyncCacheViewAuthenticPixels(image_view,exception);
3745 break;
3746 }
3747 case ReplaceMethod:
3748 {
3749 PixelInfo
3750 pixel,
3751 target;
3752
3753 /*
3754 Update color information using replace algorithm.
3755 */
3756 (void) GetOneCacheViewVirtualPixelInfo(image_view,(ssize_t)
3757 x_offset,(ssize_t) y_offset,&target,exception);
3758 if ((*image)->storage_class == DirectClass)
3759 {
3760 for (y=0; y < (int) (*image)->rows; y++)
3761 {
3762 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
3763 (*image)->columns,1,exception);
3764 if (q == (Quantum *) NULL)
3765 break;
3766 for (x=0; x < (int) (*image)->columns; x++)
3767 {
3768 GetPixelInfoPixel(*image,q,&pixel);
3769 if (IsFuzzyEquivalencePixelInfo(&pixel,&target))
3770 {
3771 SetPixelRed(*image,ScaleShortToQuantum(
3772 color.red),q);
3773 SetPixelGreen(*image,ScaleShortToQuantum(
3774 color.green),q);
3775 SetPixelBlue(*image,ScaleShortToQuantum(
3776 color.blue),q);
3777 }
3778 q+=GetPixelChannels(*image);
3779 }
3780 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3781 break;
3782 }
3783 }
3784 else
3785 {
3786 for (i=0; i < (ssize_t) (*image)->colors; i++)
3787 if (IsFuzzyEquivalencePixelInfo((*image)->colormap+i,&target))
3788 {
3789 (*image)->colormap[i].red=(double) ScaleShortToQuantum(
3790 color.red);
3791 (*image)->colormap[i].green=(double) ScaleShortToQuantum(
3792 color.green);
3793 (*image)->colormap[i].blue=(double) ScaleShortToQuantum(
3794 color.blue);
3795 }
3796 (void) SyncImage(*image,exception);
3797 }
3798 break;
3799 }
3800 case FloodfillMethod:
3801 case FillToBorderMethod:
3802 {
3803 DrawInfo
3804 *draw_info;
3805
3806 PixelInfo
3807 target;
3808
3809 /*
3810 Update color information using floodfill algorithm.
3811 */
3812 (void) GetOneVirtualPixelInfo(*image,
3813 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t)
3814 y_offset,&target,exception);
3815 if (method == FillToBorderMethod)
3816 {
3817 target.red=(double)
3818 ScaleShortToQuantum(border_color.red);
3819 target.green=(double)
3820 ScaleShortToQuantum(border_color.green);
3821 target.blue=(double)
3822 ScaleShortToQuantum(border_color.blue);
3823 }
3824 draw_info=CloneDrawInfo(resource_info->image_info,
3825 (DrawInfo *) NULL);
3826 (void) QueryColorCompliance(resource_info->pen_colors[pen_id],
3827 AllCompliance,&draw_info->fill,exception);
3828 (void) FloodfillPaintImage(*image,draw_info,&target,
3829 (ssize_t)x_offset,(ssize_t)y_offset,
3830 method != FloodfillMethod ? MagickTrue : MagickFalse,exception);
3831 draw_info=DestroyDrawInfo(draw_info);
3832 break;
3833 }
3834 case ResetMethod:
3835 {
3836 /*
3837 Update color information using reset algorithm.
3838 */
3839 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
3840 return(MagickFalse);
3841 for (y=0; y < (int) (*image)->rows; y++)
3842 {
3843 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
3844 (*image)->columns,1,exception);
3845 if (q == (Quantum *) NULL)
3846 break;
3847 for (x=0; x < (int) (*image)->columns; x++)
3848 {
3849 SetPixelRed(*image,ScaleShortToQuantum(color.red),q);
3850 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q);
3851 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q);
3852 q+=GetPixelChannels(*image);
3853 }
3854 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3855 break;
3856 }
3857 break;
3858 }
3859 }
3860 image_view=DestroyCacheView(image_view);
3861 state&=(~UpdateConfigurationState);
3862 }
3863 } while ((state & ExitState) == 0);
3864 (void) XSelectInput(display,windows->image.id,
3865 windows->image.attributes.event_mask);
3866 XSetCursorState(display,windows,MagickFalse);
3867 (void) XFreeCursor(display,cursor);
3868 return(MagickTrue);
3869 }
3870
3871 /*
3872 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3873 % %
3874 % %
3875 % %
3876 + X C o m p o s i t e I m a g e %
3877 % %
3878 % %
3879 % %
3880 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3881 %
3882 % XCompositeImage() requests an image name from the user, reads the image and
3883 % composites it with the X window image at a location the user chooses with
3884 % the pointer.
3885 %
3886 % The format of the XCompositeImage method is:
3887 %
3888 % MagickBooleanType XCompositeImage(Display *display,
3889 % XResourceInfo *resource_info,XWindows *windows,Image *image,
3890 % ExceptionInfo *exception)
3891 %
3892 % A description of each parameter follows:
3893 %
3894 % o display: Specifies a connection to an X server; returned from
3895 % XOpenDisplay.
3896 %
3897 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
3898 %
3899 % o windows: Specifies a pointer to a XWindows structure.
3900 %
3901 % o image: the image; returned from ReadImage.
3902 %
3903 % o exception: return any errors or warnings in this structure.
3904 %
3905 */
XCompositeImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,ExceptionInfo * exception)3906 static MagickBooleanType XCompositeImage(Display *display,
3907 XResourceInfo *resource_info,XWindows *windows,Image *image,
3908 ExceptionInfo *exception)
3909 {
3910 static char
3911 displacement_geometry[MagickPathExtent] = "30x30",
3912 filename[MagickPathExtent] = "\0";
3913
3914 static const char
3915 *CompositeMenu[] =
3916 {
3917 "Operators",
3918 "Dissolve",
3919 "Displace",
3920 "Help",
3921 "Dismiss",
3922 (char *) NULL
3923 };
3924
3925 static CompositeOperator
3926 compose = CopyCompositeOp;
3927
3928 static const ModeType
3929 CompositeCommands[] =
3930 {
3931 CompositeOperatorsCommand,
3932 CompositeDissolveCommand,
3933 CompositeDisplaceCommand,
3934 CompositeHelpCommand,
3935 CompositeDismissCommand
3936 };
3937
3938 char
3939 text[MagickPathExtent];
3940
3941 Cursor
3942 cursor;
3943
3944 Image
3945 *composite_image;
3946
3947 int
3948 entry,
3949 id,
3950 x,
3951 y;
3952
3953 double
3954 blend,
3955 scale_factor;
3956
3957 RectangleInfo
3958 highlight_info,
3959 composite_info;
3960
3961 unsigned int
3962 height,
3963 width;
3964
3965 size_t
3966 state;
3967
3968 XEvent
3969 event;
3970
3971 /*
3972 Request image file name from user.
3973 */
3974 XFileBrowserWidget(display,windows,"Composite",filename);
3975 if (*filename == '\0')
3976 return(MagickTrue);
3977 /*
3978 Read image.
3979 */
3980 XSetCursorState(display,windows,MagickTrue);
3981 XCheckRefreshWindows(display,windows);
3982 (void) CopyMagickString(resource_info->image_info->filename,filename,
3983 MagickPathExtent);
3984 composite_image=ReadImage(resource_info->image_info,exception);
3985 CatchException(exception);
3986 XSetCursorState(display,windows,MagickFalse);
3987 if (composite_image == (Image *) NULL)
3988 return(MagickFalse);
3989 /*
3990 Map Command widget.
3991 */
3992 (void) CloneString(&windows->command.name,"Composite");
3993 windows->command.data=1;
3994 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL);
3995 (void) XMapRaised(display,windows->command.id);
3996 XClientMessage(display,windows->image.id,windows->im_protocols,
3997 windows->im_update_widget,CurrentTime);
3998 /*
3999 Track pointer until button 1 is pressed.
4000 */
4001 XQueryPosition(display,windows->image.id,&x,&y);
4002 (void) XSelectInput(display,windows->image.id,
4003 windows->image.attributes.event_mask | PointerMotionMask);
4004 composite_info.x=(ssize_t) windows->image.x+x;
4005 composite_info.y=(ssize_t) windows->image.y+y;
4006 composite_info.width=0;
4007 composite_info.height=0;
4008 cursor=XCreateFontCursor(display,XC_ul_angle);
4009 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
4010 blend=0.0;
4011 state=DefaultState;
4012 do
4013 {
4014 if (windows->info.mapped != MagickFalse )
4015 {
4016 /*
4017 Display pointer position.
4018 */
4019 (void) FormatLocaleString(text,MagickPathExtent," %+ld%+ld ",
4020 (long) composite_info.x,(long) composite_info.y);
4021 XInfoWidget(display,windows,text);
4022 }
4023 highlight_info=composite_info;
4024 highlight_info.x=composite_info.x-windows->image.x;
4025 highlight_info.y=composite_info.y-windows->image.y;
4026 XHighlightRectangle(display,windows->image.id,
4027 windows->image.highlight_context,&highlight_info);
4028 /*
4029 Wait for next event.
4030 */
4031 XScreenEvent(display,windows,&event,exception);
4032 XHighlightRectangle(display,windows->image.id,
4033 windows->image.highlight_context,&highlight_info);
4034 if (event.xany.window == windows->command.id)
4035 {
4036 /*
4037 Select a command from the Command widget.
4038 */
4039 id=XCommandWidget(display,windows,CompositeMenu,&event);
4040 if (id < 0)
4041 continue;
4042 switch (CompositeCommands[id])
4043 {
4044 case CompositeOperatorsCommand:
4045 {
4046 char
4047 command[MagickPathExtent],
4048 **operators;
4049
4050 /*
4051 Select a command from the pop-up menu.
4052 */
4053 operators=GetCommandOptions(MagickComposeOptions);
4054 if (operators == (char **) NULL)
4055 break;
4056 entry=XMenuWidget(display,windows,CompositeMenu[id],
4057 (const char **) operators,command);
4058 if (entry >= 0)
4059 compose=(CompositeOperator) ParseCommandOption(
4060 MagickComposeOptions,MagickFalse,operators[entry]);
4061 operators=DestroyStringList(operators);
4062 break;
4063 }
4064 case CompositeDissolveCommand:
4065 {
4066 static char
4067 factor[MagickPathExtent] = "20.0";
4068
4069 /*
4070 Dissolve the two images a given percent.
4071 */
4072 (void) XSetFunction(display,windows->image.highlight_context,
4073 GXcopy);
4074 (void) XDialogWidget(display,windows,"Dissolve",
4075 "Enter the blend factor (0.0 - 99.9%):",factor);
4076 (void) XSetFunction(display,windows->image.highlight_context,
4077 GXinvert);
4078 if (*factor == '\0')
4079 break;
4080 blend=StringToDouble(factor,(char **) NULL);
4081 compose=DissolveCompositeOp;
4082 break;
4083 }
4084 case CompositeDisplaceCommand:
4085 {
4086 /*
4087 Get horizontal and vertical scale displacement geometry.
4088 */
4089 (void) XSetFunction(display,windows->image.highlight_context,
4090 GXcopy);
4091 (void) XDialogWidget(display,windows,"Displace",
4092 "Enter the horizontal and vertical scale:",displacement_geometry);
4093 (void) XSetFunction(display,windows->image.highlight_context,
4094 GXinvert);
4095 if (*displacement_geometry == '\0')
4096 break;
4097 compose=DisplaceCompositeOp;
4098 break;
4099 }
4100 case CompositeHelpCommand:
4101 {
4102 (void) XSetFunction(display,windows->image.highlight_context,
4103 GXcopy);
4104 XTextViewWidget(display,resource_info,windows,MagickFalse,
4105 "Help Viewer - Image Composite",ImageCompositeHelp);
4106 (void) XSetFunction(display,windows->image.highlight_context,
4107 GXinvert);
4108 break;
4109 }
4110 case CompositeDismissCommand:
4111 {
4112 /*
4113 Prematurely exit.
4114 */
4115 state|=EscapeState;
4116 state|=ExitState;
4117 break;
4118 }
4119 default:
4120 break;
4121 }
4122 continue;
4123 }
4124 switch (event.type)
4125 {
4126 case ButtonPress:
4127 {
4128 if (image->debug != MagickFalse )
4129 (void) LogMagickEvent(X11Event,GetMagickModule(),
4130 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
4131 event.xbutton.button,event.xbutton.x,event.xbutton.y);
4132 if (event.xbutton.button != Button1)
4133 break;
4134 if (event.xbutton.window != windows->image.id)
4135 break;
4136 /*
4137 Change cursor.
4138 */
4139 composite_info.width=composite_image->columns;
4140 composite_info.height=composite_image->rows;
4141 (void) XCheckDefineCursor(display,windows->image.id,cursor);
4142 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4143 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4144 break;
4145 }
4146 case ButtonRelease:
4147 {
4148 if (image->debug != MagickFalse )
4149 (void) LogMagickEvent(X11Event,GetMagickModule(),
4150 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
4151 event.xbutton.button,event.xbutton.x,event.xbutton.y);
4152 if (event.xbutton.button != Button1)
4153 break;
4154 if (event.xbutton.window != windows->image.id)
4155 break;
4156 if ((composite_info.width != 0) && (composite_info.height != 0))
4157 {
4158 /*
4159 User has selected the location of the composite image.
4160 */
4161 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4162 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4163 state|=ExitState;
4164 }
4165 break;
4166 }
4167 case Expose:
4168 break;
4169 case KeyPress:
4170 {
4171 char
4172 command[MagickPathExtent];
4173
4174 KeySym
4175 key_symbol;
4176
4177 int
4178 length;
4179
4180 if (event.xkey.window != windows->image.id)
4181 break;
4182 /*
4183 Respond to a user key press.
4184 */
4185 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
4186 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4187 *(command+length)='\0';
4188 if (image->debug != MagickFalse )
4189 (void) LogMagickEvent(X11Event,GetMagickModule(),
4190 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command);
4191 switch ((int) key_symbol)
4192 {
4193 case XK_Escape:
4194 case XK_F20:
4195 {
4196 /*
4197 Prematurely exit.
4198 */
4199 composite_image=DestroyImage(composite_image);
4200 state|=EscapeState;
4201 state|=ExitState;
4202 break;
4203 }
4204 case XK_F1:
4205 case XK_Help:
4206 {
4207 (void) XSetFunction(display,windows->image.highlight_context,
4208 GXcopy);
4209 XTextViewWidget(display,resource_info,windows,MagickFalse,
4210 "Help Viewer - Image Composite",ImageCompositeHelp);
4211 (void) XSetFunction(display,windows->image.highlight_context,
4212 GXinvert);
4213 break;
4214 }
4215 default:
4216 {
4217 (void) XBell(display,0);
4218 break;
4219 }
4220 }
4221 break;
4222 }
4223 case MotionNotify:
4224 {
4225 /*
4226 Map and unmap Info widget as text cursor crosses its boundaries.
4227 */
4228 x=event.xmotion.x;
4229 y=event.xmotion.y;
4230 if (windows->info.mapped != MagickFalse )
4231 {
4232 if ((x < (int) (windows->info.x+windows->info.width)) &&
4233 (y < (int) (windows->info.y+windows->info.height)))
4234 (void) XWithdrawWindow(display,windows->info.id,
4235 windows->info.screen);
4236 }
4237 else
4238 if ((x > (int) (windows->info.x+windows->info.width)) ||
4239 (y > (int) (windows->info.y+windows->info.height)))
4240 (void) XMapWindow(display,windows->info.id);
4241 composite_info.x=(ssize_t) windows->image.x+x;
4242 composite_info.y=(ssize_t) windows->image.y+y;
4243 break;
4244 }
4245 default:
4246 {
4247 if (image->debug != MagickFalse )
4248 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
4249 event.type);
4250 break;
4251 }
4252 }
4253 } while ((state & ExitState) == 0);
4254 (void) XSelectInput(display,windows->image.id,
4255 windows->image.attributes.event_mask);
4256 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
4257 XSetCursorState(display,windows,MagickFalse);
4258 (void) XFreeCursor(display,cursor);
4259 if ((state & EscapeState) != 0)
4260 return(MagickTrue);
4261 /*
4262 Image compositing is relative to image configuration.
4263 */
4264 XSetCursorState(display,windows,MagickTrue);
4265 XCheckRefreshWindows(display,windows);
4266 width=(unsigned int) image->columns;
4267 height=(unsigned int) image->rows;
4268 x=0;
4269 y=0;
4270 if (windows->image.crop_geometry != (char *) NULL)
4271 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
4272 scale_factor=(double) width/windows->image.ximage->width;
4273 composite_info.x+=x;
4274 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5);
4275 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5);
4276 scale_factor=(double) height/windows->image.ximage->height;
4277 composite_info.y+=y;
4278 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5);
4279 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5);
4280 if ((composite_info.width != composite_image->columns) ||
4281 (composite_info.height != composite_image->rows))
4282 {
4283 Image
4284 *resize_image;
4285
4286 /*
4287 Scale composite image.
4288 */
4289 resize_image=ResizeImage(composite_image,composite_info.width,
4290 composite_info.height,composite_image->filter,exception);
4291 composite_image=DestroyImage(composite_image);
4292 if (resize_image == (Image *) NULL)
4293 {
4294 XSetCursorState(display,windows,MagickFalse);
4295 return(MagickFalse);
4296 }
4297 composite_image=resize_image;
4298 }
4299 if (compose == DisplaceCompositeOp)
4300 (void) SetImageArtifact(composite_image,"compose:args",
4301 displacement_geometry);
4302 if (blend != 0.0)
4303 {
4304 CacheView
4305 *image_view;
4306
4307 int
4308 y;
4309
4310 Quantum
4311 opacity;
4312
4313 register int
4314 x;
4315
4316 register Quantum
4317 *q;
4318
4319 /*
4320 Create mattes for blending.
4321 */
4322 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel,exception);
4323 opacity=(Quantum) (ScaleQuantumToChar(QuantumRange)-
4324 ((ssize_t) ScaleQuantumToChar(QuantumRange)*blend)/100);
4325 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
4326 return(MagickFalse);
4327 image->alpha_trait=BlendPixelTrait;
4328 image_view=AcquireAuthenticCacheView(image,exception);
4329 for (y=0; y < (int) image->rows; y++)
4330 {
4331 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1,
4332 exception);
4333 if (q == (Quantum *) NULL)
4334 break;
4335 for (x=0; x < (int) image->columns; x++)
4336 {
4337 SetPixelAlpha(image,opacity,q);
4338 q+=GetPixelChannels(image);
4339 }
4340 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4341 break;
4342 }
4343 image_view=DestroyCacheView(image_view);
4344 }
4345 /*
4346 Composite image with X Image window.
4347 */
4348 (void) CompositeImage(image,composite_image,compose,MagickTrue,
4349 composite_info.x,composite_info.y,exception);
4350 composite_image=DestroyImage(composite_image);
4351 XSetCursorState(display,windows,MagickFalse);
4352 /*
4353 Update image configuration.
4354 */
4355 XConfigureImageColormap(display,resource_info,windows,image,exception);
4356 (void) XConfigureImage(display,resource_info,windows,image,exception);
4357 return(MagickTrue);
4358 }
4359
4360 /*
4361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4362 % %
4363 % %
4364 % %
4365 + X C o n f i g u r e I m a g e %
4366 % %
4367 % %
4368 % %
4369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4370 %
4371 % XConfigureImage() creates a new X image. It also notifies the window
4372 % manager of the new image size and configures the transient widows.
4373 %
4374 % The format of the XConfigureImage method is:
4375 %
4376 % MagickBooleanType XConfigureImage(Display *display,
4377 % XResourceInfo *resource_info,XWindows *windows,Image *image,
4378 % ExceptionInfo *exception)
4379 %
4380 % A description of each parameter follows:
4381 %
4382 % o display: Specifies a connection to an X server; returned from
4383 % XOpenDisplay.
4384 %
4385 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
4386 %
4387 % o windows: Specifies a pointer to a XWindows structure.
4388 %
4389 % o image: the image.
4390 %
4391 % o exception: return any errors or warnings in this structure.
4392 %
4393 % o exception: return any errors or warnings in this structure.
4394 %
4395 */
XConfigureImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,ExceptionInfo * exception)4396 static MagickBooleanType XConfigureImage(Display *display,
4397 XResourceInfo *resource_info,XWindows *windows,Image *image,
4398 ExceptionInfo *exception)
4399 {
4400 char
4401 geometry[MagickPathExtent];
4402
4403 MagickStatusType
4404 status;
4405
4406 size_t
4407 mask,
4408 height,
4409 width;
4410
4411 ssize_t
4412 x,
4413 y;
4414
4415 XSizeHints
4416 *size_hints;
4417
4418 XWindowChanges
4419 window_changes;
4420
4421 /*
4422 Dismiss if window dimensions are zero.
4423 */
4424 width=(unsigned int) windows->image.window_changes.width;
4425 height=(unsigned int) windows->image.window_changes.height;
4426 if (image->debug != MagickFalse )
4427 (void) LogMagickEvent(X11Event,GetMagickModule(),
4428 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width,
4429 windows->image.ximage->height,(double) width,(double) height);
4430 if ((width*height) == 0)
4431 return(MagickTrue);
4432 x=0;
4433 y=0;
4434 /*
4435 Resize image to fit Image window dimensions.
4436 */
4437 XSetCursorState(display,windows,MagickTrue);
4438 (void) XFlush(display);
4439 if (((int) width != windows->image.ximage->width) ||
4440 ((int) height != windows->image.ximage->height))
4441 image->taint=MagickTrue;
4442 windows->magnify.x=(int)
4443 width*windows->magnify.x/windows->image.ximage->width;
4444 windows->magnify.y=(int)
4445 height*windows->magnify.y/windows->image.ximage->height;
4446 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width);
4447 windows->image.y=(int)
4448 (height*windows->image.y/windows->image.ximage->height);
4449 status=XMakeImage(display,resource_info,&windows->image,image,
4450 (unsigned int) width,(unsigned int) height,exception);
4451 if (status == MagickFalse)
4452 XNoticeWidget(display,windows,"Unable to configure X image:",
4453 windows->image.name);
4454 /*
4455 Notify window manager of the new configuration.
4456 */
4457 if (resource_info->image_geometry != (char *) NULL)
4458 (void) FormatLocaleString(geometry,MagickPathExtent,"%s>!",
4459 resource_info->image_geometry);
4460 else
4461 (void) FormatLocaleString(geometry,MagickPathExtent,"%ux%u+0+0>!",
4462 XDisplayWidth(display,windows->image.screen),
4463 XDisplayHeight(display,windows->image.screen));
4464 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
4465 window_changes.width=(int) width;
4466 if (window_changes.width > XDisplayWidth(display,windows->image.screen))
4467 window_changes.width=XDisplayWidth(display,windows->image.screen);
4468 window_changes.height=(int) height;
4469 if (window_changes.height > XDisplayHeight(display,windows->image.screen))
4470 window_changes.height=XDisplayHeight(display,windows->image.screen);
4471 mask=(size_t) (CWWidth | CWHeight);
4472 if (resource_info->backdrop)
4473 {
4474 mask|=CWX | CWY;
4475 window_changes.x=(int)
4476 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2));
4477 window_changes.y=(int)
4478 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2));
4479 }
4480 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen,
4481 (unsigned int) mask,&window_changes);
4482 (void) XClearWindow(display,windows->image.id);
4483 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
4484 /*
4485 Update Magnify window configuration.
4486 */
4487 if (windows->magnify.mapped != MagickFalse )
4488 XMakeMagnifyImage(display,windows,exception);
4489 windows->pan.crop_geometry=windows->image.crop_geometry;
4490 XBestIconSize(display,&windows->pan,image);
4491 while (((windows->pan.width << 1) < MaxIconSize) &&
4492 ((windows->pan.height << 1) < MaxIconSize))
4493 {
4494 windows->pan.width<<=1;
4495 windows->pan.height<<=1;
4496 }
4497 if (windows->pan.geometry != (char *) NULL)
4498 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
4499 &windows->pan.width,&windows->pan.height);
4500 window_changes.width=(int) windows->pan.width;
4501 window_changes.height=(int) windows->pan.height;
4502 size_hints=XAllocSizeHints();
4503 if (size_hints != (XSizeHints *) NULL)
4504 {
4505 /*
4506 Set new size hints.
4507 */
4508 size_hints->flags=PSize | PMinSize | PMaxSize;
4509 size_hints->width=window_changes.width;
4510 size_hints->height=window_changes.height;
4511 size_hints->min_width=size_hints->width;
4512 size_hints->min_height=size_hints->height;
4513 size_hints->max_width=size_hints->width;
4514 size_hints->max_height=size_hints->height;
4515 (void) XSetNormalHints(display,windows->pan.id,size_hints);
4516 (void) XFree((void *) size_hints);
4517 }
4518 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen,
4519 (unsigned int) (CWWidth | CWHeight),&window_changes);
4520 /*
4521 Update icon window configuration.
4522 */
4523 windows->icon.crop_geometry=windows->image.crop_geometry;
4524 XBestIconSize(display,&windows->icon,image);
4525 window_changes.width=(int) windows->icon.width;
4526 window_changes.height=(int) windows->icon.height;
4527 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen,
4528 (unsigned int) (CWWidth | CWHeight),&window_changes);
4529 XSetCursorState(display,windows,MagickFalse);
4530 return(status != 0 ? MagickTrue : MagickFalse);
4531 }
4532
4533 /*
4534 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4535 % %
4536 % %
4537 % %
4538 + X C r o p I m a g e %
4539 % %
4540 % %
4541 % %
4542 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4543 %
4544 % XCropImage() allows the user to select a region of the image and crop, copy,
4545 % or cut it. For copy or cut, the image can subsequently be composited onto
4546 % the image with XPasteImage.
4547 %
4548 % The format of the XCropImage method is:
4549 %
4550 % MagickBooleanType XCropImage(Display *display,
4551 % XResourceInfo *resource_info,XWindows *windows,Image *image,
4552 % const ClipboardMode mode,ExceptionInfo *exception)
4553 %
4554 % A description of each parameter follows:
4555 %
4556 % o display: Specifies a connection to an X server; returned from
4557 % XOpenDisplay.
4558 %
4559 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
4560 %
4561 % o windows: Specifies a pointer to a XWindows structure.
4562 %
4563 % o image: the image; returned from ReadImage.
4564 %
4565 % o mode: This unsigned value specified whether the image should be
4566 % cropped, copied, or cut.
4567 %
4568 % o exception: return any errors or warnings in this structure.
4569 %
4570 */
XCropImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,const ClipboardMode mode,ExceptionInfo * exception)4571 static MagickBooleanType XCropImage(Display *display,
4572 XResourceInfo *resource_info,XWindows *windows,Image *image,
4573 const ClipboardMode mode,ExceptionInfo *exception)
4574 {
4575 static const char
4576 *CropModeMenu[] =
4577 {
4578 "Help",
4579 "Dismiss",
4580 (char *) NULL
4581 },
4582 *RectifyModeMenu[] =
4583 {
4584 "Crop",
4585 "Help",
4586 "Dismiss",
4587 (char *) NULL
4588 };
4589
4590 static const ModeType
4591 CropCommands[] =
4592 {
4593 CropHelpCommand,
4594 CropDismissCommand
4595 },
4596 RectifyCommands[] =
4597 {
4598 RectifyCopyCommand,
4599 RectifyHelpCommand,
4600 RectifyDismissCommand
4601 };
4602
4603 CacheView
4604 *image_view;
4605
4606 char
4607 command[MagickPathExtent],
4608 text[MagickPathExtent];
4609
4610 Cursor
4611 cursor;
4612
4613 int
4614 id,
4615 x,
4616 y;
4617
4618 KeySym
4619 key_symbol;
4620
4621 Image
4622 *crop_image;
4623
4624 double
4625 scale_factor;
4626
4627 RectangleInfo
4628 crop_info,
4629 highlight_info;
4630
4631 register Quantum
4632 *q;
4633
4634 unsigned int
4635 height,
4636 width;
4637
4638 size_t
4639 state;
4640
4641 XEvent
4642 event;
4643
4644 /*
4645 Map Command widget.
4646 */
4647 switch (mode)
4648 {
4649 case CopyMode:
4650 {
4651 (void) CloneString(&windows->command.name,"Copy");
4652 break;
4653 }
4654 case CropMode:
4655 {
4656 (void) CloneString(&windows->command.name,"Crop");
4657 break;
4658 }
4659 case CutMode:
4660 {
4661 (void) CloneString(&windows->command.name,"Cut");
4662 break;
4663 }
4664 }
4665 RectifyModeMenu[0]=windows->command.name;
4666 windows->command.data=0;
4667 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL);
4668 (void) XMapRaised(display,windows->command.id);
4669 XClientMessage(display,windows->image.id,windows->im_protocols,
4670 windows->im_update_widget,CurrentTime);
4671 /*
4672 Track pointer until button 1 is pressed.
4673 */
4674 XQueryPosition(display,windows->image.id,&x,&y);
4675 (void) XSelectInput(display,windows->image.id,
4676 windows->image.attributes.event_mask | PointerMotionMask);
4677 crop_info.x=(ssize_t) windows->image.x+x;
4678 crop_info.y=(ssize_t) windows->image.y+y;
4679 crop_info.width=0;
4680 crop_info.height=0;
4681 cursor=XCreateFontCursor(display,XC_fleur);
4682 state=DefaultState;
4683 do
4684 {
4685 if (windows->info.mapped != MagickFalse )
4686 {
4687 /*
4688 Display pointer position.
4689 */
4690 (void) FormatLocaleString(text,MagickPathExtent," %+ld%+ld ",
4691 (long) crop_info.x,(long) crop_info.y);
4692 XInfoWidget(display,windows,text);
4693 }
4694 /*
4695 Wait for next event.
4696 */
4697 XScreenEvent(display,windows,&event,exception);
4698 if (event.xany.window == windows->command.id)
4699 {
4700 /*
4701 Select a command from the Command widget.
4702 */
4703 id=XCommandWidget(display,windows,CropModeMenu,&event);
4704 if (id < 0)
4705 continue;
4706 switch (CropCommands[id])
4707 {
4708 case CropHelpCommand:
4709 {
4710 switch (mode)
4711 {
4712 case CopyMode:
4713 {
4714 XTextViewWidget(display,resource_info,windows,MagickFalse,
4715 "Help Viewer - Image Copy",ImageCopyHelp);
4716 break;
4717 }
4718 case CropMode:
4719 {
4720 XTextViewWidget(display,resource_info,windows,MagickFalse,
4721 "Help Viewer - Image Crop",ImageCropHelp);
4722 break;
4723 }
4724 case CutMode:
4725 {
4726 XTextViewWidget(display,resource_info,windows,MagickFalse,
4727 "Help Viewer - Image Cut",ImageCutHelp);
4728 break;
4729 }
4730 }
4731 break;
4732 }
4733 case CropDismissCommand:
4734 {
4735 /*
4736 Prematurely exit.
4737 */
4738 state|=EscapeState;
4739 state|=ExitState;
4740 break;
4741 }
4742 default:
4743 break;
4744 }
4745 continue;
4746 }
4747 switch (event.type)
4748 {
4749 case ButtonPress:
4750 {
4751 if (event.xbutton.button != Button1)
4752 break;
4753 if (event.xbutton.window != windows->image.id)
4754 break;
4755 /*
4756 Note first corner of cropping rectangle-- exit loop.
4757 */
4758 (void) XCheckDefineCursor(display,windows->image.id,cursor);
4759 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4760 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4761 state|=ExitState;
4762 break;
4763 }
4764 case ButtonRelease:
4765 break;
4766 case Expose:
4767 break;
4768 case KeyPress:
4769 {
4770 if (event.xkey.window != windows->image.id)
4771 break;
4772 /*
4773 Respond to a user key press.
4774 */
4775 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
4776 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4777 switch ((int) key_symbol)
4778 {
4779 case XK_Escape:
4780 case XK_F20:
4781 {
4782 /*
4783 Prematurely exit.
4784 */
4785 state|=EscapeState;
4786 state|=ExitState;
4787 break;
4788 }
4789 case XK_F1:
4790 case XK_Help:
4791 {
4792 switch (mode)
4793 {
4794 case CopyMode:
4795 {
4796 XTextViewWidget(display,resource_info,windows,MagickFalse,
4797 "Help Viewer - Image Copy",ImageCopyHelp);
4798 break;
4799 }
4800 case CropMode:
4801 {
4802 XTextViewWidget(display,resource_info,windows,MagickFalse,
4803 "Help Viewer - Image Crop",ImageCropHelp);
4804 break;
4805 }
4806 case CutMode:
4807 {
4808 XTextViewWidget(display,resource_info,windows,MagickFalse,
4809 "Help Viewer - Image Cut",ImageCutHelp);
4810 break;
4811 }
4812 }
4813 break;
4814 }
4815 default:
4816 {
4817 (void) XBell(display,0);
4818 break;
4819 }
4820 }
4821 break;
4822 }
4823 case MotionNotify:
4824 {
4825 if (event.xmotion.window != windows->image.id)
4826 break;
4827 /*
4828 Map and unmap Info widget as text cursor crosses its boundaries.
4829 */
4830 x=event.xmotion.x;
4831 y=event.xmotion.y;
4832 if (windows->info.mapped != MagickFalse )
4833 {
4834 if ((x < (int) (windows->info.x+windows->info.width)) &&
4835 (y < (int) (windows->info.y+windows->info.height)))
4836 (void) XWithdrawWindow(display,windows->info.id,
4837 windows->info.screen);
4838 }
4839 else
4840 if ((x > (int) (windows->info.x+windows->info.width)) ||
4841 (y > (int) (windows->info.y+windows->info.height)))
4842 (void) XMapWindow(display,windows->info.id);
4843 crop_info.x=(ssize_t) windows->image.x+x;
4844 crop_info.y=(ssize_t) windows->image.y+y;
4845 break;
4846 }
4847 default:
4848 break;
4849 }
4850 } while ((state & ExitState) == 0);
4851 (void) XSelectInput(display,windows->image.id,
4852 windows->image.attributes.event_mask);
4853 if ((state & EscapeState) != 0)
4854 {
4855 /*
4856 User want to exit without cropping.
4857 */
4858 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
4859 (void) XFreeCursor(display,cursor);
4860 return(MagickTrue);
4861 }
4862 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
4863 do
4864 {
4865 /*
4866 Size rectangle as pointer moves until the mouse button is released.
4867 */
4868 x=(int) crop_info.x;
4869 y=(int) crop_info.y;
4870 crop_info.width=0;
4871 crop_info.height=0;
4872 state=DefaultState;
4873 do
4874 {
4875 highlight_info=crop_info;
4876 highlight_info.x=crop_info.x-windows->image.x;
4877 highlight_info.y=crop_info.y-windows->image.y;
4878 if ((highlight_info.width > 3) && (highlight_info.height > 3))
4879 {
4880 /*
4881 Display info and draw cropping rectangle.
4882 */
4883 if (windows->info.mapped == MagickFalse)
4884 (void) XMapWindow(display,windows->info.id);
4885 (void) FormatLocaleString(text,MagickPathExtent,
4886 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
4887 crop_info.height,(double) crop_info.x,(double) crop_info.y);
4888 XInfoWidget(display,windows,text);
4889 XHighlightRectangle(display,windows->image.id,
4890 windows->image.highlight_context,&highlight_info);
4891 }
4892 else
4893 if (windows->info.mapped != MagickFalse )
4894 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
4895 /*
4896 Wait for next event.
4897 */
4898 XScreenEvent(display,windows,&event,exception);
4899 if ((highlight_info.width > 3) && (highlight_info.height > 3))
4900 XHighlightRectangle(display,windows->image.id,
4901 windows->image.highlight_context,&highlight_info);
4902 switch (event.type)
4903 {
4904 case ButtonPress:
4905 {
4906 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4907 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4908 break;
4909 }
4910 case ButtonRelease:
4911 {
4912 /*
4913 User has committed to cropping rectangle.
4914 */
4915 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4916 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
4917 XSetCursorState(display,windows,MagickFalse);
4918 state|=ExitState;
4919 windows->command.data=0;
4920 (void) XCommandWidget(display,windows,RectifyModeMenu,
4921 (XEvent *) NULL);
4922 break;
4923 }
4924 case Expose:
4925 break;
4926 case MotionNotify:
4927 {
4928 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x;
4929 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y;
4930 }
4931 default:
4932 break;
4933 }
4934 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) ||
4935 ((state & ExitState) != 0))
4936 {
4937 /*
4938 Check boundary conditions.
4939 */
4940 if (crop_info.x < 0)
4941 crop_info.x=0;
4942 else
4943 if (crop_info.x > (ssize_t) windows->image.ximage->width)
4944 crop_info.x=(ssize_t) windows->image.ximage->width;
4945 if ((int) crop_info.x < x)
4946 crop_info.width=(unsigned int) (x-crop_info.x);
4947 else
4948 {
4949 crop_info.width=(unsigned int) (crop_info.x-x);
4950 crop_info.x=(ssize_t) x;
4951 }
4952 if (crop_info.y < 0)
4953 crop_info.y=0;
4954 else
4955 if (crop_info.y > (ssize_t) windows->image.ximage->height)
4956 crop_info.y=(ssize_t) windows->image.ximage->height;
4957 if ((int) crop_info.y < y)
4958 crop_info.height=(unsigned int) (y-crop_info.y);
4959 else
4960 {
4961 crop_info.height=(unsigned int) (crop_info.y-y);
4962 crop_info.y=(ssize_t) y;
4963 }
4964 }
4965 } while ((state & ExitState) == 0);
4966 /*
4967 Wait for user to grab a corner of the rectangle or press return.
4968 */
4969 state=DefaultState;
4970 (void) XMapWindow(display,windows->info.id);
4971 do
4972 {
4973 if (windows->info.mapped != MagickFalse )
4974 {
4975 /*
4976 Display pointer position.
4977 */
4978 (void) FormatLocaleString(text,MagickPathExtent,
4979 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
4980 crop_info.height,(double) crop_info.x,(double) crop_info.y);
4981 XInfoWidget(display,windows,text);
4982 }
4983 highlight_info=crop_info;
4984 highlight_info.x=crop_info.x-windows->image.x;
4985 highlight_info.y=crop_info.y-windows->image.y;
4986 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
4987 {
4988 state|=EscapeState;
4989 state|=ExitState;
4990 break;
4991 }
4992 XHighlightRectangle(display,windows->image.id,
4993 windows->image.highlight_context,&highlight_info);
4994 XScreenEvent(display,windows,&event,exception);
4995 if (event.xany.window == windows->command.id)
4996 {
4997 /*
4998 Select a command from the Command widget.
4999 */
5000 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
5001 id=XCommandWidget(display,windows,RectifyModeMenu,&event);
5002 (void) XSetFunction(display,windows->image.highlight_context,
5003 GXinvert);
5004 XHighlightRectangle(display,windows->image.id,
5005 windows->image.highlight_context,&highlight_info);
5006 if (id >= 0)
5007 switch (RectifyCommands[id])
5008 {
5009 case RectifyCopyCommand:
5010 {
5011 state|=ExitState;
5012 break;
5013 }
5014 case RectifyHelpCommand:
5015 {
5016 (void) XSetFunction(display,windows->image.highlight_context,
5017 GXcopy);
5018 switch (mode)
5019 {
5020 case CopyMode:
5021 {
5022 XTextViewWidget(display,resource_info,windows,MagickFalse,
5023 "Help Viewer - Image Copy",ImageCopyHelp);
5024 break;
5025 }
5026 case CropMode:
5027 {
5028 XTextViewWidget(display,resource_info,windows,MagickFalse,
5029 "Help Viewer - Image Crop",ImageCropHelp);
5030 break;
5031 }
5032 case CutMode:
5033 {
5034 XTextViewWidget(display,resource_info,windows,MagickFalse,
5035 "Help Viewer - Image Cut",ImageCutHelp);
5036 break;
5037 }
5038 }
5039 (void) XSetFunction(display,windows->image.highlight_context,
5040 GXinvert);
5041 break;
5042 }
5043 case RectifyDismissCommand:
5044 {
5045 /*
5046 Prematurely exit.
5047 */
5048 state|=EscapeState;
5049 state|=ExitState;
5050 break;
5051 }
5052 default:
5053 break;
5054 }
5055 continue;
5056 }
5057 XHighlightRectangle(display,windows->image.id,
5058 windows->image.highlight_context,&highlight_info);
5059 switch (event.type)
5060 {
5061 case ButtonPress:
5062 {
5063 if (event.xbutton.button != Button1)
5064 break;
5065 if (event.xbutton.window != windows->image.id)
5066 break;
5067 x=windows->image.x+event.xbutton.x;
5068 y=windows->image.y+event.xbutton.y;
5069 if ((x < (int) (crop_info.x+RoiDelta)) &&
5070 (x > (int) (crop_info.x-RoiDelta)) &&
5071 (y < (int) (crop_info.y+RoiDelta)) &&
5072 (y > (int) (crop_info.y-RoiDelta)))
5073 {
5074 crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
5075 crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
5076 state|=UpdateConfigurationState;
5077 break;
5078 }
5079 if ((x < (int) (crop_info.x+RoiDelta)) &&
5080 (x > (int) (crop_info.x-RoiDelta)) &&
5081 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
5082 (y > (int) (crop_info.y+crop_info.height-RoiDelta)))
5083 {
5084 crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
5085 state|=UpdateConfigurationState;
5086 break;
5087 }
5088 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
5089 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
5090 (y < (int) (crop_info.y+RoiDelta)) &&
5091 (y > (int) (crop_info.y-RoiDelta)))
5092 {
5093 crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
5094 state|=UpdateConfigurationState;
5095 break;
5096 }
5097 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
5098 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
5099 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
5100 (y > (int) (crop_info.y+crop_info.height-RoiDelta)))
5101 {
5102 state|=UpdateConfigurationState;
5103 break;
5104 }
5105 }
5106 case ButtonRelease:
5107 {
5108 if (event.xbutton.window == windows->pan.id)
5109 if ((highlight_info.x != crop_info.x-windows->image.x) ||
5110 (highlight_info.y != crop_info.y-windows->image.y))
5111 XHighlightRectangle(display,windows->image.id,
5112 windows->image.highlight_context,&highlight_info);
5113 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
5114 event.xbutton.time);
5115 break;
5116 }
5117 case Expose:
5118 {
5119 if (event.xexpose.window == windows->image.id)
5120 if (event.xexpose.count == 0)
5121 {
5122 event.xexpose.x=(int) highlight_info.x;
5123 event.xexpose.y=(int) highlight_info.y;
5124 event.xexpose.width=(int) highlight_info.width;
5125 event.xexpose.height=(int) highlight_info.height;
5126 XRefreshWindow(display,&windows->image,&event);
5127 }
5128 if (event.xexpose.window == windows->info.id)
5129 if (event.xexpose.count == 0)
5130 XInfoWidget(display,windows,text);
5131 break;
5132 }
5133 case KeyPress:
5134 {
5135 if (event.xkey.window != windows->image.id)
5136 break;
5137 /*
5138 Respond to a user key press.
5139 */
5140 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
5141 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5142 switch ((int) key_symbol)
5143 {
5144 case XK_Escape:
5145 case XK_F20:
5146 state|=EscapeState;
5147 case XK_Return:
5148 {
5149 state|=ExitState;
5150 break;
5151 }
5152 case XK_Home:
5153 case XK_KP_Home:
5154 {
5155 crop_info.x=(ssize_t) (windows->image.width/2L-crop_info.width/
5156 2L);
5157 crop_info.y=(ssize_t) (windows->image.height/2L-crop_info.height/
5158 2L);
5159 break;
5160 }
5161 case XK_Left:
5162 case XK_KP_Left:
5163 {
5164 crop_info.x--;
5165 break;
5166 }
5167 case XK_Up:
5168 case XK_KP_Up:
5169 case XK_Next:
5170 {
5171 crop_info.y--;
5172 break;
5173 }
5174 case XK_Right:
5175 case XK_KP_Right:
5176 {
5177 crop_info.x++;
5178 break;
5179 }
5180 case XK_Prior:
5181 case XK_Down:
5182 case XK_KP_Down:
5183 {
5184 crop_info.y++;
5185 break;
5186 }
5187 case XK_F1:
5188 case XK_Help:
5189 {
5190 (void) XSetFunction(display,windows->image.highlight_context,
5191 GXcopy);
5192 switch (mode)
5193 {
5194 case CopyMode:
5195 {
5196 XTextViewWidget(display,resource_info,windows,MagickFalse,
5197 "Help Viewer - Image Copy",ImageCopyHelp);
5198 break;
5199 }
5200 case CropMode:
5201 {
5202 XTextViewWidget(display,resource_info,windows,MagickFalse,
5203 "Help Viewer - Image Cropg",ImageCropHelp);
5204 break;
5205 }
5206 case CutMode:
5207 {
5208 XTextViewWidget(display,resource_info,windows,MagickFalse,
5209 "Help Viewer - Image Cutg",ImageCutHelp);
5210 break;
5211 }
5212 }
5213 (void) XSetFunction(display,windows->image.highlight_context,
5214 GXinvert);
5215 break;
5216 }
5217 default:
5218 {
5219 (void) XBell(display,0);
5220 break;
5221 }
5222 }
5223 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
5224 event.xkey.time);
5225 break;
5226 }
5227 case KeyRelease:
5228 break;
5229 case MotionNotify:
5230 {
5231 if (event.xmotion.window != windows->image.id)
5232 break;
5233 /*
5234 Map and unmap Info widget as text cursor crosses its boundaries.
5235 */
5236 x=event.xmotion.x;
5237 y=event.xmotion.y;
5238 if (windows->info.mapped != MagickFalse )
5239 {
5240 if ((x < (int) (windows->info.x+windows->info.width)) &&
5241 (y < (int) (windows->info.y+windows->info.height)))
5242 (void) XWithdrawWindow(display,windows->info.id,
5243 windows->info.screen);
5244 }
5245 else
5246 if ((x > (int) (windows->info.x+windows->info.width)) ||
5247 (y > (int) (windows->info.y+windows->info.height)))
5248 (void) XMapWindow(display,windows->info.id);
5249 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x;
5250 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y;
5251 break;
5252 }
5253 case SelectionRequest:
5254 {
5255 XSelectionEvent
5256 notify;
5257
5258 XSelectionRequestEvent
5259 *request;
5260
5261 /*
5262 Set primary selection.
5263 */
5264 (void) FormatLocaleString(text,MagickPathExtent,
5265 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
5266 crop_info.height,(double) crop_info.x,(double) crop_info.y);
5267 request=(&(event.xselectionrequest));
5268 (void) XChangeProperty(request->display,request->requestor,
5269 request->property,request->target,8,PropModeReplace,
5270 (unsigned char *) text,(int) strlen(text));
5271 notify.type=SelectionNotify;
5272 notify.display=request->display;
5273 notify.requestor=request->requestor;
5274 notify.selection=request->selection;
5275 notify.target=request->target;
5276 notify.time=request->time;
5277 if (request->property == None)
5278 notify.property=request->target;
5279 else
5280 notify.property=request->property;
5281 (void) XSendEvent(request->display,request->requestor,False,0,
5282 (XEvent *) ¬ify);
5283 }
5284 default:
5285 break;
5286 }
5287 if ((state & UpdateConfigurationState) != 0)
5288 {
5289 (void) XPutBackEvent(display,&event);
5290 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5291 break;
5292 }
5293 } while ((state & ExitState) == 0);
5294 } while ((state & ExitState) == 0);
5295 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
5296 XSetCursorState(display,windows,MagickFalse);
5297 if ((state & EscapeState) != 0)
5298 return(MagickTrue);
5299 if (mode == CropMode)
5300 if (((int) crop_info.width != windows->image.ximage->width) ||
5301 ((int) crop_info.height != windows->image.ximage->height))
5302 {
5303 /*
5304 Reconfigure Image window as defined by cropping rectangle.
5305 */
5306 XSetCropGeometry(display,windows,&crop_info,image);
5307 windows->image.window_changes.width=(int) crop_info.width;
5308 windows->image.window_changes.height=(int) crop_info.height;
5309 (void) XConfigureImage(display,resource_info,windows,image,exception);
5310 return(MagickTrue);
5311 }
5312 /*
5313 Copy image before applying image transforms.
5314 */
5315 XSetCursorState(display,windows,MagickTrue);
5316 XCheckRefreshWindows(display,windows);
5317 width=(unsigned int) image->columns;
5318 height=(unsigned int) image->rows;
5319 x=0;
5320 y=0;
5321 if (windows->image.crop_geometry != (char *) NULL)
5322 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
5323 scale_factor=(double) width/windows->image.ximage->width;
5324 crop_info.x+=x;
5325 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
5326 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
5327 scale_factor=(double) height/windows->image.ximage->height;
5328 crop_info.y+=y;
5329 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
5330 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5);
5331 crop_image=CropImage(image,&crop_info,exception);
5332 XSetCursorState(display,windows,MagickFalse);
5333 if (crop_image == (Image *) NULL)
5334 return(MagickFalse);
5335 if (resource_info->copy_image != (Image *) NULL)
5336 resource_info->copy_image=DestroyImage(resource_info->copy_image);
5337 resource_info->copy_image=crop_image;
5338 if (mode == CopyMode)
5339 {
5340 (void) XConfigureImage(display,resource_info,windows,image,exception);
5341 return(MagickTrue);
5342 }
5343 /*
5344 Cut image.
5345 */
5346 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
5347 return(MagickFalse);
5348 image->alpha_trait=BlendPixelTrait;
5349 image_view=AcquireAuthenticCacheView(image,exception);
5350 for (y=0; y < (int) crop_info.height; y++)
5351 {
5352 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y,
5353 crop_info.width,1,exception);
5354 if (q == (Quantum *) NULL)
5355 break;
5356 for (x=0; x < (int) crop_info.width; x++)
5357 {
5358 SetPixelAlpha(image,TransparentAlpha,q);
5359 q+=GetPixelChannels(image);
5360 }
5361 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
5362 break;
5363 }
5364 image_view=DestroyCacheView(image_view);
5365 /*
5366 Update image configuration.
5367 */
5368 XConfigureImageColormap(display,resource_info,windows,image,exception);
5369 (void) XConfigureImage(display,resource_info,windows,image,exception);
5370 return(MagickTrue);
5371 }
5372
5373 /*
5374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5375 % %
5376 % %
5377 % %
5378 + X D r a w I m a g e %
5379 % %
5380 % %
5381 % %
5382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5383 %
5384 % XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on
5385 % the image.
5386 %
5387 % The format of the XDrawEditImage method is:
5388 %
5389 % MagickBooleanType XDrawEditImage(Display *display,
5390 % XResourceInfo *resource_info,XWindows *windows,Image **image,
5391 % ExceptionInfo *exception)
5392 %
5393 % A description of each parameter follows:
5394 %
5395 % o display: Specifies a connection to an X server; returned from
5396 % XOpenDisplay.
5397 %
5398 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
5399 %
5400 % o windows: Specifies a pointer to a XWindows structure.
5401 %
5402 % o image: the image.
5403 %
5404 % o exception: return any errors or warnings in this structure.
5405 %
5406 */
XDrawEditImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image ** image,ExceptionInfo * exception)5407 static MagickBooleanType XDrawEditImage(Display *display,
5408 XResourceInfo *resource_info,XWindows *windows,Image **image,
5409 ExceptionInfo *exception)
5410 {
5411 static const char
5412 *DrawMenu[] =
5413 {
5414 "Element",
5415 "Color",
5416 "Stipple",
5417 "Width",
5418 "Undo",
5419 "Help",
5420 "Dismiss",
5421 (char *) NULL
5422 };
5423
5424 static ElementType
5425 element = PointElement;
5426
5427 static const ModeType
5428 DrawCommands[] =
5429 {
5430 DrawElementCommand,
5431 DrawColorCommand,
5432 DrawStippleCommand,
5433 DrawWidthCommand,
5434 DrawUndoCommand,
5435 DrawHelpCommand,
5436 DrawDismissCommand
5437 };
5438
5439 static Pixmap
5440 stipple = (Pixmap) NULL;
5441
5442 static unsigned int
5443 pen_id = 0,
5444 line_width = 1;
5445
5446 char
5447 command[MagickPathExtent],
5448 text[MagickPathExtent];
5449
5450 Cursor
5451 cursor;
5452
5453 int
5454 entry,
5455 id,
5456 number_coordinates,
5457 x,
5458 y;
5459
5460 double
5461 degrees;
5462
5463 MagickStatusType
5464 status;
5465
5466 RectangleInfo
5467 rectangle_info;
5468
5469 register int
5470 i;
5471
5472 unsigned int
5473 distance,
5474 height,
5475 max_coordinates,
5476 width;
5477
5478 size_t
5479 state;
5480
5481 Window
5482 root_window;
5483
5484 XDrawInfo
5485 draw_info;
5486
5487 XEvent
5488 event;
5489
5490 XPoint
5491 *coordinate_info;
5492
5493 XSegment
5494 line_info;
5495
5496 /*
5497 Allocate polygon info.
5498 */
5499 max_coordinates=2048;
5500 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates,
5501 sizeof(*coordinate_info));
5502 if (coordinate_info == (XPoint *) NULL)
5503 {
5504 (void) ThrowMagickException(exception,GetMagickModule(),
5505 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
5506 return(MagickFalse);
5507 }
5508 /*
5509 Map Command widget.
5510 */
5511 (void) CloneString(&windows->command.name,"Draw");
5512 windows->command.data=4;
5513 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL);
5514 (void) XMapRaised(display,windows->command.id);
5515 XClientMessage(display,windows->image.id,windows->im_protocols,
5516 windows->im_update_widget,CurrentTime);
5517 /*
5518 Wait for first button press.
5519 */
5520 root_window=XRootWindow(display,XDefaultScreen(display));
5521 draw_info.stencil=OpaqueStencil;
5522 status=MagickTrue;
5523 cursor=XCreateFontCursor(display,XC_tcross);
5524 for ( ; ; )
5525 {
5526 XQueryPosition(display,windows->image.id,&x,&y);
5527 (void) XSelectInput(display,windows->image.id,
5528 windows->image.attributes.event_mask | PointerMotionMask);
5529 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5530 state=DefaultState;
5531 do
5532 {
5533 if (windows->info.mapped != MagickFalse )
5534 {
5535 /*
5536 Display pointer position.
5537 */
5538 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ",
5539 x+windows->image.x,y+windows->image.y);
5540 XInfoWidget(display,windows,text);
5541 }
5542 /*
5543 Wait for next event.
5544 */
5545 XScreenEvent(display,windows,&event,exception);
5546 if (event.xany.window == windows->command.id)
5547 {
5548 /*
5549 Select a command from the Command widget.
5550 */
5551 id=XCommandWidget(display,windows,DrawMenu,&event);
5552 if (id < 0)
5553 continue;
5554 switch (DrawCommands[id])
5555 {
5556 case DrawElementCommand:
5557 {
5558 static const char
5559 *Elements[] =
5560 {
5561 "point",
5562 "line",
5563 "rectangle",
5564 "fill rectangle",
5565 "circle",
5566 "fill circle",
5567 "ellipse",
5568 "fill ellipse",
5569 "polygon",
5570 "fill polygon",
5571 (char *) NULL,
5572 };
5573
5574 /*
5575 Select a command from the pop-up menu.
5576 */
5577 element=(ElementType) (XMenuWidget(display,windows,
5578 DrawMenu[id],Elements,command)+1);
5579 break;
5580 }
5581 case DrawColorCommand:
5582 {
5583 const char
5584 *ColorMenu[MaxNumberPens+1];
5585
5586 int
5587 pen_number;
5588
5589 MagickBooleanType
5590 transparent;
5591
5592 XColor
5593 color;
5594
5595 /*
5596 Initialize menu selections.
5597 */
5598 for (i=0; i < (int) (MaxNumberPens-2); i++)
5599 ColorMenu[i]=resource_info->pen_colors[i];
5600 ColorMenu[MaxNumberPens-2]="transparent";
5601 ColorMenu[MaxNumberPens-1]="Browser...";
5602 ColorMenu[MaxNumberPens]=(char *) NULL;
5603 /*
5604 Select a pen color from the pop-up menu.
5605 */
5606 pen_number=XMenuWidget(display,windows,DrawMenu[id],
5607 (const char **) ColorMenu,command);
5608 if (pen_number < 0)
5609 break;
5610 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue :
5611 MagickFalse;
5612 if (transparent != MagickFalse )
5613 {
5614 draw_info.stencil=TransparentStencil;
5615 break;
5616 }
5617 if (pen_number == (MaxNumberPens-1))
5618 {
5619 static char
5620 color_name[MagickPathExtent] = "gray";
5621
5622 /*
5623 Select a pen color from a dialog.
5624 */
5625 resource_info->pen_colors[pen_number]=color_name;
5626 XColorBrowserWidget(display,windows,"Select",color_name);
5627 if (*color_name == '\0')
5628 break;
5629 }
5630 /*
5631 Set pen color.
5632 */
5633 (void) XParseColor(display,windows->map_info->colormap,
5634 resource_info->pen_colors[pen_number],&color);
5635 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
5636 (unsigned int) MaxColors,&color);
5637 windows->pixel_info->pen_colors[pen_number]=color;
5638 pen_id=(unsigned int) pen_number;
5639 draw_info.stencil=OpaqueStencil;
5640 break;
5641 }
5642 case DrawStippleCommand:
5643 {
5644 Image
5645 *stipple_image;
5646
5647 ImageInfo
5648 *image_info;
5649
5650 int
5651 status;
5652
5653 static char
5654 filename[MagickPathExtent] = "\0";
5655
5656 static const char
5657 *StipplesMenu[] =
5658 {
5659 "Brick",
5660 "Diagonal",
5661 "Scales",
5662 "Vertical",
5663 "Wavy",
5664 "Translucent",
5665 "Opaque",
5666 (char *) NULL,
5667 (char *) NULL,
5668 };
5669
5670 /*
5671 Select a command from the pop-up menu.
5672 */
5673 StipplesMenu[7]="Open...";
5674 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu,
5675 command);
5676 if (entry < 0)
5677 break;
5678 if (stipple != (Pixmap) NULL)
5679 (void) XFreePixmap(display,stipple);
5680 stipple=(Pixmap) NULL;
5681 if (entry != 7)
5682 {
5683 switch (entry)
5684 {
5685 case 0:
5686 {
5687 stipple=XCreateBitmapFromData(display,root_window,
5688 (char *) BricksBitmap,BricksWidth,BricksHeight);
5689 break;
5690 }
5691 case 1:
5692 {
5693 stipple=XCreateBitmapFromData(display,root_window,
5694 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight);
5695 break;
5696 }
5697 case 2:
5698 {
5699 stipple=XCreateBitmapFromData(display,root_window,
5700 (char *) ScalesBitmap,ScalesWidth,ScalesHeight);
5701 break;
5702 }
5703 case 3:
5704 {
5705 stipple=XCreateBitmapFromData(display,root_window,
5706 (char *) VerticalBitmap,VerticalWidth,VerticalHeight);
5707 break;
5708 }
5709 case 4:
5710 {
5711 stipple=XCreateBitmapFromData(display,root_window,
5712 (char *) WavyBitmap,WavyWidth,WavyHeight);
5713 break;
5714 }
5715 case 5:
5716 {
5717 stipple=XCreateBitmapFromData(display,root_window,
5718 (char *) HighlightBitmap,HighlightWidth,
5719 HighlightHeight);
5720 break;
5721 }
5722 case 6:
5723 default:
5724 {
5725 stipple=XCreateBitmapFromData(display,root_window,
5726 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight);
5727 break;
5728 }
5729 }
5730 break;
5731 }
5732 XFileBrowserWidget(display,windows,"Stipple",filename);
5733 if (*filename == '\0')
5734 break;
5735 /*
5736 Read image.
5737 */
5738 XSetCursorState(display,windows,MagickTrue);
5739 XCheckRefreshWindows(display,windows);
5740 image_info=AcquireImageInfo();
5741 (void) CopyMagickString(image_info->filename,filename,
5742 MagickPathExtent);
5743 stipple_image=ReadImage(image_info,exception);
5744 CatchException(exception);
5745 XSetCursorState(display,windows,MagickFalse);
5746 if (stipple_image == (Image *) NULL)
5747 break;
5748 (void) AcquireUniqueFileResource(filename);
5749 (void) FormatLocaleString(stipple_image->filename,MagickPathExtent,
5750 "xbm:%s",filename);
5751 (void) WriteImage(image_info,stipple_image,exception);
5752 stipple_image=DestroyImage(stipple_image);
5753 image_info=DestroyImageInfo(image_info);
5754 status=XReadBitmapFile(display,root_window,filename,&width,
5755 &height,&stipple,&x,&y);
5756 (void) RelinquishUniqueFileResource(filename);
5757 if ((status != BitmapSuccess) != 0)
5758 XNoticeWidget(display,windows,"Unable to read X bitmap image:",
5759 filename);
5760 break;
5761 }
5762 case DrawWidthCommand:
5763 {
5764 static char
5765 width[MagickPathExtent] = "0";
5766
5767 static const char
5768 *WidthsMenu[] =
5769 {
5770 "1",
5771 "2",
5772 "4",
5773 "8",
5774 "16",
5775 "Dialog...",
5776 (char *) NULL,
5777 };
5778
5779 /*
5780 Select a command from the pop-up menu.
5781 */
5782 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu,
5783 command);
5784 if (entry < 0)
5785 break;
5786 if (entry != 5)
5787 {
5788 line_width=(unsigned int) StringToUnsignedLong(
5789 WidthsMenu[entry]);
5790 break;
5791 }
5792 (void) XDialogWidget(display,windows,"Ok","Enter line width:",
5793 width);
5794 if (*width == '\0')
5795 break;
5796 line_width=(unsigned int) StringToUnsignedLong(width);
5797 break;
5798 }
5799 case DrawUndoCommand:
5800 {
5801 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
5802 image,exception);
5803 break;
5804 }
5805 case DrawHelpCommand:
5806 {
5807 XTextViewWidget(display,resource_info,windows,MagickFalse,
5808 "Help Viewer - Image Rotation",ImageDrawHelp);
5809 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5810 break;
5811 }
5812 case DrawDismissCommand:
5813 {
5814 /*
5815 Prematurely exit.
5816 */
5817 state|=EscapeState;
5818 state|=ExitState;
5819 break;
5820 }
5821 default:
5822 break;
5823 }
5824 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5825 continue;
5826 }
5827 switch (event.type)
5828 {
5829 case ButtonPress:
5830 {
5831 if (event.xbutton.button != Button1)
5832 break;
5833 if (event.xbutton.window != windows->image.id)
5834 break;
5835 /*
5836 exit loop.
5837 */
5838 x=event.xbutton.x;
5839 y=event.xbutton.y;
5840 state|=ExitState;
5841 break;
5842 }
5843 case ButtonRelease:
5844 break;
5845 case Expose:
5846 break;
5847 case KeyPress:
5848 {
5849 KeySym
5850 key_symbol;
5851
5852 if (event.xkey.window != windows->image.id)
5853 break;
5854 /*
5855 Respond to a user key press.
5856 */
5857 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
5858 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5859 switch ((int) key_symbol)
5860 {
5861 case XK_Escape:
5862 case XK_F20:
5863 {
5864 /*
5865 Prematurely exit.
5866 */
5867 state|=EscapeState;
5868 state|=ExitState;
5869 break;
5870 }
5871 case XK_F1:
5872 case XK_Help:
5873 {
5874 XTextViewWidget(display,resource_info,windows,MagickFalse,
5875 "Help Viewer - Image Rotation",ImageDrawHelp);
5876 break;
5877 }
5878 default:
5879 {
5880 (void) XBell(display,0);
5881 break;
5882 }
5883 }
5884 break;
5885 }
5886 case MotionNotify:
5887 {
5888 /*
5889 Map and unmap Info widget as text cursor crosses its boundaries.
5890 */
5891 x=event.xmotion.x;
5892 y=event.xmotion.y;
5893 if (windows->info.mapped != MagickFalse )
5894 {
5895 if ((x < (int) (windows->info.x+windows->info.width)) &&
5896 (y < (int) (windows->info.y+windows->info.height)))
5897 (void) XWithdrawWindow(display,windows->info.id,
5898 windows->info.screen);
5899 }
5900 else
5901 if ((x > (int) (windows->info.x+windows->info.width)) ||
5902 (y > (int) (windows->info.y+windows->info.height)))
5903 (void) XMapWindow(display,windows->info.id);
5904 break;
5905 }
5906 }
5907 } while ((state & ExitState) == 0);
5908 (void) XSelectInput(display,windows->image.id,
5909 windows->image.attributes.event_mask);
5910 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
5911 if ((state & EscapeState) != 0)
5912 break;
5913 /*
5914 Draw element as pointer moves until the button is released.
5915 */
5916 distance=0;
5917 degrees=0.0;
5918 line_info.x1=x;
5919 line_info.y1=y;
5920 line_info.x2=x;
5921 line_info.y2=y;
5922 rectangle_info.x=(ssize_t) x;
5923 rectangle_info.y=(ssize_t) y;
5924 rectangle_info.width=0;
5925 rectangle_info.height=0;
5926 number_coordinates=1;
5927 coordinate_info->x=x;
5928 coordinate_info->y=y;
5929 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
5930 state=DefaultState;
5931 do
5932 {
5933 switch (element)
5934 {
5935 case PointElement:
5936 default:
5937 {
5938 if (number_coordinates > 1)
5939 {
5940 (void) XDrawLines(display,windows->image.id,
5941 windows->image.highlight_context,coordinate_info,
5942 number_coordinates,CoordModeOrigin);
5943 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d",
5944 coordinate_info[number_coordinates-1].x,
5945 coordinate_info[number_coordinates-1].y);
5946 XInfoWidget(display,windows,text);
5947 }
5948 break;
5949 }
5950 case LineElement:
5951 {
5952 if (distance > 9)
5953 {
5954 /*
5955 Display angle of the line.
5956 */
5957 degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
5958 line_info.y1),(double) (line_info.x2-line_info.x1)));
5959 (void) FormatLocaleString(text,MagickPathExtent," %g",
5960 (double) degrees);
5961 XInfoWidget(display,windows,text);
5962 XHighlightLine(display,windows->image.id,
5963 windows->image.highlight_context,&line_info);
5964 }
5965 else
5966 if (windows->info.mapped != MagickFalse )
5967 (void) XWithdrawWindow(display,windows->info.id,
5968 windows->info.screen);
5969 break;
5970 }
5971 case RectangleElement:
5972 case FillRectangleElement:
5973 {
5974 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
5975 {
5976 /*
5977 Display info and draw drawing rectangle.
5978 */
5979 (void) FormatLocaleString(text,MagickPathExtent,
5980 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
5981 (double) rectangle_info.height,(double) rectangle_info.x,
5982 (double) rectangle_info.y);
5983 XInfoWidget(display,windows,text);
5984 XHighlightRectangle(display,windows->image.id,
5985 windows->image.highlight_context,&rectangle_info);
5986 }
5987 else
5988 if (windows->info.mapped != MagickFalse )
5989 (void) XWithdrawWindow(display,windows->info.id,
5990 windows->info.screen);
5991 break;
5992 }
5993 case CircleElement:
5994 case FillCircleElement:
5995 case EllipseElement:
5996 case FillEllipseElement:
5997 {
5998 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
5999 {
6000 /*
6001 Display info and draw drawing rectangle.
6002 */
6003 (void) FormatLocaleString(text,MagickPathExtent,
6004 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
6005 (double) rectangle_info.height,(double) rectangle_info.x,
6006 (double) rectangle_info.y);
6007 XInfoWidget(display,windows,text);
6008 XHighlightEllipse(display,windows->image.id,
6009 windows->image.highlight_context,&rectangle_info);
6010 }
6011 else
6012 if (windows->info.mapped != MagickFalse )
6013 (void) XWithdrawWindow(display,windows->info.id,
6014 windows->info.screen);
6015 break;
6016 }
6017 case PolygonElement:
6018 case FillPolygonElement:
6019 {
6020 if (number_coordinates > 1)
6021 (void) XDrawLines(display,windows->image.id,
6022 windows->image.highlight_context,coordinate_info,
6023 number_coordinates,CoordModeOrigin);
6024 if (distance > 9)
6025 {
6026 /*
6027 Display angle of the line.
6028 */
6029 degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
6030 line_info.y1),(double) (line_info.x2-line_info.x1)));
6031 (void) FormatLocaleString(text,MagickPathExtent," %g",
6032 (double) degrees);
6033 XInfoWidget(display,windows,text);
6034 XHighlightLine(display,windows->image.id,
6035 windows->image.highlight_context,&line_info);
6036 }
6037 else
6038 if (windows->info.mapped != MagickFalse )
6039 (void) XWithdrawWindow(display,windows->info.id,
6040 windows->info.screen);
6041 break;
6042 }
6043 }
6044 /*
6045 Wait for next event.
6046 */
6047 XScreenEvent(display,windows,&event,exception);
6048 switch (element)
6049 {
6050 case PointElement:
6051 default:
6052 {
6053 if (number_coordinates > 1)
6054 (void) XDrawLines(display,windows->image.id,
6055 windows->image.highlight_context,coordinate_info,
6056 number_coordinates,CoordModeOrigin);
6057 break;
6058 }
6059 case LineElement:
6060 {
6061 if (distance > 9)
6062 XHighlightLine(display,windows->image.id,
6063 windows->image.highlight_context,&line_info);
6064 break;
6065 }
6066 case RectangleElement:
6067 case FillRectangleElement:
6068 {
6069 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6070 XHighlightRectangle(display,windows->image.id,
6071 windows->image.highlight_context,&rectangle_info);
6072 break;
6073 }
6074 case CircleElement:
6075 case FillCircleElement:
6076 case EllipseElement:
6077 case FillEllipseElement:
6078 {
6079 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6080 XHighlightEllipse(display,windows->image.id,
6081 windows->image.highlight_context,&rectangle_info);
6082 break;
6083 }
6084 case PolygonElement:
6085 case FillPolygonElement:
6086 {
6087 if (number_coordinates > 1)
6088 (void) XDrawLines(display,windows->image.id,
6089 windows->image.highlight_context,coordinate_info,
6090 number_coordinates,CoordModeOrigin);
6091 if (distance > 9)
6092 XHighlightLine(display,windows->image.id,
6093 windows->image.highlight_context,&line_info);
6094 break;
6095 }
6096 }
6097 switch (event.type)
6098 {
6099 case ButtonPress:
6100 break;
6101 case ButtonRelease:
6102 {
6103 /*
6104 User has committed to element.
6105 */
6106 line_info.x2=event.xbutton.x;
6107 line_info.y2=event.xbutton.y;
6108 rectangle_info.x=(ssize_t) event.xbutton.x;
6109 rectangle_info.y=(ssize_t) event.xbutton.y;
6110 coordinate_info[number_coordinates].x=event.xbutton.x;
6111 coordinate_info[number_coordinates].y=event.xbutton.y;
6112 if (((element != PolygonElement) &&
6113 (element != FillPolygonElement)) || (distance <= 9))
6114 {
6115 state|=ExitState;
6116 break;
6117 }
6118 number_coordinates++;
6119 if (number_coordinates < (int) max_coordinates)
6120 {
6121 line_info.x1=event.xbutton.x;
6122 line_info.y1=event.xbutton.y;
6123 break;
6124 }
6125 max_coordinates<<=1;
6126 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
6127 max_coordinates,sizeof(*coordinate_info));
6128 if (coordinate_info == (XPoint *) NULL)
6129 (void) ThrowMagickException(exception,GetMagickModule(),
6130 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
6131 break;
6132 }
6133 case Expose:
6134 break;
6135 case MotionNotify:
6136 {
6137 if (event.xmotion.window != windows->image.id)
6138 break;
6139 if (element != PointElement)
6140 {
6141 line_info.x2=event.xmotion.x;
6142 line_info.y2=event.xmotion.y;
6143 rectangle_info.x=(ssize_t) event.xmotion.x;
6144 rectangle_info.y=(ssize_t) event.xmotion.y;
6145 break;
6146 }
6147 coordinate_info[number_coordinates].x=event.xbutton.x;
6148 coordinate_info[number_coordinates].y=event.xbutton.y;
6149 number_coordinates++;
6150 if (number_coordinates < (int) max_coordinates)
6151 break;
6152 max_coordinates<<=1;
6153 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
6154 max_coordinates,sizeof(*coordinate_info));
6155 if (coordinate_info == (XPoint *) NULL)
6156 (void) ThrowMagickException(exception,GetMagickModule(),
6157 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
6158 break;
6159 }
6160 default:
6161 break;
6162 }
6163 /*
6164 Check boundary conditions.
6165 */
6166 if (line_info.x2 < 0)
6167 line_info.x2=0;
6168 else
6169 if (line_info.x2 > (int) windows->image.width)
6170 line_info.x2=(short) windows->image.width;
6171 if (line_info.y2 < 0)
6172 line_info.y2=0;
6173 else
6174 if (line_info.y2 > (int) windows->image.height)
6175 line_info.y2=(short) windows->image.height;
6176 distance=(unsigned int)
6177 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+
6178 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1)));
6179 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) ||
6180 ((state & ExitState) != 0))
6181 {
6182 if (rectangle_info.x < 0)
6183 rectangle_info.x=0;
6184 else
6185 if (rectangle_info.x > (ssize_t) windows->image.width)
6186 rectangle_info.x=(ssize_t) windows->image.width;
6187 if ((int) rectangle_info.x < x)
6188 rectangle_info.width=(unsigned int) (x-rectangle_info.x);
6189 else
6190 {
6191 rectangle_info.width=(unsigned int) (rectangle_info.x-x);
6192 rectangle_info.x=(ssize_t) x;
6193 }
6194 if (rectangle_info.y < 0)
6195 rectangle_info.y=0;
6196 else
6197 if (rectangle_info.y > (ssize_t) windows->image.height)
6198 rectangle_info.y=(ssize_t) windows->image.height;
6199 if ((int) rectangle_info.y < y)
6200 rectangle_info.height=(unsigned int) (y-rectangle_info.y);
6201 else
6202 {
6203 rectangle_info.height=(unsigned int) (rectangle_info.y-y);
6204 rectangle_info.y=(ssize_t) y;
6205 }
6206 }
6207 } while ((state & ExitState) == 0);
6208 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
6209 if ((element == PointElement) || (element == PolygonElement) ||
6210 (element == FillPolygonElement))
6211 {
6212 /*
6213 Determine polygon bounding box.
6214 */
6215 rectangle_info.x=(ssize_t) coordinate_info->x;
6216 rectangle_info.y=(ssize_t) coordinate_info->y;
6217 x=coordinate_info->x;
6218 y=coordinate_info->y;
6219 for (i=1; i < number_coordinates; i++)
6220 {
6221 if (coordinate_info[i].x > x)
6222 x=coordinate_info[i].x;
6223 if (coordinate_info[i].y > y)
6224 y=coordinate_info[i].y;
6225 if ((ssize_t) coordinate_info[i].x < rectangle_info.x)
6226 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0);
6227 if ((ssize_t) coordinate_info[i].y < rectangle_info.y)
6228 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0);
6229 }
6230 rectangle_info.width=(size_t) (x-rectangle_info.x);
6231 rectangle_info.height=(size_t) (y-rectangle_info.y);
6232 for (i=0; i < number_coordinates; i++)
6233 {
6234 coordinate_info[i].x-=rectangle_info.x;
6235 coordinate_info[i].y-=rectangle_info.y;
6236 }
6237 }
6238 else
6239 if (distance <= 9)
6240 continue;
6241 else
6242 if ((element == RectangleElement) ||
6243 (element == CircleElement) || (element == EllipseElement))
6244 {
6245 rectangle_info.width--;
6246 rectangle_info.height--;
6247 }
6248 /*
6249 Drawing is relative to image configuration.
6250 */
6251 draw_info.x=(int) rectangle_info.x;
6252 draw_info.y=(int) rectangle_info.y;
6253 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand,
6254 image,exception);
6255 width=(unsigned int) (*image)->columns;
6256 height=(unsigned int) (*image)->rows;
6257 x=0;
6258 y=0;
6259 if (windows->image.crop_geometry != (char *) NULL)
6260 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
6261 draw_info.x+=windows->image.x-(line_width/2);
6262 if (draw_info.x < 0)
6263 draw_info.x=0;
6264 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width);
6265 draw_info.y+=windows->image.y-(line_width/2);
6266 if (draw_info.y < 0)
6267 draw_info.y=0;
6268 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height;
6269 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1);
6270 if (draw_info.width > (unsigned int) (*image)->columns)
6271 draw_info.width=(unsigned int) (*image)->columns;
6272 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1);
6273 if (draw_info.height > (unsigned int) (*image)->rows)
6274 draw_info.height=(unsigned int) (*image)->rows;
6275 (void) FormatLocaleString(draw_info.geometry,MagickPathExtent,"%ux%u%+d%+d",
6276 width*draw_info.width/windows->image.ximage->width,
6277 height*draw_info.height/windows->image.ximage->height,
6278 draw_info.x+x,draw_info.y+y);
6279 /*
6280 Initialize drawing attributes.
6281 */
6282 draw_info.degrees=0.0;
6283 draw_info.element=element;
6284 draw_info.stipple=stipple;
6285 draw_info.line_width=line_width;
6286 draw_info.line_info=line_info;
6287 if (line_info.x1 > (int) (line_width/2))
6288 draw_info.line_info.x1=(short) line_width/2;
6289 if (line_info.y1 > (int) (line_width/2))
6290 draw_info.line_info.y1=(short) line_width/2;
6291 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2));
6292 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2));
6293 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0))
6294 {
6295 draw_info.line_info.x2=(-draw_info.line_info.x2);
6296 draw_info.line_info.y2=(-draw_info.line_info.y2);
6297 }
6298 if (draw_info.line_info.x2 < 0)
6299 {
6300 draw_info.line_info.x2=(-draw_info.line_info.x2);
6301 Swap(draw_info.line_info.x1,draw_info.line_info.x2);
6302 }
6303 if (draw_info.line_info.y2 < 0)
6304 {
6305 draw_info.line_info.y2=(-draw_info.line_info.y2);
6306 Swap(draw_info.line_info.y1,draw_info.line_info.y2);
6307 }
6308 draw_info.rectangle_info=rectangle_info;
6309 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2))
6310 draw_info.rectangle_info.x=(ssize_t) line_width/2;
6311 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2))
6312 draw_info.rectangle_info.y=(ssize_t) line_width/2;
6313 draw_info.number_coordinates=(unsigned int) number_coordinates;
6314 draw_info.coordinate_info=coordinate_info;
6315 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
6316 /*
6317 Draw element on image.
6318 */
6319 XSetCursorState(display,windows,MagickTrue);
6320 XCheckRefreshWindows(display,windows);
6321 status=XDrawImage(display,windows->pixel_info,&draw_info,*image,exception);
6322 XSetCursorState(display,windows,MagickFalse);
6323 /*
6324 Update image colormap and return to image drawing.
6325 */
6326 XConfigureImageColormap(display,resource_info,windows,*image,exception);
6327 (void) XConfigureImage(display,resource_info,windows,*image,exception);
6328 }
6329 XSetCursorState(display,windows,MagickFalse);
6330 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info);
6331 return(status != 0 ? MagickTrue : MagickFalse);
6332 }
6333
6334 /*
6335 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6336 % %
6337 % %
6338 % %
6339 + X D r a w P a n R e c t a n g l e %
6340 % %
6341 % %
6342 % %
6343 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6344 %
6345 % XDrawPanRectangle() draws a rectangle in the pan window. The pan window
6346 % displays a zoom image and the rectangle shows which portion of the image is
6347 % displayed in the Image window.
6348 %
6349 % The format of the XDrawPanRectangle method is:
6350 %
6351 % XDrawPanRectangle(Display *display,XWindows *windows)
6352 %
6353 % A description of each parameter follows:
6354 %
6355 % o display: Specifies a connection to an X server; returned from
6356 % XOpenDisplay.
6357 %
6358 % o windows: Specifies a pointer to a XWindows structure.
6359 %
6360 */
XDrawPanRectangle(Display * display,XWindows * windows)6361 static void XDrawPanRectangle(Display *display,XWindows *windows)
6362 {
6363 double
6364 scale_factor;
6365
6366 RectangleInfo
6367 highlight_info;
6368
6369 /*
6370 Determine dimensions of the panning rectangle.
6371 */
6372 scale_factor=(double) windows->pan.width/windows->image.ximage->width;
6373 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5);
6374 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5);
6375 scale_factor=(double)
6376 windows->pan.height/windows->image.ximage->height;
6377 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5);
6378 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5);
6379 /*
6380 Display the panning rectangle.
6381 */
6382 (void) XClearWindow(display,windows->pan.id);
6383 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context,
6384 &highlight_info);
6385 }
6386
6387 /*
6388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6389 % %
6390 % %
6391 % %
6392 + X I m a g e C a c h e %
6393 % %
6394 % %
6395 % %
6396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6397 %
6398 % XImageCache() handles the creation, manipulation, and destruction of the
6399 % image cache (undo and redo buffers).
6400 %
6401 % The format of the XImageCache method is:
6402 %
6403 % void XImageCache(Display *display,XResourceInfo *resource_info,
6404 % XWindows *windows,const CommandType command,Image **image,
6405 % ExceptionInfo *exception)
6406 %
6407 % A description of each parameter follows:
6408 %
6409 % o display: Specifies a connection to an X server; returned from
6410 % XOpenDisplay.
6411 %
6412 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6413 %
6414 % o windows: Specifies a pointer to a XWindows structure.
6415 %
6416 % o command: Specifies a command to perform.
6417 %
6418 % o image: the image; XImageCache may transform the image and return a new
6419 % image pointer.
6420 %
6421 % o exception: return any errors or warnings in this structure.
6422 %
6423 */
XImageCache(Display * display,XResourceInfo * resource_info,XWindows * windows,const CommandType command,Image ** image,ExceptionInfo * exception)6424 static void XImageCache(Display *display,XResourceInfo *resource_info,
6425 XWindows *windows,const CommandType command,Image **image,
6426 ExceptionInfo *exception)
6427 {
6428 Image
6429 *cache_image;
6430
6431 static Image
6432 *redo_image = (Image *) NULL,
6433 *undo_image = (Image *) NULL;
6434
6435 switch (command)
6436 {
6437 case FreeBuffersCommand:
6438 {
6439 /*
6440 Free memory from the undo and redo cache.
6441 */
6442 while (undo_image != (Image *) NULL)
6443 {
6444 cache_image=undo_image;
6445 undo_image=GetPreviousImageInList(undo_image);
6446 cache_image->list=DestroyImage(cache_image->list);
6447 cache_image=DestroyImage(cache_image);
6448 }
6449 undo_image=NewImageList();
6450 if (redo_image != (Image *) NULL)
6451 redo_image=DestroyImage(redo_image);
6452 redo_image=NewImageList();
6453 return;
6454 }
6455 case UndoCommand:
6456 {
6457 char
6458 image_geometry[MagickPathExtent];
6459
6460 /*
6461 Undo the last image transformation.
6462 */
6463 if (undo_image == (Image *) NULL)
6464 {
6465 (void) XBell(display,0);
6466 return;
6467 }
6468 cache_image=undo_image;
6469 undo_image=GetPreviousImageInList(undo_image);
6470 windows->image.window_changes.width=(int) cache_image->columns;
6471 windows->image.window_changes.height=(int) cache_image->rows;
6472 (void) FormatLocaleString(image_geometry,MagickPathExtent,"%dx%d!",
6473 windows->image.ximage->width,windows->image.ximage->height);
6474 (void) TransformImage(image,windows->image.crop_geometry,image_geometry,
6475 exception);
6476 if (windows->image.crop_geometry != (char *) NULL)
6477 windows->image.crop_geometry=(char *) RelinquishMagickMemory(
6478 windows->image.crop_geometry);
6479 windows->image.crop_geometry=cache_image->geometry;
6480 if (redo_image != (Image *) NULL)
6481 redo_image=DestroyImage(redo_image);
6482 redo_image=(*image);
6483 *image=cache_image->list;
6484 cache_image=DestroyImage(cache_image);
6485 if (windows->image.orphan != MagickFalse )
6486 return;
6487 XConfigureImageColormap(display,resource_info,windows,*image,exception);
6488 (void) XConfigureImage(display,resource_info,windows,*image,exception);
6489 return;
6490 }
6491 case CutCommand:
6492 case PasteCommand:
6493 case ApplyCommand:
6494 case HalfSizeCommand:
6495 case OriginalSizeCommand:
6496 case DoubleSizeCommand:
6497 case ResizeCommand:
6498 case TrimCommand:
6499 case CropCommand:
6500 case ChopCommand:
6501 case FlipCommand:
6502 case FlopCommand:
6503 case RotateRightCommand:
6504 case RotateLeftCommand:
6505 case RotateCommand:
6506 case ShearCommand:
6507 case RollCommand:
6508 case NegateCommand:
6509 case ContrastStretchCommand:
6510 case SigmoidalContrastCommand:
6511 case NormalizeCommand:
6512 case EqualizeCommand:
6513 case HueCommand:
6514 case SaturationCommand:
6515 case BrightnessCommand:
6516 case GammaCommand:
6517 case SpiffCommand:
6518 case DullCommand:
6519 case GrayscaleCommand:
6520 case MapCommand:
6521 case QuantizeCommand:
6522 case DespeckleCommand:
6523 case EmbossCommand:
6524 case ReduceNoiseCommand:
6525 case AddNoiseCommand:
6526 case SharpenCommand:
6527 case BlurCommand:
6528 case ThresholdCommand:
6529 case EdgeDetectCommand:
6530 case SpreadCommand:
6531 case ShadeCommand:
6532 case RaiseCommand:
6533 case SegmentCommand:
6534 case SolarizeCommand:
6535 case SepiaToneCommand:
6536 case SwirlCommand:
6537 case ImplodeCommand:
6538 case VignetteCommand:
6539 case WaveCommand:
6540 case OilPaintCommand:
6541 case CharcoalDrawCommand:
6542 case AnnotateCommand:
6543 case AddBorderCommand:
6544 case AddFrameCommand:
6545 case CompositeCommand:
6546 case CommentCommand:
6547 case LaunchCommand:
6548 case RegionofInterestCommand:
6549 case SaveToUndoBufferCommand:
6550 case RedoCommand:
6551 {
6552 Image
6553 *previous_image;
6554
6555 ssize_t
6556 bytes;
6557
6558 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelInfo));
6559 if (undo_image != (Image *) NULL)
6560 {
6561 /*
6562 Ensure the undo cache has enough memory available.
6563 */
6564 previous_image=undo_image;
6565 while (previous_image != (Image *) NULL)
6566 {
6567 bytes+=previous_image->list->columns*previous_image->list->rows*
6568 sizeof(PixelInfo);
6569 if (bytes <= (ssize_t) (resource_info->undo_cache << 20))
6570 {
6571 previous_image=GetPreviousImageInList(previous_image);
6572 continue;
6573 }
6574 bytes-=previous_image->list->columns*previous_image->list->rows*
6575 sizeof(PixelInfo);
6576 if (previous_image == undo_image)
6577 undo_image=NewImageList();
6578 else
6579 previous_image->next->previous=NewImageList();
6580 break;
6581 }
6582 while (previous_image != (Image *) NULL)
6583 {
6584 /*
6585 Delete any excess memory from undo cache.
6586 */
6587 cache_image=previous_image;
6588 previous_image=GetPreviousImageInList(previous_image);
6589 cache_image->list=DestroyImage(cache_image->list);
6590 cache_image=DestroyImage(cache_image);
6591 }
6592 }
6593 if (bytes > (ssize_t) (resource_info->undo_cache << 20))
6594 break;
6595 /*
6596 Save image before transformations are applied.
6597 */
6598 cache_image=AcquireImage((ImageInfo *) NULL,exception);
6599 if (cache_image == (Image *) NULL)
6600 break;
6601 XSetCursorState(display,windows,MagickTrue);
6602 XCheckRefreshWindows(display,windows);
6603 cache_image->list=CloneImage(*image,0,0,MagickTrue,exception);
6604 XSetCursorState(display,windows,MagickFalse);
6605 if (cache_image->list == (Image *) NULL)
6606 {
6607 cache_image=DestroyImage(cache_image);
6608 break;
6609 }
6610 cache_image->columns=(size_t) windows->image.ximage->width;
6611 cache_image->rows=(size_t) windows->image.ximage->height;
6612 cache_image->geometry=windows->image.crop_geometry;
6613 if (windows->image.crop_geometry != (char *) NULL)
6614 {
6615 cache_image->geometry=AcquireString((char *) NULL);
6616 (void) CopyMagickString(cache_image->geometry,
6617 windows->image.crop_geometry,MagickPathExtent);
6618 }
6619 if (undo_image == (Image *) NULL)
6620 {
6621 undo_image=cache_image;
6622 break;
6623 }
6624 undo_image->next=cache_image;
6625 undo_image->next->previous=undo_image;
6626 undo_image=undo_image->next;
6627 break;
6628 }
6629 default:
6630 break;
6631 }
6632 if (command == RedoCommand)
6633 {
6634 /*
6635 Redo the last image transformation.
6636 */
6637 if (redo_image == (Image *) NULL)
6638 {
6639 (void) XBell(display,0);
6640 return;
6641 }
6642 windows->image.window_changes.width=(int) redo_image->columns;
6643 windows->image.window_changes.height=(int) redo_image->rows;
6644 if (windows->image.crop_geometry != (char *) NULL)
6645 windows->image.crop_geometry=(char *)
6646 RelinquishMagickMemory(windows->image.crop_geometry);
6647 windows->image.crop_geometry=redo_image->geometry;
6648 *image=DestroyImage(*image);
6649 *image=redo_image;
6650 redo_image=NewImageList();
6651 if (windows->image.orphan != MagickFalse )
6652 return;
6653 XConfigureImageColormap(display,resource_info,windows,*image,exception);
6654 (void) XConfigureImage(display,resource_info,windows,*image,exception);
6655 return;
6656 }
6657 if (command != InfoCommand)
6658 return;
6659 /*
6660 Display image info.
6661 */
6662 XSetCursorState(display,windows,MagickTrue);
6663 XCheckRefreshWindows(display,windows);
6664 XDisplayImageInfo(display,resource_info,windows,undo_image,*image,exception);
6665 XSetCursorState(display,windows,MagickFalse);
6666 }
6667
6668 /*
6669 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6670 % %
6671 % %
6672 % %
6673 + X I m a g e W i n d o w C o m m a n d %
6674 % %
6675 % %
6676 % %
6677 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6678 %
6679 % XImageWindowCommand() makes a transform to the image or Image window as
6680 % specified by a user menu button or keyboard command.
6681 %
6682 % The format of the XImageWindowCommand method is:
6683 %
6684 % CommandType XImageWindowCommand(Display *display,
6685 % XResourceInfo *resource_info,XWindows *windows,
6686 % const MagickStatusType state,KeySym key_symbol,Image **image,
6687 % ExceptionInfo *exception)
6688 %
6689 % A description of each parameter follows:
6690 %
6691 % o nexus: Method XImageWindowCommand returns an image when the
6692 % user chooses 'Open Image' from the command menu. Otherwise a null
6693 % image is returned.
6694 %
6695 % o display: Specifies a connection to an X server; returned from
6696 % XOpenDisplay.
6697 %
6698 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6699 %
6700 % o windows: Specifies a pointer to a XWindows structure.
6701 %
6702 % o state: key mask.
6703 %
6704 % o key_symbol: Specifies a command to perform.
6705 %
6706 % o image: the image; XImageWIndowCommand may transform the image and
6707 % return a new image pointer.
6708 %
6709 % o exception: return any errors or warnings in this structure.
6710 %
6711 */
XImageWindowCommand(Display * display,XResourceInfo * resource_info,XWindows * windows,const MagickStatusType state,KeySym key_symbol,Image ** image,ExceptionInfo * exception)6712 static CommandType XImageWindowCommand(Display *display,
6713 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state,
6714 KeySym key_symbol,Image **image,ExceptionInfo *exception)
6715 {
6716 static char
6717 delta[MagickPathExtent] = "";
6718
6719 static const char
6720 Digits[] = "01234567890";
6721
6722 static KeySym
6723 last_symbol = XK_0;
6724
6725 if ((key_symbol >= XK_0) && (key_symbol <= XK_9))
6726 {
6727 if (((last_symbol < XK_0) || (last_symbol > XK_9)))
6728 {
6729 *delta='\0';
6730 resource_info->quantum=1;
6731 }
6732 last_symbol=key_symbol;
6733 delta[strlen(delta)+1]='\0';
6734 delta[strlen(delta)]=Digits[key_symbol-XK_0];
6735 resource_info->quantum=StringToLong(delta);
6736 return(NullCommand);
6737 }
6738 last_symbol=key_symbol;
6739 if (resource_info->immutable)
6740 {
6741 /*
6742 Virtual image window has a restricted command set.
6743 */
6744 switch (key_symbol)
6745 {
6746 case XK_question:
6747 return(InfoCommand);
6748 case XK_p:
6749 case XK_Print:
6750 return(PrintCommand);
6751 case XK_space:
6752 return(NextCommand);
6753 case XK_q:
6754 case XK_Escape:
6755 return(QuitCommand);
6756 default:
6757 break;
6758 }
6759 return(NullCommand);
6760 }
6761 switch ((int) key_symbol)
6762 {
6763 case XK_o:
6764 {
6765 if ((state & ControlMask) == 0)
6766 break;
6767 return(OpenCommand);
6768 }
6769 case XK_space:
6770 return(NextCommand);
6771 case XK_BackSpace:
6772 return(FormerCommand);
6773 case XK_s:
6774 {
6775 if ((state & Mod1Mask) != 0)
6776 return(SwirlCommand);
6777 if ((state & ControlMask) == 0)
6778 return(ShearCommand);
6779 return(SaveCommand);
6780 }
6781 case XK_p:
6782 case XK_Print:
6783 {
6784 if ((state & Mod1Mask) != 0)
6785 return(OilPaintCommand);
6786 if ((state & Mod4Mask) != 0)
6787 return(ColorCommand);
6788 if ((state & ControlMask) == 0)
6789 return(NullCommand);
6790 return(PrintCommand);
6791 }
6792 case XK_d:
6793 {
6794 if ((state & Mod4Mask) != 0)
6795 return(DrawCommand);
6796 if ((state & ControlMask) == 0)
6797 return(NullCommand);
6798 return(DeleteCommand);
6799 }
6800 case XK_Select:
6801 {
6802 if ((state & ControlMask) == 0)
6803 return(NullCommand);
6804 return(SelectCommand);
6805 }
6806 case XK_n:
6807 {
6808 if ((state & ControlMask) == 0)
6809 return(NullCommand);
6810 return(NewCommand);
6811 }
6812 case XK_q:
6813 case XK_Escape:
6814 return(QuitCommand);
6815 case XK_z:
6816 case XK_Undo:
6817 {
6818 if ((state & ControlMask) == 0)
6819 return(NullCommand);
6820 return(UndoCommand);
6821 }
6822 case XK_r:
6823 case XK_Redo:
6824 {
6825 if ((state & ControlMask) == 0)
6826 return(RollCommand);
6827 return(RedoCommand);
6828 }
6829 case XK_x:
6830 {
6831 if ((state & ControlMask) == 0)
6832 return(NullCommand);
6833 return(CutCommand);
6834 }
6835 case XK_c:
6836 {
6837 if ((state & Mod1Mask) != 0)
6838 return(CharcoalDrawCommand);
6839 if ((state & ControlMask) == 0)
6840 return(CropCommand);
6841 return(CopyCommand);
6842 }
6843 case XK_v:
6844 case XK_Insert:
6845 {
6846 if ((state & Mod4Mask) != 0)
6847 return(CompositeCommand);
6848 if ((state & ControlMask) == 0)
6849 return(FlipCommand);
6850 return(PasteCommand);
6851 }
6852 case XK_less:
6853 return(HalfSizeCommand);
6854 case XK_minus:
6855 return(OriginalSizeCommand);
6856 case XK_greater:
6857 return(DoubleSizeCommand);
6858 case XK_percent:
6859 return(ResizeCommand);
6860 case XK_at:
6861 return(RefreshCommand);
6862 case XK_bracketleft:
6863 return(ChopCommand);
6864 case XK_h:
6865 return(FlopCommand);
6866 case XK_slash:
6867 return(RotateRightCommand);
6868 case XK_backslash:
6869 return(RotateLeftCommand);
6870 case XK_asterisk:
6871 return(RotateCommand);
6872 case XK_t:
6873 return(TrimCommand);
6874 case XK_H:
6875 return(HueCommand);
6876 case XK_S:
6877 return(SaturationCommand);
6878 case XK_L:
6879 return(BrightnessCommand);
6880 case XK_G:
6881 return(GammaCommand);
6882 case XK_C:
6883 return(SpiffCommand);
6884 case XK_Z:
6885 return(DullCommand);
6886 case XK_N:
6887 return(NormalizeCommand);
6888 case XK_equal:
6889 return(EqualizeCommand);
6890 case XK_asciitilde:
6891 return(NegateCommand);
6892 case XK_period:
6893 return(GrayscaleCommand);
6894 case XK_numbersign:
6895 return(QuantizeCommand);
6896 case XK_F2:
6897 return(DespeckleCommand);
6898 case XK_F3:
6899 return(EmbossCommand);
6900 case XK_F4:
6901 return(ReduceNoiseCommand);
6902 case XK_F5:
6903 return(AddNoiseCommand);
6904 case XK_F6:
6905 return(SharpenCommand);
6906 case XK_F7:
6907 return(BlurCommand);
6908 case XK_F8:
6909 return(ThresholdCommand);
6910 case XK_F9:
6911 return(EdgeDetectCommand);
6912 case XK_F10:
6913 return(SpreadCommand);
6914 case XK_F11:
6915 return(ShadeCommand);
6916 case XK_F12:
6917 return(RaiseCommand);
6918 case XK_F13:
6919 return(SegmentCommand);
6920 case XK_i:
6921 {
6922 if ((state & Mod1Mask) == 0)
6923 return(NullCommand);
6924 return(ImplodeCommand);
6925 }
6926 case XK_w:
6927 {
6928 if ((state & Mod1Mask) == 0)
6929 return(NullCommand);
6930 return(WaveCommand);
6931 }
6932 case XK_m:
6933 {
6934 if ((state & Mod4Mask) == 0)
6935 return(NullCommand);
6936 return(MatteCommand);
6937 }
6938 case XK_b:
6939 {
6940 if ((state & Mod4Mask) == 0)
6941 return(NullCommand);
6942 return(AddBorderCommand);
6943 }
6944 case XK_f:
6945 {
6946 if ((state & Mod4Mask) == 0)
6947 return(NullCommand);
6948 return(AddFrameCommand);
6949 }
6950 case XK_exclam:
6951 {
6952 if ((state & Mod4Mask) == 0)
6953 return(NullCommand);
6954 return(CommentCommand);
6955 }
6956 case XK_a:
6957 {
6958 if ((state & Mod1Mask) != 0)
6959 return(ApplyCommand);
6960 if ((state & Mod4Mask) != 0)
6961 return(AnnotateCommand);
6962 if ((state & ControlMask) == 0)
6963 return(NullCommand);
6964 return(RegionofInterestCommand);
6965 }
6966 case XK_question:
6967 return(InfoCommand);
6968 case XK_plus:
6969 return(ZoomCommand);
6970 case XK_P:
6971 {
6972 if ((state & ShiftMask) == 0)
6973 return(NullCommand);
6974 return(ShowPreviewCommand);
6975 }
6976 case XK_Execute:
6977 return(LaunchCommand);
6978 case XK_F1:
6979 return(HelpCommand);
6980 case XK_Find:
6981 return(BrowseDocumentationCommand);
6982 case XK_Menu:
6983 {
6984 (void) XMapRaised(display,windows->command.id);
6985 return(NullCommand);
6986 }
6987 case XK_Next:
6988 case XK_Prior:
6989 case XK_Home:
6990 case XK_KP_Home:
6991 {
6992 XTranslateImage(display,windows,*image,key_symbol);
6993 return(NullCommand);
6994 }
6995 case XK_Up:
6996 case XK_KP_Up:
6997 case XK_Down:
6998 case XK_KP_Down:
6999 case XK_Left:
7000 case XK_KP_Left:
7001 case XK_Right:
7002 case XK_KP_Right:
7003 {
7004 if ((state & Mod1Mask) != 0)
7005 {
7006 RectangleInfo
7007 crop_info;
7008
7009 /*
7010 Trim one pixel from edge of image.
7011 */
7012 crop_info.x=0;
7013 crop_info.y=0;
7014 crop_info.width=(size_t) windows->image.ximage->width;
7015 crop_info.height=(size_t) windows->image.ximage->height;
7016 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up))
7017 {
7018 if (resource_info->quantum >= (int) crop_info.height)
7019 resource_info->quantum=(int) crop_info.height-1;
7020 crop_info.height-=resource_info->quantum;
7021 }
7022 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down))
7023 {
7024 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y))
7025 resource_info->quantum=(int) (crop_info.height-crop_info.y-1);
7026 crop_info.y+=resource_info->quantum;
7027 crop_info.height-=resource_info->quantum;
7028 }
7029 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left))
7030 {
7031 if (resource_info->quantum >= (int) crop_info.width)
7032 resource_info->quantum=(int) crop_info.width-1;
7033 crop_info.width-=resource_info->quantum;
7034 }
7035 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right))
7036 {
7037 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x))
7038 resource_info->quantum=(int) (crop_info.width-crop_info.x-1);
7039 crop_info.x+=resource_info->quantum;
7040 crop_info.width-=resource_info->quantum;
7041 }
7042 if ((int) (windows->image.x+windows->image.width) >
7043 (int) crop_info.width)
7044 windows->image.x=(int) (crop_info.width-windows->image.width);
7045 if ((int) (windows->image.y+windows->image.height) >
7046 (int) crop_info.height)
7047 windows->image.y=(int) (crop_info.height-windows->image.height);
7048 XSetCropGeometry(display,windows,&crop_info,*image);
7049 windows->image.window_changes.width=(int) crop_info.width;
7050 windows->image.window_changes.height=(int) crop_info.height;
7051 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None);
7052 (void) XConfigureImage(display,resource_info,windows,*image,
7053 exception);
7054 return(NullCommand);
7055 }
7056 XTranslateImage(display,windows,*image,key_symbol);
7057 return(NullCommand);
7058 }
7059 default:
7060 return(NullCommand);
7061 }
7062 return(NullCommand);
7063 }
7064
7065 /*
7066 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7067 % %
7068 % %
7069 % %
7070 + X M a g i c k C o m m a n d %
7071 % %
7072 % %
7073 % %
7074 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7075 %
7076 % XMagickCommand() makes a transform to the image or Image window as
7077 % specified by a user menu button or keyboard command.
7078 %
7079 % The format of the XMagickCommand method is:
7080 %
7081 % Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
7082 % XWindows *windows,const CommandType command,Image **image,
7083 % ExceptionInfo *exception)
7084 %
7085 % A description of each parameter follows:
7086 %
7087 % o display: Specifies a connection to an X server; returned from
7088 % XOpenDisplay.
7089 %
7090 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
7091 %
7092 % o windows: Specifies a pointer to a XWindows structure.
7093 %
7094 % o command: Specifies a command to perform.
7095 %
7096 % o image: the image; XMagickCommand may transform the image and return a
7097 % new image pointer.
7098 %
7099 % o exception: return any errors or warnings in this structure.
7100 %
7101 */
XMagickCommand(Display * display,XResourceInfo * resource_info,XWindows * windows,const CommandType command,Image ** image,ExceptionInfo * exception)7102 static Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
7103 XWindows *windows,const CommandType command,Image **image,
7104 ExceptionInfo *exception)
7105 {
7106 char
7107 filename[MagickPathExtent],
7108 geometry[MagickPathExtent],
7109 modulate_factors[MagickPathExtent];
7110
7111 GeometryInfo
7112 geometry_info;
7113
7114 Image
7115 *nexus;
7116
7117 ImageInfo
7118 *image_info;
7119
7120 int
7121 x,
7122 y;
7123
7124 MagickStatusType
7125 flags,
7126 status;
7127
7128 QuantizeInfo
7129 quantize_info;
7130
7131 RectangleInfo
7132 page_geometry;
7133
7134 register int
7135 i;
7136
7137 static char
7138 color[MagickPathExtent] = "gray";
7139
7140 unsigned int
7141 height,
7142 width;
7143
7144 /*
7145 Process user command.
7146 */
7147 XCheckRefreshWindows(display,windows);
7148 XImageCache(display,resource_info,windows,command,image,exception);
7149 nexus=NewImageList();
7150 windows->image.window_changes.width=windows->image.ximage->width;
7151 windows->image.window_changes.height=windows->image.ximage->height;
7152 image_info=CloneImageInfo(resource_info->image_info);
7153 SetGeometryInfo(&geometry_info);
7154 GetQuantizeInfo(&quantize_info);
7155 switch (command)
7156 {
7157 case OpenCommand:
7158 {
7159 /*
7160 Load image.
7161 */
7162 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
7163 break;
7164 }
7165 case NextCommand:
7166 {
7167 /*
7168 Display next image.
7169 */
7170 for (i=0; i < resource_info->quantum; i++)
7171 XClientMessage(display,windows->image.id,windows->im_protocols,
7172 windows->im_next_image,CurrentTime);
7173 break;
7174 }
7175 case FormerCommand:
7176 {
7177 /*
7178 Display former image.
7179 */
7180 for (i=0; i < resource_info->quantum; i++)
7181 XClientMessage(display,windows->image.id,windows->im_protocols,
7182 windows->im_former_image,CurrentTime);
7183 break;
7184 }
7185 case SelectCommand:
7186 {
7187 int
7188 status;
7189
7190 /*
7191 Select image.
7192 */
7193 if (*resource_info->home_directory == '\0')
7194 (void) CopyMagickString(resource_info->home_directory,".",
7195 MagickPathExtent);
7196 status=chdir(resource_info->home_directory);
7197 if (status == -1)
7198 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
7199 "UnableToOpenFile","%s",resource_info->home_directory);
7200 nexus=XOpenImage(display,resource_info,windows,MagickTrue);
7201 break;
7202 }
7203 case SaveCommand:
7204 {
7205 /*
7206 Save image.
7207 */
7208 status=XSaveImage(display,resource_info,windows,*image,exception);
7209 if (status == MagickFalse)
7210 {
7211 char
7212 message[MagickPathExtent];
7213
7214 (void) FormatLocaleString(message,MagickPathExtent,"%s:%s",
7215 exception->reason != (char *) NULL ? exception->reason : "",
7216 exception->description != (char *) NULL ? exception->description :
7217 "");
7218 XNoticeWidget(display,windows,"Unable to save file:",message);
7219 break;
7220 }
7221 break;
7222 }
7223 case PrintCommand:
7224 {
7225 /*
7226 Print image.
7227 */
7228 status=XPrintImage(display,resource_info,windows,*image,exception);
7229 if (status == MagickFalse)
7230 {
7231 char
7232 message[MagickPathExtent];
7233
7234 (void) FormatLocaleString(message,MagickPathExtent,"%s:%s",
7235 exception->reason != (char *) NULL ? exception->reason : "",
7236 exception->description != (char *) NULL ? exception->description :
7237 "");
7238 XNoticeWidget(display,windows,"Unable to print file:",message);
7239 break;
7240 }
7241 break;
7242 }
7243 case DeleteCommand:
7244 {
7245 static char
7246 filename[MagickPathExtent] = "\0";
7247
7248 /*
7249 Delete image file.
7250 */
7251 XFileBrowserWidget(display,windows,"Delete",filename);
7252 if (*filename == '\0')
7253 break;
7254 status=ShredFile(filename);
7255 if (status != MagickFalse )
7256 XNoticeWidget(display,windows,"Unable to delete image file:",filename);
7257 break;
7258 }
7259 case NewCommand:
7260 {
7261 int
7262 status;
7263
7264 static char
7265 color[MagickPathExtent] = "gray",
7266 geometry[MagickPathExtent] = "640x480";
7267
7268 static const char
7269 *format = "gradient";
7270
7271 /*
7272 Query user for canvas geometry.
7273 */
7274 status=XDialogWidget(display,windows,"New","Enter image geometry:",
7275 geometry);
7276 if (*geometry == '\0')
7277 break;
7278 if (status == 0)
7279 format="xc";
7280 XColorBrowserWidget(display,windows,"Select",color);
7281 if (*color == '\0')
7282 break;
7283 /*
7284 Create canvas.
7285 */
7286 (void) FormatLocaleString(image_info->filename,MagickPathExtent,
7287 "%s:%s",format,color);
7288 (void) CloneString(&image_info->size,geometry);
7289 nexus=ReadImage(image_info,exception);
7290 CatchException(exception);
7291 XClientMessage(display,windows->image.id,windows->im_protocols,
7292 windows->im_next_image,CurrentTime);
7293 break;
7294 }
7295 case VisualDirectoryCommand:
7296 {
7297 /*
7298 Visual Image directory.
7299 */
7300 nexus=XVisualDirectoryImage(display,resource_info,windows,exception);
7301 break;
7302 }
7303 case QuitCommand:
7304 {
7305 /*
7306 exit program.
7307 */
7308 if (resource_info->confirm_exit == MagickFalse)
7309 XClientMessage(display,windows->image.id,windows->im_protocols,
7310 windows->im_exit,CurrentTime);
7311 else
7312 {
7313 int
7314 status;
7315
7316 /*
7317 Confirm program exit.
7318 */
7319 status=XConfirmWidget(display,windows,"Do you really want to exit",
7320 resource_info->client_name);
7321 if (status > 0)
7322 XClientMessage(display,windows->image.id,windows->im_protocols,
7323 windows->im_exit,CurrentTime);
7324 }
7325 break;
7326 }
7327 case CutCommand:
7328 {
7329 /*
7330 Cut image.
7331 */
7332 (void) XCropImage(display,resource_info,windows,*image,CutMode,exception);
7333 break;
7334 }
7335 case CopyCommand:
7336 {
7337 /*
7338 Copy image.
7339 */
7340 (void) XCropImage(display,resource_info,windows,*image,CopyMode,
7341 exception);
7342 break;
7343 }
7344 case PasteCommand:
7345 {
7346 /*
7347 Paste image.
7348 */
7349 status=XPasteImage(display,resource_info,windows,*image,exception);
7350 if (status == MagickFalse)
7351 {
7352 XNoticeWidget(display,windows,"Unable to paste X image",
7353 (*image)->filename);
7354 break;
7355 }
7356 break;
7357 }
7358 case HalfSizeCommand:
7359 {
7360 /*
7361 Half image size.
7362 */
7363 windows->image.window_changes.width=windows->image.ximage->width/2;
7364 windows->image.window_changes.height=windows->image.ximage->height/2;
7365 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7366 break;
7367 }
7368 case OriginalSizeCommand:
7369 {
7370 /*
7371 Original image size.
7372 */
7373 windows->image.window_changes.width=(int) (*image)->columns;
7374 windows->image.window_changes.height=(int) (*image)->rows;
7375 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7376 break;
7377 }
7378 case DoubleSizeCommand:
7379 {
7380 /*
7381 Double the image size.
7382 */
7383 windows->image.window_changes.width=windows->image.ximage->width << 1;
7384 windows->image.window_changes.height=windows->image.ximage->height << 1;
7385 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7386 break;
7387 }
7388 case ResizeCommand:
7389 {
7390 int
7391 status;
7392
7393 size_t
7394 height,
7395 width;
7396
7397 ssize_t
7398 x,
7399 y;
7400
7401 /*
7402 Resize image.
7403 */
7404 width=(size_t) windows->image.ximage->width;
7405 height=(size_t) windows->image.ximage->height;
7406 x=0;
7407 y=0;
7408 (void) FormatLocaleString(geometry,MagickPathExtent,"%.20gx%.20g+0+0",
7409 (double) width,(double) height);
7410 status=XDialogWidget(display,windows,"Resize",
7411 "Enter resize geometry (e.g. 640x480, 200%):",geometry);
7412 if (*geometry == '\0')
7413 break;
7414 if (status == 0)
7415 (void) ConcatenateMagickString(geometry,"!",MagickPathExtent);
7416 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
7417 windows->image.window_changes.width=(int) width;
7418 windows->image.window_changes.height=(int) height;
7419 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7420 break;
7421 }
7422 case ApplyCommand:
7423 {
7424 char
7425 image_geometry[MagickPathExtent];
7426
7427 if ((windows->image.crop_geometry == (char *) NULL) &&
7428 ((int) (*image)->columns == windows->image.ximage->width) &&
7429 ((int) (*image)->rows == windows->image.ximage->height))
7430 break;
7431 /*
7432 Apply size transforms to image.
7433 */
7434 XSetCursorState(display,windows,MagickTrue);
7435 XCheckRefreshWindows(display,windows);
7436 /*
7437 Crop and/or scale displayed image.
7438 */
7439 (void) FormatLocaleString(image_geometry,MagickPathExtent,"%dx%d!",
7440 windows->image.ximage->width,windows->image.ximage->height);
7441 (void) TransformImage(image,windows->image.crop_geometry,image_geometry,
7442 exception);
7443 if (windows->image.crop_geometry != (char *) NULL)
7444 windows->image.crop_geometry=(char *) RelinquishMagickMemory(
7445 windows->image.crop_geometry);
7446 windows->image.x=0;
7447 windows->image.y=0;
7448 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7449 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7450 break;
7451 }
7452 case RefreshCommand:
7453 {
7454 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7455 break;
7456 }
7457 case RestoreCommand:
7458 {
7459 /*
7460 Restore Image window to its original size.
7461 */
7462 if ((windows->image.width == (unsigned int) (*image)->columns) &&
7463 (windows->image.height == (unsigned int) (*image)->rows) &&
7464 (windows->image.crop_geometry == (char *) NULL))
7465 {
7466 (void) XBell(display,0);
7467 break;
7468 }
7469 windows->image.window_changes.width=(int) (*image)->columns;
7470 windows->image.window_changes.height=(int) (*image)->rows;
7471 if (windows->image.crop_geometry != (char *) NULL)
7472 {
7473 windows->image.crop_geometry=(char *)
7474 RelinquishMagickMemory(windows->image.crop_geometry);
7475 windows->image.crop_geometry=(char *) NULL;
7476 windows->image.x=0;
7477 windows->image.y=0;
7478 }
7479 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7480 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7481 break;
7482 }
7483 case CropCommand:
7484 {
7485 /*
7486 Crop image.
7487 */
7488 (void) XCropImage(display,resource_info,windows,*image,CropMode,
7489 exception);
7490 break;
7491 }
7492 case ChopCommand:
7493 {
7494 /*
7495 Chop image.
7496 */
7497 status=XChopImage(display,resource_info,windows,image,exception);
7498 if (status == MagickFalse)
7499 {
7500 XNoticeWidget(display,windows,"Unable to cut X image",
7501 (*image)->filename);
7502 break;
7503 }
7504 break;
7505 }
7506 case FlopCommand:
7507 {
7508 Image
7509 *flop_image;
7510
7511 /*
7512 Flop image scanlines.
7513 */
7514 XSetCursorState(display,windows,MagickTrue);
7515 XCheckRefreshWindows(display,windows);
7516 flop_image=FlopImage(*image,exception);
7517 if (flop_image != (Image *) NULL)
7518 {
7519 *image=DestroyImage(*image);
7520 *image=flop_image;
7521 }
7522 CatchException(exception);
7523 XSetCursorState(display,windows,MagickFalse);
7524 if (windows->image.crop_geometry != (char *) NULL)
7525 {
7526 /*
7527 Flop crop geometry.
7528 */
7529 width=(unsigned int) (*image)->columns;
7530 height=(unsigned int) (*image)->rows;
7531 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7532 &width,&height);
7533 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent,
7534 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y);
7535 }
7536 if (windows->image.orphan != MagickFalse )
7537 break;
7538 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7539 break;
7540 }
7541 case FlipCommand:
7542 {
7543 Image
7544 *flip_image;
7545
7546 /*
7547 Flip image scanlines.
7548 */
7549 XSetCursorState(display,windows,MagickTrue);
7550 XCheckRefreshWindows(display,windows);
7551 flip_image=FlipImage(*image,exception);
7552 if (flip_image != (Image *) NULL)
7553 {
7554 *image=DestroyImage(*image);
7555 *image=flip_image;
7556 }
7557 CatchException(exception);
7558 XSetCursorState(display,windows,MagickFalse);
7559 if (windows->image.crop_geometry != (char *) NULL)
7560 {
7561 /*
7562 Flip crop geometry.
7563 */
7564 width=(unsigned int) (*image)->columns;
7565 height=(unsigned int) (*image)->rows;
7566 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7567 &width,&height);
7568 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent,
7569 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y);
7570 }
7571 if (windows->image.orphan != MagickFalse )
7572 break;
7573 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7574 break;
7575 }
7576 case RotateRightCommand:
7577 {
7578 /*
7579 Rotate image 90 degrees clockwise.
7580 */
7581 status=XRotateImage(display,resource_info,windows,90.0,image,exception);
7582 if (status == MagickFalse)
7583 {
7584 XNoticeWidget(display,windows,"Unable to rotate X image",
7585 (*image)->filename);
7586 break;
7587 }
7588 break;
7589 }
7590 case RotateLeftCommand:
7591 {
7592 /*
7593 Rotate image 90 degrees counter-clockwise.
7594 */
7595 status=XRotateImage(display,resource_info,windows,-90.0,image,exception);
7596 if (status == MagickFalse)
7597 {
7598 XNoticeWidget(display,windows,"Unable to rotate X image",
7599 (*image)->filename);
7600 break;
7601 }
7602 break;
7603 }
7604 case RotateCommand:
7605 {
7606 /*
7607 Rotate image.
7608 */
7609 status=XRotateImage(display,resource_info,windows,0.0,image,exception);
7610 if (status == MagickFalse)
7611 {
7612 XNoticeWidget(display,windows,"Unable to rotate X image",
7613 (*image)->filename);
7614 break;
7615 }
7616 break;
7617 }
7618 case ShearCommand:
7619 {
7620 Image
7621 *shear_image;
7622
7623 static char
7624 geometry[MagickPathExtent] = "45.0x45.0";
7625
7626 /*
7627 Query user for shear color and geometry.
7628 */
7629 XColorBrowserWidget(display,windows,"Select",color);
7630 if (*color == '\0')
7631 break;
7632 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:",
7633 geometry);
7634 if (*geometry == '\0')
7635 break;
7636 /*
7637 Shear image.
7638 */
7639 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
7640 exception);
7641 XSetCursorState(display,windows,MagickTrue);
7642 XCheckRefreshWindows(display,windows);
7643 (void) QueryColorCompliance(color,AllCompliance,
7644 &(*image)->background_color,exception);
7645 flags=ParseGeometry(geometry,&geometry_info);
7646 if ((flags & SigmaValue) == 0)
7647 geometry_info.sigma=geometry_info.rho;
7648 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma,
7649 exception);
7650 if (shear_image != (Image *) NULL)
7651 {
7652 *image=DestroyImage(*image);
7653 *image=shear_image;
7654 }
7655 CatchException(exception);
7656 XSetCursorState(display,windows,MagickFalse);
7657 if (windows->image.orphan != MagickFalse )
7658 break;
7659 windows->image.window_changes.width=(int) (*image)->columns;
7660 windows->image.window_changes.height=(int) (*image)->rows;
7661 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7662 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7663 break;
7664 }
7665 case RollCommand:
7666 {
7667 Image
7668 *roll_image;
7669
7670 static char
7671 geometry[MagickPathExtent] = "+2+2";
7672
7673 /*
7674 Query user for the roll geometry.
7675 */
7676 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:",
7677 geometry);
7678 if (*geometry == '\0')
7679 break;
7680 /*
7681 Roll image.
7682 */
7683 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
7684 exception);
7685 XSetCursorState(display,windows,MagickTrue);
7686 XCheckRefreshWindows(display,windows);
7687 (void) ParsePageGeometry(*image,geometry,&page_geometry,
7688 exception);
7689 roll_image=RollImage(*image,page_geometry.x,page_geometry.y,
7690 exception);
7691 if (roll_image != (Image *) NULL)
7692 {
7693 *image=DestroyImage(*image);
7694 *image=roll_image;
7695 }
7696 CatchException(exception);
7697 XSetCursorState(display,windows,MagickFalse);
7698 if (windows->image.orphan != MagickFalse )
7699 break;
7700 windows->image.window_changes.width=(int) (*image)->columns;
7701 windows->image.window_changes.height=(int) (*image)->rows;
7702 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7703 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7704 break;
7705 }
7706 case TrimCommand:
7707 {
7708 static char
7709 fuzz[MagickPathExtent];
7710
7711 /*
7712 Query user for the fuzz factor.
7713 */
7714 (void) FormatLocaleString(fuzz,MagickPathExtent,"%g%%",100.0*
7715 (*image)->fuzz/(QuantumRange+1.0));
7716 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz);
7717 if (*fuzz == '\0')
7718 break;
7719 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+1.0);
7720 /*
7721 Trim image.
7722 */
7723 status=XTrimImage(display,resource_info,windows,*image,exception);
7724 if (status == MagickFalse)
7725 {
7726 XNoticeWidget(display,windows,"Unable to trim X image",
7727 (*image)->filename);
7728 break;
7729 }
7730 break;
7731 }
7732 case HueCommand:
7733 {
7734 static char
7735 hue_percent[MagickPathExtent] = "110";
7736
7737 /*
7738 Query user for percent hue change.
7739 */
7740 (void) XDialogWidget(display,windows,"Apply",
7741 "Enter percent change in image hue (0-200):",hue_percent);
7742 if (*hue_percent == '\0')
7743 break;
7744 /*
7745 Vary the image hue.
7746 */
7747 XSetCursorState(display,windows,MagickTrue);
7748 XCheckRefreshWindows(display,windows);
7749 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MagickPathExtent);
7750 (void) ConcatenateMagickString(modulate_factors,hue_percent,
7751 MagickPathExtent);
7752 (void) ModulateImage(*image,modulate_factors,exception);
7753 XSetCursorState(display,windows,MagickFalse);
7754 if (windows->image.orphan != MagickFalse )
7755 break;
7756 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7757 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7758 break;
7759 }
7760 case SaturationCommand:
7761 {
7762 static char
7763 saturation_percent[MagickPathExtent] = "110";
7764
7765 /*
7766 Query user for percent saturation change.
7767 */
7768 (void) XDialogWidget(display,windows,"Apply",
7769 "Enter percent change in color saturation (0-200):",saturation_percent);
7770 if (*saturation_percent == '\0')
7771 break;
7772 /*
7773 Vary color saturation.
7774 */
7775 XSetCursorState(display,windows,MagickTrue);
7776 XCheckRefreshWindows(display,windows);
7777 (void) CopyMagickString(modulate_factors,"100.0/",MagickPathExtent);
7778 (void) ConcatenateMagickString(modulate_factors,saturation_percent,
7779 MagickPathExtent);
7780 (void) ModulateImage(*image,modulate_factors,exception);
7781 XSetCursorState(display,windows,MagickFalse);
7782 if (windows->image.orphan != MagickFalse )
7783 break;
7784 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7785 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7786 break;
7787 }
7788 case BrightnessCommand:
7789 {
7790 static char
7791 brightness_percent[MagickPathExtent] = "110";
7792
7793 /*
7794 Query user for percent brightness change.
7795 */
7796 (void) XDialogWidget(display,windows,"Apply",
7797 "Enter percent change in color brightness (0-200):",brightness_percent);
7798 if (*brightness_percent == '\0')
7799 break;
7800 /*
7801 Vary the color brightness.
7802 */
7803 XSetCursorState(display,windows,MagickTrue);
7804 XCheckRefreshWindows(display,windows);
7805 (void) CopyMagickString(modulate_factors,brightness_percent,
7806 MagickPathExtent);
7807 (void) ModulateImage(*image,modulate_factors,exception);
7808 XSetCursorState(display,windows,MagickFalse);
7809 if (windows->image.orphan != MagickFalse )
7810 break;
7811 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7812 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7813 break;
7814 }
7815 case GammaCommand:
7816 {
7817 static char
7818 factor[MagickPathExtent] = "1.6";
7819
7820 /*
7821 Query user for gamma value.
7822 */
7823 (void) XDialogWidget(display,windows,"Gamma",
7824 "Enter gamma value (e.g. 1.2):",factor);
7825 if (*factor == '\0')
7826 break;
7827 /*
7828 Gamma correct image.
7829 */
7830 XSetCursorState(display,windows,MagickTrue);
7831 XCheckRefreshWindows(display,windows);
7832 (void) GammaImage(*image,strtod(factor,(char **) NULL),exception);
7833 XSetCursorState(display,windows,MagickFalse);
7834 if (windows->image.orphan != MagickFalse )
7835 break;
7836 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7837 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7838 break;
7839 }
7840 case SpiffCommand:
7841 {
7842 /*
7843 Sharpen the image contrast.
7844 */
7845 XSetCursorState(display,windows,MagickTrue);
7846 XCheckRefreshWindows(display,windows);
7847 (void) ContrastImage(*image,MagickTrue,exception);
7848 XSetCursorState(display,windows,MagickFalse);
7849 if (windows->image.orphan != MagickFalse )
7850 break;
7851 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7852 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7853 break;
7854 }
7855 case DullCommand:
7856 {
7857 /*
7858 Dull the image contrast.
7859 */
7860 XSetCursorState(display,windows,MagickTrue);
7861 XCheckRefreshWindows(display,windows);
7862 (void) ContrastImage(*image,MagickFalse,exception);
7863 XSetCursorState(display,windows,MagickFalse);
7864 if (windows->image.orphan != MagickFalse )
7865 break;
7866 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7867 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7868 break;
7869 }
7870 case ContrastStretchCommand:
7871 {
7872 double
7873 black_point,
7874 white_point;
7875
7876 static char
7877 levels[MagickPathExtent] = "1%";
7878
7879 /*
7880 Query user for gamma value.
7881 */
7882 (void) XDialogWidget(display,windows,"Contrast Stretch",
7883 "Enter black and white points:",levels);
7884 if (*levels == '\0')
7885 break;
7886 /*
7887 Contrast stretch image.
7888 */
7889 XSetCursorState(display,windows,MagickTrue);
7890 XCheckRefreshWindows(display,windows);
7891 flags=ParseGeometry(levels,&geometry_info);
7892 black_point=geometry_info.rho;
7893 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point;
7894 if ((flags & PercentValue) != 0)
7895 {
7896 black_point*=(double) (*image)->columns*(*image)->rows/100.0;
7897 white_point*=(double) (*image)->columns*(*image)->rows/100.0;
7898 }
7899 white_point=(double) (*image)->columns*(*image)->rows-white_point;
7900 (void) ContrastStretchImage(*image,black_point,white_point,
7901 exception);
7902 XSetCursorState(display,windows,MagickFalse);
7903 if (windows->image.orphan != MagickFalse )
7904 break;
7905 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7906 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7907 break;
7908 }
7909 case SigmoidalContrastCommand:
7910 {
7911 GeometryInfo
7912 geometry_info;
7913
7914 MagickStatusType
7915 flags;
7916
7917 static char
7918 levels[MagickPathExtent] = "3x50%";
7919
7920 /*
7921 Query user for gamma value.
7922 */
7923 (void) XDialogWidget(display,windows,"Sigmoidal Contrast",
7924 "Enter contrast and midpoint:",levels);
7925 if (*levels == '\0')
7926 break;
7927 /*
7928 Contrast stretch image.
7929 */
7930 XSetCursorState(display,windows,MagickTrue);
7931 XCheckRefreshWindows(display,windows);
7932 flags=ParseGeometry(levels,&geometry_info);
7933 if ((flags & SigmaValue) == 0)
7934 geometry_info.sigma=1.0*QuantumRange/2.0;
7935 if ((flags & PercentValue) != 0)
7936 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0;
7937 (void) SigmoidalContrastImage(*image,MagickTrue,geometry_info.rho,
7938 geometry_info.sigma,exception);
7939 XSetCursorState(display,windows,MagickFalse);
7940 if (windows->image.orphan != MagickFalse )
7941 break;
7942 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7943 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7944 break;
7945 }
7946 case NormalizeCommand:
7947 {
7948 /*
7949 Perform histogram normalization on the image.
7950 */
7951 XSetCursorState(display,windows,MagickTrue);
7952 XCheckRefreshWindows(display,windows);
7953 (void) NormalizeImage(*image,exception);
7954 XSetCursorState(display,windows,MagickFalse);
7955 if (windows->image.orphan != MagickFalse )
7956 break;
7957 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7958 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7959 break;
7960 }
7961 case EqualizeCommand:
7962 {
7963 /*
7964 Perform histogram equalization on the image.
7965 */
7966 XSetCursorState(display,windows,MagickTrue);
7967 XCheckRefreshWindows(display,windows);
7968 (void) EqualizeImage(*image,exception);
7969 XSetCursorState(display,windows,MagickFalse);
7970 if (windows->image.orphan != MagickFalse )
7971 break;
7972 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7973 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7974 break;
7975 }
7976 case NegateCommand:
7977 {
7978 /*
7979 Negate colors in image.
7980 */
7981 XSetCursorState(display,windows,MagickTrue);
7982 XCheckRefreshWindows(display,windows);
7983 (void) NegateImage(*image,MagickFalse,exception);
7984 XSetCursorState(display,windows,MagickFalse);
7985 if (windows->image.orphan != MagickFalse )
7986 break;
7987 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7988 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7989 break;
7990 }
7991 case GrayscaleCommand:
7992 {
7993 /*
7994 Convert image to grayscale.
7995 */
7996 XSetCursorState(display,windows,MagickTrue);
7997 XCheckRefreshWindows(display,windows);
7998 (void) SetImageType(*image,(*image)->alpha_trait == UndefinedPixelTrait ?
7999 GrayscaleType : GrayscaleAlphaType,exception);
8000 XSetCursorState(display,windows,MagickFalse);
8001 if (windows->image.orphan != MagickFalse )
8002 break;
8003 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8004 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8005 break;
8006 }
8007 case MapCommand:
8008 {
8009 Image
8010 *affinity_image;
8011
8012 static char
8013 filename[MagickPathExtent] = "\0";
8014
8015 /*
8016 Request image file name from user.
8017 */
8018 XFileBrowserWidget(display,windows,"Map",filename);
8019 if (*filename == '\0')
8020 break;
8021 /*
8022 Map image.
8023 */
8024 XSetCursorState(display,windows,MagickTrue);
8025 XCheckRefreshWindows(display,windows);
8026 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
8027 affinity_image=ReadImage(image_info,exception);
8028 if (affinity_image != (Image *) NULL)
8029 {
8030 (void) RemapImage(&quantize_info,*image,affinity_image,exception);
8031 affinity_image=DestroyImage(affinity_image);
8032 }
8033 CatchException(exception);
8034 XSetCursorState(display,windows,MagickFalse);
8035 if (windows->image.orphan != MagickFalse )
8036 break;
8037 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8038 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8039 break;
8040 }
8041 case QuantizeCommand:
8042 {
8043 int
8044 status;
8045
8046 static char
8047 colors[MagickPathExtent] = "256";
8048
8049 /*
8050 Query user for maximum number of colors.
8051 */
8052 status=XDialogWidget(display,windows,"Quantize",
8053 "Maximum number of colors:",colors);
8054 if (*colors == '\0')
8055 break;
8056 /*
8057 Color reduce the image.
8058 */
8059 XSetCursorState(display,windows,MagickTrue);
8060 XCheckRefreshWindows(display,windows);
8061 quantize_info.number_colors=StringToUnsignedLong(colors);
8062 quantize_info.dither_method=status != 0 ? RiemersmaDitherMethod :
8063 NoDitherMethod;
8064 (void) QuantizeImage(&quantize_info,*image,exception);
8065 XSetCursorState(display,windows,MagickFalse);
8066 if (windows->image.orphan != MagickFalse )
8067 break;
8068 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8069 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8070 break;
8071 }
8072 case DespeckleCommand:
8073 {
8074 Image
8075 *despeckle_image;
8076
8077 /*
8078 Despeckle image.
8079 */
8080 XSetCursorState(display,windows,MagickTrue);
8081 XCheckRefreshWindows(display,windows);
8082 despeckle_image=DespeckleImage(*image,exception);
8083 if (despeckle_image != (Image *) NULL)
8084 {
8085 *image=DestroyImage(*image);
8086 *image=despeckle_image;
8087 }
8088 CatchException(exception);
8089 XSetCursorState(display,windows,MagickFalse);
8090 if (windows->image.orphan != MagickFalse )
8091 break;
8092 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8093 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8094 break;
8095 }
8096 case EmbossCommand:
8097 {
8098 Image
8099 *emboss_image;
8100
8101 static char
8102 radius[MagickPathExtent] = "0.0x1.0";
8103
8104 /*
8105 Query user for emboss radius.
8106 */
8107 (void) XDialogWidget(display,windows,"Emboss",
8108 "Enter the emboss radius and standard deviation:",radius);
8109 if (*radius == '\0')
8110 break;
8111 /*
8112 Reduce noise in the image.
8113 */
8114 XSetCursorState(display,windows,MagickTrue);
8115 XCheckRefreshWindows(display,windows);
8116 flags=ParseGeometry(radius,&geometry_info);
8117 if ((flags & SigmaValue) == 0)
8118 geometry_info.sigma=1.0;
8119 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma,
8120 exception);
8121 if (emboss_image != (Image *) NULL)
8122 {
8123 *image=DestroyImage(*image);
8124 *image=emboss_image;
8125 }
8126 CatchException(exception);
8127 XSetCursorState(display,windows,MagickFalse);
8128 if (windows->image.orphan != MagickFalse )
8129 break;
8130 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8131 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8132 break;
8133 }
8134 case ReduceNoiseCommand:
8135 {
8136 Image
8137 *noise_image;
8138
8139 static char
8140 radius[MagickPathExtent] = "0";
8141
8142 /*
8143 Query user for noise radius.
8144 */
8145 (void) XDialogWidget(display,windows,"Reduce Noise",
8146 "Enter the noise radius:",radius);
8147 if (*radius == '\0')
8148 break;
8149 /*
8150 Reduce noise in the image.
8151 */
8152 XSetCursorState(display,windows,MagickTrue);
8153 XCheckRefreshWindows(display,windows);
8154 flags=ParseGeometry(radius,&geometry_info);
8155 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t)
8156 geometry_info.rho,(size_t) geometry_info.rho,exception);
8157 if (noise_image != (Image *) NULL)
8158 {
8159 *image=DestroyImage(*image);
8160 *image=noise_image;
8161 }
8162 CatchException(exception);
8163 XSetCursorState(display,windows,MagickFalse);
8164 if (windows->image.orphan != MagickFalse )
8165 break;
8166 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8167 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8168 break;
8169 }
8170 case AddNoiseCommand:
8171 {
8172 char
8173 **noises;
8174
8175 Image
8176 *noise_image;
8177
8178 static char
8179 noise_type[MagickPathExtent] = "Gaussian";
8180
8181 /*
8182 Add noise to the image.
8183 */
8184 noises=GetCommandOptions(MagickNoiseOptions);
8185 if (noises == (char **) NULL)
8186 break;
8187 XListBrowserWidget(display,windows,&windows->widget,
8188 (const char **) noises,"Add Noise",
8189 "Select a type of noise to add to your image:",noise_type);
8190 noises=DestroyStringList(noises);
8191 if (*noise_type == '\0')
8192 break;
8193 XSetCursorState(display,windows,MagickTrue);
8194 XCheckRefreshWindows(display,windows);
8195 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption(
8196 MagickNoiseOptions,MagickFalse,noise_type),1.0,exception);
8197 if (noise_image != (Image *) NULL)
8198 {
8199 *image=DestroyImage(*image);
8200 *image=noise_image;
8201 }
8202 CatchException(exception);
8203 XSetCursorState(display,windows,MagickFalse);
8204 if (windows->image.orphan != MagickFalse )
8205 break;
8206 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8207 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8208 break;
8209 }
8210 case SharpenCommand:
8211 {
8212 Image
8213 *sharp_image;
8214
8215 static char
8216 radius[MagickPathExtent] = "0.0x1.0";
8217
8218 /*
8219 Query user for sharpen radius.
8220 */
8221 (void) XDialogWidget(display,windows,"Sharpen",
8222 "Enter the sharpen radius and standard deviation:",radius);
8223 if (*radius == '\0')
8224 break;
8225 /*
8226 Sharpen image scanlines.
8227 */
8228 XSetCursorState(display,windows,MagickTrue);
8229 XCheckRefreshWindows(display,windows);
8230 flags=ParseGeometry(radius,&geometry_info);
8231 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma,
8232 exception);
8233 if (sharp_image != (Image *) NULL)
8234 {
8235 *image=DestroyImage(*image);
8236 *image=sharp_image;
8237 }
8238 CatchException(exception);
8239 XSetCursorState(display,windows,MagickFalse);
8240 if (windows->image.orphan != MagickFalse )
8241 break;
8242 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8243 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8244 break;
8245 }
8246 case BlurCommand:
8247 {
8248 Image
8249 *blur_image;
8250
8251 static char
8252 radius[MagickPathExtent] = "0.0x1.0";
8253
8254 /*
8255 Query user for blur radius.
8256 */
8257 (void) XDialogWidget(display,windows,"Blur",
8258 "Enter the blur radius and standard deviation:",radius);
8259 if (*radius == '\0')
8260 break;
8261 /*
8262 Blur an image.
8263 */
8264 XSetCursorState(display,windows,MagickTrue);
8265 XCheckRefreshWindows(display,windows);
8266 flags=ParseGeometry(radius,&geometry_info);
8267 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma,
8268 exception);
8269 if (blur_image != (Image *) NULL)
8270 {
8271 *image=DestroyImage(*image);
8272 *image=blur_image;
8273 }
8274 CatchException(exception);
8275 XSetCursorState(display,windows,MagickFalse);
8276 if (windows->image.orphan != MagickFalse )
8277 break;
8278 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8279 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8280 break;
8281 }
8282 case ThresholdCommand:
8283 {
8284 double
8285 threshold;
8286
8287 static char
8288 factor[MagickPathExtent] = "128";
8289
8290 /*
8291 Query user for threshold value.
8292 */
8293 (void) XDialogWidget(display,windows,"Threshold",
8294 "Enter threshold value:",factor);
8295 if (*factor == '\0')
8296 break;
8297 /*
8298 Gamma correct image.
8299 */
8300 XSetCursorState(display,windows,MagickTrue);
8301 XCheckRefreshWindows(display,windows);
8302 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
8303 (void) BilevelImage(*image,threshold,exception);
8304 XSetCursorState(display,windows,MagickFalse);
8305 if (windows->image.orphan != MagickFalse )
8306 break;
8307 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8308 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8309 break;
8310 }
8311 case EdgeDetectCommand:
8312 {
8313 Image
8314 *edge_image;
8315
8316 static char
8317 radius[MagickPathExtent] = "0";
8318
8319 /*
8320 Query user for edge factor.
8321 */
8322 (void) XDialogWidget(display,windows,"Detect Edges",
8323 "Enter the edge detect radius:",radius);
8324 if (*radius == '\0')
8325 break;
8326 /*
8327 Detect edge in image.
8328 */
8329 XSetCursorState(display,windows,MagickTrue);
8330 XCheckRefreshWindows(display,windows);
8331 flags=ParseGeometry(radius,&geometry_info);
8332 edge_image=EdgeImage(*image,geometry_info.rho,exception);
8333 if (edge_image != (Image *) NULL)
8334 {
8335 *image=DestroyImage(*image);
8336 *image=edge_image;
8337 }
8338 CatchException(exception);
8339 XSetCursorState(display,windows,MagickFalse);
8340 if (windows->image.orphan != MagickFalse )
8341 break;
8342 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8343 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8344 break;
8345 }
8346 case SpreadCommand:
8347 {
8348 Image
8349 *spread_image;
8350
8351 static char
8352 amount[MagickPathExtent] = "2";
8353
8354 /*
8355 Query user for spread amount.
8356 */
8357 (void) XDialogWidget(display,windows,"Spread",
8358 "Enter the displacement amount:",amount);
8359 if (*amount == '\0')
8360 break;
8361 /*
8362 Displace image pixels by a random amount.
8363 */
8364 XSetCursorState(display,windows,MagickTrue);
8365 XCheckRefreshWindows(display,windows);
8366 flags=ParseGeometry(amount,&geometry_info);
8367 spread_image=EdgeImage(*image,geometry_info.rho,exception);
8368 if (spread_image != (Image *) NULL)
8369 {
8370 *image=DestroyImage(*image);
8371 *image=spread_image;
8372 }
8373 CatchException(exception);
8374 XSetCursorState(display,windows,MagickFalse);
8375 if (windows->image.orphan != MagickFalse )
8376 break;
8377 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8378 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8379 break;
8380 }
8381 case ShadeCommand:
8382 {
8383 Image
8384 *shade_image;
8385
8386 int
8387 status;
8388
8389 static char
8390 geometry[MagickPathExtent] = "30x30";
8391
8392 /*
8393 Query user for the shade geometry.
8394 */
8395 status=XDialogWidget(display,windows,"Shade",
8396 "Enter the azimuth and elevation of the light source:",geometry);
8397 if (*geometry == '\0')
8398 break;
8399 /*
8400 Shade image pixels.
8401 */
8402 XSetCursorState(display,windows,MagickTrue);
8403 XCheckRefreshWindows(display,windows);
8404 flags=ParseGeometry(geometry,&geometry_info);
8405 if ((flags & SigmaValue) == 0)
8406 geometry_info.sigma=1.0;
8407 shade_image=ShadeImage(*image,status != 0 ? MagickTrue : MagickFalse,
8408 geometry_info.rho,geometry_info.sigma,exception);
8409 if (shade_image != (Image *) NULL)
8410 {
8411 *image=DestroyImage(*image);
8412 *image=shade_image;
8413 }
8414 CatchException(exception);
8415 XSetCursorState(display,windows,MagickFalse);
8416 if (windows->image.orphan != MagickFalse )
8417 break;
8418 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8419 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8420 break;
8421 }
8422 case RaiseCommand:
8423 {
8424 static char
8425 bevel_width[MagickPathExtent] = "10";
8426
8427 /*
8428 Query user for bevel width.
8429 */
8430 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width);
8431 if (*bevel_width == '\0')
8432 break;
8433 /*
8434 Raise an image.
8435 */
8436 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8437 exception);
8438 XSetCursorState(display,windows,MagickTrue);
8439 XCheckRefreshWindows(display,windows);
8440 (void) ParsePageGeometry(*image,bevel_width,&page_geometry,
8441 exception);
8442 (void) RaiseImage(*image,&page_geometry,MagickTrue,exception);
8443 XSetCursorState(display,windows,MagickFalse);
8444 if (windows->image.orphan != MagickFalse )
8445 break;
8446 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8447 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8448 break;
8449 }
8450 case SegmentCommand:
8451 {
8452 static char
8453 threshold[MagickPathExtent] = "1.0x1.5";
8454
8455 /*
8456 Query user for smoothing threshold.
8457 */
8458 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:",
8459 threshold);
8460 if (*threshold == '\0')
8461 break;
8462 /*
8463 Segment an image.
8464 */
8465 XSetCursorState(display,windows,MagickTrue);
8466 XCheckRefreshWindows(display,windows);
8467 flags=ParseGeometry(threshold,&geometry_info);
8468 if ((flags & SigmaValue) == 0)
8469 geometry_info.sigma=1.0;
8470 (void) SegmentImage(*image,sRGBColorspace,MagickFalse,geometry_info.rho,
8471 geometry_info.sigma,exception);
8472 XSetCursorState(display,windows,MagickFalse);
8473 if (windows->image.orphan != MagickFalse )
8474 break;
8475 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8476 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8477 break;
8478 }
8479 case SepiaToneCommand:
8480 {
8481 double
8482 threshold;
8483
8484 Image
8485 *sepia_image;
8486
8487 static char
8488 factor[MagickPathExtent] = "80%";
8489
8490 /*
8491 Query user for sepia-tone factor.
8492 */
8493 (void) XDialogWidget(display,windows,"Sepia Tone",
8494 "Enter the sepia tone factor (0 - 99.9%):",factor);
8495 if (*factor == '\0')
8496 break;
8497 /*
8498 Sepia tone image pixels.
8499 */
8500 XSetCursorState(display,windows,MagickTrue);
8501 XCheckRefreshWindows(display,windows);
8502 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
8503 sepia_image=SepiaToneImage(*image,threshold,exception);
8504 if (sepia_image != (Image *) NULL)
8505 {
8506 *image=DestroyImage(*image);
8507 *image=sepia_image;
8508 }
8509 CatchException(exception);
8510 XSetCursorState(display,windows,MagickFalse);
8511 if (windows->image.orphan != MagickFalse )
8512 break;
8513 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8514 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8515 break;
8516 }
8517 case SolarizeCommand:
8518 {
8519 double
8520 threshold;
8521
8522 static char
8523 factor[MagickPathExtent] = "60%";
8524
8525 /*
8526 Query user for solarize factor.
8527 */
8528 (void) XDialogWidget(display,windows,"Solarize",
8529 "Enter the solarize factor (0 - 99.9%):",factor);
8530 if (*factor == '\0')
8531 break;
8532 /*
8533 Solarize image pixels.
8534 */
8535 XSetCursorState(display,windows,MagickTrue);
8536 XCheckRefreshWindows(display,windows);
8537 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
8538 (void) SolarizeImage(*image,threshold,exception);
8539 XSetCursorState(display,windows,MagickFalse);
8540 if (windows->image.orphan != MagickFalse )
8541 break;
8542 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8543 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8544 break;
8545 }
8546 case SwirlCommand:
8547 {
8548 Image
8549 *swirl_image;
8550
8551 static char
8552 degrees[MagickPathExtent] = "60";
8553
8554 /*
8555 Query user for swirl angle.
8556 */
8557 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:",
8558 degrees);
8559 if (*degrees == '\0')
8560 break;
8561 /*
8562 Swirl image pixels about the center.
8563 */
8564 XSetCursorState(display,windows,MagickTrue);
8565 XCheckRefreshWindows(display,windows);
8566 flags=ParseGeometry(degrees,&geometry_info);
8567 swirl_image=SwirlImage(*image,geometry_info.rho,(*image)->interpolate,
8568 exception);
8569 if (swirl_image != (Image *) NULL)
8570 {
8571 *image=DestroyImage(*image);
8572 *image=swirl_image;
8573 }
8574 CatchException(exception);
8575 XSetCursorState(display,windows,MagickFalse);
8576 if (windows->image.orphan != MagickFalse )
8577 break;
8578 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8579 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8580 break;
8581 }
8582 case ImplodeCommand:
8583 {
8584 Image
8585 *implode_image;
8586
8587 static char
8588 factor[MagickPathExtent] = "0.3";
8589
8590 /*
8591 Query user for implode factor.
8592 */
8593 (void) XDialogWidget(display,windows,"Implode",
8594 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor);
8595 if (*factor == '\0')
8596 break;
8597 /*
8598 Implode image pixels about the center.
8599 */
8600 XSetCursorState(display,windows,MagickTrue);
8601 XCheckRefreshWindows(display,windows);
8602 flags=ParseGeometry(factor,&geometry_info);
8603 implode_image=ImplodeImage(*image,geometry_info.rho,(*image)->interpolate,
8604 exception);
8605 if (implode_image != (Image *) NULL)
8606 {
8607 *image=DestroyImage(*image);
8608 *image=implode_image;
8609 }
8610 CatchException(exception);
8611 XSetCursorState(display,windows,MagickFalse);
8612 if (windows->image.orphan != MagickFalse )
8613 break;
8614 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8615 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8616 break;
8617 }
8618 case VignetteCommand:
8619 {
8620 Image
8621 *vignette_image;
8622
8623 static char
8624 geometry[MagickPathExtent] = "0x20";
8625
8626 /*
8627 Query user for the vignette geometry.
8628 */
8629 (void) XDialogWidget(display,windows,"Vignette",
8630 "Enter the radius, sigma, and x and y offsets:",geometry);
8631 if (*geometry == '\0')
8632 break;
8633 /*
8634 Soften the edges of the image in vignette style
8635 */
8636 XSetCursorState(display,windows,MagickTrue);
8637 XCheckRefreshWindows(display,windows);
8638 flags=ParseGeometry(geometry,&geometry_info);
8639 if ((flags & SigmaValue) == 0)
8640 geometry_info.sigma=1.0;
8641 if ((flags & XiValue) == 0)
8642 geometry_info.xi=0.1*(*image)->columns;
8643 if ((flags & PsiValue) == 0)
8644 geometry_info.psi=0.1*(*image)->rows;
8645 vignette_image=VignetteImage(*image,geometry_info.rho,0.0,(ssize_t)
8646 ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-0.5),
8647 exception);
8648 if (vignette_image != (Image *) NULL)
8649 {
8650 *image=DestroyImage(*image);
8651 *image=vignette_image;
8652 }
8653 CatchException(exception);
8654 XSetCursorState(display,windows,MagickFalse);
8655 if (windows->image.orphan != MagickFalse )
8656 break;
8657 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8658 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8659 break;
8660 }
8661 case WaveCommand:
8662 {
8663 Image
8664 *wave_image;
8665
8666 static char
8667 geometry[MagickPathExtent] = "25x150";
8668
8669 /*
8670 Query user for the wave geometry.
8671 */
8672 (void) XDialogWidget(display,windows,"Wave",
8673 "Enter the amplitude and length of the wave:",geometry);
8674 if (*geometry == '\0')
8675 break;
8676 /*
8677 Alter an image along a sine wave.
8678 */
8679 XSetCursorState(display,windows,MagickTrue);
8680 XCheckRefreshWindows(display,windows);
8681 flags=ParseGeometry(geometry,&geometry_info);
8682 if ((flags & SigmaValue) == 0)
8683 geometry_info.sigma=1.0;
8684 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma,
8685 (*image)->interpolate,exception);
8686 if (wave_image != (Image *) NULL)
8687 {
8688 *image=DestroyImage(*image);
8689 *image=wave_image;
8690 }
8691 CatchException(exception);
8692 XSetCursorState(display,windows,MagickFalse);
8693 if (windows->image.orphan != MagickFalse )
8694 break;
8695 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8696 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8697 break;
8698 }
8699 case OilPaintCommand:
8700 {
8701 Image
8702 *paint_image;
8703
8704 static char
8705 radius[MagickPathExtent] = "0";
8706
8707 /*
8708 Query user for circular neighborhood radius.
8709 */
8710 (void) XDialogWidget(display,windows,"Oil Paint",
8711 "Enter the mask radius:",radius);
8712 if (*radius == '\0')
8713 break;
8714 /*
8715 OilPaint image scanlines.
8716 */
8717 XSetCursorState(display,windows,MagickTrue);
8718 XCheckRefreshWindows(display,windows);
8719 flags=ParseGeometry(radius,&geometry_info);
8720 paint_image=OilPaintImage(*image,geometry_info.rho,geometry_info.sigma,
8721 exception);
8722 if (paint_image != (Image *) NULL)
8723 {
8724 *image=DestroyImage(*image);
8725 *image=paint_image;
8726 }
8727 CatchException(exception);
8728 XSetCursorState(display,windows,MagickFalse);
8729 if (windows->image.orphan != MagickFalse )
8730 break;
8731 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8732 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8733 break;
8734 }
8735 case CharcoalDrawCommand:
8736 {
8737 Image
8738 *charcoal_image;
8739
8740 static char
8741 radius[MagickPathExtent] = "0x1";
8742
8743 /*
8744 Query user for charcoal radius.
8745 */
8746 (void) XDialogWidget(display,windows,"Charcoal Draw",
8747 "Enter the charcoal radius and sigma:",radius);
8748 if (*radius == '\0')
8749 break;
8750 /*
8751 Charcoal the image.
8752 */
8753 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8754 exception);
8755 XSetCursorState(display,windows,MagickTrue);
8756 XCheckRefreshWindows(display,windows);
8757 flags=ParseGeometry(radius,&geometry_info);
8758 if ((flags & SigmaValue) == 0)
8759 geometry_info.sigma=geometry_info.rho;
8760 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma,
8761 exception);
8762 if (charcoal_image != (Image *) NULL)
8763 {
8764 *image=DestroyImage(*image);
8765 *image=charcoal_image;
8766 }
8767 CatchException(exception);
8768 XSetCursorState(display,windows,MagickFalse);
8769 if (windows->image.orphan != MagickFalse )
8770 break;
8771 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8772 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8773 break;
8774 }
8775 case AnnotateCommand:
8776 {
8777 /*
8778 Annotate the image with text.
8779 */
8780 status=XAnnotateEditImage(display,resource_info,windows,*image,exception);
8781 if (status == MagickFalse)
8782 {
8783 XNoticeWidget(display,windows,"Unable to annotate X image",
8784 (*image)->filename);
8785 break;
8786 }
8787 break;
8788 }
8789 case DrawCommand:
8790 {
8791 /*
8792 Draw image.
8793 */
8794 status=XDrawEditImage(display,resource_info,windows,image,exception);
8795 if (status == MagickFalse)
8796 {
8797 XNoticeWidget(display,windows,"Unable to draw on the X image",
8798 (*image)->filename);
8799 break;
8800 }
8801 break;
8802 }
8803 case ColorCommand:
8804 {
8805 /*
8806 Color edit.
8807 */
8808 status=XColorEditImage(display,resource_info,windows,image,exception);
8809 if (status == MagickFalse)
8810 {
8811 XNoticeWidget(display,windows,"Unable to pixel edit X image",
8812 (*image)->filename);
8813 break;
8814 }
8815 break;
8816 }
8817 case MatteCommand:
8818 {
8819 /*
8820 Matte edit.
8821 */
8822 status=XMatteEditImage(display,resource_info,windows,image,exception);
8823 if (status == MagickFalse)
8824 {
8825 XNoticeWidget(display,windows,"Unable to matte edit X image",
8826 (*image)->filename);
8827 break;
8828 }
8829 break;
8830 }
8831 case CompositeCommand:
8832 {
8833 /*
8834 Composite image.
8835 */
8836 status=XCompositeImage(display,resource_info,windows,*image,
8837 exception);
8838 if (status == MagickFalse)
8839 {
8840 XNoticeWidget(display,windows,"Unable to composite X image",
8841 (*image)->filename);
8842 break;
8843 }
8844 break;
8845 }
8846 case AddBorderCommand:
8847 {
8848 Image
8849 *border_image;
8850
8851 static char
8852 geometry[MagickPathExtent] = "6x6";
8853
8854 /*
8855 Query user for border color and geometry.
8856 */
8857 XColorBrowserWidget(display,windows,"Select",color);
8858 if (*color == '\0')
8859 break;
8860 (void) XDialogWidget(display,windows,"Add Border",
8861 "Enter border geometry:",geometry);
8862 if (*geometry == '\0')
8863 break;
8864 /*
8865 Add a border to the image.
8866 */
8867 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8868 exception);
8869 XSetCursorState(display,windows,MagickTrue);
8870 XCheckRefreshWindows(display,windows);
8871 (void) QueryColorCompliance(color,AllCompliance,&(*image)->border_color,
8872 exception);
8873 (void) ParsePageGeometry(*image,geometry,&page_geometry,
8874 exception);
8875 border_image=BorderImage(*image,&page_geometry,(*image)->compose,
8876 exception);
8877 if (border_image != (Image *) NULL)
8878 {
8879 *image=DestroyImage(*image);
8880 *image=border_image;
8881 }
8882 CatchException(exception);
8883 XSetCursorState(display,windows,MagickFalse);
8884 if (windows->image.orphan != MagickFalse )
8885 break;
8886 windows->image.window_changes.width=(int) (*image)->columns;
8887 windows->image.window_changes.height=(int) (*image)->rows;
8888 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8889 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8890 break;
8891 }
8892 case AddFrameCommand:
8893 {
8894 FrameInfo
8895 frame_info;
8896
8897 Image
8898 *frame_image;
8899
8900 static char
8901 geometry[MagickPathExtent] = "6x6";
8902
8903 /*
8904 Query user for frame color and geometry.
8905 */
8906 XColorBrowserWidget(display,windows,"Select",color);
8907 if (*color == '\0')
8908 break;
8909 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:",
8910 geometry);
8911 if (*geometry == '\0')
8912 break;
8913 /*
8914 Surround image with an ornamental border.
8915 */
8916 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8917 exception);
8918 XSetCursorState(display,windows,MagickTrue);
8919 XCheckRefreshWindows(display,windows);
8920 (void) QueryColorCompliance(color,AllCompliance,&(*image)->alpha_color,
8921 exception);
8922 (void) ParsePageGeometry(*image,geometry,&page_geometry,
8923 exception);
8924 frame_info.width=page_geometry.width;
8925 frame_info.height=page_geometry.height;
8926 frame_info.outer_bevel=page_geometry.x;
8927 frame_info.inner_bevel=page_geometry.y;
8928 frame_info.x=(ssize_t) frame_info.width;
8929 frame_info.y=(ssize_t) frame_info.height;
8930 frame_info.width=(*image)->columns+2*frame_info.width;
8931 frame_info.height=(*image)->rows+2*frame_info.height;
8932 frame_image=FrameImage(*image,&frame_info,(*image)->compose,exception);
8933 if (frame_image != (Image *) NULL)
8934 {
8935 *image=DestroyImage(*image);
8936 *image=frame_image;
8937 }
8938 CatchException(exception);
8939 XSetCursorState(display,windows,MagickFalse);
8940 if (windows->image.orphan != MagickFalse )
8941 break;
8942 windows->image.window_changes.width=(int) (*image)->columns;
8943 windows->image.window_changes.height=(int) (*image)->rows;
8944 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8945 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8946 break;
8947 }
8948 case CommentCommand:
8949 {
8950 const char
8951 *value;
8952
8953 FILE
8954 *file;
8955
8956 int
8957 unique_file;
8958
8959 /*
8960 Edit image comment.
8961 */
8962 unique_file=AcquireUniqueFileResource(image_info->filename);
8963 if (unique_file == -1)
8964 XNoticeWidget(display,windows,"Unable to edit image comment",
8965 image_info->filename);
8966 value=GetImageProperty(*image,"comment",exception);
8967 if (value == (char *) NULL)
8968 unique_file=close(unique_file)-1;
8969 else
8970 {
8971 register const char
8972 *p;
8973
8974 file=fdopen(unique_file,"w");
8975 if (file == (FILE *) NULL)
8976 {
8977 XNoticeWidget(display,windows,"Unable to edit image comment",
8978 image_info->filename);
8979 break;
8980 }
8981 for (p=value; *p != '\0'; p++)
8982 (void) fputc((int) *p,file);
8983 (void) fputc('\n',file);
8984 (void) fclose(file);
8985 }
8986 XSetCursorState(display,windows,MagickTrue);
8987 XCheckRefreshWindows(display,windows);
8988 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL,
8989 exception);
8990 if (status == MagickFalse)
8991 XNoticeWidget(display,windows,"Unable to edit image comment",
8992 (char *) NULL);
8993 else
8994 {
8995 char
8996 *comment;
8997
8998 comment=FileToString(image_info->filename,~0UL,exception);
8999 if (comment != (char *) NULL)
9000 {
9001 (void) SetImageProperty(*image,"comment",comment,exception);
9002 (*image)->taint=MagickTrue;
9003 }
9004 }
9005 (void) RelinquishUniqueFileResource(image_info->filename);
9006 XSetCursorState(display,windows,MagickFalse);
9007 break;
9008 }
9009 case LaunchCommand:
9010 {
9011 /*
9012 Launch program.
9013 */
9014 XSetCursorState(display,windows,MagickTrue);
9015 XCheckRefreshWindows(display,windows);
9016 (void) AcquireUniqueFilename(filename);
9017 (void) FormatLocaleString((*image)->filename,MagickPathExtent,"launch:%s",
9018 filename);
9019 status=WriteImage(image_info,*image,exception);
9020 if (status == MagickFalse)
9021 XNoticeWidget(display,windows,"Unable to launch image editor",
9022 (char *) NULL);
9023 else
9024 {
9025 nexus=ReadImage(resource_info->image_info,exception);
9026 CatchException(exception);
9027 XClientMessage(display,windows->image.id,windows->im_protocols,
9028 windows->im_next_image,CurrentTime);
9029 }
9030 (void) RelinquishUniqueFileResource(filename);
9031 XSetCursorState(display,windows,MagickFalse);
9032 break;
9033 }
9034 case RegionofInterestCommand:
9035 {
9036 /*
9037 Apply an image processing technique to a region of interest.
9038 */
9039 (void) XROIImage(display,resource_info,windows,image,exception);
9040 break;
9041 }
9042 case InfoCommand:
9043 break;
9044 case ZoomCommand:
9045 {
9046 /*
9047 Zoom image.
9048 */
9049 if (windows->magnify.mapped != MagickFalse )
9050 (void) XRaiseWindow(display,windows->magnify.id);
9051 else
9052 {
9053 /*
9054 Make magnify image.
9055 */
9056 XSetCursorState(display,windows,MagickTrue);
9057 (void) XMapRaised(display,windows->magnify.id);
9058 XSetCursorState(display,windows,MagickFalse);
9059 }
9060 break;
9061 }
9062 case ShowPreviewCommand:
9063 {
9064 char
9065 **previews,
9066 value[MagickPathExtent];
9067
9068 Image
9069 *preview_image;
9070
9071 PreviewType
9072 preview;
9073
9074 static char
9075 preview_type[MagickPathExtent] = "Gamma";
9076
9077 /*
9078 Select preview type from menu.
9079 */
9080 previews=GetCommandOptions(MagickPreviewOptions);
9081 if (previews == (char **) NULL)
9082 break;
9083 XListBrowserWidget(display,windows,&windows->widget,
9084 (const char **) previews,"Preview",
9085 "Select an enhancement, effect, or F/X:",preview_type);
9086 previews=DestroyStringList(previews);
9087 if (*preview_type == '\0')
9088 break;
9089 /*
9090 Show image preview.
9091 */
9092 XSetCursorState(display,windows,MagickTrue);
9093 XCheckRefreshWindows(display,windows);
9094 preview=(PreviewType) ParseCommandOption(MagickPreviewOptions,
9095 MagickFalse,preview_type);
9096 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
9097 windows->image.id);
9098 (void) SetImageProperty(*image,"group",value,exception);
9099 (void) DeleteImageProperty(*image,"label");
9100 (void) SetImageProperty(*image,"label","Preview",exception);
9101 preview_image=PreviewImage(*image,preview,exception);
9102 if (preview_image == (Image *) NULL)
9103 break;
9104 (void) AcquireUniqueFilename(filename);
9105 (void) FormatLocaleString(preview_image->filename,MagickPathExtent,
9106 "show:%s",filename);
9107 status=WriteImage(image_info,preview_image,exception);
9108 (void) RelinquishUniqueFileResource(filename);
9109 preview_image=DestroyImage(preview_image);
9110 if (status == MagickFalse)
9111 XNoticeWidget(display,windows,"Unable to show image preview",
9112 (*image)->filename);
9113 XDelay(display,1500);
9114 XSetCursorState(display,windows,MagickFalse);
9115 break;
9116 }
9117 case ShowHistogramCommand:
9118 {
9119 char
9120 value[MagickPathExtent];
9121
9122 Image
9123 *histogram_image;
9124
9125 /*
9126 Show image histogram.
9127 */
9128 XSetCursorState(display,windows,MagickTrue);
9129 XCheckRefreshWindows(display,windows);
9130 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
9131 windows->image.id);
9132 (void) SetImageProperty(*image,"group",value,exception);
9133 (void) DeleteImageProperty(*image,"label");
9134 (void) SetImageProperty(*image,"label","Histogram",exception);
9135 (void) AcquireUniqueFilename(filename);
9136 (void) FormatLocaleString((*image)->filename,MagickPathExtent,"histogram:%s",
9137 filename);
9138 status=WriteImage(image_info,*image,exception);
9139 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
9140 histogram_image=ReadImage(image_info,exception);
9141 (void) RelinquishUniqueFileResource(filename);
9142 if (histogram_image == (Image *) NULL)
9143 break;
9144 (void) FormatLocaleString(histogram_image->filename,MagickPathExtent,
9145 "show:%s",filename);
9146 status=WriteImage(image_info,histogram_image,exception);
9147 histogram_image=DestroyImage(histogram_image);
9148 if (status == MagickFalse)
9149 XNoticeWidget(display,windows,"Unable to show histogram",
9150 (*image)->filename);
9151 XDelay(display,1500);
9152 XSetCursorState(display,windows,MagickFalse);
9153 break;
9154 }
9155 case ShowMatteCommand:
9156 {
9157 char
9158 value[MagickPathExtent];
9159
9160 Image
9161 *matte_image;
9162
9163 if ((*image)->alpha_trait == UndefinedPixelTrait)
9164 {
9165 XNoticeWidget(display,windows,
9166 "Image does not have any matte information",(*image)->filename);
9167 break;
9168 }
9169 /*
9170 Show image matte.
9171 */
9172 XSetCursorState(display,windows,MagickTrue);
9173 XCheckRefreshWindows(display,windows);
9174 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
9175 windows->image.id);
9176 (void) SetImageProperty(*image,"group",value,exception);
9177 (void) DeleteImageProperty(*image,"label");
9178 (void) SetImageProperty(*image,"label","Matte",exception);
9179 (void) AcquireUniqueFilename(filename);
9180 (void) FormatLocaleString((*image)->filename,MagickPathExtent,"matte:%s",
9181 filename);
9182 status=WriteImage(image_info,*image,exception);
9183 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
9184 matte_image=ReadImage(image_info,exception);
9185 (void) RelinquishUniqueFileResource(filename);
9186 if (matte_image == (Image *) NULL)
9187 break;
9188 (void) FormatLocaleString(matte_image->filename,MagickPathExtent,"show:%s",
9189 filename);
9190 status=WriteImage(image_info,matte_image,exception);
9191 matte_image=DestroyImage(matte_image);
9192 if (status == MagickFalse)
9193 XNoticeWidget(display,windows,"Unable to show matte",
9194 (*image)->filename);
9195 XDelay(display,1500);
9196 XSetCursorState(display,windows,MagickFalse);
9197 break;
9198 }
9199 case BackgroundCommand:
9200 {
9201 /*
9202 Background image.
9203 */
9204 status=XBackgroundImage(display,resource_info,windows,image,exception);
9205 if (status == MagickFalse)
9206 break;
9207 nexus=CloneImage(*image,0,0,MagickTrue,exception);
9208 if (nexus != (Image *) NULL)
9209 XClientMessage(display,windows->image.id,windows->im_protocols,
9210 windows->im_next_image,CurrentTime);
9211 break;
9212 }
9213 case SlideShowCommand:
9214 {
9215 static char
9216 delay[MagickPathExtent] = "5";
9217
9218 /*
9219 Display next image after pausing.
9220 */
9221 (void) XDialogWidget(display,windows,"Slide Show",
9222 "Pause how many 1/100ths of a second between images:",delay);
9223 if (*delay == '\0')
9224 break;
9225 resource_info->delay=StringToUnsignedLong(delay);
9226 XClientMessage(display,windows->image.id,windows->im_protocols,
9227 windows->im_next_image,CurrentTime);
9228 break;
9229 }
9230 case PreferencesCommand:
9231 {
9232 /*
9233 Set user preferences.
9234 */
9235 status=XPreferencesWidget(display,resource_info,windows);
9236 if (status == MagickFalse)
9237 break;
9238 nexus=CloneImage(*image,0,0,MagickTrue,exception);
9239 if (nexus != (Image *) NULL)
9240 XClientMessage(display,windows->image.id,windows->im_protocols,
9241 windows->im_next_image,CurrentTime);
9242 break;
9243 }
9244 case HelpCommand:
9245 {
9246 /*
9247 User requested help.
9248 */
9249 XTextViewWidget(display,resource_info,windows,MagickFalse,
9250 "Help Viewer - Display",DisplayHelp);
9251 break;
9252 }
9253 case BrowseDocumentationCommand:
9254 {
9255 Atom
9256 mozilla_atom;
9257
9258 Window
9259 mozilla_window,
9260 root_window;
9261
9262 /*
9263 Browse the ImageMagick documentation.
9264 */
9265 root_window=XRootWindow(display,XDefaultScreen(display));
9266 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse);
9267 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom);
9268 if (mozilla_window != (Window) NULL)
9269 {
9270 char
9271 command[MagickPathExtent],
9272 *url;
9273
9274 /*
9275 Display documentation using Netscape remote control.
9276 */
9277 url=GetMagickHomeURL();
9278 (void) FormatLocaleString(command,MagickPathExtent,
9279 "openurl(%s,new-tab)",url);
9280 url=DestroyString(url);
9281 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse);
9282 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING,
9283 8,PropModeReplace,(unsigned char *) command,(int) strlen(command));
9284 XSetCursorState(display,windows,MagickFalse);
9285 break;
9286 }
9287 XSetCursorState(display,windows,MagickTrue);
9288 XCheckRefreshWindows(display,windows);
9289 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL,
9290 exception);
9291 if (status == MagickFalse)
9292 XNoticeWidget(display,windows,"Unable to browse documentation",
9293 (char *) NULL);
9294 XDelay(display,1500);
9295 XSetCursorState(display,windows,MagickFalse);
9296 break;
9297 }
9298 case VersionCommand:
9299 {
9300 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL),
9301 GetMagickCopyright());
9302 break;
9303 }
9304 case SaveToUndoBufferCommand:
9305 break;
9306 default:
9307 {
9308 (void) XBell(display,0);
9309 break;
9310 }
9311 }
9312 image_info=DestroyImageInfo(image_info);
9313 return(nexus);
9314 }
9315
9316 /*
9317 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9318 % %
9319 % %
9320 % %
9321 + X M a g n i f y I m a g e %
9322 % %
9323 % %
9324 % %
9325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9326 %
9327 % XMagnifyImage() magnifies portions of the image as indicated by the pointer.
9328 % The magnified portion is displayed in a separate window.
9329 %
9330 % The format of the XMagnifyImage method is:
9331 %
9332 % void XMagnifyImage(Display *display,XWindows *windows,XEvent *event,
9333 % ExceptionInfo *exception)
9334 %
9335 % A description of each parameter follows:
9336 %
9337 % o display: Specifies a connection to an X server; returned from
9338 % XOpenDisplay.
9339 %
9340 % o windows: Specifies a pointer to a XWindows structure.
9341 %
9342 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
9343 % the entire image is refreshed.
9344 %
9345 % o exception: return any errors or warnings in this structure.
9346 %
9347 */
XMagnifyImage(Display * display,XWindows * windows,XEvent * event,ExceptionInfo * exception)9348 static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event,
9349 ExceptionInfo *exception)
9350 {
9351 char
9352 text[MagickPathExtent];
9353
9354 register int
9355 x,
9356 y;
9357
9358 size_t
9359 state;
9360
9361 /*
9362 Update magnified image until the mouse button is released.
9363 */
9364 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor);
9365 state=DefaultState;
9366 x=event->xbutton.x;
9367 y=event->xbutton.y;
9368 windows->magnify.x=(int) windows->image.x+x;
9369 windows->magnify.y=(int) windows->image.y+y;
9370 do
9371 {
9372 /*
9373 Map and unmap Info widget as text cursor crosses its boundaries.
9374 */
9375 if (windows->info.mapped != MagickFalse )
9376 {
9377 if ((x < (int) (windows->info.x+windows->info.width)) &&
9378 (y < (int) (windows->info.y+windows->info.height)))
9379 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
9380 }
9381 else
9382 if ((x > (int) (windows->info.x+windows->info.width)) ||
9383 (y > (int) (windows->info.y+windows->info.height)))
9384 (void) XMapWindow(display,windows->info.id);
9385 if (windows->info.mapped != MagickFalse )
9386 {
9387 /*
9388 Display pointer position.
9389 */
9390 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ",
9391 windows->magnify.x,windows->magnify.y);
9392 XInfoWidget(display,windows,text);
9393 }
9394 /*
9395 Wait for next event.
9396 */
9397 XScreenEvent(display,windows,event,exception);
9398 switch (event->type)
9399 {
9400 case ButtonPress:
9401 break;
9402 case ButtonRelease:
9403 {
9404 /*
9405 User has finished magnifying image.
9406 */
9407 x=event->xbutton.x;
9408 y=event->xbutton.y;
9409 state|=ExitState;
9410 break;
9411 }
9412 case Expose:
9413 break;
9414 case MotionNotify:
9415 {
9416 x=event->xmotion.x;
9417 y=event->xmotion.y;
9418 break;
9419 }
9420 default:
9421 break;
9422 }
9423 /*
9424 Check boundary conditions.
9425 */
9426 if (x < 0)
9427 x=0;
9428 else
9429 if (x >= (int) windows->image.width)
9430 x=(int) windows->image.width-1;
9431 if (y < 0)
9432 y=0;
9433 else
9434 if (y >= (int) windows->image.height)
9435 y=(int) windows->image.height-1;
9436 } while ((state & ExitState) == 0);
9437 /*
9438 Display magnified image.
9439 */
9440 XSetCursorState(display,windows,MagickFalse);
9441 }
9442
9443 /*
9444 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9445 % %
9446 % %
9447 % %
9448 + X M a g n i f y W i n d o w C o m m a n d %
9449 % %
9450 % %
9451 % %
9452 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9453 %
9454 % XMagnifyWindowCommand() moves the image within an Magnify window by one
9455 % pixel as specified by the key symbol.
9456 %
9457 % The format of the XMagnifyWindowCommand method is:
9458 %
9459 % void XMagnifyWindowCommand(Display *display,XWindows *windows,
9460 % const MagickStatusType state,const KeySym key_symbol,
9461 % ExceptionInfo *exception)
9462 %
9463 % A description of each parameter follows:
9464 %
9465 % o display: Specifies a connection to an X server; returned from
9466 % XOpenDisplay.
9467 %
9468 % o windows: Specifies a pointer to a XWindows structure.
9469 %
9470 % o state: key mask.
9471 %
9472 % o key_symbol: Specifies a KeySym which indicates which side of the image
9473 % to trim.
9474 %
9475 % o exception: return any errors or warnings in this structure.
9476 %
9477 */
XMagnifyWindowCommand(Display * display,XWindows * windows,const MagickStatusType state,const KeySym key_symbol,ExceptionInfo * exception)9478 static void XMagnifyWindowCommand(Display *display,XWindows *windows,
9479 const MagickStatusType state,const KeySym key_symbol,ExceptionInfo *exception)
9480 {
9481 unsigned int
9482 quantum;
9483
9484 /*
9485 User specified a magnify factor or position.
9486 */
9487 quantum=1;
9488 if ((state & Mod1Mask) != 0)
9489 quantum=10;
9490 switch ((int) key_symbol)
9491 {
9492 case QuitCommand:
9493 {
9494 (void) XWithdrawWindow(display,windows->magnify.id,
9495 windows->magnify.screen);
9496 break;
9497 }
9498 case XK_Home:
9499 case XK_KP_Home:
9500 {
9501 windows->magnify.x=(int) windows->image.width/2;
9502 windows->magnify.y=(int) windows->image.height/2;
9503 break;
9504 }
9505 case XK_Left:
9506 case XK_KP_Left:
9507 {
9508 if (windows->magnify.x > 0)
9509 windows->magnify.x-=quantum;
9510 break;
9511 }
9512 case XK_Up:
9513 case XK_KP_Up:
9514 {
9515 if (windows->magnify.y > 0)
9516 windows->magnify.y-=quantum;
9517 break;
9518 }
9519 case XK_Right:
9520 case XK_KP_Right:
9521 {
9522 if (windows->magnify.x < (int) (windows->image.ximage->width-1))
9523 windows->magnify.x+=quantum;
9524 break;
9525 }
9526 case XK_Down:
9527 case XK_KP_Down:
9528 {
9529 if (windows->magnify.y < (int) (windows->image.ximage->height-1))
9530 windows->magnify.y+=quantum;
9531 break;
9532 }
9533 case XK_0:
9534 case XK_1:
9535 case XK_2:
9536 case XK_3:
9537 case XK_4:
9538 case XK_5:
9539 case XK_6:
9540 case XK_7:
9541 case XK_8:
9542 case XK_9:
9543 {
9544 windows->magnify.data=(key_symbol-XK_0);
9545 break;
9546 }
9547 case XK_KP_0:
9548 case XK_KP_1:
9549 case XK_KP_2:
9550 case XK_KP_3:
9551 case XK_KP_4:
9552 case XK_KP_5:
9553 case XK_KP_6:
9554 case XK_KP_7:
9555 case XK_KP_8:
9556 case XK_KP_9:
9557 {
9558 windows->magnify.data=(key_symbol-XK_KP_0);
9559 break;
9560 }
9561 default:
9562 break;
9563 }
9564 XMakeMagnifyImage(display,windows,exception);
9565 }
9566
9567 /*
9568 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9569 % %
9570 % %
9571 % %
9572 + X M a k e P a n I m a g e %
9573 % %
9574 % %
9575 % %
9576 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9577 %
9578 % XMakePanImage() creates a thumbnail of the image and displays it in the Pan
9579 % icon window.
9580 %
9581 % The format of the XMakePanImage method is:
9582 %
9583 % void XMakePanImage(Display *display,XResourceInfo *resource_info,
9584 % XWindows *windows,Image *image,ExceptionInfo *exception)
9585 %
9586 % A description of each parameter follows:
9587 %
9588 % o display: Specifies a connection to an X server; returned from
9589 % XOpenDisplay.
9590 %
9591 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9592 %
9593 % o windows: Specifies a pointer to a XWindows structure.
9594 %
9595 % o image: the image.
9596 %
9597 % o exception: return any errors or warnings in this structure.
9598 %
9599 */
XMakePanImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,ExceptionInfo * exception)9600 static void XMakePanImage(Display *display,XResourceInfo *resource_info,
9601 XWindows *windows,Image *image,ExceptionInfo *exception)
9602 {
9603 MagickStatusType
9604 status;
9605
9606 /*
9607 Create and display image for panning icon.
9608 */
9609 XSetCursorState(display,windows,MagickTrue);
9610 XCheckRefreshWindows(display,windows);
9611 windows->pan.x=(int) windows->image.x;
9612 windows->pan.y=(int) windows->image.y;
9613 status=XMakeImage(display,resource_info,&windows->pan,image,
9614 windows->pan.width,windows->pan.height,exception);
9615 if (status == MagickFalse)
9616 ThrowXWindowException(ResourceLimitError,
9617 "MemoryAllocationFailed",image->filename);
9618 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
9619 windows->pan.pixmap);
9620 (void) XClearWindow(display,windows->pan.id);
9621 XDrawPanRectangle(display,windows);
9622 XSetCursorState(display,windows,MagickFalse);
9623 }
9624
9625 /*
9626 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9627 % %
9628 % %
9629 % %
9630 + X M a t t a E d i t I m a g e %
9631 % %
9632 % %
9633 % %
9634 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9635 %
9636 % XMatteEditImage() allows the user to interactively change the Matte channel
9637 % of an image. If the image is PseudoClass it is promoted to DirectClass
9638 % before the matte information is stored.
9639 %
9640 % The format of the XMatteEditImage method is:
9641 %
9642 % MagickBooleanType XMatteEditImage(Display *display,
9643 % XResourceInfo *resource_info,XWindows *windows,Image **image,
9644 % ExceptionInfo *exception)
9645 %
9646 % A description of each parameter follows:
9647 %
9648 % o display: Specifies a connection to an X server; returned from
9649 % XOpenDisplay.
9650 %
9651 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9652 %
9653 % o windows: Specifies a pointer to a XWindows structure.
9654 %
9655 % o image: the image; returned from ReadImage.
9656 %
9657 % o exception: return any errors or warnings in this structure.
9658 %
9659 */
XMatteEditImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image ** image,ExceptionInfo * exception)9660 static MagickBooleanType XMatteEditImage(Display *display,
9661 XResourceInfo *resource_info,XWindows *windows,Image **image,
9662 ExceptionInfo *exception)
9663 {
9664 static char
9665 matte[MagickPathExtent] = "0";
9666
9667 static const char
9668 *MatteEditMenu[] =
9669 {
9670 "Method",
9671 "Border Color",
9672 "Fuzz",
9673 "Matte Value",
9674 "Undo",
9675 "Help",
9676 "Dismiss",
9677 (char *) NULL
9678 };
9679
9680 static const ModeType
9681 MatteEditCommands[] =
9682 {
9683 MatteEditMethod,
9684 MatteEditBorderCommand,
9685 MatteEditFuzzCommand,
9686 MatteEditValueCommand,
9687 MatteEditUndoCommand,
9688 MatteEditHelpCommand,
9689 MatteEditDismissCommand
9690 };
9691
9692 static PaintMethod
9693 method = PointMethod;
9694
9695 static XColor
9696 border_color = { 0, 0, 0, 0, 0, 0 };
9697
9698 char
9699 command[MagickPathExtent],
9700 text[MagickPathExtent];
9701
9702 Cursor
9703 cursor;
9704
9705 int
9706 entry,
9707 id,
9708 x,
9709 x_offset,
9710 y,
9711 y_offset;
9712
9713 register int
9714 i;
9715
9716 register Quantum
9717 *q;
9718
9719 unsigned int
9720 height,
9721 width;
9722
9723 size_t
9724 state;
9725
9726 XEvent
9727 event;
9728
9729 /*
9730 Map Command widget.
9731 */
9732 (void) CloneString(&windows->command.name,"Matte Edit");
9733 windows->command.data=4;
9734 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL);
9735 (void) XMapRaised(display,windows->command.id);
9736 XClientMessage(display,windows->image.id,windows->im_protocols,
9737 windows->im_update_widget,CurrentTime);
9738 /*
9739 Make cursor.
9740 */
9741 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
9742 resource_info->background_color,resource_info->foreground_color);
9743 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9744 /*
9745 Track pointer until button 1 is pressed.
9746 */
9747 XQueryPosition(display,windows->image.id,&x,&y);
9748 (void) XSelectInput(display,windows->image.id,
9749 windows->image.attributes.event_mask | PointerMotionMask);
9750 state=DefaultState;
9751 do
9752 {
9753 if (windows->info.mapped != MagickFalse )
9754 {
9755 /*
9756 Display pointer position.
9757 */
9758 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ",
9759 x+windows->image.x,y+windows->image.y);
9760 XInfoWidget(display,windows,text);
9761 }
9762 /*
9763 Wait for next event.
9764 */
9765 XScreenEvent(display,windows,&event,exception);
9766 if (event.xany.window == windows->command.id)
9767 {
9768 /*
9769 Select a command from the Command widget.
9770 */
9771 id=XCommandWidget(display,windows,MatteEditMenu,&event);
9772 if (id < 0)
9773 {
9774 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9775 continue;
9776 }
9777 switch (MatteEditCommands[id])
9778 {
9779 case MatteEditMethod:
9780 {
9781 char
9782 **methods;
9783
9784 /*
9785 Select a method from the pop-up menu.
9786 */
9787 methods=GetCommandOptions(MagickMethodOptions);
9788 if (methods == (char **) NULL)
9789 break;
9790 entry=XMenuWidget(display,windows,MatteEditMenu[id],
9791 (const char **) methods,command);
9792 if (entry >= 0)
9793 method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
9794 MagickFalse,methods[entry]);
9795 methods=DestroyStringList(methods);
9796 break;
9797 }
9798 case MatteEditBorderCommand:
9799 {
9800 const char
9801 *ColorMenu[MaxNumberPens];
9802
9803 int
9804 pen_number;
9805
9806 /*
9807 Initialize menu selections.
9808 */
9809 for (i=0; i < (int) (MaxNumberPens-2); i++)
9810 ColorMenu[i]=resource_info->pen_colors[i];
9811 ColorMenu[MaxNumberPens-2]="Browser...";
9812 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
9813 /*
9814 Select a pen color from the pop-up menu.
9815 */
9816 pen_number=XMenuWidget(display,windows,MatteEditMenu[id],
9817 (const char **) ColorMenu,command);
9818 if (pen_number < 0)
9819 break;
9820 if (pen_number == (MaxNumberPens-2))
9821 {
9822 static char
9823 color_name[MagickPathExtent] = "gray";
9824
9825 /*
9826 Select a pen color from a dialog.
9827 */
9828 resource_info->pen_colors[pen_number]=color_name;
9829 XColorBrowserWidget(display,windows,"Select",color_name);
9830 if (*color_name == '\0')
9831 break;
9832 }
9833 /*
9834 Set border color.
9835 */
9836 (void) XParseColor(display,windows->map_info->colormap,
9837 resource_info->pen_colors[pen_number],&border_color);
9838 break;
9839 }
9840 case MatteEditFuzzCommand:
9841 {
9842 static char
9843 fuzz[MagickPathExtent];
9844
9845 static const char
9846 *FuzzMenu[] =
9847 {
9848 "0%",
9849 "2%",
9850 "5%",
9851 "10%",
9852 "15%",
9853 "Dialog...",
9854 (char *) NULL,
9855 };
9856
9857 /*
9858 Select a command from the pop-up menu.
9859 */
9860 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu,
9861 command);
9862 if (entry < 0)
9863 break;
9864 if (entry != 5)
9865 {
9866 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double)
9867 QuantumRange+1.0);
9868 break;
9869 }
9870 (void) CopyMagickString(fuzz,"20%",MagickPathExtent);
9871 (void) XDialogWidget(display,windows,"Ok",
9872 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
9873 if (*fuzz == '\0')
9874 break;
9875 (void) ConcatenateMagickString(fuzz,"%",MagickPathExtent);
9876 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+
9877 1.0);
9878 break;
9879 }
9880 case MatteEditValueCommand:
9881 {
9882 static char
9883 message[MagickPathExtent];
9884
9885 static const char
9886 *MatteMenu[] =
9887 {
9888 "Opaque",
9889 "Transparent",
9890 "Dialog...",
9891 (char *) NULL,
9892 };
9893
9894 /*
9895 Select a command from the pop-up menu.
9896 */
9897 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu,
9898 command);
9899 if (entry < 0)
9900 break;
9901 if (entry != 2)
9902 {
9903 (void) FormatLocaleString(matte,MagickPathExtent,QuantumFormat,
9904 OpaqueAlpha);
9905 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0)
9906 (void) FormatLocaleString(matte,MagickPathExtent,QuantumFormat,
9907 (Quantum) TransparentAlpha);
9908 break;
9909 }
9910 (void) FormatLocaleString(message,MagickPathExtent,
9911 "Enter matte value (0 - " QuantumFormat "):",(Quantum)
9912 QuantumRange);
9913 (void) XDialogWidget(display,windows,"Matte",message,matte);
9914 if (*matte == '\0')
9915 break;
9916 break;
9917 }
9918 case MatteEditUndoCommand:
9919 {
9920 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
9921 image,exception);
9922 break;
9923 }
9924 case MatteEditHelpCommand:
9925 {
9926 XTextViewWidget(display,resource_info,windows,MagickFalse,
9927 "Help Viewer - Matte Edit",ImageMatteEditHelp);
9928 break;
9929 }
9930 case MatteEditDismissCommand:
9931 {
9932 /*
9933 Prematurely exit.
9934 */
9935 state|=EscapeState;
9936 state|=ExitState;
9937 break;
9938 }
9939 default:
9940 break;
9941 }
9942 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9943 continue;
9944 }
9945 switch (event.type)
9946 {
9947 case ButtonPress:
9948 {
9949 if (event.xbutton.button != Button1)
9950 break;
9951 if ((event.xbutton.window != windows->image.id) &&
9952 (event.xbutton.window != windows->magnify.id))
9953 break;
9954 /*
9955 Update matte data.
9956 */
9957 x=event.xbutton.x;
9958 y=event.xbutton.y;
9959 (void) XMagickCommand(display,resource_info,windows,
9960 SaveToUndoBufferCommand,image,exception);
9961 state|=UpdateConfigurationState;
9962 break;
9963 }
9964 case ButtonRelease:
9965 {
9966 if (event.xbutton.button != Button1)
9967 break;
9968 if ((event.xbutton.window != windows->image.id) &&
9969 (event.xbutton.window != windows->magnify.id))
9970 break;
9971 /*
9972 Update colormap information.
9973 */
9974 x=event.xbutton.x;
9975 y=event.xbutton.y;
9976 XConfigureImageColormap(display,resource_info,windows,*image,exception);
9977 (void) XConfigureImage(display,resource_info,windows,*image,exception);
9978 XInfoWidget(display,windows,text);
9979 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9980 state&=(~UpdateConfigurationState);
9981 break;
9982 }
9983 case Expose:
9984 break;
9985 case KeyPress:
9986 {
9987 char
9988 command[MagickPathExtent];
9989
9990 KeySym
9991 key_symbol;
9992
9993 if (event.xkey.window == windows->magnify.id)
9994 {
9995 Window
9996 window;
9997
9998 window=windows->magnify.id;
9999 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
10000 }
10001 if (event.xkey.window != windows->image.id)
10002 break;
10003 /*
10004 Respond to a user key press.
10005 */
10006 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
10007 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
10008 switch ((int) key_symbol)
10009 {
10010 case XK_Escape:
10011 case XK_F20:
10012 {
10013 /*
10014 Prematurely exit.
10015 */
10016 state|=ExitState;
10017 break;
10018 }
10019 case XK_F1:
10020 case XK_Help:
10021 {
10022 XTextViewWidget(display,resource_info,windows,MagickFalse,
10023 "Help Viewer - Matte Edit",ImageMatteEditHelp);
10024 break;
10025 }
10026 default:
10027 {
10028 (void) XBell(display,0);
10029 break;
10030 }
10031 }
10032 break;
10033 }
10034 case MotionNotify:
10035 {
10036 /*
10037 Map and unmap Info widget as cursor crosses its boundaries.
10038 */
10039 x=event.xmotion.x;
10040 y=event.xmotion.y;
10041 if (windows->info.mapped != MagickFalse )
10042 {
10043 if ((x < (int) (windows->info.x+windows->info.width)) &&
10044 (y < (int) (windows->info.y+windows->info.height)))
10045 (void) XWithdrawWindow(display,windows->info.id,
10046 windows->info.screen);
10047 }
10048 else
10049 if ((x > (int) (windows->info.x+windows->info.width)) ||
10050 (y > (int) (windows->info.y+windows->info.height)))
10051 (void) XMapWindow(display,windows->info.id);
10052 break;
10053 }
10054 default:
10055 break;
10056 }
10057 if (event.xany.window == windows->magnify.id)
10058 {
10059 x=windows->magnify.x-windows->image.x;
10060 y=windows->magnify.y-windows->image.y;
10061 }
10062 x_offset=x;
10063 y_offset=y;
10064 if ((state & UpdateConfigurationState) != 0)
10065 {
10066 CacheView
10067 *image_view;
10068
10069 int
10070 x,
10071 y;
10072
10073 /*
10074 Matte edit is relative to image configuration.
10075 */
10076 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
10077 MagickTrue);
10078 XPutPixel(windows->image.ximage,x_offset,y_offset,
10079 windows->pixel_info->background_color.pixel);
10080 width=(unsigned int) (*image)->columns;
10081 height=(unsigned int) (*image)->rows;
10082 x=0;
10083 y=0;
10084 if (windows->image.crop_geometry != (char *) NULL)
10085 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,
10086 &height);
10087 x_offset=(int) (width*(windows->image.x+x_offset)/
10088 windows->image.ximage->width+x);
10089 y_offset=(int) (height*(windows->image.y+y_offset)/
10090 windows->image.ximage->height+y);
10091 if ((x_offset < 0) || (y_offset < 0))
10092 continue;
10093 if ((x_offset >= (int) (*image)->columns) ||
10094 (y_offset >= (int) (*image)->rows))
10095 continue;
10096 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
10097 return(MagickFalse);
10098 if ((*image)->alpha_trait == UndefinedPixelTrait)
10099 (void) SetImageAlphaChannel(*image,OpaqueAlphaChannel,exception);
10100 image_view=AcquireAuthenticCacheView(*image,exception);
10101 switch (method)
10102 {
10103 case PointMethod:
10104 default:
10105 {
10106 /*
10107 Update matte information using point algorithm.
10108 */
10109 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,
10110 (ssize_t) y_offset,1,1,exception);
10111 if (q == (Quantum *) NULL)
10112 break;
10113 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
10114 (void) SyncCacheViewAuthenticPixels(image_view,exception);
10115 break;
10116 }
10117 case ReplaceMethod:
10118 {
10119 PixelInfo
10120 pixel,
10121 target;
10122
10123 /*
10124 Update matte information using replace algorithm.
10125 */
10126 (void) GetOneCacheViewVirtualPixelInfo(image_view,(ssize_t)
10127 x_offset,(ssize_t) y_offset,&target,exception);
10128 for (y=0; y < (int) (*image)->rows; y++)
10129 {
10130 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
10131 (*image)->columns,1,exception);
10132 if (q == (Quantum *) NULL)
10133 break;
10134 for (x=0; x < (int) (*image)->columns; x++)
10135 {
10136 GetPixelInfoPixel(*image,q,&pixel);
10137 if (IsFuzzyEquivalencePixelInfo(&pixel,&target))
10138 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
10139 q+=GetPixelChannels(*image);
10140 }
10141 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
10142 break;
10143 }
10144 break;
10145 }
10146 case FloodfillMethod:
10147 case FillToBorderMethod:
10148 {
10149 ChannelType
10150 channel_mask;
10151
10152 DrawInfo
10153 *draw_info;
10154
10155 PixelInfo
10156 target;
10157
10158 /*
10159 Update matte information using floodfill algorithm.
10160 */
10161 (void) GetOneVirtualPixelInfo(*image,
10162 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t)
10163 y_offset,&target,exception);
10164 if (method == FillToBorderMethod)
10165 {
10166 target.red=(double) ScaleShortToQuantum(
10167 border_color.red);
10168 target.green=(double) ScaleShortToQuantum(
10169 border_color.green);
10170 target.blue=(double) ScaleShortToQuantum(
10171 border_color.blue);
10172 }
10173 draw_info=CloneDrawInfo(resource_info->image_info,
10174 (DrawInfo *) NULL);
10175 draw_info->fill.alpha=(double) ClampToQuantum(
10176 StringToDouble(matte,(char **) NULL));
10177 channel_mask=SetImageChannelMask(*image,AlphaChannel);
10178 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t)
10179 x_offset,(ssize_t) y_offset,
10180 method != FloodfillMethod ? MagickTrue : MagickFalse,exception);
10181 (void) SetPixelChannelMask(*image,channel_mask);
10182 draw_info=DestroyDrawInfo(draw_info);
10183 break;
10184 }
10185 case ResetMethod:
10186 {
10187 /*
10188 Update matte information using reset algorithm.
10189 */
10190 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
10191 return(MagickFalse);
10192 for (y=0; y < (int) (*image)->rows; y++)
10193 {
10194 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
10195 (*image)->columns,1,exception);
10196 if (q == (Quantum *) NULL)
10197 break;
10198 for (x=0; x < (int) (*image)->columns; x++)
10199 {
10200 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
10201 q+=GetPixelChannels(*image);
10202 }
10203 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
10204 break;
10205 }
10206 if (StringToLong(matte) == (long) OpaqueAlpha)
10207 (*image)->alpha_trait=UndefinedPixelTrait;
10208 break;
10209 }
10210 }
10211 image_view=DestroyCacheView(image_view);
10212 state&=(~UpdateConfigurationState);
10213 }
10214 } while ((state & ExitState) == 0);
10215 (void) XSelectInput(display,windows->image.id,
10216 windows->image.attributes.event_mask);
10217 XSetCursorState(display,windows,MagickFalse);
10218 (void) XFreeCursor(display,cursor);
10219 return(MagickTrue);
10220 }
10221
10222 /*
10223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10224 % %
10225 % %
10226 % %
10227 + X O p e n I m a g e %
10228 % %
10229 % %
10230 % %
10231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10232 %
10233 % XOpenImage() loads an image from a file.
10234 %
10235 % The format of the XOpenImage method is:
10236 %
10237 % Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10238 % XWindows *windows,const unsigned int command)
10239 %
10240 % A description of each parameter follows:
10241 %
10242 % o display: Specifies a connection to an X server; returned from
10243 % XOpenDisplay.
10244 %
10245 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10246 %
10247 % o windows: Specifies a pointer to a XWindows structure.
10248 %
10249 % o command: A value other than zero indicates that the file is selected
10250 % from the command line argument list.
10251 %
10252 */
XOpenImage(Display * display,XResourceInfo * resource_info,XWindows * windows,const MagickBooleanType command)10253 static Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10254 XWindows *windows,const MagickBooleanType command)
10255 {
10256 const MagickInfo
10257 *magick_info;
10258
10259 ExceptionInfo
10260 *exception;
10261
10262 Image
10263 *nexus;
10264
10265 ImageInfo
10266 *image_info;
10267
10268 static char
10269 filename[MagickPathExtent] = "\0";
10270
10271 /*
10272 Request file name from user.
10273 */
10274 if (command == MagickFalse)
10275 XFileBrowserWidget(display,windows,"Open",filename);
10276 else
10277 {
10278 char
10279 **filelist,
10280 **files;
10281
10282 int
10283 count,
10284 status;
10285
10286 register int
10287 i,
10288 j;
10289
10290 /*
10291 Select next image from the command line.
10292 */
10293 status=XGetCommand(display,windows->image.id,&files,&count);
10294 if (status == 0)
10295 {
10296 ThrowXWindowException(XServerError,"UnableToGetProperty","...");
10297 return((Image *) NULL);
10298 }
10299 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist));
10300 if (filelist == (char **) NULL)
10301 {
10302 ThrowXWindowException(ResourceLimitError,
10303 "MemoryAllocationFailed","...");
10304 (void) XFreeStringList(files);
10305 return((Image *) NULL);
10306 }
10307 j=0;
10308 for (i=1; i < count; i++)
10309 if (*files[i] != '-')
10310 filelist[j++]=files[i];
10311 filelist[j]=(char *) NULL;
10312 XListBrowserWidget(display,windows,&windows->widget,
10313 (const char **) filelist,"Load","Select Image to Load:",filename);
10314 filelist=(char **) RelinquishMagickMemory(filelist);
10315 (void) XFreeStringList(files);
10316 }
10317 if (*filename == '\0')
10318 return((Image *) NULL);
10319 image_info=CloneImageInfo(resource_info->image_info);
10320 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL,
10321 (void *) NULL);
10322 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
10323 exception=AcquireExceptionInfo();
10324 (void) SetImageInfo(image_info,0,exception);
10325 if (LocaleCompare(image_info->magick,"X") == 0)
10326 {
10327 char
10328 seconds[MagickPathExtent];
10329
10330 /*
10331 User may want to delay the X server screen grab.
10332 */
10333 (void) CopyMagickString(seconds,"0",MagickPathExtent);
10334 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:",
10335 seconds);
10336 if (*seconds == '\0')
10337 return((Image *) NULL);
10338 XDelay(display,(size_t) (1000*StringToLong(seconds)));
10339 }
10340 magick_info=GetMagickInfo(image_info->magick,exception);
10341 if ((magick_info != (const MagickInfo *) NULL) &&
10342 GetMagickRawSupport(magick_info) == MagickTrue)
10343 {
10344 char
10345 geometry[MagickPathExtent];
10346
10347 /*
10348 Request image size from the user.
10349 */
10350 (void) CopyMagickString(geometry,"512x512",MagickPathExtent);
10351 if (image_info->size != (char *) NULL)
10352 (void) CopyMagickString(geometry,image_info->size,MagickPathExtent);
10353 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:",
10354 geometry);
10355 (void) CloneString(&image_info->size,geometry);
10356 }
10357 /*
10358 Load the image.
10359 */
10360 XSetCursorState(display,windows,MagickTrue);
10361 XCheckRefreshWindows(display,windows);
10362 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
10363 nexus=ReadImage(image_info,exception);
10364 CatchException(exception);
10365 XSetCursorState(display,windows,MagickFalse);
10366 if (nexus != (Image *) NULL)
10367 XClientMessage(display,windows->image.id,windows->im_protocols,
10368 windows->im_next_image,CurrentTime);
10369 else
10370 {
10371 char
10372 *text,
10373 **textlist;
10374
10375 /*
10376 Unknown image format.
10377 */
10378 text=FileToString(filename,~0UL,exception);
10379 if (text == (char *) NULL)
10380 return((Image *) NULL);
10381 textlist=StringToList(text);
10382 if (textlist != (char **) NULL)
10383 {
10384 char
10385 title[MagickPathExtent];
10386
10387 register int
10388 i;
10389
10390 (void) FormatLocaleString(title,MagickPathExtent,
10391 "Unknown format: %s",filename);
10392 XTextViewWidget(display,resource_info,windows,MagickTrue,title,
10393 (const char **) textlist);
10394 for (i=0; textlist[i] != (char *) NULL; i++)
10395 textlist[i]=DestroyString(textlist[i]);
10396 textlist=(char **) RelinquishMagickMemory(textlist);
10397 }
10398 text=DestroyString(text);
10399 }
10400 exception=DestroyExceptionInfo(exception);
10401 image_info=DestroyImageInfo(image_info);
10402 return(nexus);
10403 }
10404
10405 /*
10406 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10407 % %
10408 % %
10409 % %
10410 + X P a n I m a g e %
10411 % %
10412 % %
10413 % %
10414 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10415 %
10416 % XPanImage() pans the image until the mouse button is released.
10417 %
10418 % The format of the XPanImage method is:
10419 %
10420 % void XPanImage(Display *display,XWindows *windows,XEvent *event,
10421 % ExceptionInfo *exception)
10422 %
10423 % A description of each parameter follows:
10424 %
10425 % o display: Specifies a connection to an X server; returned from
10426 % XOpenDisplay.
10427 %
10428 % o windows: Specifies a pointer to a XWindows structure.
10429 %
10430 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
10431 % the entire image is refreshed.
10432 %
10433 % o exception: return any errors or warnings in this structure.
10434 %
10435 */
XPanImage(Display * display,XWindows * windows,XEvent * event,ExceptionInfo * exception)10436 static void XPanImage(Display *display,XWindows *windows,XEvent *event,
10437 ExceptionInfo *exception)
10438 {
10439 char
10440 text[MagickPathExtent];
10441
10442 Cursor
10443 cursor;
10444
10445 double
10446 x_factor,
10447 y_factor;
10448
10449 RectangleInfo
10450 pan_info;
10451
10452 size_t
10453 state;
10454
10455 /*
10456 Define cursor.
10457 */
10458 if ((windows->image.ximage->width > (int) windows->image.width) &&
10459 (windows->image.ximage->height > (int) windows->image.height))
10460 cursor=XCreateFontCursor(display,XC_fleur);
10461 else
10462 if (windows->image.ximage->width > (int) windows->image.width)
10463 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow);
10464 else
10465 if (windows->image.ximage->height > (int) windows->image.height)
10466 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow);
10467 else
10468 cursor=XCreateFontCursor(display,XC_arrow);
10469 (void) XCheckDefineCursor(display,windows->pan.id,cursor);
10470 /*
10471 Pan image as pointer moves until the mouse button is released.
10472 */
10473 x_factor=(double) windows->image.ximage->width/windows->pan.width;
10474 y_factor=(double) windows->image.ximage->height/windows->pan.height;
10475 pan_info.width=windows->pan.width*windows->image.width/
10476 windows->image.ximage->width;
10477 pan_info.height=windows->pan.height*windows->image.height/
10478 windows->image.ximage->height;
10479 pan_info.x=0;
10480 pan_info.y=0;
10481 state=UpdateConfigurationState;
10482 do
10483 {
10484 switch (event->type)
10485 {
10486 case ButtonPress:
10487 {
10488 /*
10489 User choose an initial pan location.
10490 */
10491 pan_info.x=(ssize_t) event->xbutton.x;
10492 pan_info.y=(ssize_t) event->xbutton.y;
10493 state|=UpdateConfigurationState;
10494 break;
10495 }
10496 case ButtonRelease:
10497 {
10498 /*
10499 User has finished panning the image.
10500 */
10501 pan_info.x=(ssize_t) event->xbutton.x;
10502 pan_info.y=(ssize_t) event->xbutton.y;
10503 state|=UpdateConfigurationState | ExitState;
10504 break;
10505 }
10506 case MotionNotify:
10507 {
10508 pan_info.x=(ssize_t) event->xmotion.x;
10509 pan_info.y=(ssize_t) event->xmotion.y;
10510 state|=UpdateConfigurationState;
10511 }
10512 default:
10513 break;
10514 }
10515 if ((state & UpdateConfigurationState) != 0)
10516 {
10517 /*
10518 Check boundary conditions.
10519 */
10520 if (pan_info.x < (ssize_t) (pan_info.width/2))
10521 pan_info.x=0;
10522 else
10523 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2)));
10524 if (pan_info.x < 0)
10525 pan_info.x=0;
10526 else
10527 if ((int) (pan_info.x+windows->image.width) >
10528 windows->image.ximage->width)
10529 pan_info.x=(ssize_t)
10530 (windows->image.ximage->width-windows->image.width);
10531 if (pan_info.y < (ssize_t) (pan_info.height/2))
10532 pan_info.y=0;
10533 else
10534 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2)));
10535 if (pan_info.y < 0)
10536 pan_info.y=0;
10537 else
10538 if ((int) (pan_info.y+windows->image.height) >
10539 windows->image.ximage->height)
10540 pan_info.y=(ssize_t)
10541 (windows->image.ximage->height-windows->image.height);
10542 if ((windows->image.x != (int) pan_info.x) ||
10543 (windows->image.y != (int) pan_info.y))
10544 {
10545 /*
10546 Display image pan offset.
10547 */
10548 windows->image.x=(int) pan_info.x;
10549 windows->image.y=(int) pan_info.y;
10550 (void) FormatLocaleString(text,MagickPathExtent," %ux%u%+d%+d ",
10551 windows->image.width,windows->image.height,windows->image.x,
10552 windows->image.y);
10553 XInfoWidget(display,windows,text);
10554 /*
10555 Refresh Image window.
10556 */
10557 XDrawPanRectangle(display,windows);
10558 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
10559 }
10560 state&=(~UpdateConfigurationState);
10561 }
10562 /*
10563 Wait for next event.
10564 */
10565 if ((state & ExitState) == 0)
10566 XScreenEvent(display,windows,event,exception);
10567 } while ((state & ExitState) == 0);
10568 /*
10569 Restore cursor.
10570 */
10571 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor);
10572 (void) XFreeCursor(display,cursor);
10573 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
10574 }
10575
10576 /*
10577 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10578 % %
10579 % %
10580 % %
10581 + X P a s t e I m a g e %
10582 % %
10583 % %
10584 % %
10585 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10586 %
10587 % XPasteImage() pastes an image previously saved with XCropImage in the X
10588 % window image at a location the user chooses with the pointer.
10589 %
10590 % The format of the XPasteImage method is:
10591 %
10592 % MagickBooleanType XPasteImage(Display *display,
10593 % XResourceInfo *resource_info,XWindows *windows,Image *image,
10594 % ExceptionInfo *exception)
10595 %
10596 % A description of each parameter follows:
10597 %
10598 % o display: Specifies a connection to an X server; returned from
10599 % XOpenDisplay.
10600 %
10601 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10602 %
10603 % o windows: Specifies a pointer to a XWindows structure.
10604 %
10605 % o image: the image; returned from ReadImage.
10606 %
10607 % o exception: return any errors or warnings in this structure.
10608 %
10609 */
XPasteImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,ExceptionInfo * exception)10610 static MagickBooleanType XPasteImage(Display *display,
10611 XResourceInfo *resource_info,XWindows *windows,Image *image,
10612 ExceptionInfo *exception)
10613 {
10614 static const char
10615 *PasteMenu[] =
10616 {
10617 "Operator",
10618 "Help",
10619 "Dismiss",
10620 (char *) NULL
10621 };
10622
10623 static const ModeType
10624 PasteCommands[] =
10625 {
10626 PasteOperatorsCommand,
10627 PasteHelpCommand,
10628 PasteDismissCommand
10629 };
10630
10631 static CompositeOperator
10632 compose = CopyCompositeOp;
10633
10634 char
10635 text[MagickPathExtent];
10636
10637 Cursor
10638 cursor;
10639
10640 Image
10641 *paste_image;
10642
10643 int
10644 entry,
10645 id,
10646 x,
10647 y;
10648
10649 double
10650 scale_factor;
10651
10652 RectangleInfo
10653 highlight_info,
10654 paste_info;
10655
10656 unsigned int
10657 height,
10658 width;
10659
10660 size_t
10661 state;
10662
10663 XEvent
10664 event;
10665
10666 /*
10667 Copy image.
10668 */
10669 if (resource_info->copy_image == (Image *) NULL)
10670 return(MagickFalse);
10671 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,exception);
10672 /*
10673 Map Command widget.
10674 */
10675 (void) CloneString(&windows->command.name,"Paste");
10676 windows->command.data=1;
10677 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL);
10678 (void) XMapRaised(display,windows->command.id);
10679 XClientMessage(display,windows->image.id,windows->im_protocols,
10680 windows->im_update_widget,CurrentTime);
10681 /*
10682 Track pointer until button 1 is pressed.
10683 */
10684 XSetCursorState(display,windows,MagickFalse);
10685 XQueryPosition(display,windows->image.id,&x,&y);
10686 (void) XSelectInput(display,windows->image.id,
10687 windows->image.attributes.event_mask | PointerMotionMask);
10688 paste_info.x=(ssize_t) windows->image.x+x;
10689 paste_info.y=(ssize_t) windows->image.y+y;
10690 paste_info.width=0;
10691 paste_info.height=0;
10692 cursor=XCreateFontCursor(display,XC_ul_angle);
10693 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
10694 state=DefaultState;
10695 do
10696 {
10697 if (windows->info.mapped != MagickFalse )
10698 {
10699 /*
10700 Display pointer position.
10701 */
10702 (void) FormatLocaleString(text,MagickPathExtent," %+ld%+ld ",
10703 (long) paste_info.x,(long) paste_info.y);
10704 XInfoWidget(display,windows,text);
10705 }
10706 highlight_info=paste_info;
10707 highlight_info.x=paste_info.x-windows->image.x;
10708 highlight_info.y=paste_info.y-windows->image.y;
10709 XHighlightRectangle(display,windows->image.id,
10710 windows->image.highlight_context,&highlight_info);
10711 /*
10712 Wait for next event.
10713 */
10714 XScreenEvent(display,windows,&event,exception);
10715 XHighlightRectangle(display,windows->image.id,
10716 windows->image.highlight_context,&highlight_info);
10717 if (event.xany.window == windows->command.id)
10718 {
10719 /*
10720 Select a command from the Command widget.
10721 */
10722 id=XCommandWidget(display,windows,PasteMenu,&event);
10723 if (id < 0)
10724 continue;
10725 switch (PasteCommands[id])
10726 {
10727 case PasteOperatorsCommand:
10728 {
10729 char
10730 command[MagickPathExtent],
10731 **operators;
10732
10733 /*
10734 Select a command from the pop-up menu.
10735 */
10736 operators=GetCommandOptions(MagickComposeOptions);
10737 if (operators == (char **) NULL)
10738 break;
10739 entry=XMenuWidget(display,windows,PasteMenu[id],
10740 (const char **) operators,command);
10741 if (entry >= 0)
10742 compose=(CompositeOperator) ParseCommandOption(
10743 MagickComposeOptions,MagickFalse,operators[entry]);
10744 operators=DestroyStringList(operators);
10745 break;
10746 }
10747 case PasteHelpCommand:
10748 {
10749 XTextViewWidget(display,resource_info,windows,MagickFalse,
10750 "Help Viewer - Image Composite",ImagePasteHelp);
10751 break;
10752 }
10753 case PasteDismissCommand:
10754 {
10755 /*
10756 Prematurely exit.
10757 */
10758 state|=EscapeState;
10759 state|=ExitState;
10760 break;
10761 }
10762 default:
10763 break;
10764 }
10765 continue;
10766 }
10767 switch (event.type)
10768 {
10769 case ButtonPress:
10770 {
10771 if (image->debug != MagickFalse )
10772 (void) LogMagickEvent(X11Event,GetMagickModule(),
10773 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
10774 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10775 if (event.xbutton.button != Button1)
10776 break;
10777 if (event.xbutton.window != windows->image.id)
10778 break;
10779 /*
10780 Paste rectangle is relative to image configuration.
10781 */
10782 width=(unsigned int) image->columns;
10783 height=(unsigned int) image->rows;
10784 x=0;
10785 y=0;
10786 if (windows->image.crop_geometry != (char *) NULL)
10787 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
10788 &width,&height);
10789 scale_factor=(double) windows->image.ximage->width/width;
10790 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5);
10791 scale_factor=(double) windows->image.ximage->height/height;
10792 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5);
10793 (void) XCheckDefineCursor(display,windows->image.id,cursor);
10794 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10795 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
10796 break;
10797 }
10798 case ButtonRelease:
10799 {
10800 if (image->debug != MagickFalse )
10801 (void) LogMagickEvent(X11Event,GetMagickModule(),
10802 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
10803 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10804 if (event.xbutton.button != Button1)
10805 break;
10806 if (event.xbutton.window != windows->image.id)
10807 break;
10808 if ((paste_info.width != 0) && (paste_info.height != 0))
10809 {
10810 /*
10811 User has selected the location of the paste image.
10812 */
10813 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10814 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
10815 state|=ExitState;
10816 }
10817 break;
10818 }
10819 case Expose:
10820 break;
10821 case KeyPress:
10822 {
10823 char
10824 command[MagickPathExtent];
10825
10826 KeySym
10827 key_symbol;
10828
10829 int
10830 length;
10831
10832 if (event.xkey.window != windows->image.id)
10833 break;
10834 /*
10835 Respond to a user key press.
10836 */
10837 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
10838 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
10839 *(command+length)='\0';
10840 if (image->debug != MagickFalse )
10841 (void) LogMagickEvent(X11Event,GetMagickModule(),
10842 "Key press: 0x%lx (%s)",(long) key_symbol,command);
10843 switch ((int) key_symbol)
10844 {
10845 case XK_Escape:
10846 case XK_F20:
10847 {
10848 /*
10849 Prematurely exit.
10850 */
10851 paste_image=DestroyImage(paste_image);
10852 state|=EscapeState;
10853 state|=ExitState;
10854 break;
10855 }
10856 case XK_F1:
10857 case XK_Help:
10858 {
10859 (void) XSetFunction(display,windows->image.highlight_context,
10860 GXcopy);
10861 XTextViewWidget(display,resource_info,windows,MagickFalse,
10862 "Help Viewer - Image Composite",ImagePasteHelp);
10863 (void) XSetFunction(display,windows->image.highlight_context,
10864 GXinvert);
10865 break;
10866 }
10867 default:
10868 {
10869 (void) XBell(display,0);
10870 break;
10871 }
10872 }
10873 break;
10874 }
10875 case MotionNotify:
10876 {
10877 /*
10878 Map and unmap Info widget as text cursor crosses its boundaries.
10879 */
10880 x=event.xmotion.x;
10881 y=event.xmotion.y;
10882 if (windows->info.mapped != MagickFalse )
10883 {
10884 if ((x < (int) (windows->info.x+windows->info.width)) &&
10885 (y < (int) (windows->info.y+windows->info.height)))
10886 (void) XWithdrawWindow(display,windows->info.id,
10887 windows->info.screen);
10888 }
10889 else
10890 if ((x > (int) (windows->info.x+windows->info.width)) ||
10891 (y > (int) (windows->info.y+windows->info.height)))
10892 (void) XMapWindow(display,windows->info.id);
10893 paste_info.x=(ssize_t) windows->image.x+x;
10894 paste_info.y=(ssize_t) windows->image.y+y;
10895 break;
10896 }
10897 default:
10898 {
10899 if (image->debug != MagickFalse )
10900 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
10901 event.type);
10902 break;
10903 }
10904 }
10905 } while ((state & ExitState) == 0);
10906 (void) XSelectInput(display,windows->image.id,
10907 windows->image.attributes.event_mask);
10908 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
10909 XSetCursorState(display,windows,MagickFalse);
10910 (void) XFreeCursor(display,cursor);
10911 if ((state & EscapeState) != 0)
10912 return(MagickTrue);
10913 /*
10914 Image pasting is relative to image configuration.
10915 */
10916 XSetCursorState(display,windows,MagickTrue);
10917 XCheckRefreshWindows(display,windows);
10918 width=(unsigned int) image->columns;
10919 height=(unsigned int) image->rows;
10920 x=0;
10921 y=0;
10922 if (windows->image.crop_geometry != (char *) NULL)
10923 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
10924 scale_factor=(double) width/windows->image.ximage->width;
10925 paste_info.x+=x;
10926 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5);
10927 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5);
10928 scale_factor=(double) height/windows->image.ximage->height;
10929 paste_info.y+=y;
10930 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5);
10931 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5);
10932 /*
10933 Paste image with X Image window.
10934 */
10935 (void) CompositeImage(image,paste_image,compose,MagickTrue,paste_info.x,
10936 paste_info.y,exception);
10937 paste_image=DestroyImage(paste_image);
10938 XSetCursorState(display,windows,MagickFalse);
10939 /*
10940 Update image colormap.
10941 */
10942 XConfigureImageColormap(display,resource_info,windows,image,exception);
10943 (void) XConfigureImage(display,resource_info,windows,image,exception);
10944 return(MagickTrue);
10945 }
10946
10947 /*
10948 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10949 % %
10950 % %
10951 % %
10952 + X P r i n t I m a g e %
10953 % %
10954 % %
10955 % %
10956 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10957 %
10958 % XPrintImage() prints an image to a Postscript printer.
10959 %
10960 % The format of the XPrintImage method is:
10961 %
10962 % MagickBooleanType XPrintImage(Display *display,
10963 % XResourceInfo *resource_info,XWindows *windows,Image *image,
10964 % ExceptionInfo *exception)
10965 %
10966 % A description of each parameter follows:
10967 %
10968 % o display: Specifies a connection to an X server; returned from
10969 % XOpenDisplay.
10970 %
10971 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10972 %
10973 % o windows: Specifies a pointer to a XWindows structure.
10974 %
10975 % o image: the image.
10976 %
10977 % o exception: return any errors or warnings in this structure.
10978 %
10979 */
XPrintImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,ExceptionInfo * exception)10980 static MagickBooleanType XPrintImage(Display *display,
10981 XResourceInfo *resource_info,XWindows *windows,Image *image,
10982 ExceptionInfo *exception)
10983 {
10984 char
10985 filename[MagickPathExtent],
10986 geometry[MagickPathExtent];
10987
10988 Image
10989 *print_image;
10990
10991 ImageInfo
10992 *image_info;
10993
10994 MagickStatusType
10995 status;
10996
10997 /*
10998 Request Postscript page geometry from user.
10999 */
11000 image_info=CloneImageInfo(resource_info->image_info);
11001 (void) FormatLocaleString(geometry,MagickPathExtent,"Letter");
11002 if (image_info->page != (char *) NULL)
11003 (void) CopyMagickString(geometry,image_info->page,MagickPathExtent);
11004 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
11005 "Select Postscript Page Geometry:",geometry);
11006 if (*geometry == '\0')
11007 return(MagickTrue);
11008 image_info->page=GetPageGeometry(geometry);
11009 /*
11010 Apply image transforms.
11011 */
11012 XSetCursorState(display,windows,MagickTrue);
11013 XCheckRefreshWindows(display,windows);
11014 print_image=CloneImage(image,0,0,MagickTrue,exception);
11015 if (print_image == (Image *) NULL)
11016 return(MagickFalse);
11017 (void) FormatLocaleString(geometry,MagickPathExtent,"%dx%d!",
11018 windows->image.ximage->width,windows->image.ximage->height);
11019 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry,
11020 exception);
11021 /*
11022 Print image.
11023 */
11024 (void) AcquireUniqueFilename(filename);
11025 (void) FormatLocaleString(print_image->filename,MagickPathExtent,"print:%s",
11026 filename);
11027 status=WriteImage(image_info,print_image,exception);
11028 (void) RelinquishUniqueFileResource(filename);
11029 print_image=DestroyImage(print_image);
11030 image_info=DestroyImageInfo(image_info);
11031 XSetCursorState(display,windows,MagickFalse);
11032 return(status != 0 ? MagickTrue : MagickFalse);
11033 }
11034
11035 /*
11036 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11037 % %
11038 % %
11039 % %
11040 + X R O I I m a g e %
11041 % %
11042 % %
11043 % %
11044 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11045 %
11046 % XROIImage() applies an image processing technique to a region of interest.
11047 %
11048 % The format of the XROIImage method is:
11049 %
11050 % MagickBooleanType XROIImage(Display *display,
11051 % XResourceInfo *resource_info,XWindows *windows,Image **image,
11052 % ExceptionInfo *exception)
11053 %
11054 % A description of each parameter follows:
11055 %
11056 % o display: Specifies a connection to an X server; returned from
11057 % XOpenDisplay.
11058 %
11059 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
11060 %
11061 % o windows: Specifies a pointer to a XWindows structure.
11062 %
11063 % o image: the image; returned from ReadImage.
11064 %
11065 % o exception: return any errors or warnings in this structure.
11066 %
11067 */
XROIImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image ** image,ExceptionInfo * exception)11068 static MagickBooleanType XROIImage(Display *display,
11069 XResourceInfo *resource_info,XWindows *windows,Image **image,
11070 ExceptionInfo *exception)
11071 {
11072 #define ApplyMenus 7
11073
11074 static const char
11075 *ROIMenu[] =
11076 {
11077 "Help",
11078 "Dismiss",
11079 (char *) NULL
11080 },
11081 *ApplyMenu[] =
11082 {
11083 "File",
11084 "Edit",
11085 "Transform",
11086 "Enhance",
11087 "Effects",
11088 "F/X",
11089 "Miscellany",
11090 "Help",
11091 "Dismiss",
11092 (char *) NULL
11093 },
11094 *FileMenu[] =
11095 {
11096 "Save...",
11097 "Print...",
11098 (char *) NULL
11099 },
11100 *EditMenu[] =
11101 {
11102 "Undo",
11103 "Redo",
11104 (char *) NULL
11105 },
11106 *TransformMenu[] =
11107 {
11108 "Flop",
11109 "Flip",
11110 "Rotate Right",
11111 "Rotate Left",
11112 (char *) NULL
11113 },
11114 *EnhanceMenu[] =
11115 {
11116 "Hue...",
11117 "Saturation...",
11118 "Brightness...",
11119 "Gamma...",
11120 "Spiff",
11121 "Dull",
11122 "Contrast Stretch...",
11123 "Sigmoidal Contrast...",
11124 "Normalize",
11125 "Equalize",
11126 "Negate",
11127 "Grayscale",
11128 "Map...",
11129 "Quantize...",
11130 (char *) NULL
11131 },
11132 *EffectsMenu[] =
11133 {
11134 "Despeckle",
11135 "Emboss",
11136 "Reduce Noise",
11137 "Add Noise",
11138 "Sharpen...",
11139 "Blur...",
11140 "Threshold...",
11141 "Edge Detect...",
11142 "Spread...",
11143 "Shade...",
11144 "Raise...",
11145 "Segment...",
11146 (char *) NULL
11147 },
11148 *FXMenu[] =
11149 {
11150 "Solarize...",
11151 "Sepia Tone...",
11152 "Swirl...",
11153 "Implode...",
11154 "Vignette...",
11155 "Wave...",
11156 "Oil Paint...",
11157 "Charcoal Draw...",
11158 (char *) NULL
11159 },
11160 *MiscellanyMenu[] =
11161 {
11162 "Image Info",
11163 "Zoom Image",
11164 "Show Preview...",
11165 "Show Histogram",
11166 "Show Matte",
11167 (char *) NULL
11168 };
11169
11170 static const char
11171 **Menus[ApplyMenus] =
11172 {
11173 FileMenu,
11174 EditMenu,
11175 TransformMenu,
11176 EnhanceMenu,
11177 EffectsMenu,
11178 FXMenu,
11179 MiscellanyMenu
11180 };
11181
11182 static const CommandType
11183 ApplyCommands[] =
11184 {
11185 NullCommand,
11186 NullCommand,
11187 NullCommand,
11188 NullCommand,
11189 NullCommand,
11190 NullCommand,
11191 NullCommand,
11192 HelpCommand,
11193 QuitCommand
11194 },
11195 FileCommands[] =
11196 {
11197 SaveCommand,
11198 PrintCommand
11199 },
11200 EditCommands[] =
11201 {
11202 UndoCommand,
11203 RedoCommand
11204 },
11205 TransformCommands[] =
11206 {
11207 FlopCommand,
11208 FlipCommand,
11209 RotateRightCommand,
11210 RotateLeftCommand
11211 },
11212 EnhanceCommands[] =
11213 {
11214 HueCommand,
11215 SaturationCommand,
11216 BrightnessCommand,
11217 GammaCommand,
11218 SpiffCommand,
11219 DullCommand,
11220 ContrastStretchCommand,
11221 SigmoidalContrastCommand,
11222 NormalizeCommand,
11223 EqualizeCommand,
11224 NegateCommand,
11225 GrayscaleCommand,
11226 MapCommand,
11227 QuantizeCommand
11228 },
11229 EffectsCommands[] =
11230 {
11231 DespeckleCommand,
11232 EmbossCommand,
11233 ReduceNoiseCommand,
11234 AddNoiseCommand,
11235 SharpenCommand,
11236 BlurCommand,
11237 EdgeDetectCommand,
11238 SpreadCommand,
11239 ShadeCommand,
11240 RaiseCommand,
11241 SegmentCommand
11242 },
11243 FXCommands[] =
11244 {
11245 SolarizeCommand,
11246 SepiaToneCommand,
11247 SwirlCommand,
11248 ImplodeCommand,
11249 VignetteCommand,
11250 WaveCommand,
11251 OilPaintCommand,
11252 CharcoalDrawCommand
11253 },
11254 MiscellanyCommands[] =
11255 {
11256 InfoCommand,
11257 ZoomCommand,
11258 ShowPreviewCommand,
11259 ShowHistogramCommand,
11260 ShowMatteCommand
11261 },
11262 ROICommands[] =
11263 {
11264 ROIHelpCommand,
11265 ROIDismissCommand
11266 };
11267
11268 static const CommandType
11269 *Commands[ApplyMenus] =
11270 {
11271 FileCommands,
11272 EditCommands,
11273 TransformCommands,
11274 EnhanceCommands,
11275 EffectsCommands,
11276 FXCommands,
11277 MiscellanyCommands
11278 };
11279
11280 char
11281 command[MagickPathExtent],
11282 text[MagickPathExtent];
11283
11284 CommandType
11285 command_type;
11286
11287 Cursor
11288 cursor;
11289
11290 Image
11291 *roi_image;
11292
11293 int
11294 entry,
11295 id,
11296 x,
11297 y;
11298
11299 double
11300 scale_factor;
11301
11302 MagickProgressMonitor
11303 progress_monitor;
11304
11305 RectangleInfo
11306 crop_info,
11307 highlight_info,
11308 roi_info;
11309
11310 unsigned int
11311 height,
11312 width;
11313
11314 size_t
11315 state;
11316
11317 XEvent
11318 event;
11319
11320 /*
11321 Map Command widget.
11322 */
11323 (void) CloneString(&windows->command.name,"ROI");
11324 windows->command.data=0;
11325 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL);
11326 (void) XMapRaised(display,windows->command.id);
11327 XClientMessage(display,windows->image.id,windows->im_protocols,
11328 windows->im_update_widget,CurrentTime);
11329 /*
11330 Track pointer until button 1 is pressed.
11331 */
11332 XQueryPosition(display,windows->image.id,&x,&y);
11333 (void) XSelectInput(display,windows->image.id,
11334 windows->image.attributes.event_mask | PointerMotionMask);
11335 roi_info.x=(ssize_t) windows->image.x+x;
11336 roi_info.y=(ssize_t) windows->image.y+y;
11337 roi_info.width=0;
11338 roi_info.height=0;
11339 cursor=XCreateFontCursor(display,XC_fleur);
11340 state=DefaultState;
11341 do
11342 {
11343 if (windows->info.mapped != MagickFalse )
11344 {
11345 /*
11346 Display pointer position.
11347 */
11348 (void) FormatLocaleString(text,MagickPathExtent," %+ld%+ld ",
11349 (long) roi_info.x,(long) roi_info.y);
11350 XInfoWidget(display,windows,text);
11351 }
11352 /*
11353 Wait for next event.
11354 */
11355 XScreenEvent(display,windows,&event,exception);
11356 if (event.xany.window == windows->command.id)
11357 {
11358 /*
11359 Select a command from the Command widget.
11360 */
11361 id=XCommandWidget(display,windows,ROIMenu,&event);
11362 if (id < 0)
11363 continue;
11364 switch (ROICommands[id])
11365 {
11366 case ROIHelpCommand:
11367 {
11368 XTextViewWidget(display,resource_info,windows,MagickFalse,
11369 "Help Viewer - Region of Interest",ImageROIHelp);
11370 break;
11371 }
11372 case ROIDismissCommand:
11373 {
11374 /*
11375 Prematurely exit.
11376 */
11377 state|=EscapeState;
11378 state|=ExitState;
11379 break;
11380 }
11381 default:
11382 break;
11383 }
11384 continue;
11385 }
11386 switch (event.type)
11387 {
11388 case ButtonPress:
11389 {
11390 if (event.xbutton.button != Button1)
11391 break;
11392 if (event.xbutton.window != windows->image.id)
11393 break;
11394 /*
11395 Note first corner of region of interest rectangle-- exit loop.
11396 */
11397 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11398 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11399 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11400 state|=ExitState;
11401 break;
11402 }
11403 case ButtonRelease:
11404 break;
11405 case Expose:
11406 break;
11407 case KeyPress:
11408 {
11409 KeySym
11410 key_symbol;
11411
11412 if (event.xkey.window != windows->image.id)
11413 break;
11414 /*
11415 Respond to a user key press.
11416 */
11417 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11418 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11419 switch ((int) key_symbol)
11420 {
11421 case XK_Escape:
11422 case XK_F20:
11423 {
11424 /*
11425 Prematurely exit.
11426 */
11427 state|=EscapeState;
11428 state|=ExitState;
11429 break;
11430 }
11431 case XK_F1:
11432 case XK_Help:
11433 {
11434 XTextViewWidget(display,resource_info,windows,MagickFalse,
11435 "Help Viewer - Region of Interest",ImageROIHelp);
11436 break;
11437 }
11438 default:
11439 {
11440 (void) XBell(display,0);
11441 break;
11442 }
11443 }
11444 break;
11445 }
11446 case MotionNotify:
11447 {
11448 /*
11449 Map and unmap Info widget as text cursor crosses its boundaries.
11450 */
11451 x=event.xmotion.x;
11452 y=event.xmotion.y;
11453 if (windows->info.mapped != MagickFalse )
11454 {
11455 if ((x < (int) (windows->info.x+windows->info.width)) &&
11456 (y < (int) (windows->info.y+windows->info.height)))
11457 (void) XWithdrawWindow(display,windows->info.id,
11458 windows->info.screen);
11459 }
11460 else
11461 if ((x > (int) (windows->info.x+windows->info.width)) ||
11462 (y > (int) (windows->info.y+windows->info.height)))
11463 (void) XMapWindow(display,windows->info.id);
11464 roi_info.x=(ssize_t) windows->image.x+x;
11465 roi_info.y=(ssize_t) windows->image.y+y;
11466 break;
11467 }
11468 default:
11469 break;
11470 }
11471 } while ((state & ExitState) == 0);
11472 (void) XSelectInput(display,windows->image.id,
11473 windows->image.attributes.event_mask);
11474 if ((state & EscapeState) != 0)
11475 {
11476 /*
11477 User want to exit without region of interest.
11478 */
11479 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11480 (void) XFreeCursor(display,cursor);
11481 return(MagickTrue);
11482 }
11483 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
11484 do
11485 {
11486 /*
11487 Size rectangle as pointer moves until the mouse button is released.
11488 */
11489 x=(int) roi_info.x;
11490 y=(int) roi_info.y;
11491 roi_info.width=0;
11492 roi_info.height=0;
11493 state=DefaultState;
11494 do
11495 {
11496 highlight_info=roi_info;
11497 highlight_info.x=roi_info.x-windows->image.x;
11498 highlight_info.y=roi_info.y-windows->image.y;
11499 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11500 {
11501 /*
11502 Display info and draw region of interest rectangle.
11503 */
11504 if (windows->info.mapped == MagickFalse)
11505 (void) XMapWindow(display,windows->info.id);
11506 (void) FormatLocaleString(text,MagickPathExtent,
11507 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11508 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11509 XInfoWidget(display,windows,text);
11510 XHighlightRectangle(display,windows->image.id,
11511 windows->image.highlight_context,&highlight_info);
11512 }
11513 else
11514 if (windows->info.mapped != MagickFalse )
11515 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11516 /*
11517 Wait for next event.
11518 */
11519 XScreenEvent(display,windows,&event,exception);
11520 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11521 XHighlightRectangle(display,windows->image.id,
11522 windows->image.highlight_context,&highlight_info);
11523 switch (event.type)
11524 {
11525 case ButtonPress:
11526 {
11527 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11528 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11529 break;
11530 }
11531 case ButtonRelease:
11532 {
11533 /*
11534 User has committed to region of interest rectangle.
11535 */
11536 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11537 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11538 XSetCursorState(display,windows,MagickFalse);
11539 state|=ExitState;
11540 if (LocaleCompare(windows->command.name,"Apply") == 0)
11541 break;
11542 (void) CloneString(&windows->command.name,"Apply");
11543 windows->command.data=ApplyMenus;
11544 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL);
11545 break;
11546 }
11547 case Expose:
11548 break;
11549 case MotionNotify:
11550 {
11551 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11552 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
11553 }
11554 default:
11555 break;
11556 }
11557 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) ||
11558 ((state & ExitState) != 0))
11559 {
11560 /*
11561 Check boundary conditions.
11562 */
11563 if (roi_info.x < 0)
11564 roi_info.x=0;
11565 else
11566 if (roi_info.x > (ssize_t) windows->image.ximage->width)
11567 roi_info.x=(ssize_t) windows->image.ximage->width;
11568 if ((int) roi_info.x < x)
11569 roi_info.width=(unsigned int) (x-roi_info.x);
11570 else
11571 {
11572 roi_info.width=(unsigned int) (roi_info.x-x);
11573 roi_info.x=(ssize_t) x;
11574 }
11575 if (roi_info.y < 0)
11576 roi_info.y=0;
11577 else
11578 if (roi_info.y > (ssize_t) windows->image.ximage->height)
11579 roi_info.y=(ssize_t) windows->image.ximage->height;
11580 if ((int) roi_info.y < y)
11581 roi_info.height=(unsigned int) (y-roi_info.y);
11582 else
11583 {
11584 roi_info.height=(unsigned int) (roi_info.y-y);
11585 roi_info.y=(ssize_t) y;
11586 }
11587 }
11588 } while ((state & ExitState) == 0);
11589 /*
11590 Wait for user to grab a corner of the rectangle or press return.
11591 */
11592 state=DefaultState;
11593 command_type=NullCommand;
11594 crop_info.x=0;
11595 crop_info.y=0;
11596 (void) XMapWindow(display,windows->info.id);
11597 do
11598 {
11599 if (windows->info.mapped != MagickFalse )
11600 {
11601 /*
11602 Display pointer position.
11603 */
11604 (void) FormatLocaleString(text,MagickPathExtent,
11605 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11606 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11607 XInfoWidget(display,windows,text);
11608 }
11609 highlight_info=roi_info;
11610 highlight_info.x=roi_info.x-windows->image.x;
11611 highlight_info.y=roi_info.y-windows->image.y;
11612 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
11613 {
11614 state|=EscapeState;
11615 state|=ExitState;
11616 break;
11617 }
11618 if ((state & UpdateRegionState) != 0)
11619 {
11620 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11621 switch (command_type)
11622 {
11623 case UndoCommand:
11624 case RedoCommand:
11625 {
11626 (void) XMagickCommand(display,resource_info,windows,command_type,
11627 image,exception);
11628 break;
11629 }
11630 default:
11631 {
11632 /*
11633 Region of interest is relative to image configuration.
11634 */
11635 progress_monitor=SetImageProgressMonitor(*image,
11636 (MagickProgressMonitor) NULL,(*image)->client_data);
11637 crop_info=roi_info;
11638 width=(unsigned int) (*image)->columns;
11639 height=(unsigned int) (*image)->rows;
11640 x=0;
11641 y=0;
11642 if (windows->image.crop_geometry != (char *) NULL)
11643 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
11644 &width,&height);
11645 scale_factor=(double) width/windows->image.ximage->width;
11646 crop_info.x+=x;
11647 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
11648 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
11649 scale_factor=(double)
11650 height/windows->image.ximage->height;
11651 crop_info.y+=y;
11652 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
11653 crop_info.height=(unsigned int)
11654 (scale_factor*crop_info.height+0.5);
11655 roi_image=CropImage(*image,&crop_info,exception);
11656 (void) SetImageProgressMonitor(*image,progress_monitor,
11657 (*image)->client_data);
11658 if (roi_image == (Image *) NULL)
11659 continue;
11660 /*
11661 Apply image processing technique to the region of interest.
11662 */
11663 windows->image.orphan=MagickTrue;
11664 (void) XMagickCommand(display,resource_info,windows,command_type,
11665 &roi_image,exception);
11666 progress_monitor=SetImageProgressMonitor(*image,
11667 (MagickProgressMonitor) NULL,(*image)->client_data);
11668 (void) XMagickCommand(display,resource_info,windows,
11669 SaveToUndoBufferCommand,image,exception);
11670 windows->image.orphan=MagickFalse;
11671 (void) CompositeImage(*image,roi_image,CopyCompositeOp,
11672 MagickTrue,crop_info.x,crop_info.y,exception);
11673 roi_image=DestroyImage(roi_image);
11674 (void) SetImageProgressMonitor(*image,progress_monitor,
11675 (*image)->client_data);
11676 break;
11677 }
11678 }
11679 if (command_type != InfoCommand)
11680 {
11681 XConfigureImageColormap(display,resource_info,windows,*image,
11682 exception);
11683 (void) XConfigureImage(display,resource_info,windows,*image,
11684 exception);
11685 }
11686 XCheckRefreshWindows(display,windows);
11687 XInfoWidget(display,windows,text);
11688 (void) XSetFunction(display,windows->image.highlight_context,
11689 GXinvert);
11690 state&=(~UpdateRegionState);
11691 }
11692 XHighlightRectangle(display,windows->image.id,
11693 windows->image.highlight_context,&highlight_info);
11694 XScreenEvent(display,windows,&event,exception);
11695 if (event.xany.window == windows->command.id)
11696 {
11697 /*
11698 Select a command from the Command widget.
11699 */
11700 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11701 command_type=NullCommand;
11702 id=XCommandWidget(display,windows,ApplyMenu,&event);
11703 if (id >= 0)
11704 {
11705 (void) CopyMagickString(command,ApplyMenu[id],MagickPathExtent);
11706 command_type=ApplyCommands[id];
11707 if (id < ApplyMenus)
11708 {
11709 /*
11710 Select a command from a pop-up menu.
11711 */
11712 entry=XMenuWidget(display,windows,ApplyMenu[id],
11713 (const char **) Menus[id],command);
11714 if (entry >= 0)
11715 {
11716 (void) CopyMagickString(command,Menus[id][entry],
11717 MagickPathExtent);
11718 command_type=Commands[id][entry];
11719 }
11720 }
11721 }
11722 (void) XSetFunction(display,windows->image.highlight_context,
11723 GXinvert);
11724 XHighlightRectangle(display,windows->image.id,
11725 windows->image.highlight_context,&highlight_info);
11726 if (command_type == HelpCommand)
11727 {
11728 (void) XSetFunction(display,windows->image.highlight_context,
11729 GXcopy);
11730 XTextViewWidget(display,resource_info,windows,MagickFalse,
11731 "Help Viewer - Region of Interest",ImageROIHelp);
11732 (void) XSetFunction(display,windows->image.highlight_context,
11733 GXinvert);
11734 continue;
11735 }
11736 if (command_type == QuitCommand)
11737 {
11738 /*
11739 exit.
11740 */
11741 state|=EscapeState;
11742 state|=ExitState;
11743 continue;
11744 }
11745 if (command_type != NullCommand)
11746 state|=UpdateRegionState;
11747 continue;
11748 }
11749 XHighlightRectangle(display,windows->image.id,
11750 windows->image.highlight_context,&highlight_info);
11751 switch (event.type)
11752 {
11753 case ButtonPress:
11754 {
11755 x=windows->image.x;
11756 y=windows->image.y;
11757 if (event.xbutton.button != Button1)
11758 break;
11759 if (event.xbutton.window != windows->image.id)
11760 break;
11761 x=windows->image.x+event.xbutton.x;
11762 y=windows->image.y+event.xbutton.y;
11763 if ((x < (int) (roi_info.x+RoiDelta)) &&
11764 (x > (int) (roi_info.x-RoiDelta)) &&
11765 (y < (int) (roi_info.y+RoiDelta)) &&
11766 (y > (int) (roi_info.y-RoiDelta)))
11767 {
11768 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
11769 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
11770 state|=UpdateConfigurationState;
11771 break;
11772 }
11773 if ((x < (int) (roi_info.x+RoiDelta)) &&
11774 (x > (int) (roi_info.x-RoiDelta)) &&
11775 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11776 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11777 {
11778 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
11779 state|=UpdateConfigurationState;
11780 break;
11781 }
11782 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11783 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11784 (y < (int) (roi_info.y+RoiDelta)) &&
11785 (y > (int) (roi_info.y-RoiDelta)))
11786 {
11787 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
11788 state|=UpdateConfigurationState;
11789 break;
11790 }
11791 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11792 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11793 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11794 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11795 {
11796 state|=UpdateConfigurationState;
11797 break;
11798 }
11799 }
11800 case ButtonRelease:
11801 {
11802 if (event.xbutton.window == windows->pan.id)
11803 if ((highlight_info.x != crop_info.x-windows->image.x) ||
11804 (highlight_info.y != crop_info.y-windows->image.y))
11805 XHighlightRectangle(display,windows->image.id,
11806 windows->image.highlight_context,&highlight_info);
11807 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11808 event.xbutton.time);
11809 break;
11810 }
11811 case Expose:
11812 {
11813 if (event.xexpose.window == windows->image.id)
11814 if (event.xexpose.count == 0)
11815 {
11816 event.xexpose.x=(int) highlight_info.x;
11817 event.xexpose.y=(int) highlight_info.y;
11818 event.xexpose.width=(int) highlight_info.width;
11819 event.xexpose.height=(int) highlight_info.height;
11820 XRefreshWindow(display,&windows->image,&event);
11821 }
11822 if (event.xexpose.window == windows->info.id)
11823 if (event.xexpose.count == 0)
11824 XInfoWidget(display,windows,text);
11825 break;
11826 }
11827 case KeyPress:
11828 {
11829 KeySym
11830 key_symbol;
11831
11832 if (event.xkey.window != windows->image.id)
11833 break;
11834 /*
11835 Respond to a user key press.
11836 */
11837 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11838 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11839 switch ((int) key_symbol)
11840 {
11841 case XK_Shift_L:
11842 case XK_Shift_R:
11843 break;
11844 case XK_Escape:
11845 case XK_F20:
11846 state|=EscapeState;
11847 case XK_Return:
11848 {
11849 state|=ExitState;
11850 break;
11851 }
11852 case XK_Home:
11853 case XK_KP_Home:
11854 {
11855 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L);
11856 roi_info.y=(ssize_t) (windows->image.height/2L-
11857 roi_info.height/2L);
11858 break;
11859 }
11860 case XK_Left:
11861 case XK_KP_Left:
11862 {
11863 roi_info.x--;
11864 break;
11865 }
11866 case XK_Up:
11867 case XK_KP_Up:
11868 case XK_Next:
11869 {
11870 roi_info.y--;
11871 break;
11872 }
11873 case XK_Right:
11874 case XK_KP_Right:
11875 {
11876 roi_info.x++;
11877 break;
11878 }
11879 case XK_Prior:
11880 case XK_Down:
11881 case XK_KP_Down:
11882 {
11883 roi_info.y++;
11884 break;
11885 }
11886 case XK_F1:
11887 case XK_Help:
11888 {
11889 (void) XSetFunction(display,windows->image.highlight_context,
11890 GXcopy);
11891 XTextViewWidget(display,resource_info,windows,MagickFalse,
11892 "Help Viewer - Region of Interest",ImageROIHelp);
11893 (void) XSetFunction(display,windows->image.highlight_context,
11894 GXinvert);
11895 break;
11896 }
11897 default:
11898 {
11899 command_type=XImageWindowCommand(display,resource_info,windows,
11900 event.xkey.state,key_symbol,image,exception);
11901 if (command_type != NullCommand)
11902 state|=UpdateRegionState;
11903 break;
11904 }
11905 }
11906 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11907 event.xkey.time);
11908 break;
11909 }
11910 case KeyRelease:
11911 break;
11912 case MotionNotify:
11913 {
11914 if (event.xbutton.window != windows->image.id)
11915 break;
11916 /*
11917 Map and unmap Info widget as text cursor crosses its boundaries.
11918 */
11919 x=event.xmotion.x;
11920 y=event.xmotion.y;
11921 if (windows->info.mapped != MagickFalse )
11922 {
11923 if ((x < (int) (windows->info.x+windows->info.width)) &&
11924 (y < (int) (windows->info.y+windows->info.height)))
11925 (void) XWithdrawWindow(display,windows->info.id,
11926 windows->info.screen);
11927 }
11928 else
11929 if ((x > (int) (windows->info.x+windows->info.width)) ||
11930 (y > (int) (windows->info.y+windows->info.height)))
11931 (void) XMapWindow(display,windows->info.id);
11932 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11933 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
11934 break;
11935 }
11936 case SelectionRequest:
11937 {
11938 XSelectionEvent
11939 notify;
11940
11941 XSelectionRequestEvent
11942 *request;
11943
11944 /*
11945 Set primary selection.
11946 */
11947 (void) FormatLocaleString(text,MagickPathExtent,
11948 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11949 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11950 request=(&(event.xselectionrequest));
11951 (void) XChangeProperty(request->display,request->requestor,
11952 request->property,request->target,8,PropModeReplace,
11953 (unsigned char *) text,(int) strlen(text));
11954 notify.type=SelectionNotify;
11955 notify.display=request->display;
11956 notify.requestor=request->requestor;
11957 notify.selection=request->selection;
11958 notify.target=request->target;
11959 notify.time=request->time;
11960 if (request->property == None)
11961 notify.property=request->target;
11962 else
11963 notify.property=request->property;
11964 (void) XSendEvent(request->display,request->requestor,False,0,
11965 (XEvent *) ¬ify);
11966 }
11967 default:
11968 break;
11969 }
11970 if ((state & UpdateConfigurationState) != 0)
11971 {
11972 (void) XPutBackEvent(display,&event);
11973 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11974 break;
11975 }
11976 } while ((state & ExitState) == 0);
11977 } while ((state & ExitState) == 0);
11978 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11979 XSetCursorState(display,windows,MagickFalse);
11980 if ((state & EscapeState) != 0)
11981 return(MagickTrue);
11982 return(MagickTrue);
11983 }
11984
11985 /*
11986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11987 % %
11988 % %
11989 % %
11990 + X R o t a t e I m a g e %
11991 % %
11992 % %
11993 % %
11994 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11995 %
11996 % XRotateImage() rotates the X image. If the degrees parameter if zero, the
11997 % rotation angle is computed from the slope of a line drawn by the user.
11998 %
11999 % The format of the XRotateImage method is:
12000 %
12001 % MagickBooleanType XRotateImage(Display *display,
12002 % XResourceInfo *resource_info,XWindows *windows,double degrees,
12003 % Image **image,ExceptionInfo *exception)
12004 %
12005 % A description of each parameter follows:
12006 %
12007 % o display: Specifies a connection to an X server; returned from
12008 % XOpenDisplay.
12009 %
12010 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12011 %
12012 % o windows: Specifies a pointer to a XWindows structure.
12013 %
12014 % o degrees: Specifies the number of degrees to rotate the image.
12015 %
12016 % o image: the image.
12017 %
12018 % o exception: return any errors or warnings in this structure.
12019 %
12020 */
XRotateImage(Display * display,XResourceInfo * resource_info,XWindows * windows,double degrees,Image ** image,ExceptionInfo * exception)12021 static MagickBooleanType XRotateImage(Display *display,
12022 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image,
12023 ExceptionInfo *exception)
12024 {
12025 static const char
12026 *RotateMenu[] =
12027 {
12028 "Pixel Color",
12029 "Direction",
12030 "Help",
12031 "Dismiss",
12032 (char *) NULL
12033 };
12034
12035 static ModeType
12036 direction = HorizontalRotateCommand;
12037
12038 static const ModeType
12039 DirectionCommands[] =
12040 {
12041 HorizontalRotateCommand,
12042 VerticalRotateCommand
12043 },
12044 RotateCommands[] =
12045 {
12046 RotateColorCommand,
12047 RotateDirectionCommand,
12048 RotateHelpCommand,
12049 RotateDismissCommand
12050 };
12051
12052 static unsigned int
12053 pen_id = 0;
12054
12055 char
12056 command[MagickPathExtent],
12057 text[MagickPathExtent];
12058
12059 Image
12060 *rotate_image;
12061
12062 int
12063 id,
12064 x,
12065 y;
12066
12067 double
12068 normalized_degrees;
12069
12070 register int
12071 i;
12072
12073 unsigned int
12074 height,
12075 rotations,
12076 width;
12077
12078 if (degrees == 0.0)
12079 {
12080 unsigned int
12081 distance;
12082
12083 size_t
12084 state;
12085
12086 XEvent
12087 event;
12088
12089 XSegment
12090 rotate_info;
12091
12092 /*
12093 Map Command widget.
12094 */
12095 (void) CloneString(&windows->command.name,"Rotate");
12096 windows->command.data=2;
12097 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL);
12098 (void) XMapRaised(display,windows->command.id);
12099 XClientMessage(display,windows->image.id,windows->im_protocols,
12100 windows->im_update_widget,CurrentTime);
12101 /*
12102 Wait for first button press.
12103 */
12104 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
12105 XQueryPosition(display,windows->image.id,&x,&y);
12106 rotate_info.x1=x;
12107 rotate_info.y1=y;
12108 rotate_info.x2=x;
12109 rotate_info.y2=y;
12110 state=DefaultState;
12111 do
12112 {
12113 XHighlightLine(display,windows->image.id,
12114 windows->image.highlight_context,&rotate_info);
12115 /*
12116 Wait for next event.
12117 */
12118 XScreenEvent(display,windows,&event,exception);
12119 XHighlightLine(display,windows->image.id,
12120 windows->image.highlight_context,&rotate_info);
12121 if (event.xany.window == windows->command.id)
12122 {
12123 /*
12124 Select a command from the Command widget.
12125 */
12126 id=XCommandWidget(display,windows,RotateMenu,&event);
12127 if (id < 0)
12128 continue;
12129 (void) XSetFunction(display,windows->image.highlight_context,
12130 GXcopy);
12131 switch (RotateCommands[id])
12132 {
12133 case RotateColorCommand:
12134 {
12135 const char
12136 *ColorMenu[MaxNumberPens];
12137
12138 int
12139 pen_number;
12140
12141 XColor
12142 color;
12143
12144 /*
12145 Initialize menu selections.
12146 */
12147 for (i=0; i < (int) (MaxNumberPens-2); i++)
12148 ColorMenu[i]=resource_info->pen_colors[i];
12149 ColorMenu[MaxNumberPens-2]="Browser...";
12150 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
12151 /*
12152 Select a pen color from the pop-up menu.
12153 */
12154 pen_number=XMenuWidget(display,windows,RotateMenu[id],
12155 (const char **) ColorMenu,command);
12156 if (pen_number < 0)
12157 break;
12158 if (pen_number == (MaxNumberPens-2))
12159 {
12160 static char
12161 color_name[MagickPathExtent] = "gray";
12162
12163 /*
12164 Select a pen color from a dialog.
12165 */
12166 resource_info->pen_colors[pen_number]=color_name;
12167 XColorBrowserWidget(display,windows,"Select",color_name);
12168 if (*color_name == '\0')
12169 break;
12170 }
12171 /*
12172 Set pen color.
12173 */
12174 (void) XParseColor(display,windows->map_info->colormap,
12175 resource_info->pen_colors[pen_number],&color);
12176 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
12177 (unsigned int) MaxColors,&color);
12178 windows->pixel_info->pen_colors[pen_number]=color;
12179 pen_id=(unsigned int) pen_number;
12180 break;
12181 }
12182 case RotateDirectionCommand:
12183 {
12184 static const char
12185 *Directions[] =
12186 {
12187 "horizontal",
12188 "vertical",
12189 (char *) NULL,
12190 };
12191
12192 /*
12193 Select a command from the pop-up menu.
12194 */
12195 id=XMenuWidget(display,windows,RotateMenu[id],
12196 Directions,command);
12197 if (id >= 0)
12198 direction=DirectionCommands[id];
12199 break;
12200 }
12201 case RotateHelpCommand:
12202 {
12203 XTextViewWidget(display,resource_info,windows,MagickFalse,
12204 "Help Viewer - Image Rotation",ImageRotateHelp);
12205 break;
12206 }
12207 case RotateDismissCommand:
12208 {
12209 /*
12210 Prematurely exit.
12211 */
12212 state|=EscapeState;
12213 state|=ExitState;
12214 break;
12215 }
12216 default:
12217 break;
12218 }
12219 (void) XSetFunction(display,windows->image.highlight_context,
12220 GXinvert);
12221 continue;
12222 }
12223 switch (event.type)
12224 {
12225 case ButtonPress:
12226 {
12227 if (event.xbutton.button != Button1)
12228 break;
12229 if (event.xbutton.window != windows->image.id)
12230 break;
12231 /*
12232 exit loop.
12233 */
12234 (void) XSetFunction(display,windows->image.highlight_context,
12235 GXcopy);
12236 rotate_info.x1=event.xbutton.x;
12237 rotate_info.y1=event.xbutton.y;
12238 state|=ExitState;
12239 break;
12240 }
12241 case ButtonRelease:
12242 break;
12243 case Expose:
12244 break;
12245 case KeyPress:
12246 {
12247 char
12248 command[MagickPathExtent];
12249
12250 KeySym
12251 key_symbol;
12252
12253 if (event.xkey.window != windows->image.id)
12254 break;
12255 /*
12256 Respond to a user key press.
12257 */
12258 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
12259 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12260 switch ((int) key_symbol)
12261 {
12262 case XK_Escape:
12263 case XK_F20:
12264 {
12265 /*
12266 Prematurely exit.
12267 */
12268 state|=EscapeState;
12269 state|=ExitState;
12270 break;
12271 }
12272 case XK_F1:
12273 case XK_Help:
12274 {
12275 (void) XSetFunction(display,windows->image.highlight_context,
12276 GXcopy);
12277 XTextViewWidget(display,resource_info,windows,MagickFalse,
12278 "Help Viewer - Image Rotation",ImageRotateHelp);
12279 (void) XSetFunction(display,windows->image.highlight_context,
12280 GXinvert);
12281 break;
12282 }
12283 default:
12284 {
12285 (void) XBell(display,0);
12286 break;
12287 }
12288 }
12289 break;
12290 }
12291 case MotionNotify:
12292 {
12293 rotate_info.x1=event.xmotion.x;
12294 rotate_info.y1=event.xmotion.y;
12295 }
12296 }
12297 rotate_info.x2=rotate_info.x1;
12298 rotate_info.y2=rotate_info.y1;
12299 if (direction == HorizontalRotateCommand)
12300 rotate_info.x2+=32;
12301 else
12302 rotate_info.y2-=32;
12303 } while ((state & ExitState) == 0);
12304 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12305 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12306 if ((state & EscapeState) != 0)
12307 return(MagickTrue);
12308 /*
12309 Draw line as pointer moves until the mouse button is released.
12310 */
12311 distance=0;
12312 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
12313 state=DefaultState;
12314 do
12315 {
12316 if (distance > 9)
12317 {
12318 /*
12319 Display info and draw rotation line.
12320 */
12321 if (windows->info.mapped == MagickFalse)
12322 (void) XMapWindow(display,windows->info.id);
12323 (void) FormatLocaleString(text,MagickPathExtent," %g",
12324 direction == VerticalRotateCommand ? degrees-90.0 : degrees);
12325 XInfoWidget(display,windows,text);
12326 XHighlightLine(display,windows->image.id,
12327 windows->image.highlight_context,&rotate_info);
12328 }
12329 else
12330 if (windows->info.mapped != MagickFalse )
12331 (void) XWithdrawWindow(display,windows->info.id,
12332 windows->info.screen);
12333 /*
12334 Wait for next event.
12335 */
12336 XScreenEvent(display,windows,&event,exception);
12337 if (distance > 9)
12338 XHighlightLine(display,windows->image.id,
12339 windows->image.highlight_context,&rotate_info);
12340 switch (event.type)
12341 {
12342 case ButtonPress:
12343 break;
12344 case ButtonRelease:
12345 {
12346 /*
12347 User has committed to rotation line.
12348 */
12349 rotate_info.x2=event.xbutton.x;
12350 rotate_info.y2=event.xbutton.y;
12351 state|=ExitState;
12352 break;
12353 }
12354 case Expose:
12355 break;
12356 case MotionNotify:
12357 {
12358 rotate_info.x2=event.xmotion.x;
12359 rotate_info.y2=event.xmotion.y;
12360 }
12361 default:
12362 break;
12363 }
12364 /*
12365 Check boundary conditions.
12366 */
12367 if (rotate_info.x2 < 0)
12368 rotate_info.x2=0;
12369 else
12370 if (rotate_info.x2 > (int) windows->image.width)
12371 rotate_info.x2=(short) windows->image.width;
12372 if (rotate_info.y2 < 0)
12373 rotate_info.y2=0;
12374 else
12375 if (rotate_info.y2 > (int) windows->image.height)
12376 rotate_info.y2=(short) windows->image.height;
12377 /*
12378 Compute rotation angle from the slope of the line.
12379 */
12380 degrees=0.0;
12381 distance=(unsigned int)
12382 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+
12383 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1));
12384 if (distance > 9)
12385 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2-
12386 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1)));
12387 } while ((state & ExitState) == 0);
12388 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12389 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12390 if (distance <= 9)
12391 return(MagickTrue);
12392 }
12393 if (direction == VerticalRotateCommand)
12394 degrees-=90.0;
12395 if (degrees == 0.0)
12396 return(MagickTrue);
12397 /*
12398 Rotate image.
12399 */
12400 normalized_degrees=degrees;
12401 while (normalized_degrees < -45.0)
12402 normalized_degrees+=360.0;
12403 for (rotations=0; normalized_degrees > 45.0; rotations++)
12404 normalized_degrees-=90.0;
12405 if (normalized_degrees != 0.0)
12406 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
12407 exception);
12408 XSetCursorState(display,windows,MagickTrue);
12409 XCheckRefreshWindows(display,windows);
12410 (*image)->background_color.red=(double) ScaleShortToQuantum(
12411 windows->pixel_info->pen_colors[pen_id].red);
12412 (*image)->background_color.green=(double) ScaleShortToQuantum(
12413 windows->pixel_info->pen_colors[pen_id].green);
12414 (*image)->background_color.blue=(double) ScaleShortToQuantum(
12415 windows->pixel_info->pen_colors[pen_id].blue);
12416 rotate_image=RotateImage(*image,degrees,exception);
12417 XSetCursorState(display,windows,MagickFalse);
12418 if (rotate_image == (Image *) NULL)
12419 return(MagickFalse);
12420 *image=DestroyImage(*image);
12421 *image=rotate_image;
12422 if (windows->image.crop_geometry != (char *) NULL)
12423 {
12424 /*
12425 Rotate crop geometry.
12426 */
12427 width=(unsigned int) (*image)->columns;
12428 height=(unsigned int) (*image)->rows;
12429 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12430 switch (rotations % 4)
12431 {
12432 default:
12433 case 0:
12434 break;
12435 case 1:
12436 {
12437 /*
12438 Rotate 90 degrees.
12439 */
12440 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent,
12441 "%ux%u%+d%+d",height,width,(int) (*image)->columns-
12442 (int) height-y,x);
12443 break;
12444 }
12445 case 2:
12446 {
12447 /*
12448 Rotate 180 degrees.
12449 */
12450 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent,
12451 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y);
12452 break;
12453 }
12454 case 3:
12455 {
12456 /*
12457 Rotate 270 degrees.
12458 */
12459 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent,
12460 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x);
12461 break;
12462 }
12463 }
12464 }
12465 if (windows->image.orphan != MagickFalse )
12466 return(MagickTrue);
12467 if (normalized_degrees != 0.0)
12468 {
12469 /*
12470 Update image colormap.
12471 */
12472 windows->image.window_changes.width=(int) (*image)->columns;
12473 windows->image.window_changes.height=(int) (*image)->rows;
12474 if (windows->image.crop_geometry != (char *) NULL)
12475 {
12476 /*
12477 Obtain dimensions of image from crop geometry.
12478 */
12479 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
12480 &width,&height);
12481 windows->image.window_changes.width=(int) width;
12482 windows->image.window_changes.height=(int) height;
12483 }
12484 XConfigureImageColormap(display,resource_info,windows,*image,exception);
12485 }
12486 else
12487 if (((rotations % 4) == 1) || ((rotations % 4) == 3))
12488 {
12489 windows->image.window_changes.width=windows->image.ximage->height;
12490 windows->image.window_changes.height=windows->image.ximage->width;
12491 }
12492 /*
12493 Update image configuration.
12494 */
12495 (void) XConfigureImage(display,resource_info,windows,*image,exception);
12496 return(MagickTrue);
12497 }
12498
12499 /*
12500 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12501 % %
12502 % %
12503 % %
12504 + X S a v e I m a g e %
12505 % %
12506 % %
12507 % %
12508 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12509 %
12510 % XSaveImage() saves an image to a file.
12511 %
12512 % The format of the XSaveImage method is:
12513 %
12514 % MagickBooleanType XSaveImage(Display *display,
12515 % XResourceInfo *resource_info,XWindows *windows,Image *image,
12516 % ExceptionInfo *exception)
12517 %
12518 % A description of each parameter follows:
12519 %
12520 % o display: Specifies a connection to an X server; returned from
12521 % XOpenDisplay.
12522 %
12523 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12524 %
12525 % o windows: Specifies a pointer to a XWindows structure.
12526 %
12527 % o image: the image.
12528 %
12529 % o exception: return any errors or warnings in this structure.
12530 %
12531 */
XSaveImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,ExceptionInfo * exception)12532 static MagickBooleanType XSaveImage(Display *display,
12533 XResourceInfo *resource_info,XWindows *windows,Image *image,
12534 ExceptionInfo *exception)
12535 {
12536 char
12537 filename[MagickPathExtent],
12538 geometry[MagickPathExtent];
12539
12540 Image
12541 *save_image;
12542
12543 ImageInfo
12544 *image_info;
12545
12546 MagickStatusType
12547 status;
12548
12549 /*
12550 Request file name from user.
12551 */
12552 if (resource_info->write_filename != (char *) NULL)
12553 (void) CopyMagickString(filename,resource_info->write_filename,
12554 MagickPathExtent);
12555 else
12556 {
12557 char
12558 path[MagickPathExtent];
12559
12560 int
12561 status;
12562
12563 GetPathComponent(image->filename,HeadPath,path);
12564 GetPathComponent(image->filename,TailPath,filename);
12565 if (*path != '\0')
12566 {
12567 status=chdir(path);
12568 if (status == -1)
12569 (void) ThrowMagickException(exception,GetMagickModule(),
12570 FileOpenError,"UnableToOpenFile","%s",path);
12571 }
12572 }
12573 XFileBrowserWidget(display,windows,"Save",filename);
12574 if (*filename == '\0')
12575 return(MagickTrue);
12576 if (IsPathAccessible(filename) != MagickFalse )
12577 {
12578 int
12579 status;
12580
12581 /*
12582 File exists-- seek user's permission before overwriting.
12583 */
12584 status=XConfirmWidget(display,windows,"Overwrite",filename);
12585 if (status <= 0)
12586 return(MagickTrue);
12587 }
12588 image_info=CloneImageInfo(resource_info->image_info);
12589 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
12590 (void) SetImageInfo(image_info,1,exception);
12591 if ((LocaleCompare(image_info->magick,"JPEG") == 0) ||
12592 (LocaleCompare(image_info->magick,"JPG") == 0))
12593 {
12594 char
12595 quality[MagickPathExtent];
12596
12597 int
12598 status;
12599
12600 /*
12601 Request JPEG quality from user.
12602 */
12603 (void) FormatLocaleString(quality,MagickPathExtent,"%.20g",(double)
12604 image->quality);
12605 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
12606 quality);
12607 if (*quality == '\0')
12608 return(MagickTrue);
12609 image->quality=StringToUnsignedLong(quality);
12610 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace;
12611 }
12612 if ((LocaleCompare(image_info->magick,"EPS") == 0) ||
12613 (LocaleCompare(image_info->magick,"PDF") == 0) ||
12614 (LocaleCompare(image_info->magick,"PS") == 0) ||
12615 (LocaleCompare(image_info->magick,"PS2") == 0))
12616 {
12617 char
12618 geometry[MagickPathExtent];
12619
12620 /*
12621 Request page geometry from user.
12622 */
12623 (void) CopyMagickString(geometry,PSPageGeometry,MagickPathExtent);
12624 if (LocaleCompare(image_info->magick,"PDF") == 0)
12625 (void) CopyMagickString(geometry,PSPageGeometry,MagickPathExtent);
12626 if (image_info->page != (char *) NULL)
12627 (void) CopyMagickString(geometry,image_info->page,MagickPathExtent);
12628 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
12629 "Select page geometry:",geometry);
12630 if (*geometry != '\0')
12631 image_info->page=GetPageGeometry(geometry);
12632 }
12633 /*
12634 Apply image transforms.
12635 */
12636 XSetCursorState(display,windows,MagickTrue);
12637 XCheckRefreshWindows(display,windows);
12638 save_image=CloneImage(image,0,0,MagickTrue,exception);
12639 if (save_image == (Image *) NULL)
12640 return(MagickFalse);
12641 (void) FormatLocaleString(geometry,MagickPathExtent,"%dx%d!",
12642 windows->image.ximage->width,windows->image.ximage->height);
12643 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry,
12644 exception);
12645 /*
12646 Write image.
12647 */
12648 (void) CopyMagickString(save_image->filename,filename,MagickPathExtent);
12649 status=WriteImage(image_info,save_image,exception);
12650 if (status != MagickFalse )
12651 image->taint=MagickFalse;
12652 save_image=DestroyImage(save_image);
12653 image_info=DestroyImageInfo(image_info);
12654 XSetCursorState(display,windows,MagickFalse);
12655 return(status != 0 ? MagickTrue : MagickFalse);
12656 }
12657
12658 /*
12659 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12660 % %
12661 % %
12662 % %
12663 + X S c r e e n E v e n t %
12664 % %
12665 % %
12666 % %
12667 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12668 %
12669 % XScreenEvent() handles global events associated with the Pan and Magnify
12670 % windows.
12671 %
12672 % The format of the XScreenEvent function is:
12673 %
12674 % void XScreenEvent(Display *display,XWindows *windows,XEvent *event,
12675 % ExceptionInfo *exception)
12676 %
12677 % A description of each parameter follows:
12678 %
12679 % o display: Specifies a pointer to the Display structure; returned from
12680 % XOpenDisplay.
12681 %
12682 % o windows: Specifies a pointer to a XWindows structure.
12683 %
12684 % o event: Specifies a pointer to a X11 XEvent structure.
12685 %
12686 % o exception: return any errors or warnings in this structure.
12687 %
12688 */
12689
12690 #if defined(__cplusplus) || defined(c_plusplus)
12691 extern "C" {
12692 #endif
12693
XPredicate(Display * magick_unused (display),XEvent * event,char * data)12694 static int XPredicate(Display *magick_unused(display),XEvent *event,char *data)
12695 {
12696 register XWindows
12697 *windows;
12698
12699 windows=(XWindows *) data;
12700 if ((event->type == ClientMessage) &&
12701 (event->xclient.window == windows->image.id))
12702 return(MagickFalse);
12703 return(MagickTrue);
12704 }
12705
12706 #if defined(__cplusplus) || defined(c_plusplus)
12707 }
12708 #endif
12709
XScreenEvent(Display * display,XWindows * windows,XEvent * event,ExceptionInfo * exception)12710 static void XScreenEvent(Display *display,XWindows *windows,XEvent *event,
12711 ExceptionInfo *exception)
12712 {
12713 register int
12714 x,
12715 y;
12716
12717 (void) XIfEvent(display,event,XPredicate,(char *) windows);
12718 if (event->xany.window == windows->command.id)
12719 return;
12720 switch (event->type)
12721 {
12722 case ButtonPress:
12723 case ButtonRelease:
12724 {
12725 if ((event->xbutton.button == Button3) &&
12726 (event->xbutton.state & Mod1Mask))
12727 {
12728 /*
12729 Convert Alt-Button3 to Button2.
12730 */
12731 event->xbutton.button=Button2;
12732 event->xbutton.state&=(~Mod1Mask);
12733 }
12734 if (event->xbutton.window == windows->backdrop.id)
12735 {
12736 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent,
12737 event->xbutton.time);
12738 break;
12739 }
12740 if (event->xbutton.window == windows->pan.id)
12741 {
12742 XPanImage(display,windows,event,exception);
12743 break;
12744 }
12745 if (event->xbutton.window == windows->image.id)
12746 if (event->xbutton.button == Button2)
12747 {
12748 /*
12749 Update magnified image.
12750 */
12751 x=event->xbutton.x;
12752 y=event->xbutton.y;
12753 if (x < 0)
12754 x=0;
12755 else
12756 if (x >= (int) windows->image.width)
12757 x=(int) (windows->image.width-1);
12758 windows->magnify.x=(int) windows->image.x+x;
12759 if (y < 0)
12760 y=0;
12761 else
12762 if (y >= (int) windows->image.height)
12763 y=(int) (windows->image.height-1);
12764 windows->magnify.y=windows->image.y+y;
12765 if (windows->magnify.mapped == MagickFalse)
12766 (void) XMapRaised(display,windows->magnify.id);
12767 XMakeMagnifyImage(display,windows,exception);
12768 if (event->type == ButtonRelease)
12769 (void) XWithdrawWindow(display,windows->info.id,
12770 windows->info.screen);
12771 break;
12772 }
12773 break;
12774 }
12775 case ClientMessage:
12776 {
12777 /*
12778 If client window delete message, exit.
12779 */
12780 if (event->xclient.message_type != windows->wm_protocols)
12781 break;
12782 if (*event->xclient.data.l != (long) windows->wm_delete_window)
12783 break;
12784 if (event->xclient.window == windows->magnify.id)
12785 {
12786 (void) XWithdrawWindow(display,windows->magnify.id,
12787 windows->magnify.screen);
12788 break;
12789 }
12790 break;
12791 }
12792 case ConfigureNotify:
12793 {
12794 if (event->xconfigure.window == windows->magnify.id)
12795 {
12796 unsigned int
12797 magnify;
12798
12799 /*
12800 Magnify window has a new configuration.
12801 */
12802 windows->magnify.width=(unsigned int) event->xconfigure.width;
12803 windows->magnify.height=(unsigned int) event->xconfigure.height;
12804 if (windows->magnify.mapped == MagickFalse)
12805 break;
12806 magnify=1;
12807 while ((int) magnify <= event->xconfigure.width)
12808 magnify<<=1;
12809 while ((int) magnify <= event->xconfigure.height)
12810 magnify<<=1;
12811 magnify>>=1;
12812 if (((int) magnify != event->xconfigure.width) ||
12813 ((int) magnify != event->xconfigure.height))
12814 {
12815 XWindowChanges
12816 window_changes;
12817
12818 window_changes.width=(int) magnify;
12819 window_changes.height=(int) magnify;
12820 (void) XReconfigureWMWindow(display,windows->magnify.id,
12821 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
12822 &window_changes);
12823 break;
12824 }
12825 XMakeMagnifyImage(display,windows,exception);
12826 break;
12827 }
12828 break;
12829 }
12830 case Expose:
12831 {
12832 if (event->xexpose.window == windows->image.id)
12833 {
12834 XRefreshWindow(display,&windows->image,event);
12835 break;
12836 }
12837 if (event->xexpose.window == windows->pan.id)
12838 if (event->xexpose.count == 0)
12839 {
12840 XDrawPanRectangle(display,windows);
12841 break;
12842 }
12843 if (event->xexpose.window == windows->magnify.id)
12844 if (event->xexpose.count == 0)
12845 {
12846 XMakeMagnifyImage(display,windows,exception);
12847 break;
12848 }
12849 break;
12850 }
12851 case KeyPress:
12852 {
12853 char
12854 command[MagickPathExtent];
12855
12856 KeySym
12857 key_symbol;
12858
12859 if (event->xkey.window != windows->magnify.id)
12860 break;
12861 /*
12862 Respond to a user key press.
12863 */
12864 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int)
12865 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12866 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol,
12867 exception);
12868 break;
12869 }
12870 case MapNotify:
12871 {
12872 if (event->xmap.window == windows->magnify.id)
12873 {
12874 windows->magnify.mapped=MagickTrue;
12875 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12876 break;
12877 }
12878 if (event->xmap.window == windows->info.id)
12879 {
12880 windows->info.mapped=MagickTrue;
12881 break;
12882 }
12883 break;
12884 }
12885 case MotionNotify:
12886 {
12887 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ;
12888 if (event->xmotion.window == windows->image.id)
12889 if (windows->magnify.mapped != MagickFalse )
12890 {
12891 /*
12892 Update magnified image.
12893 */
12894 x=event->xmotion.x;
12895 y=event->xmotion.y;
12896 if (x < 0)
12897 x=0;
12898 else
12899 if (x >= (int) windows->image.width)
12900 x=(int) (windows->image.width-1);
12901 windows->magnify.x=(int) windows->image.x+x;
12902 if (y < 0)
12903 y=0;
12904 else
12905 if (y >= (int) windows->image.height)
12906 y=(int) (windows->image.height-1);
12907 windows->magnify.y=windows->image.y+y;
12908 XMakeMagnifyImage(display,windows,exception);
12909 }
12910 break;
12911 }
12912 case UnmapNotify:
12913 {
12914 if (event->xunmap.window == windows->magnify.id)
12915 {
12916 windows->magnify.mapped=MagickFalse;
12917 break;
12918 }
12919 if (event->xunmap.window == windows->info.id)
12920 {
12921 windows->info.mapped=MagickFalse;
12922 break;
12923 }
12924 break;
12925 }
12926 default:
12927 break;
12928 }
12929 }
12930
12931 /*
12932 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12933 % %
12934 % %
12935 % %
12936 + X S e t C r o p G e o m e t r y %
12937 % %
12938 % %
12939 % %
12940 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12941 %
12942 % XSetCropGeometry() accepts a cropping geometry relative to the Image window
12943 % and translates it to a cropping geometry relative to the image.
12944 %
12945 % The format of the XSetCropGeometry method is:
12946 %
12947 % void XSetCropGeometry(Display *display,XWindows *windows,
12948 % RectangleInfo *crop_info,Image *image)
12949 %
12950 % A description of each parameter follows:
12951 %
12952 % o display: Specifies a connection to an X server; returned from
12953 % XOpenDisplay.
12954 %
12955 % o windows: Specifies a pointer to a XWindows structure.
12956 %
12957 % o crop_info: A pointer to a RectangleInfo that defines a region of the
12958 % Image window to crop.
12959 %
12960 % o image: the image.
12961 %
12962 */
XSetCropGeometry(Display * display,XWindows * windows,RectangleInfo * crop_info,Image * image)12963 static void XSetCropGeometry(Display *display,XWindows *windows,
12964 RectangleInfo *crop_info,Image *image)
12965 {
12966 char
12967 text[MagickPathExtent];
12968
12969 int
12970 x,
12971 y;
12972
12973 double
12974 scale_factor;
12975
12976 unsigned int
12977 height,
12978 width;
12979
12980 if (windows->info.mapped != MagickFalse )
12981 {
12982 /*
12983 Display info on cropping rectangle.
12984 */
12985 (void) FormatLocaleString(text,MagickPathExtent," %.20gx%.20g%+.20g%+.20g",
12986 (double) crop_info->width,(double) crop_info->height,(double)
12987 crop_info->x,(double) crop_info->y);
12988 XInfoWidget(display,windows,text);
12989 }
12990 /*
12991 Cropping geometry is relative to any previous crop geometry.
12992 */
12993 x=0;
12994 y=0;
12995 width=(unsigned int) image->columns;
12996 height=(unsigned int) image->rows;
12997 if (windows->image.crop_geometry != (char *) NULL)
12998 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12999 else
13000 windows->image.crop_geometry=AcquireString((char *) NULL);
13001 /*
13002 Define the crop geometry string from the cropping rectangle.
13003 */
13004 scale_factor=(double) width/windows->image.ximage->width;
13005 if (crop_info->x > 0)
13006 x+=(int) (scale_factor*crop_info->x+0.5);
13007 width=(unsigned int) (scale_factor*crop_info->width+0.5);
13008 if (width == 0)
13009 width=1;
13010 scale_factor=(double) height/windows->image.ximage->height;
13011 if (crop_info->y > 0)
13012 y+=(int) (scale_factor*crop_info->y+0.5);
13013 height=(unsigned int) (scale_factor*crop_info->height+0.5);
13014 if (height == 0)
13015 height=1;
13016 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent,
13017 "%ux%u%+d%+d",width,height,x,y);
13018 }
13019
13020 /*
13021 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13022 % %
13023 % %
13024 % %
13025 + X T i l e I m a g e %
13026 % %
13027 % %
13028 % %
13029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13030 %
13031 % XTileImage() loads or deletes a selected tile from a visual image directory.
13032 % The load or delete command is chosen from a menu.
13033 %
13034 % The format of the XTileImage method is:
13035 %
13036 % Image *XTileImage(Display *display,XResourceInfo *resource_info,
13037 % XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception)
13038 %
13039 % A description of each parameter follows:
13040 %
13041 % o tile_image: XTileImage reads or deletes the tile image
13042 % and returns it. A null image is returned if an error occurs.
13043 %
13044 % o display: Specifies a connection to an X server; returned from
13045 % XOpenDisplay.
13046 %
13047 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13048 %
13049 % o windows: Specifies a pointer to a XWindows structure.
13050 %
13051 % o image: the image; returned from ReadImage.
13052 %
13053 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
13054 % the entire image is refreshed.
13055 %
13056 % o exception: return any errors or warnings in this structure.
13057 %
13058 */
XTileImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,XEvent * event,ExceptionInfo * exception)13059 static Image *XTileImage(Display *display,XResourceInfo *resource_info,
13060 XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception)
13061 {
13062 static const char
13063 *VerbMenu[] =
13064 {
13065 "Load",
13066 "Next",
13067 "Former",
13068 "Delete",
13069 "Update",
13070 (char *) NULL,
13071 };
13072
13073 static const ModeType
13074 TileCommands[] =
13075 {
13076 TileLoadCommand,
13077 TileNextCommand,
13078 TileFormerCommand,
13079 TileDeleteCommand,
13080 TileUpdateCommand
13081 };
13082
13083 char
13084 command[MagickPathExtent],
13085 filename[MagickPathExtent];
13086
13087 Image
13088 *tile_image;
13089
13090 int
13091 id,
13092 status,
13093 tile,
13094 x,
13095 y;
13096
13097 double
13098 scale_factor;
13099
13100 register char
13101 *p,
13102 *q;
13103
13104 register int
13105 i;
13106
13107 unsigned int
13108 height,
13109 width;
13110
13111 /*
13112 Tile image is relative to montage image configuration.
13113 */
13114 x=0;
13115 y=0;
13116 width=(unsigned int) image->columns;
13117 height=(unsigned int) image->rows;
13118 if (windows->image.crop_geometry != (char *) NULL)
13119 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
13120 scale_factor=(double) width/windows->image.ximage->width;
13121 event->xbutton.x+=windows->image.x;
13122 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5);
13123 scale_factor=(double) height/windows->image.ximage->height;
13124 event->xbutton.y+=windows->image.y;
13125 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5);
13126 /*
13127 Determine size and location of each tile in the visual image directory.
13128 */
13129 width=(unsigned int) image->columns;
13130 height=(unsigned int) image->rows;
13131 x=0;
13132 y=0;
13133 (void) XParseGeometry(image->montage,&x,&y,&width,&height);
13134 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+
13135 (event->xbutton.x-x)/width;
13136 if (tile < 0)
13137 {
13138 /*
13139 Button press is outside any tile.
13140 */
13141 (void) XBell(display,0);
13142 return((Image *) NULL);
13143 }
13144 /*
13145 Determine file name from the tile directory.
13146 */
13147 p=image->directory;
13148 for (i=tile; (i != 0) && (*p != '\0'); )
13149 {
13150 if (*p == '\n')
13151 i--;
13152 p++;
13153 }
13154 if (*p == '\0')
13155 {
13156 /*
13157 Button press is outside any tile.
13158 */
13159 (void) XBell(display,0);
13160 return((Image *) NULL);
13161 }
13162 /*
13163 Select a command from the pop-up menu.
13164 */
13165 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command);
13166 if (id < 0)
13167 return((Image *) NULL);
13168 q=p;
13169 while ((*q != '\n') && (*q != '\0'))
13170 q++;
13171 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13172 /*
13173 Perform command for the selected tile.
13174 */
13175 XSetCursorState(display,windows,MagickTrue);
13176 XCheckRefreshWindows(display,windows);
13177 tile_image=NewImageList();
13178 switch (TileCommands[id])
13179 {
13180 case TileLoadCommand:
13181 {
13182 /*
13183 Load tile image.
13184 */
13185 XCheckRefreshWindows(display,windows);
13186 (void) CopyMagickString(resource_info->image_info->magick,"MIFF",
13187 MagickPathExtent);
13188 (void) CopyMagickString(resource_info->image_info->filename,filename,
13189 MagickPathExtent);
13190 tile_image=ReadImage(resource_info->image_info,exception);
13191 CatchException(exception);
13192 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13193 break;
13194 }
13195 case TileNextCommand:
13196 {
13197 /*
13198 Display next image.
13199 */
13200 XClientMessage(display,windows->image.id,windows->im_protocols,
13201 windows->im_next_image,CurrentTime);
13202 break;
13203 }
13204 case TileFormerCommand:
13205 {
13206 /*
13207 Display former image.
13208 */
13209 XClientMessage(display,windows->image.id,windows->im_protocols,
13210 windows->im_former_image,CurrentTime);
13211 break;
13212 }
13213 case TileDeleteCommand:
13214 {
13215 /*
13216 Delete tile image.
13217 */
13218 if (IsPathAccessible(filename) == MagickFalse)
13219 {
13220 XNoticeWidget(display,windows,"Image file does not exist:",filename);
13221 break;
13222 }
13223 status=XConfirmWidget(display,windows,"Really delete tile",filename);
13224 if (status <= 0)
13225 break;
13226 status=ShredFile(filename);
13227 if (status != MagickFalse )
13228 {
13229 XNoticeWidget(display,windows,"Unable to delete image file:",
13230 filename);
13231 break;
13232 }
13233 }
13234 case TileUpdateCommand:
13235 {
13236 int
13237 x_offset,
13238 y_offset;
13239
13240 PixelInfo
13241 pixel;
13242
13243 register int
13244 j;
13245
13246 register Quantum
13247 *s;
13248
13249 /*
13250 Ensure all the images exist.
13251 */
13252 tile=0;
13253 GetPixelInfo(image,&pixel);
13254 for (p=image->directory; *p != '\0'; p++)
13255 {
13256 CacheView
13257 *image_view;
13258
13259 q=p;
13260 while ((*q != '\n') && (*q != '\0'))
13261 q++;
13262 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13263 p=q;
13264 if (IsPathAccessible(filename) != MagickFalse )
13265 {
13266 tile++;
13267 continue;
13268 }
13269 /*
13270 Overwrite tile with background color.
13271 */
13272 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x);
13273 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y);
13274 image_view=AcquireAuthenticCacheView(image,exception);
13275 (void) GetOneCacheViewVirtualPixelInfo(image_view,0,0,&pixel,exception);
13276 for (i=0; i < (int) height; i++)
13277 {
13278 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t)
13279 y_offset+i,width,1,exception);
13280 if (s == (Quantum *) NULL)
13281 break;
13282 for (j=0; j < (int) width; j++)
13283 {
13284 SetPixelViaPixelInfo(image,&pixel,s);
13285 s+=GetPixelChannels(image);
13286 }
13287 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
13288 break;
13289 }
13290 image_view=DestroyCacheView(image_view);
13291 tile++;
13292 }
13293 windows->image.window_changes.width=(int) image->columns;
13294 windows->image.window_changes.height=(int) image->rows;
13295 XConfigureImageColormap(display,resource_info,windows,image,exception);
13296 (void) XConfigureImage(display,resource_info,windows,image,exception);
13297 break;
13298 }
13299 default:
13300 break;
13301 }
13302 XSetCursorState(display,windows,MagickFalse);
13303 return(tile_image);
13304 }
13305
13306 /*
13307 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13308 % %
13309 % %
13310 % %
13311 + X T r a n s l a t e I m a g e %
13312 % %
13313 % %
13314 % %
13315 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13316 %
13317 % XTranslateImage() translates the image within an Image window by one pixel
13318 % as specified by the key symbol. If the image has a montage string the
13319 % translation is respect to the width and height contained within the string.
13320 %
13321 % The format of the XTranslateImage method is:
13322 %
13323 % void XTranslateImage(Display *display,XWindows *windows,
13324 % Image *image,const KeySym key_symbol)
13325 %
13326 % A description of each parameter follows:
13327 %
13328 % o display: Specifies a connection to an X server; returned from
13329 % XOpenDisplay.
13330 %
13331 % o windows: Specifies a pointer to a XWindows structure.
13332 %
13333 % o image: the image.
13334 %
13335 % o key_symbol: Specifies a KeySym which indicates which side of the image
13336 % to trim.
13337 %
13338 */
XTranslateImage(Display * display,XWindows * windows,Image * image,const KeySym key_symbol)13339 static void XTranslateImage(Display *display,XWindows *windows,
13340 Image *image,const KeySym key_symbol)
13341 {
13342 char
13343 text[MagickPathExtent];
13344
13345 int
13346 x,
13347 y;
13348
13349 unsigned int
13350 x_offset,
13351 y_offset;
13352
13353 /*
13354 User specified a pan position offset.
13355 */
13356 x_offset=windows->image.width;
13357 y_offset=windows->image.height;
13358 if (image->montage != (char *) NULL)
13359 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset);
13360 switch ((int) key_symbol)
13361 {
13362 case XK_Home:
13363 case XK_KP_Home:
13364 {
13365 windows->image.x=(int) windows->image.width/2;
13366 windows->image.y=(int) windows->image.height/2;
13367 break;
13368 }
13369 case XK_Left:
13370 case XK_KP_Left:
13371 {
13372 windows->image.x-=x_offset;
13373 break;
13374 }
13375 case XK_Next:
13376 case XK_Up:
13377 case XK_KP_Up:
13378 {
13379 windows->image.y-=y_offset;
13380 break;
13381 }
13382 case XK_Right:
13383 case XK_KP_Right:
13384 {
13385 windows->image.x+=x_offset;
13386 break;
13387 }
13388 case XK_Prior:
13389 case XK_Down:
13390 case XK_KP_Down:
13391 {
13392 windows->image.y+=y_offset;
13393 break;
13394 }
13395 default:
13396 return;
13397 }
13398 /*
13399 Check boundary conditions.
13400 */
13401 if (windows->image.x < 0)
13402 windows->image.x=0;
13403 else
13404 if ((int) (windows->image.x+windows->image.width) >
13405 windows->image.ximage->width)
13406 windows->image.x=(int) windows->image.ximage->width-windows->image.width;
13407 if (windows->image.y < 0)
13408 windows->image.y=0;
13409 else
13410 if ((int) (windows->image.y+windows->image.height) >
13411 windows->image.ximage->height)
13412 windows->image.y=(int) windows->image.ximage->height-windows->image.height;
13413 /*
13414 Refresh Image window.
13415 */
13416 (void) FormatLocaleString(text,MagickPathExtent," %ux%u%+d%+d ",
13417 windows->image.width,windows->image.height,windows->image.x,
13418 windows->image.y);
13419 XInfoWidget(display,windows,text);
13420 XCheckRefreshWindows(display,windows);
13421 XDrawPanRectangle(display,windows);
13422 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
13423 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13424 }
13425
13426 /*
13427 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13428 % %
13429 % %
13430 % %
13431 + X T r i m I m a g e %
13432 % %
13433 % %
13434 % %
13435 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13436 %
13437 % XTrimImage() trims the edges from the Image window.
13438 %
13439 % The format of the XTrimImage method is:
13440 %
13441 % MagickBooleanType XTrimImage(Display *display,
13442 % XResourceInfo *resource_info,XWindows *windows,Image *image,
13443 % ExceptionInfo *exception)
13444 %
13445 % A description of each parameter follows:
13446 %
13447 % o display: Specifies a connection to an X server; returned from
13448 % XOpenDisplay.
13449 %
13450 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13451 %
13452 % o windows: Specifies a pointer to a XWindows structure.
13453 %
13454 % o image: the image.
13455 %
13456 % o exception: return any errors or warnings in this structure.
13457 %
13458 */
XTrimImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,ExceptionInfo * exception)13459 static MagickBooleanType XTrimImage(Display *display,
13460 XResourceInfo *resource_info,XWindows *windows,Image *image,
13461 ExceptionInfo *exception)
13462 {
13463 RectangleInfo
13464 trim_info;
13465
13466 register int
13467 x,
13468 y;
13469
13470 size_t
13471 background,
13472 pixel;
13473
13474 /*
13475 Trim edges from image.
13476 */
13477 XSetCursorState(display,windows,MagickTrue);
13478 XCheckRefreshWindows(display,windows);
13479 /*
13480 Crop the left edge.
13481 */
13482 background=XGetPixel(windows->image.ximage,0,0);
13483 trim_info.width=(size_t) windows->image.ximage->width;
13484 for (x=0; x < windows->image.ximage->width; x++)
13485 {
13486 for (y=0; y < windows->image.ximage->height; y++)
13487 {
13488 pixel=XGetPixel(windows->image.ximage,x,y);
13489 if (pixel != background)
13490 break;
13491 }
13492 if (y < windows->image.ximage->height)
13493 break;
13494 }
13495 trim_info.x=(ssize_t) x;
13496 if (trim_info.x == (ssize_t) windows->image.ximage->width)
13497 {
13498 XSetCursorState(display,windows,MagickFalse);
13499 return(MagickFalse);
13500 }
13501 /*
13502 Crop the right edge.
13503 */
13504 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0);
13505 for (x=windows->image.ximage->width-1; x != 0; x--)
13506 {
13507 for (y=0; y < windows->image.ximage->height; y++)
13508 {
13509 pixel=XGetPixel(windows->image.ximage,x,y);
13510 if (pixel != background)
13511 break;
13512 }
13513 if (y < windows->image.ximage->height)
13514 break;
13515 }
13516 trim_info.width=(size_t) (x-trim_info.x+1);
13517 /*
13518 Crop the top edge.
13519 */
13520 background=XGetPixel(windows->image.ximage,0,0);
13521 trim_info.height=(size_t) windows->image.ximage->height;
13522 for (y=0; y < windows->image.ximage->height; y++)
13523 {
13524 for (x=0; x < windows->image.ximage->width; x++)
13525 {
13526 pixel=XGetPixel(windows->image.ximage,x,y);
13527 if (pixel != background)
13528 break;
13529 }
13530 if (x < windows->image.ximage->width)
13531 break;
13532 }
13533 trim_info.y=(ssize_t) y;
13534 /*
13535 Crop the bottom edge.
13536 */
13537 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1);
13538 for (y=windows->image.ximage->height-1; y != 0; y--)
13539 {
13540 for (x=0; x < windows->image.ximage->width; x++)
13541 {
13542 pixel=XGetPixel(windows->image.ximage,x,y);
13543 if (pixel != background)
13544 break;
13545 }
13546 if (x < windows->image.ximage->width)
13547 break;
13548 }
13549 trim_info.height=(size_t) y-trim_info.y+1;
13550 if (((unsigned int) trim_info.width != windows->image.width) ||
13551 ((unsigned int) trim_info.height != windows->image.height))
13552 {
13553 /*
13554 Reconfigure Image window as defined by the trimming rectangle.
13555 */
13556 XSetCropGeometry(display,windows,&trim_info,image);
13557 windows->image.window_changes.width=(int) trim_info.width;
13558 windows->image.window_changes.height=(int) trim_info.height;
13559 (void) XConfigureImage(display,resource_info,windows,image,exception);
13560 }
13561 XSetCursorState(display,windows,MagickFalse);
13562 return(MagickTrue);
13563 }
13564
13565 /*
13566 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13567 % %
13568 % %
13569 % %
13570 + X V i s u a l D i r e c t o r y I m a g e %
13571 % %
13572 % %
13573 % %
13574 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13575 %
13576 % XVisualDirectoryImage() creates a Visual Image Directory.
13577 %
13578 % The format of the XVisualDirectoryImage method is:
13579 %
13580 % Image *XVisualDirectoryImage(Display *display,
13581 % XResourceInfo *resource_info,XWindows *windows,
13582 % ExceptionInfo *exception)
13583 %
13584 % A description of each parameter follows:
13585 %
13586 % o display: Specifies a connection to an X server; returned from
13587 % XOpenDisplay.
13588 %
13589 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13590 %
13591 % o windows: Specifies a pointer to a XWindows structure.
13592 %
13593 % o exception: return any errors or warnings in this structure.
13594 %
13595 */
XVisualDirectoryImage(Display * display,XResourceInfo * resource_info,XWindows * windows,ExceptionInfo * exception)13596 static Image *XVisualDirectoryImage(Display *display,
13597 XResourceInfo *resource_info,XWindows *windows,ExceptionInfo *exception)
13598 {
13599 #define TileImageTag "Scale/Image"
13600 #define XClientName "montage"
13601
13602 char
13603 **filelist;
13604
13605 Image
13606 *images,
13607 *montage_image,
13608 *next_image,
13609 *thumbnail_image;
13610
13611 ImageInfo
13612 *read_info;
13613
13614 int
13615 number_files;
13616
13617 MagickBooleanType
13618 backdrop;
13619
13620 MagickStatusType
13621 status;
13622
13623 MontageInfo
13624 *montage_info;
13625
13626 RectangleInfo
13627 geometry;
13628
13629 register int
13630 i;
13631
13632 static char
13633 filename[MagickPathExtent] = "\0",
13634 filenames[MagickPathExtent] = "*";
13635
13636 XResourceInfo
13637 background_resources;
13638
13639 /*
13640 Request file name from user.
13641 */
13642 XFileBrowserWidget(display,windows,"Directory",filenames);
13643 if (*filenames == '\0')
13644 return((Image *) NULL);
13645 /*
13646 Expand the filenames.
13647 */
13648 filelist=(char **) AcquireMagickMemory(sizeof(*filelist));
13649 if (filelist == (char **) NULL)
13650 {
13651 ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
13652 filenames);
13653 return((Image *) NULL);
13654 }
13655 number_files=1;
13656 filelist[0]=filenames;
13657 status=ExpandFilenames(&number_files,&filelist);
13658 if ((status == MagickFalse) || (number_files == 0))
13659 {
13660 if (number_files == 0)
13661 ThrowXWindowException(ImageError,"NoImagesWereFound",filenames)
13662 else
13663 ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
13664 filenames);
13665 return((Image *) NULL);
13666 }
13667 /*
13668 Set image background resources.
13669 */
13670 background_resources=(*resource_info);
13671 background_resources.window_id=AcquireString("");
13672 (void) FormatLocaleString(background_resources.window_id,MagickPathExtent,
13673 "0x%lx",windows->image.id);
13674 background_resources.backdrop=MagickTrue;
13675 /*
13676 Read each image and convert them to a tile.
13677 */
13678 backdrop=((windows->visual_info->klass == TrueColor) ||
13679 (windows->visual_info->klass == DirectColor)) ? MagickTrue : MagickFalse;
13680 read_info=CloneImageInfo(resource_info->image_info);
13681 (void) SetImageOption(read_info,"jpeg:size","120x120");
13682 (void) CloneString(&read_info->size,DefaultTileGeometry);
13683 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL,
13684 (void *) NULL);
13685 images=NewImageList();
13686 XSetCursorState(display,windows,MagickTrue);
13687 XCheckRefreshWindows(display,windows);
13688 for (i=0; i < (int) number_files; i++)
13689 {
13690 (void) CopyMagickString(read_info->filename,filelist[i],MagickPathExtent);
13691 filelist[i]=DestroyString(filelist[i]);
13692 *read_info->magick='\0';
13693 next_image=ReadImage(read_info,exception);
13694 CatchException(exception);
13695 if (next_image != (Image *) NULL)
13696 {
13697 (void) DeleteImageProperty(next_image,"label");
13698 (void) SetImageProperty(next_image,"label",InterpretImageProperties(
13699 read_info,next_image,DefaultTileLabel,exception),exception);
13700 (void) ParseRegionGeometry(next_image,read_info->size,&geometry,
13701 exception);
13702 thumbnail_image=ThumbnailImage(next_image,geometry.width,
13703 geometry.height,exception);
13704 if (thumbnail_image != (Image *) NULL)
13705 {
13706 next_image=DestroyImage(next_image);
13707 next_image=thumbnail_image;
13708 }
13709 if (backdrop)
13710 {
13711 (void) XDisplayBackgroundImage(display,&background_resources,
13712 next_image,exception);
13713 XSetCursorState(display,windows,MagickTrue);
13714 }
13715 AppendImageToList(&images,next_image);
13716 if (images->progress_monitor != (MagickProgressMonitor) NULL)
13717 {
13718 MagickBooleanType
13719 proceed;
13720
13721 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i,
13722 (MagickSizeType) number_files);
13723 if (proceed == MagickFalse)
13724 break;
13725 }
13726 }
13727 }
13728 filelist=(char **) RelinquishMagickMemory(filelist);
13729 if (images == (Image *) NULL)
13730 {
13731 read_info=DestroyImageInfo(read_info);
13732 XSetCursorState(display,windows,MagickFalse);
13733 ThrowXWindowException(ImageError,"NoImagesWereLoaded",filenames);
13734 return((Image *) NULL);
13735 }
13736 /*
13737 Create the Visual Image Directory.
13738 */
13739 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL);
13740 montage_info->pointsize=10;
13741 if (resource_info->font != (char *) NULL)
13742 (void) CloneString(&montage_info->font,resource_info->font);
13743 (void) CopyMagickString(montage_info->filename,filename,MagickPathExtent);
13744 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList(
13745 images),exception);
13746 images=DestroyImageList(images);
13747 montage_info=DestroyMontageInfo(montage_info);
13748 read_info=DestroyImageInfo(read_info);
13749 XSetCursorState(display,windows,MagickFalse);
13750 if (montage_image == (Image *) NULL)
13751 return(montage_image);
13752 XClientMessage(display,windows->image.id,windows->im_protocols,
13753 windows->im_next_image,CurrentTime);
13754 return(montage_image);
13755 }
13756
13757 /*
13758 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13759 % %
13760 % %
13761 % %
13762 % X D i s p l a y B a c k g r o u n d I m a g e %
13763 % %
13764 % %
13765 % %
13766 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13767 %
13768 % XDisplayBackgroundImage() displays an image in the background of a window.
13769 %
13770 % The format of the XDisplayBackgroundImage method is:
13771 %
13772 % MagickBooleanType XDisplayBackgroundImage(Display *display,
13773 % XResourceInfo *resource_info,Image *image,ExceptionInfo *exception)
13774 %
13775 % A description of each parameter follows:
13776 %
13777 % o display: Specifies a connection to an X server; returned from
13778 % XOpenDisplay.
13779 %
13780 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13781 %
13782 % o image: the image.
13783 %
13784 % o exception: return any errors or warnings in this structure.
13785 %
13786 */
XDisplayBackgroundImage(Display * display,XResourceInfo * resource_info,Image * image,ExceptionInfo * exception)13787 MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display,
13788 XResourceInfo *resource_info,Image *image,ExceptionInfo *exception)
13789 {
13790 char
13791 geometry[MagickPathExtent],
13792 visual_type[MagickPathExtent];
13793
13794 int
13795 height,
13796 status,
13797 width;
13798
13799 RectangleInfo
13800 geometry_info;
13801
13802 static XPixelInfo
13803 pixel;
13804
13805 static XStandardColormap
13806 *map_info;
13807
13808 static XVisualInfo
13809 *visual_info = (XVisualInfo *) NULL;
13810
13811 static XWindowInfo
13812 window_info;
13813
13814 size_t
13815 delay;
13816
13817 Window
13818 root_window;
13819
13820 XGCValues
13821 context_values;
13822
13823 XResourceInfo
13824 resources;
13825
13826 XWindowAttributes
13827 window_attributes;
13828
13829 /*
13830 Determine target window.
13831 */
13832 assert(image != (Image *) NULL);
13833 assert(image->signature == MagickCoreSignature);
13834 if (image->debug != MagickFalse )
13835 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
13836 resources=(*resource_info);
13837 window_info.id=(Window) NULL;
13838 root_window=XRootWindow(display,XDefaultScreen(display));
13839 if (LocaleCompare(resources.window_id,"root") == 0)
13840 window_info.id=root_window;
13841 else
13842 {
13843 if (isdigit((int) ((unsigned char) *resources.window_id)) != 0)
13844 window_info.id=XWindowByID(display,root_window,
13845 (Window) strtol((char *) resources.window_id,(char **) NULL,0));
13846 if (window_info.id == (Window) NULL)
13847 window_info.id=XWindowByName(display,root_window,resources.window_id);
13848 }
13849 if (window_info.id == (Window) NULL)
13850 {
13851 ThrowXWindowException(XServerError,"NoWindowWithSpecifiedIDExists",
13852 resources.window_id);
13853 return(MagickFalse);
13854 }
13855 /*
13856 Determine window visual id.
13857 */
13858 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display));
13859 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display));
13860 (void) CopyMagickString(visual_type,"default",MagickPathExtent);
13861 status=XGetWindowAttributes(display,window_info.id,&window_attributes);
13862 if (status != 0)
13863 (void) FormatLocaleString(visual_type,MagickPathExtent,"0x%lx",
13864 XVisualIDFromVisual(window_attributes.visual));
13865 if (visual_info == (XVisualInfo *) NULL)
13866 {
13867 /*
13868 Allocate standard colormap.
13869 */
13870 map_info=XAllocStandardColormap();
13871 if (map_info == (XStandardColormap *) NULL)
13872 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
13873 image->filename);
13874 map_info->colormap=(Colormap) NULL;
13875 pixel.pixels=(unsigned long *) NULL;
13876 /*
13877 Initialize visual info.
13878 */
13879 resources.map_type=(char *) NULL;
13880 resources.visual_type=visual_type;
13881 visual_info=XBestVisualInfo(display,map_info,&resources);
13882 if (visual_info == (XVisualInfo *) NULL)
13883 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual",
13884 resources.visual_type);
13885 /*
13886 Initialize window info.
13887 */
13888 window_info.ximage=(XImage *) NULL;
13889 window_info.matte_image=(XImage *) NULL;
13890 window_info.pixmap=(Pixmap) NULL;
13891 window_info.matte_pixmap=(Pixmap) NULL;
13892 }
13893 /*
13894 Free previous root colors.
13895 */
13896 if (window_info.id == root_window)
13897 (void) XDestroyWindowColors(display,root_window);
13898 /*
13899 Initialize Standard Colormap.
13900 */
13901 resources.colormap=SharedColormap;
13902 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel,
13903 exception);
13904 /*
13905 Graphic context superclass.
13906 */
13907 context_values.background=pixel.background_color.pixel;
13908 context_values.foreground=pixel.foreground_color.pixel;
13909 pixel.annotate_context=XCreateGC(display,window_info.id,
13910 (size_t) (GCBackground | GCForeground),&context_values);
13911 if (pixel.annotate_context == (GC) NULL)
13912 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
13913 image->filename);
13914 /*
13915 Initialize Image window attributes.
13916 */
13917 window_info.name=AcquireString("\0");
13918 window_info.icon_name=AcquireString("\0");
13919 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL,
13920 &resources,&window_info);
13921 /*
13922 Create the X image.
13923 */
13924 window_info.width=(unsigned int) image->columns;
13925 window_info.height=(unsigned int) image->rows;
13926 if ((image->columns != window_info.width) ||
13927 (image->rows != window_info.height))
13928 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13929 image->filename);
13930 (void) FormatLocaleString(geometry,MagickPathExtent,"%ux%u+0+0>",
13931 window_attributes.width,window_attributes.height);
13932 geometry_info.width=window_info.width;
13933 geometry_info.height=window_info.height;
13934 geometry_info.x=(ssize_t) window_info.x;
13935 geometry_info.y=(ssize_t) window_info.y;
13936 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
13937 &geometry_info.width,&geometry_info.height);
13938 window_info.width=(unsigned int) geometry_info.width;
13939 window_info.height=(unsigned int) geometry_info.height;
13940 window_info.x=(int) geometry_info.x;
13941 window_info.y=(int) geometry_info.y;
13942 status=XMakeImage(display,&resources,&window_info,image,window_info.width,
13943 window_info.height,exception);
13944 if (status == MagickFalse)
13945 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13946 image->filename);
13947 window_info.x=0;
13948 window_info.y=0;
13949 if (image->debug != MagickFalse )
13950 {
13951 (void) LogMagickEvent(X11Event,GetMagickModule(),
13952 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene,
13953 (double) image->columns,(double) image->rows);
13954 if (image->colors != 0)
13955 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
13956 image->colors);
13957 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick);
13958 }
13959 /*
13960 Adjust image dimensions as specified by backdrop or geometry options.
13961 */
13962 width=(int) window_info.width;
13963 height=(int) window_info.height;
13964 if (resources.backdrop != MagickFalse )
13965 {
13966 /*
13967 Center image on window.
13968 */
13969 window_info.x=(window_attributes.width/2)-
13970 (window_info.ximage->width/2);
13971 window_info.y=(window_attributes.height/2)-
13972 (window_info.ximage->height/2);
13973 width=window_attributes.width;
13974 height=window_attributes.height;
13975 }
13976 if ((resources.image_geometry != (char *) NULL) &&
13977 (*resources.image_geometry != '\0'))
13978 {
13979 char
13980 default_geometry[MagickPathExtent];
13981
13982 int
13983 flags,
13984 gravity;
13985
13986 XSizeHints
13987 *size_hints;
13988
13989 /*
13990 User specified geometry.
13991 */
13992 size_hints=XAllocSizeHints();
13993 if (size_hints == (XSizeHints *) NULL)
13994 ThrowXWindowFatalException(ResourceLimitFatalError,
13995 "MemoryAllocationFailed",image->filename);
13996 size_hints->flags=0L;
13997 (void) FormatLocaleString(default_geometry,MagickPathExtent,"%dx%d",
13998 width,height);
13999 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry,
14000 default_geometry,window_info.border_width,size_hints,&window_info.x,
14001 &window_info.y,&width,&height,&gravity);
14002 if (flags & (XValue | YValue))
14003 {
14004 width=window_attributes.width;
14005 height=window_attributes.height;
14006 }
14007 (void) XFree((void *) size_hints);
14008 }
14009 /*
14010 Create the X pixmap.
14011 */
14012 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width,
14013 (unsigned int) height,window_info.depth);
14014 if (window_info.pixmap == (Pixmap) NULL)
14015 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
14016 image->filename);
14017 /*
14018 Display pixmap on the window.
14019 */
14020 if (((unsigned int) width > window_info.width) ||
14021 ((unsigned int) height > window_info.height))
14022 (void) XFillRectangle(display,window_info.pixmap,
14023 window_info.annotate_context,0,0,(unsigned int) width,
14024 (unsigned int) height);
14025 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
14026 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int)
14027 window_info.width,(unsigned int) window_info.height);
14028 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
14029 (void) XClearWindow(display,window_info.id);
14030 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L);
14031 XDelay(display,delay == 0UL ? 10UL : delay);
14032 (void) XSync(display,MagickFalse);
14033 return(window_info.id == root_window ? MagickTrue : MagickFalse);
14034 }
14035
14036 /*
14037 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14038 % %
14039 % %
14040 % %
14041 + X D i s p l a y I m a g e %
14042 % %
14043 % %
14044 % %
14045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14046 %
14047 % XDisplayImage() displays an image via X11. A new image is created and
14048 % returned if the user interactively transforms the displayed image.
14049 %
14050 % The format of the XDisplayImage method is:
14051 %
14052 % Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
14053 % char **argv,int argc,Image **image,size_t *state,
14054 % ExceptionInfo *exception)
14055 %
14056 % A description of each parameter follows:
14057 %
14058 % o nexus: Method XDisplayImage returns an image when the
14059 % user chooses 'Open Image' from the command menu or picks a tile
14060 % from the image directory. Otherwise a null image is returned.
14061 %
14062 % o display: Specifies a connection to an X server; returned from
14063 % XOpenDisplay.
14064 %
14065 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
14066 %
14067 % o argv: Specifies the application's argument list.
14068 %
14069 % o argc: Specifies the number of arguments.
14070 %
14071 % o image: Specifies an address to an address of an Image structure;
14072 %
14073 % o exception: return any errors or warnings in this structure.
14074 %
14075 */
XDisplayImage(Display * display,XResourceInfo * resource_info,char ** argv,int argc,Image ** image,size_t * state,ExceptionInfo * exception)14076 MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
14077 char **argv,int argc,Image **image,size_t *state,ExceptionInfo *exception)
14078 {
14079 #define MagnifySize 256 /* must be a power of 2 */
14080 #define MagickMenus 10
14081 #define MagickTitle "Commands"
14082
14083 static const char
14084 *CommandMenu[] =
14085 {
14086 "File",
14087 "Edit",
14088 "View",
14089 "Transform",
14090 "Enhance",
14091 "Effects",
14092 "F/X",
14093 "Image Edit",
14094 "Miscellany",
14095 "Help",
14096 (char *) NULL
14097 },
14098 *FileMenu[] =
14099 {
14100 "Open...",
14101 "Next",
14102 "Former",
14103 "Select...",
14104 "Save...",
14105 "Print...",
14106 "Delete...",
14107 "New...",
14108 "Visual Directory...",
14109 "Quit",
14110 (char *) NULL
14111 },
14112 *EditMenu[] =
14113 {
14114 "Undo",
14115 "Redo",
14116 "Cut",
14117 "Copy",
14118 "Paste",
14119 (char *) NULL
14120 },
14121 *ViewMenu[] =
14122 {
14123 "Half Size",
14124 "Original Size",
14125 "Double Size",
14126 "Resize...",
14127 "Apply",
14128 "Refresh",
14129 "Restore",
14130 (char *) NULL
14131 },
14132 *TransformMenu[] =
14133 {
14134 "Crop",
14135 "Chop",
14136 "Flop",
14137 "Flip",
14138 "Rotate Right",
14139 "Rotate Left",
14140 "Rotate...",
14141 "Shear...",
14142 "Roll...",
14143 "Trim Edges",
14144 (char *) NULL
14145 },
14146 *EnhanceMenu[] =
14147 {
14148 "Hue...",
14149 "Saturation...",
14150 "Brightness...",
14151 "Gamma...",
14152 "Spiff",
14153 "Dull",
14154 "Contrast Stretch...",
14155 "Sigmoidal Contrast...",
14156 "Normalize",
14157 "Equalize",
14158 "Negate",
14159 "Grayscale",
14160 "Map...",
14161 "Quantize...",
14162 (char *) NULL
14163 },
14164 *EffectsMenu[] =
14165 {
14166 "Despeckle",
14167 "Emboss",
14168 "Reduce Noise",
14169 "Add Noise...",
14170 "Sharpen...",
14171 "Blur...",
14172 "Threshold...",
14173 "Edge Detect...",
14174 "Spread...",
14175 "Shade...",
14176 "Raise...",
14177 "Segment...",
14178 (char *) NULL
14179 },
14180 *FXMenu[] =
14181 {
14182 "Solarize...",
14183 "Sepia Tone...",
14184 "Swirl...",
14185 "Implode...",
14186 "Vignette...",
14187 "Wave...",
14188 "Oil Paint...",
14189 "Charcoal Draw...",
14190 (char *) NULL
14191 },
14192 *ImageEditMenu[] =
14193 {
14194 "Annotate...",
14195 "Draw...",
14196 "Color...",
14197 "Matte...",
14198 "Composite...",
14199 "Add Border...",
14200 "Add Frame...",
14201 "Comment...",
14202 "Launch...",
14203 "Region of Interest...",
14204 (char *) NULL
14205 },
14206 *MiscellanyMenu[] =
14207 {
14208 "Image Info",
14209 "Zoom Image",
14210 "Show Preview...",
14211 "Show Histogram",
14212 "Show Matte",
14213 "Background...",
14214 "Slide Show...",
14215 "Preferences...",
14216 (char *) NULL
14217 },
14218 *HelpMenu[] =
14219 {
14220 "Overview",
14221 "Browse Documentation",
14222 "About Display",
14223 (char *) NULL
14224 },
14225 *ShortCutsMenu[] =
14226 {
14227 "Next",
14228 "Former",
14229 "Open...",
14230 "Save...",
14231 "Print...",
14232 "Undo",
14233 "Restore",
14234 "Image Info",
14235 "Quit",
14236 (char *) NULL
14237 },
14238 *VirtualMenu[] =
14239 {
14240 "Image Info",
14241 "Print",
14242 "Next",
14243 "Quit",
14244 (char *) NULL
14245 };
14246
14247 static const char
14248 **Menus[MagickMenus] =
14249 {
14250 FileMenu,
14251 EditMenu,
14252 ViewMenu,
14253 TransformMenu,
14254 EnhanceMenu,
14255 EffectsMenu,
14256 FXMenu,
14257 ImageEditMenu,
14258 MiscellanyMenu,
14259 HelpMenu
14260 };
14261
14262 static CommandType
14263 CommandMenus[] =
14264 {
14265 NullCommand,
14266 NullCommand,
14267 NullCommand,
14268 NullCommand,
14269 NullCommand,
14270 NullCommand,
14271 NullCommand,
14272 NullCommand,
14273 NullCommand,
14274 NullCommand,
14275 },
14276 FileCommands[] =
14277 {
14278 OpenCommand,
14279 NextCommand,
14280 FormerCommand,
14281 SelectCommand,
14282 SaveCommand,
14283 PrintCommand,
14284 DeleteCommand,
14285 NewCommand,
14286 VisualDirectoryCommand,
14287 QuitCommand
14288 },
14289 EditCommands[] =
14290 {
14291 UndoCommand,
14292 RedoCommand,
14293 CutCommand,
14294 CopyCommand,
14295 PasteCommand
14296 },
14297 ViewCommands[] =
14298 {
14299 HalfSizeCommand,
14300 OriginalSizeCommand,
14301 DoubleSizeCommand,
14302 ResizeCommand,
14303 ApplyCommand,
14304 RefreshCommand,
14305 RestoreCommand
14306 },
14307 TransformCommands[] =
14308 {
14309 CropCommand,
14310 ChopCommand,
14311 FlopCommand,
14312 FlipCommand,
14313 RotateRightCommand,
14314 RotateLeftCommand,
14315 RotateCommand,
14316 ShearCommand,
14317 RollCommand,
14318 TrimCommand
14319 },
14320 EnhanceCommands[] =
14321 {
14322 HueCommand,
14323 SaturationCommand,
14324 BrightnessCommand,
14325 GammaCommand,
14326 SpiffCommand,
14327 DullCommand,
14328 ContrastStretchCommand,
14329 SigmoidalContrastCommand,
14330 NormalizeCommand,
14331 EqualizeCommand,
14332 NegateCommand,
14333 GrayscaleCommand,
14334 MapCommand,
14335 QuantizeCommand
14336 },
14337 EffectsCommands[] =
14338 {
14339 DespeckleCommand,
14340 EmbossCommand,
14341 ReduceNoiseCommand,
14342 AddNoiseCommand,
14343 SharpenCommand,
14344 BlurCommand,
14345 ThresholdCommand,
14346 EdgeDetectCommand,
14347 SpreadCommand,
14348 ShadeCommand,
14349 RaiseCommand,
14350 SegmentCommand
14351 },
14352 FXCommands[] =
14353 {
14354 SolarizeCommand,
14355 SepiaToneCommand,
14356 SwirlCommand,
14357 ImplodeCommand,
14358 VignetteCommand,
14359 WaveCommand,
14360 OilPaintCommand,
14361 CharcoalDrawCommand
14362 },
14363 ImageEditCommands[] =
14364 {
14365 AnnotateCommand,
14366 DrawCommand,
14367 ColorCommand,
14368 MatteCommand,
14369 CompositeCommand,
14370 AddBorderCommand,
14371 AddFrameCommand,
14372 CommentCommand,
14373 LaunchCommand,
14374 RegionofInterestCommand
14375 },
14376 MiscellanyCommands[] =
14377 {
14378 InfoCommand,
14379 ZoomCommand,
14380 ShowPreviewCommand,
14381 ShowHistogramCommand,
14382 ShowMatteCommand,
14383 BackgroundCommand,
14384 SlideShowCommand,
14385 PreferencesCommand
14386 },
14387 HelpCommands[] =
14388 {
14389 HelpCommand,
14390 BrowseDocumentationCommand,
14391 VersionCommand
14392 },
14393 ShortCutsCommands[] =
14394 {
14395 NextCommand,
14396 FormerCommand,
14397 OpenCommand,
14398 SaveCommand,
14399 PrintCommand,
14400 UndoCommand,
14401 RestoreCommand,
14402 InfoCommand,
14403 QuitCommand
14404 },
14405 VirtualCommands[] =
14406 {
14407 InfoCommand,
14408 PrintCommand,
14409 NextCommand,
14410 QuitCommand
14411 };
14412
14413 static CommandType
14414 *Commands[MagickMenus] =
14415 {
14416 FileCommands,
14417 EditCommands,
14418 ViewCommands,
14419 TransformCommands,
14420 EnhanceCommands,
14421 EffectsCommands,
14422 FXCommands,
14423 ImageEditCommands,
14424 MiscellanyCommands,
14425 HelpCommands
14426 };
14427
14428 char
14429 command[MagickPathExtent],
14430 *directory,
14431 geometry[MagickPathExtent],
14432 resource_name[MagickPathExtent];
14433
14434 CommandType
14435 command_type;
14436
14437 Image
14438 *display_image,
14439 *nexus;
14440
14441 int
14442 entry,
14443 id;
14444
14445 KeySym
14446 key_symbol;
14447
14448 MagickStatusType
14449 context_mask,
14450 status;
14451
14452 RectangleInfo
14453 geometry_info;
14454
14455 register int
14456 i;
14457
14458 static char
14459 working_directory[MagickPathExtent];
14460
14461 static XPoint
14462 vid_info;
14463
14464 static XWindowInfo
14465 *magick_windows[MaxXWindows];
14466
14467 static unsigned int
14468 number_windows;
14469
14470 struct stat
14471 attributes;
14472
14473 time_t
14474 timer,
14475 timestamp,
14476 update_time;
14477
14478 unsigned int
14479 height,
14480 width;
14481
14482 size_t
14483 delay;
14484
14485 WarningHandler
14486 warning_handler;
14487
14488 Window
14489 root_window;
14490
14491 XClassHint
14492 *class_hints;
14493
14494 XEvent
14495 event;
14496
14497 XFontStruct
14498 *font_info;
14499
14500 XGCValues
14501 context_values;
14502
14503 XPixelInfo
14504 *icon_pixel,
14505 *pixel;
14506
14507 XResourceInfo
14508 *icon_resources;
14509
14510 XStandardColormap
14511 *icon_map,
14512 *map_info;
14513
14514 XVisualInfo
14515 *icon_visual,
14516 *visual_info;
14517
14518 XWindowChanges
14519 window_changes;
14520
14521 XWindows
14522 *windows;
14523
14524 XWMHints
14525 *manager_hints;
14526
14527 assert(image != (Image **) NULL);
14528 assert((*image)->signature == MagickCoreSignature);
14529 if ((*image)->debug != MagickFalse )
14530 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
14531 display_image=(*image);
14532 warning_handler=(WarningHandler) NULL;
14533 windows=XSetWindows((XWindows *) ~0);
14534 if (windows != (XWindows *) NULL)
14535 {
14536 int
14537 status;
14538
14539 if (*working_directory == '\0')
14540 (void) CopyMagickString(working_directory,".",MagickPathExtent);
14541 status=chdir(working_directory);
14542 if (status == -1)
14543 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
14544 "UnableToOpenFile","%s",working_directory);
14545 warning_handler=resource_info->display_warnings ?
14546 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
14547 warning_handler=resource_info->display_warnings ?
14548 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
14549 }
14550 else
14551 {
14552 /*
14553 Allocate windows structure.
14554 */
14555 resource_info->colors=display_image->colors;
14556 windows=XSetWindows(XInitializeWindows(display,resource_info));
14557 if (windows == (XWindows *) NULL)
14558 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow",
14559 (*image)->filename);
14560 /*
14561 Initialize window id's.
14562 */
14563 number_windows=0;
14564 magick_windows[number_windows++]=(&windows->icon);
14565 magick_windows[number_windows++]=(&windows->backdrop);
14566 magick_windows[number_windows++]=(&windows->image);
14567 magick_windows[number_windows++]=(&windows->info);
14568 magick_windows[number_windows++]=(&windows->command);
14569 magick_windows[number_windows++]=(&windows->widget);
14570 magick_windows[number_windows++]=(&windows->popup);
14571 magick_windows[number_windows++]=(&windows->magnify);
14572 magick_windows[number_windows++]=(&windows->pan);
14573 for (i=0; i < (int) number_windows; i++)
14574 magick_windows[i]->id=(Window) NULL;
14575 vid_info.x=0;
14576 vid_info.y=0;
14577 }
14578 /*
14579 Initialize font info.
14580 */
14581 if (windows->font_info != (XFontStruct *) NULL)
14582 (void) XFreeFont(display,windows->font_info);
14583 windows->font_info=XBestFont(display,resource_info,MagickFalse);
14584 if (windows->font_info == (XFontStruct *) NULL)
14585 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont",
14586 resource_info->font);
14587 /*
14588 Initialize Standard Colormap.
14589 */
14590 map_info=windows->map_info;
14591 icon_map=windows->icon_map;
14592 visual_info=windows->visual_info;
14593 icon_visual=windows->icon_visual;
14594 pixel=windows->pixel_info;
14595 icon_pixel=windows->icon_pixel;
14596 font_info=windows->font_info;
14597 icon_resources=windows->icon_resources;
14598 class_hints=windows->class_hints;
14599 manager_hints=windows->manager_hints;
14600 root_window=XRootWindow(display,visual_info->screen);
14601 nexus=NewImageList();
14602 if (display_image->debug != MagickFalse )
14603 {
14604 (void) LogMagickEvent(X11Event,GetMagickModule(),
14605 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename,
14606 (double) display_image->scene,(double) display_image->columns,
14607 (double) display_image->rows);
14608 if (display_image->colors != 0)
14609 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
14610 display_image->colors);
14611 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
14612 display_image->magick);
14613 }
14614 XMakeStandardColormap(display,visual_info,resource_info,display_image,
14615 map_info,pixel,exception);
14616 display_image->taint=MagickFalse;
14617 /*
14618 Initialize graphic context.
14619 */
14620 windows->context.id=(Window) NULL;
14621 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14622 resource_info,&windows->context);
14623 (void) CloneString(&class_hints->res_name,resource_info->client_name);
14624 (void) CloneString(&class_hints->res_class,resource_info->client_name);
14625 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]);
14626 manager_hints->flags=InputHint | StateHint;
14627 manager_hints->input=MagickFalse;
14628 manager_hints->initial_state=WithdrawnState;
14629 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14630 &windows->context);
14631 if (display_image->debug != MagickFalse )
14632 (void) LogMagickEvent(X11Event,GetMagickModule(),
14633 "Window id: 0x%lx (context)",windows->context.id);
14634 context_values.background=pixel->background_color.pixel;
14635 context_values.font=font_info->fid;
14636 context_values.foreground=pixel->foreground_color.pixel;
14637 context_values.graphics_exposures=MagickFalse;
14638 context_mask=(MagickStatusType)
14639 (GCBackground | GCFont | GCForeground | GCGraphicsExposures);
14640 if (pixel->annotate_context != (GC) NULL)
14641 (void) XFreeGC(display,pixel->annotate_context);
14642 pixel->annotate_context=XCreateGC(display,windows->context.id,
14643 context_mask,&context_values);
14644 if (pixel->annotate_context == (GC) NULL)
14645 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14646 display_image->filename);
14647 context_values.background=pixel->depth_color.pixel;
14648 if (pixel->widget_context != (GC) NULL)
14649 (void) XFreeGC(display,pixel->widget_context);
14650 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask,
14651 &context_values);
14652 if (pixel->widget_context == (GC) NULL)
14653 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14654 display_image->filename);
14655 context_values.background=pixel->foreground_color.pixel;
14656 context_values.foreground=pixel->background_color.pixel;
14657 context_values.plane_mask=context_values.background ^
14658 context_values.foreground;
14659 if (pixel->highlight_context != (GC) NULL)
14660 (void) XFreeGC(display,pixel->highlight_context);
14661 pixel->highlight_context=XCreateGC(display,windows->context.id,
14662 (size_t) (context_mask | GCPlaneMask),&context_values);
14663 if (pixel->highlight_context == (GC) NULL)
14664 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14665 display_image->filename);
14666 (void) XDestroyWindow(display,windows->context.id);
14667 /*
14668 Initialize icon window.
14669 */
14670 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL,
14671 icon_resources,&windows->icon);
14672 windows->icon.geometry=resource_info->icon_geometry;
14673 XBestIconSize(display,&windows->icon,display_image);
14674 windows->icon.attributes.colormap=XDefaultColormap(display,
14675 icon_visual->screen);
14676 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask;
14677 manager_hints->flags=InputHint | StateHint;
14678 manager_hints->input=MagickFalse;
14679 manager_hints->initial_state=IconicState;
14680 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14681 &windows->icon);
14682 if (display_image->debug != MagickFalse )
14683 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)",
14684 windows->icon.id);
14685 /*
14686 Initialize graphic context for icon window.
14687 */
14688 if (icon_pixel->annotate_context != (GC) NULL)
14689 (void) XFreeGC(display,icon_pixel->annotate_context);
14690 context_values.background=icon_pixel->background_color.pixel;
14691 context_values.foreground=icon_pixel->foreground_color.pixel;
14692 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id,
14693 (size_t) (GCBackground | GCForeground),&context_values);
14694 if (icon_pixel->annotate_context == (GC) NULL)
14695 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14696 display_image->filename);
14697 windows->icon.annotate_context=icon_pixel->annotate_context;
14698 /*
14699 Initialize Image window.
14700 */
14701 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14702 &windows->image);
14703 windows->image.shape=MagickTrue; /* non-rectangular shape hint */
14704 if (resource_info->use_shared_memory == MagickFalse)
14705 windows->image.shared_memory=MagickFalse;
14706 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState))
14707 {
14708 char
14709 *title;
14710
14711 title=InterpretImageProperties(resource_info->image_info,display_image,
14712 resource_info->title,exception);
14713 (void) CopyMagickString(windows->image.name,title,MagickPathExtent);
14714 (void) CopyMagickString(windows->image.icon_name,title,MagickPathExtent);
14715 title=DestroyString(title);
14716 }
14717 else
14718 {
14719 char
14720 filename[MagickPathExtent];
14721
14722 /*
14723 Window name is the base of the filename.
14724 */
14725 GetPathComponent(display_image->magick_filename,TailPath,filename);
14726 if (display_image->scene == 0)
14727 (void) FormatLocaleString(windows->image.name,MagickPathExtent,
14728 "%s: %s",MagickPackageName,filename);
14729 else
14730 (void) FormatLocaleString(windows->image.name,MagickPathExtent,
14731 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename,
14732 (double) display_image->scene,(double) GetImageListLength(
14733 display_image));
14734 (void) CopyMagickString(windows->image.icon_name,filename,MagickPathExtent);
14735 }
14736 if (resource_info->immutable)
14737 windows->image.immutable=MagickTrue;
14738 windows->image.use_pixmap=resource_info->use_pixmap;
14739 windows->image.geometry=resource_info->image_geometry;
14740 (void) FormatLocaleString(geometry,MagickPathExtent,"%ux%u+0+0>!",
14741 XDisplayWidth(display,visual_info->screen),
14742 XDisplayHeight(display,visual_info->screen));
14743 geometry_info.width=display_image->columns;
14744 geometry_info.height=display_image->rows;
14745 geometry_info.x=0;
14746 geometry_info.y=0;
14747 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
14748 &geometry_info.width,&geometry_info.height);
14749 windows->image.width=(unsigned int) geometry_info.width;
14750 windows->image.height=(unsigned int) geometry_info.height;
14751 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14752 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14753 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14754 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask;
14755 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14756 resource_info,&windows->backdrop);
14757 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL))
14758 {
14759 /*
14760 Initialize backdrop window.
14761 */
14762 windows->backdrop.x=0;
14763 windows->backdrop.y=0;
14764 (void) CloneString(&windows->backdrop.name,"Backdrop");
14765 windows->backdrop.flags=(size_t) (USSize | USPosition);
14766 windows->backdrop.width=(unsigned int)
14767 XDisplayWidth(display,visual_info->screen);
14768 windows->backdrop.height=(unsigned int)
14769 XDisplayHeight(display,visual_info->screen);
14770 windows->backdrop.border_width=0;
14771 windows->backdrop.immutable=MagickTrue;
14772 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask |
14773 ButtonReleaseMask;
14774 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask |
14775 StructureNotifyMask;
14776 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14777 manager_hints->icon_window=windows->icon.id;
14778 manager_hints->input=MagickTrue;
14779 manager_hints->initial_state=resource_info->iconic ? IconicState :
14780 NormalState;
14781 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14782 &windows->backdrop);
14783 if (display_image->debug != MagickFalse )
14784 (void) LogMagickEvent(X11Event,GetMagickModule(),
14785 "Window id: 0x%lx (backdrop)",windows->backdrop.id);
14786 (void) XMapWindow(display,windows->backdrop.id);
14787 (void) XClearWindow(display,windows->backdrop.id);
14788 if (windows->image.id != (Window) NULL)
14789 {
14790 (void) XDestroyWindow(display,windows->image.id);
14791 windows->image.id=(Window) NULL;
14792 }
14793 /*
14794 Position image in the center the backdrop.
14795 */
14796 windows->image.flags|=USPosition;
14797 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)-
14798 (windows->image.width/2);
14799 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)-
14800 (windows->image.height/2);
14801 }
14802 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14803 manager_hints->icon_window=windows->icon.id;
14804 manager_hints->input=MagickTrue;
14805 manager_hints->initial_state=resource_info->iconic ? IconicState :
14806 NormalState;
14807 if (windows->group_leader.id != (Window) NULL)
14808 {
14809 /*
14810 Follow the leader.
14811 */
14812 manager_hints->flags|=WindowGroupHint;
14813 manager_hints->window_group=windows->group_leader.id;
14814 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask);
14815 if (display_image->debug != MagickFalse )
14816 (void) LogMagickEvent(X11Event,GetMagickModule(),
14817 "Window id: 0x%lx (group leader)",windows->group_leader.id);
14818 }
14819 XMakeWindow(display,
14820 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window),
14821 argv,argc,class_hints,manager_hints,&windows->image);
14822 (void) XChangeProperty(display,windows->image.id,windows->im_protocols,
14823 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0);
14824 if (windows->group_leader.id != (Window) NULL)
14825 (void) XSetTransientForHint(display,windows->image.id,
14826 windows->group_leader.id);
14827 if (display_image->debug != MagickFalse )
14828 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)",
14829 windows->image.id);
14830 /*
14831 Initialize Info widget.
14832 */
14833 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14834 &windows->info);
14835 (void) CloneString(&windows->info.name,"Info");
14836 (void) CloneString(&windows->info.icon_name,"Info");
14837 windows->info.border_width=1;
14838 windows->info.x=2;
14839 windows->info.y=2;
14840 windows->info.flags|=PPosition;
14841 windows->info.attributes.win_gravity=UnmapGravity;
14842 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask |
14843 StructureNotifyMask;
14844 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14845 manager_hints->input=MagickFalse;
14846 manager_hints->initial_state=NormalState;
14847 manager_hints->window_group=windows->image.id;
14848 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints,
14849 &windows->info);
14850 windows->info.highlight_stipple=XCreateBitmapFromData(display,
14851 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14852 windows->info.shadow_stipple=XCreateBitmapFromData(display,
14853 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14854 (void) XSetTransientForHint(display,windows->info.id,windows->image.id);
14855 if (windows->image.mapped != MagickFalse )
14856 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14857 if (display_image->debug != MagickFalse )
14858 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)",
14859 windows->info.id);
14860 /*
14861 Initialize Command widget.
14862 */
14863 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14864 resource_info,&windows->command);
14865 windows->command.data=MagickMenus;
14866 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL);
14867 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.command",
14868 resource_info->client_name);
14869 windows->command.geometry=XGetResourceClass(resource_info->resource_database,
14870 resource_name,"geometry",(char *) NULL);
14871 (void) CloneString(&windows->command.name,MagickTitle);
14872 windows->command.border_width=0;
14873 windows->command.flags|=PPosition;
14874 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14875 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask |
14876 OwnerGrabButtonMask | StructureNotifyMask;
14877 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14878 manager_hints->input=MagickTrue;
14879 manager_hints->initial_state=NormalState;
14880 manager_hints->window_group=windows->image.id;
14881 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14882 &windows->command);
14883 windows->command.highlight_stipple=XCreateBitmapFromData(display,
14884 windows->command.id,(char *) HighlightBitmap,HighlightWidth,
14885 HighlightHeight);
14886 windows->command.shadow_stipple=XCreateBitmapFromData(display,
14887 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14888 (void) XSetTransientForHint(display,windows->command.id,windows->image.id);
14889 if (windows->command.mapped != MagickFalse )
14890 (void) XMapRaised(display,windows->command.id);
14891 if (display_image->debug != MagickFalse )
14892 (void) LogMagickEvent(X11Event,GetMagickModule(),
14893 "Window id: 0x%lx (command)",windows->command.id);
14894 /*
14895 Initialize Widget window.
14896 */
14897 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14898 resource_info,&windows->widget);
14899 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.widget",
14900 resource_info->client_name);
14901 windows->widget.geometry=XGetResourceClass(resource_info->resource_database,
14902 resource_name,"geometry",(char *) NULL);
14903 windows->widget.border_width=0;
14904 windows->widget.flags|=PPosition;
14905 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14906 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14907 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14908 StructureNotifyMask;
14909 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14910 manager_hints->input=MagickTrue;
14911 manager_hints->initial_state=NormalState;
14912 manager_hints->window_group=windows->image.id;
14913 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14914 &windows->widget);
14915 windows->widget.highlight_stipple=XCreateBitmapFromData(display,
14916 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14917 windows->widget.shadow_stipple=XCreateBitmapFromData(display,
14918 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14919 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id);
14920 if (display_image->debug != MagickFalse )
14921 (void) LogMagickEvent(X11Event,GetMagickModule(),
14922 "Window id: 0x%lx (widget)",windows->widget.id);
14923 /*
14924 Initialize popup window.
14925 */
14926 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14927 resource_info,&windows->popup);
14928 windows->popup.border_width=0;
14929 windows->popup.flags|=PPosition;
14930 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14931 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14932 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask;
14933 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14934 manager_hints->input=MagickTrue;
14935 manager_hints->initial_state=NormalState;
14936 manager_hints->window_group=windows->image.id;
14937 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14938 &windows->popup);
14939 windows->popup.highlight_stipple=XCreateBitmapFromData(display,
14940 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14941 windows->popup.shadow_stipple=XCreateBitmapFromData(display,
14942 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14943 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id);
14944 if (display_image->debug != MagickFalse )
14945 (void) LogMagickEvent(X11Event,GetMagickModule(),
14946 "Window id: 0x%lx (pop up)",windows->popup.id);
14947 /*
14948 Initialize Magnify window and cursor.
14949 */
14950 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14951 resource_info,&windows->magnify);
14952 if (resource_info->use_shared_memory == MagickFalse)
14953 windows->magnify.shared_memory=MagickFalse;
14954 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.magnify",
14955 resource_info->client_name);
14956 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database,
14957 resource_name,"geometry",(char *) NULL);
14958 (void) FormatLocaleString(windows->magnify.name,MagickPathExtent,"Magnify %uX",
14959 resource_info->magnify);
14960 if (windows->magnify.cursor != (Cursor) NULL)
14961 (void) XFreeCursor(display,windows->magnify.cursor);
14962 windows->magnify.cursor=XMakeCursor(display,windows->image.id,
14963 map_info->colormap,resource_info->background_color,
14964 resource_info->foreground_color);
14965 if (windows->magnify.cursor == (Cursor) NULL)
14966 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor",
14967 display_image->filename);
14968 windows->magnify.width=MagnifySize;
14969 windows->magnify.height=MagnifySize;
14970 windows->magnify.flags|=PPosition;
14971 windows->magnify.min_width=MagnifySize;
14972 windows->magnify.min_height=MagnifySize;
14973 windows->magnify.width_inc=MagnifySize;
14974 windows->magnify.height_inc=MagnifySize;
14975 windows->magnify.data=resource_info->magnify;
14976 windows->magnify.attributes.cursor=windows->magnify.cursor;
14977 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask |
14978 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask |
14979 StructureNotifyMask;
14980 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14981 manager_hints->input=MagickTrue;
14982 manager_hints->initial_state=NormalState;
14983 manager_hints->window_group=windows->image.id;
14984 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14985 &windows->magnify);
14986 if (display_image->debug != MagickFalse )
14987 (void) LogMagickEvent(X11Event,GetMagickModule(),
14988 "Window id: 0x%lx (magnify)",windows->magnify.id);
14989 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id);
14990 /*
14991 Initialize panning window.
14992 */
14993 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14994 resource_info,&windows->pan);
14995 (void) CloneString(&windows->pan.name,"Pan Icon");
14996 windows->pan.width=windows->icon.width;
14997 windows->pan.height=windows->icon.height;
14998 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.pan",
14999 resource_info->client_name);
15000 windows->pan.geometry=XGetResourceClass(resource_info->resource_database,
15001 resource_name,"geometry",(char *) NULL);
15002 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
15003 &windows->pan.width,&windows->pan.height);
15004 windows->pan.flags|=PPosition;
15005 windows->pan.immutable=MagickTrue;
15006 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
15007 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask |
15008 StructureNotifyMask;
15009 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
15010 manager_hints->input=MagickFalse;
15011 manager_hints->initial_state=NormalState;
15012 manager_hints->window_group=windows->image.id;
15013 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
15014 &windows->pan);
15015 if (display_image->debug != MagickFalse )
15016 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)",
15017 windows->pan.id);
15018 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id);
15019 if (windows->info.mapped != MagickFalse )
15020 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
15021 if ((windows->image.mapped == MagickFalse) ||
15022 (windows->backdrop.id != (Window) NULL))
15023 (void) XMapWindow(display,windows->image.id);
15024 /*
15025 Set our progress monitor and warning handlers.
15026 */
15027 if (warning_handler == (WarningHandler) NULL)
15028 {
15029 warning_handler=resource_info->display_warnings ?
15030 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
15031 warning_handler=resource_info->display_warnings ?
15032 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
15033 }
15034 /*
15035 Initialize Image and Magnify X images.
15036 */
15037 windows->image.x=0;
15038 windows->image.y=0;
15039 windows->magnify.shape=MagickFalse;
15040 width=(unsigned int) display_image->columns;
15041 height=(unsigned int) display_image->rows;
15042 if ((display_image->columns != width) || (display_image->rows != height))
15043 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
15044 display_image->filename);
15045 status=XMakeImage(display,resource_info,&windows->image,display_image,
15046 width,height,exception);
15047 if (status == MagickFalse)
15048 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
15049 display_image->filename);
15050 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL,
15051 windows->magnify.width,windows->magnify.height,exception);
15052 if (status == MagickFalse)
15053 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
15054 display_image->filename);
15055 if (windows->magnify.mapped != MagickFalse )
15056 (void) XMapRaised(display,windows->magnify.id);
15057 if (windows->pan.mapped != MagickFalse )
15058 (void) XMapRaised(display,windows->pan.id);
15059 windows->image.window_changes.width=(int) display_image->columns;
15060 windows->image.window_changes.height=(int) display_image->rows;
15061 (void) XConfigureImage(display,resource_info,windows,display_image,exception);
15062 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
15063 (void) XSync(display,MagickFalse);
15064 /*
15065 Respond to events.
15066 */
15067 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L);
15068 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15069 update_time=0;
15070 if (resource_info->update != MagickFalse )
15071 {
15072 MagickBooleanType
15073 status;
15074
15075 /*
15076 Determine when file data was last modified.
15077 */
15078 status=GetPathAttributes(display_image->filename,&attributes);
15079 if (status != MagickFalse )
15080 update_time=attributes.st_mtime;
15081 }
15082 *state&=(~FormerImageState);
15083 *state&=(~MontageImageState);
15084 *state&=(~NextImageState);
15085 do
15086 {
15087 /*
15088 Handle a window event.
15089 */
15090 if (windows->image.mapped != MagickFalse )
15091 if ((display_image->delay != 0) || (resource_info->update != 0))
15092 {
15093 if (timer < time((time_t *) NULL))
15094 {
15095 if (resource_info->update == MagickFalse)
15096 *state|=NextImageState | ExitState;
15097 else
15098 {
15099 MagickBooleanType
15100 status;
15101
15102 /*
15103 Determine if image file was modified.
15104 */
15105 status=GetPathAttributes(display_image->filename,&attributes);
15106 if (status != MagickFalse )
15107 if (update_time != attributes.st_mtime)
15108 {
15109 /*
15110 Redisplay image.
15111 */
15112 (void) FormatLocaleString(
15113 resource_info->image_info->filename,MagickPathExtent,
15114 "%s:%s",display_image->magick,
15115 display_image->filename);
15116 nexus=ReadImage(resource_info->image_info,exception);
15117 if (nexus != (Image *) NULL)
15118 *state|=NextImageState | ExitState;
15119 }
15120 delay=display_image->delay/MagickMax(
15121 display_image->ticks_per_second,1L);
15122 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15123 }
15124 }
15125 if (XEventsQueued(display,QueuedAfterFlush) == 0)
15126 {
15127 /*
15128 Do not block if delay > 0.
15129 */
15130 XDelay(display,SuspendTime << 2);
15131 continue;
15132 }
15133 }
15134 timestamp=time((time_t *) NULL);
15135 (void) XNextEvent(display,&event);
15136 if ((windows->image.stasis == MagickFalse) ||
15137 (windows->magnify.stasis == MagickFalse))
15138 {
15139 if ((time((time_t *) NULL)-timestamp) > 0)
15140 {
15141 windows->image.stasis=MagickTrue;
15142 windows->magnify.stasis=MagickTrue;
15143 }
15144 }
15145 if (event.xany.window == windows->command.id)
15146 {
15147 /*
15148 Select a command from the Command widget.
15149 */
15150 id=XCommandWidget(display,windows,CommandMenu,&event);
15151 if (id < 0)
15152 continue;
15153 (void) CopyMagickString(command,CommandMenu[id],MagickPathExtent);
15154 command_type=CommandMenus[id];
15155 if (id < MagickMenus)
15156 {
15157 /*
15158 Select a command from a pop-up menu.
15159 */
15160 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id],
15161 command);
15162 if (entry < 0)
15163 continue;
15164 (void) CopyMagickString(command,Menus[id][entry],MagickPathExtent);
15165 command_type=Commands[id][entry];
15166 }
15167 if (command_type != NullCommand)
15168 nexus=XMagickCommand(display,resource_info,windows,command_type,
15169 &display_image,exception);
15170 continue;
15171 }
15172 switch (event.type)
15173 {
15174 case ButtonPress:
15175 {
15176 if (display_image->debug != MagickFalse )
15177 (void) LogMagickEvent(X11Event,GetMagickModule(),
15178 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
15179 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15180 if ((event.xbutton.button == Button3) &&
15181 (event.xbutton.state & Mod1Mask))
15182 {
15183 /*
15184 Convert Alt-Button3 to Button2.
15185 */
15186 event.xbutton.button=Button2;
15187 event.xbutton.state&=(~Mod1Mask);
15188 }
15189 if (event.xbutton.window == windows->backdrop.id)
15190 {
15191 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent,
15192 event.xbutton.time);
15193 break;
15194 }
15195 if (event.xbutton.window == windows->image.id)
15196 {
15197 switch (event.xbutton.button)
15198 {
15199 case Button1:
15200 {
15201 if (resource_info->immutable)
15202 {
15203 /*
15204 Select a command from the Virtual menu.
15205 */
15206 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15207 command);
15208 if (entry >= 0)
15209 nexus=XMagickCommand(display,resource_info,windows,
15210 VirtualCommands[entry],&display_image,exception);
15211 break;
15212 }
15213 /*
15214 Map/unmap Command widget.
15215 */
15216 if (windows->command.mapped != MagickFalse )
15217 (void) XWithdrawWindow(display,windows->command.id,
15218 windows->command.screen);
15219 else
15220 {
15221 (void) XCommandWidget(display,windows,CommandMenu,
15222 (XEvent *) NULL);
15223 (void) XMapRaised(display,windows->command.id);
15224 }
15225 break;
15226 }
15227 case Button2:
15228 {
15229 /*
15230 User pressed the image magnify button.
15231 */
15232 (void) XMagickCommand(display,resource_info,windows,ZoomCommand,
15233 &display_image,exception);
15234 XMagnifyImage(display,windows,&event,exception);
15235 break;
15236 }
15237 case Button3:
15238 {
15239 if (resource_info->immutable)
15240 {
15241 /*
15242 Select a command from the Virtual menu.
15243 */
15244 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15245 command);
15246 if (entry >= 0)
15247 nexus=XMagickCommand(display,resource_info,windows,
15248 VirtualCommands[entry],&display_image,exception);
15249 break;
15250 }
15251 if (display_image->montage != (char *) NULL)
15252 {
15253 /*
15254 Open or delete a tile from a visual image directory.
15255 */
15256 nexus=XTileImage(display,resource_info,windows,
15257 display_image,&event,exception);
15258 if (nexus != (Image *) NULL)
15259 *state|=MontageImageState | NextImageState | ExitState;
15260 vid_info.x=(short int) windows->image.x;
15261 vid_info.y=(short int) windows->image.y;
15262 break;
15263 }
15264 /*
15265 Select a command from the Short Cuts menu.
15266 */
15267 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu,
15268 command);
15269 if (entry >= 0)
15270 nexus=XMagickCommand(display,resource_info,windows,
15271 ShortCutsCommands[entry],&display_image,exception);
15272 break;
15273 }
15274 case Button4:
15275 {
15276 /*
15277 Wheel up.
15278 */
15279 XTranslateImage(display,windows,*image,XK_Up);
15280 break;
15281 }
15282 case Button5:
15283 {
15284 /*
15285 Wheel down.
15286 */
15287 XTranslateImage(display,windows,*image,XK_Down);
15288 break;
15289 }
15290 default:
15291 break;
15292 }
15293 break;
15294 }
15295 if (event.xbutton.window == windows->magnify.id)
15296 {
15297 int
15298 factor;
15299
15300 static const char
15301 *MagnifyMenu[] =
15302 {
15303 "2",
15304 "4",
15305 "5",
15306 "6",
15307 "7",
15308 "8",
15309 "9",
15310 "3",
15311 (char *) NULL,
15312 };
15313
15314 static KeySym
15315 MagnifyCommands[] =
15316 {
15317 XK_2,
15318 XK_4,
15319 XK_5,
15320 XK_6,
15321 XK_7,
15322 XK_8,
15323 XK_9,
15324 XK_3
15325 };
15326
15327 /*
15328 Select a magnify factor from the pop-up menu.
15329 */
15330 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command);
15331 if (factor >= 0)
15332 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor],
15333 exception);
15334 break;
15335 }
15336 if (event.xbutton.window == windows->pan.id)
15337 {
15338 switch (event.xbutton.button)
15339 {
15340 case Button4:
15341 {
15342 /*
15343 Wheel up.
15344 */
15345 XTranslateImage(display,windows,*image,XK_Up);
15346 break;
15347 }
15348 case Button5:
15349 {
15350 /*
15351 Wheel down.
15352 */
15353 XTranslateImage(display,windows,*image,XK_Down);
15354 break;
15355 }
15356 default:
15357 {
15358 XPanImage(display,windows,&event,exception);
15359 break;
15360 }
15361 }
15362 break;
15363 }
15364 delay=display_image->delay/MagickMax(display_image->ticks_per_second,
15365 1L);
15366 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15367 break;
15368 }
15369 case ButtonRelease:
15370 {
15371 if (display_image->debug != MagickFalse )
15372 (void) LogMagickEvent(X11Event,GetMagickModule(),
15373 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
15374 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15375 break;
15376 }
15377 case ClientMessage:
15378 {
15379 if (display_image->debug != MagickFalse )
15380 (void) LogMagickEvent(X11Event,GetMagickModule(),
15381 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window,
15382 event.xclient.message_type,event.xclient.format,(unsigned long)
15383 event.xclient.data.l[0]);
15384 if (event.xclient.message_type == windows->im_protocols)
15385 {
15386 if (*event.xclient.data.l == (long) windows->im_update_widget)
15387 {
15388 (void) CloneString(&windows->command.name,MagickTitle);
15389 windows->command.data=MagickMenus;
15390 (void) XCommandWidget(display,windows,CommandMenu,
15391 (XEvent *) NULL);
15392 break;
15393 }
15394 if (*event.xclient.data.l == (long) windows->im_update_colormap)
15395 {
15396 /*
15397 Update graphic context and window colormap.
15398 */
15399 for (i=0; i < (int) number_windows; i++)
15400 {
15401 if (magick_windows[i]->id == windows->icon.id)
15402 continue;
15403 context_values.background=pixel->background_color.pixel;
15404 context_values.foreground=pixel->foreground_color.pixel;
15405 (void) XChangeGC(display,magick_windows[i]->annotate_context,
15406 context_mask,&context_values);
15407 (void) XChangeGC(display,magick_windows[i]->widget_context,
15408 context_mask,&context_values);
15409 context_values.background=pixel->foreground_color.pixel;
15410 context_values.foreground=pixel->background_color.pixel;
15411 context_values.plane_mask=context_values.background ^
15412 context_values.foreground;
15413 (void) XChangeGC(display,magick_windows[i]->highlight_context,
15414 (size_t) (context_mask | GCPlaneMask),
15415 &context_values);
15416 magick_windows[i]->attributes.background_pixel=
15417 pixel->background_color.pixel;
15418 magick_windows[i]->attributes.border_pixel=
15419 pixel->border_color.pixel;
15420 magick_windows[i]->attributes.colormap=map_info->colormap;
15421 (void) XChangeWindowAttributes(display,magick_windows[i]->id,
15422 (unsigned long) magick_windows[i]->mask,
15423 &magick_windows[i]->attributes);
15424 }
15425 if (windows->pan.mapped != MagickFalse )
15426 {
15427 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
15428 windows->pan.pixmap);
15429 (void) XClearWindow(display,windows->pan.id);
15430 XDrawPanRectangle(display,windows);
15431 }
15432 if (windows->backdrop.id != (Window) NULL)
15433 (void) XInstallColormap(display,map_info->colormap);
15434 break;
15435 }
15436 if (*event.xclient.data.l == (long) windows->im_former_image)
15437 {
15438 *state|=FormerImageState | ExitState;
15439 break;
15440 }
15441 if (*event.xclient.data.l == (long) windows->im_next_image)
15442 {
15443 *state|=NextImageState | ExitState;
15444 break;
15445 }
15446 if (*event.xclient.data.l == (long) windows->im_retain_colors)
15447 {
15448 *state|=RetainColorsState;
15449 break;
15450 }
15451 if (*event.xclient.data.l == (long) windows->im_exit)
15452 {
15453 *state|=ExitState;
15454 break;
15455 }
15456 break;
15457 }
15458 if (event.xclient.message_type == windows->dnd_protocols)
15459 {
15460 Atom
15461 selection,
15462 type;
15463
15464 int
15465 format,
15466 status;
15467
15468 unsigned char
15469 *data;
15470
15471 unsigned long
15472 after,
15473 length;
15474
15475 /*
15476 Display image named by the Drag-and-Drop selection.
15477 */
15478 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128))
15479 break;
15480 selection=XInternAtom(display,"DndSelection",MagickFalse);
15481 status=XGetWindowProperty(display,root_window,selection,0L,(long)
15482 MagickPathExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format,
15483 &length,&after,&data);
15484 if ((status != Success) || (length == 0))
15485 break;
15486 if (*event.xclient.data.l == 2)
15487 {
15488 /*
15489 Offix DND.
15490 */
15491 (void) CopyMagickString(resource_info->image_info->filename,
15492 (char *) data,MagickPathExtent);
15493 }
15494 else
15495 {
15496 /*
15497 XDND.
15498 */
15499 if (strncmp((char *) data, "file:", 5) != 0)
15500 {
15501 (void) XFree((void *) data);
15502 break;
15503 }
15504 (void) CopyMagickString(resource_info->image_info->filename,
15505 ((char *) data)+5,MagickPathExtent);
15506 }
15507 nexus=ReadImage(resource_info->image_info,exception);
15508 CatchException(exception);
15509 if (nexus != (Image *) NULL)
15510 *state|=NextImageState | ExitState;
15511 (void) XFree((void *) data);
15512 break;
15513 }
15514 /*
15515 If client window delete message, exit.
15516 */
15517 if (event.xclient.message_type != windows->wm_protocols)
15518 break;
15519 if (*event.xclient.data.l != (long) windows->wm_delete_window)
15520 break;
15521 (void) XWithdrawWindow(display,event.xclient.window,
15522 visual_info->screen);
15523 if (event.xclient.window == windows->image.id)
15524 {
15525 *state|=ExitState;
15526 break;
15527 }
15528 if (event.xclient.window == windows->pan.id)
15529 {
15530 /*
15531 Restore original image size when pan window is deleted.
15532 */
15533 windows->image.window_changes.width=windows->image.ximage->width;
15534 windows->image.window_changes.height=windows->image.ximage->height;
15535 (void) XConfigureImage(display,resource_info,windows,
15536 display_image,exception);
15537 }
15538 break;
15539 }
15540 case ConfigureNotify:
15541 {
15542 if (display_image->debug != MagickFalse )
15543 (void) LogMagickEvent(X11Event,GetMagickModule(),
15544 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window,
15545 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x,
15546 event.xconfigure.y,event.xconfigure.send_event);
15547 if (event.xconfigure.window == windows->image.id)
15548 {
15549 /*
15550 Image window has a new configuration.
15551 */
15552 if (event.xconfigure.send_event != 0)
15553 {
15554 XWindowChanges
15555 window_changes;
15556
15557 /*
15558 Position the transient windows relative of the Image window.
15559 */
15560 if (windows->command.geometry == (char *) NULL)
15561 if (windows->command.mapped == MagickFalse)
15562 {
15563 windows->command.x=event.xconfigure.x-
15564 windows->command.width-25;
15565 windows->command.y=event.xconfigure.y;
15566 XConstrainWindowPosition(display,&windows->command);
15567 window_changes.x=windows->command.x;
15568 window_changes.y=windows->command.y;
15569 (void) XReconfigureWMWindow(display,windows->command.id,
15570 windows->command.screen,(unsigned int) (CWX | CWY),
15571 &window_changes);
15572 }
15573 if (windows->widget.geometry == (char *) NULL)
15574 if (windows->widget.mapped == MagickFalse)
15575 {
15576 windows->widget.x=event.xconfigure.x+
15577 event.xconfigure.width/10;
15578 windows->widget.y=event.xconfigure.y+
15579 event.xconfigure.height/10;
15580 XConstrainWindowPosition(display,&windows->widget);
15581 window_changes.x=windows->widget.x;
15582 window_changes.y=windows->widget.y;
15583 (void) XReconfigureWMWindow(display,windows->widget.id,
15584 windows->widget.screen,(unsigned int) (CWX | CWY),
15585 &window_changes);
15586 }
15587 if (windows->magnify.geometry == (char *) NULL)
15588 if (windows->magnify.mapped == MagickFalse)
15589 {
15590 windows->magnify.x=event.xconfigure.x+
15591 event.xconfigure.width+25;
15592 windows->magnify.y=event.xconfigure.y;
15593 XConstrainWindowPosition(display,&windows->magnify);
15594 window_changes.x=windows->magnify.x;
15595 window_changes.y=windows->magnify.y;
15596 (void) XReconfigureWMWindow(display,windows->magnify.id,
15597 windows->magnify.screen,(unsigned int) (CWX | CWY),
15598 &window_changes);
15599 }
15600 if (windows->pan.geometry == (char *) NULL)
15601 if (windows->pan.mapped == MagickFalse)
15602 {
15603 windows->pan.x=event.xconfigure.x+
15604 event.xconfigure.width+25;
15605 windows->pan.y=event.xconfigure.y+
15606 windows->magnify.height+50;
15607 XConstrainWindowPosition(display,&windows->pan);
15608 window_changes.x=windows->pan.x;
15609 window_changes.y=windows->pan.y;
15610 (void) XReconfigureWMWindow(display,windows->pan.id,
15611 windows->pan.screen,(unsigned int) (CWX | CWY),
15612 &window_changes);
15613 }
15614 }
15615 if ((event.xconfigure.width == (int) windows->image.width) &&
15616 (event.xconfigure.height == (int) windows->image.height))
15617 break;
15618 windows->image.width=(unsigned int) event.xconfigure.width;
15619 windows->image.height=(unsigned int) event.xconfigure.height;
15620 windows->image.x=0;
15621 windows->image.y=0;
15622 if (display_image->montage != (char *) NULL)
15623 {
15624 windows->image.x=vid_info.x;
15625 windows->image.y=vid_info.y;
15626 }
15627 if (windows->image.mapped != MagickFalse &&
15628 windows->image.stasis != MagickFalse )
15629 {
15630 /*
15631 Update image window configuration.
15632 */
15633 windows->image.window_changes.width=event.xconfigure.width;
15634 windows->image.window_changes.height=event.xconfigure.height;
15635 (void) XConfigureImage(display,resource_info,windows,
15636 display_image,exception);
15637 }
15638 /*
15639 Update pan window configuration.
15640 */
15641 if ((event.xconfigure.width < windows->image.ximage->width) ||
15642 (event.xconfigure.height < windows->image.ximage->height))
15643 {
15644 (void) XMapRaised(display,windows->pan.id);
15645 XDrawPanRectangle(display,windows);
15646 }
15647 else
15648 if (windows->pan.mapped != MagickFalse )
15649 (void) XWithdrawWindow(display,windows->pan.id,
15650 windows->pan.screen);
15651 break;
15652 }
15653 if (event.xconfigure.window == windows->magnify.id)
15654 {
15655 unsigned int
15656 magnify;
15657
15658 /*
15659 Magnify window has a new configuration.
15660 */
15661 windows->magnify.width=(unsigned int) event.xconfigure.width;
15662 windows->magnify.height=(unsigned int) event.xconfigure.height;
15663 if (windows->magnify.mapped == MagickFalse)
15664 break;
15665 magnify=1;
15666 while ((int) magnify <= event.xconfigure.width)
15667 magnify<<=1;
15668 while ((int) magnify <= event.xconfigure.height)
15669 magnify<<=1;
15670 magnify>>=1;
15671 if (((int) magnify != event.xconfigure.width) ||
15672 ((int) magnify != event.xconfigure.height))
15673 {
15674 window_changes.width=(int) magnify;
15675 window_changes.height=(int) magnify;
15676 (void) XReconfigureWMWindow(display,windows->magnify.id,
15677 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
15678 &window_changes);
15679 break;
15680 }
15681 if (windows->magnify.mapped != MagickFalse &&
15682 windows->magnify.stasis != MagickFalse )
15683 {
15684 status=XMakeImage(display,resource_info,&windows->magnify,
15685 display_image,windows->magnify.width,windows->magnify.height,
15686 exception);
15687 XMakeMagnifyImage(display,windows,exception);
15688 }
15689 break;
15690 }
15691 if (windows->magnify.mapped != MagickFalse &&
15692 (event.xconfigure.window == windows->pan.id))
15693 {
15694 /*
15695 Pan icon window has a new configuration.
15696 */
15697 if (event.xconfigure.send_event != 0)
15698 {
15699 windows->pan.x=event.xconfigure.x;
15700 windows->pan.y=event.xconfigure.y;
15701 }
15702 windows->pan.width=(unsigned int) event.xconfigure.width;
15703 windows->pan.height=(unsigned int) event.xconfigure.height;
15704 break;
15705 }
15706 if (event.xconfigure.window == windows->icon.id)
15707 {
15708 /*
15709 Icon window has a new configuration.
15710 */
15711 windows->icon.width=(unsigned int) event.xconfigure.width;
15712 windows->icon.height=(unsigned int) event.xconfigure.height;
15713 break;
15714 }
15715 break;
15716 }
15717 case DestroyNotify:
15718 {
15719 /*
15720 Group leader has exited.
15721 */
15722 if (display_image->debug != MagickFalse )
15723 (void) LogMagickEvent(X11Event,GetMagickModule(),
15724 "Destroy Notify: 0x%lx",event.xdestroywindow.window);
15725 if (event.xdestroywindow.window == windows->group_leader.id)
15726 {
15727 *state|=ExitState;
15728 break;
15729 }
15730 break;
15731 }
15732 case EnterNotify:
15733 {
15734 /*
15735 Selectively install colormap.
15736 */
15737 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15738 if (event.xcrossing.mode != NotifyUngrab)
15739 XInstallColormap(display,map_info->colormap);
15740 break;
15741 }
15742 case Expose:
15743 {
15744 if (display_image->debug != MagickFalse )
15745 (void) LogMagickEvent(X11Event,GetMagickModule(),
15746 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window,
15747 event.xexpose.width,event.xexpose.height,event.xexpose.x,
15748 event.xexpose.y);
15749 /*
15750 Refresh windows that are now exposed.
15751 */
15752 if ((event.xexpose.window == windows->image.id) &&
15753 windows->image.mapped != MagickFalse )
15754 {
15755 XRefreshWindow(display,&windows->image,&event);
15756 delay=display_image->delay/MagickMax(
15757 display_image->ticks_per_second,1L);
15758 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15759 break;
15760 }
15761 if ((event.xexpose.window == windows->magnify.id) &&
15762 windows->magnify.mapped != MagickFalse)
15763 {
15764 XMakeMagnifyImage(display,windows,exception);
15765 break;
15766 }
15767 if (event.xexpose.window == windows->pan.id)
15768 {
15769 XDrawPanRectangle(display,windows);
15770 break;
15771 }
15772 if (event.xexpose.window == windows->icon.id)
15773 {
15774 XRefreshWindow(display,&windows->icon,&event);
15775 break;
15776 }
15777 break;
15778 }
15779 case KeyPress:
15780 {
15781 int
15782 length;
15783
15784 /*
15785 Respond to a user key press.
15786 */
15787 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
15788 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15789 *(command+length)='\0';
15790 if (display_image->debug != MagickFalse )
15791 (void) LogMagickEvent(X11Event,GetMagickModule(),
15792 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long)
15793 key_symbol,command);
15794 if (event.xkey.window == windows->image.id)
15795 {
15796 command_type=XImageWindowCommand(display,resource_info,windows,
15797 event.xkey.state,key_symbol,&display_image,exception);
15798 if (command_type != NullCommand)
15799 nexus=XMagickCommand(display,resource_info,windows,command_type,
15800 &display_image,exception);
15801 }
15802 if (event.xkey.window == windows->magnify.id)
15803 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol,
15804 exception);
15805 if (event.xkey.window == windows->pan.id)
15806 {
15807 if ((key_symbol == XK_q) || (key_symbol == XK_Escape))
15808 (void) XWithdrawWindow(display,windows->pan.id,
15809 windows->pan.screen);
15810 else
15811 if ((key_symbol == XK_F1) || (key_symbol == XK_Help))
15812 XTextViewWidget(display,resource_info,windows,MagickFalse,
15813 "Help Viewer - Image Pan",ImagePanHelp);
15814 else
15815 XTranslateImage(display,windows,*image,key_symbol);
15816 }
15817 delay=display_image->delay/MagickMax(
15818 display_image->ticks_per_second,1L);
15819 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15820 break;
15821 }
15822 case KeyRelease:
15823 {
15824 /*
15825 Respond to a user key release.
15826 */
15827 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
15828 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15829 if (display_image->debug != MagickFalse )
15830 (void) LogMagickEvent(X11Event,GetMagickModule(),
15831 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command);
15832 break;
15833 }
15834 case LeaveNotify:
15835 {
15836 /*
15837 Selectively uninstall colormap.
15838 */
15839 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15840 if (event.xcrossing.mode != NotifyUngrab)
15841 XUninstallColormap(display,map_info->colormap);
15842 break;
15843 }
15844 case MapNotify:
15845 {
15846 if (display_image->debug != MagickFalse )
15847 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx",
15848 event.xmap.window);
15849 if (event.xmap.window == windows->backdrop.id)
15850 {
15851 (void) XSetInputFocus(display,event.xmap.window,RevertToParent,
15852 CurrentTime);
15853 windows->backdrop.mapped=MagickTrue;
15854 break;
15855 }
15856 if (event.xmap.window == windows->image.id)
15857 {
15858 if (windows->backdrop.id != (Window) NULL)
15859 (void) XInstallColormap(display,map_info->colormap);
15860 if (LocaleCompare(display_image->magick,"LOGO") == 0)
15861 {
15862 if (LocaleCompare(display_image->filename,"LOGO") == 0)
15863 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
15864 }
15865 if (((int) windows->image.width < windows->image.ximage->width) ||
15866 ((int) windows->image.height < windows->image.ximage->height))
15867 (void) XMapRaised(display,windows->pan.id);
15868 windows->image.mapped=MagickTrue;
15869 break;
15870 }
15871 if (event.xmap.window == windows->magnify.id)
15872 {
15873 XMakeMagnifyImage(display,windows,exception);
15874 windows->magnify.mapped=MagickTrue;
15875 (void) XWithdrawWindow(display,windows->info.id,
15876 windows->info.screen);
15877 break;
15878 }
15879 if (event.xmap.window == windows->pan.id)
15880 {
15881 XMakePanImage(display,resource_info,windows,display_image,
15882 exception);
15883 windows->pan.mapped=MagickTrue;
15884 break;
15885 }
15886 if (event.xmap.window == windows->info.id)
15887 {
15888 windows->info.mapped=MagickTrue;
15889 break;
15890 }
15891 if (event.xmap.window == windows->icon.id)
15892 {
15893 MagickBooleanType
15894 taint;
15895
15896 /*
15897 Create an icon image.
15898 */
15899 taint=display_image->taint;
15900 XMakeStandardColormap(display,icon_visual,icon_resources,
15901 display_image,icon_map,icon_pixel,exception);
15902 (void) XMakeImage(display,icon_resources,&windows->icon,
15903 display_image,windows->icon.width,windows->icon.height,
15904 exception);
15905 display_image->taint=taint;
15906 (void) XSetWindowBackgroundPixmap(display,windows->icon.id,
15907 windows->icon.pixmap);
15908 (void) XClearWindow(display,windows->icon.id);
15909 (void) XWithdrawWindow(display,windows->info.id,
15910 windows->info.screen);
15911 windows->icon.mapped=MagickTrue;
15912 break;
15913 }
15914 if (event.xmap.window == windows->command.id)
15915 {
15916 windows->command.mapped=MagickTrue;
15917 break;
15918 }
15919 if (event.xmap.window == windows->popup.id)
15920 {
15921 windows->popup.mapped=MagickTrue;
15922 break;
15923 }
15924 if (event.xmap.window == windows->widget.id)
15925 {
15926 windows->widget.mapped=MagickTrue;
15927 break;
15928 }
15929 break;
15930 }
15931 case MappingNotify:
15932 {
15933 (void) XRefreshKeyboardMapping(&event.xmapping);
15934 break;
15935 }
15936 case NoExpose:
15937 break;
15938 case PropertyNotify:
15939 {
15940 Atom
15941 type;
15942
15943 int
15944 format,
15945 status;
15946
15947 unsigned char
15948 *data;
15949
15950 unsigned long
15951 after,
15952 length;
15953
15954 if (display_image->debug != MagickFalse )
15955 (void) LogMagickEvent(X11Event,GetMagickModule(),
15956 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window,
15957 event.xproperty.atom,event.xproperty.state);
15958 if (event.xproperty.atom != windows->im_remote_command)
15959 break;
15960 /*
15961 Display image named by the remote command protocol.
15962 */
15963 status=XGetWindowProperty(display,event.xproperty.window,
15964 event.xproperty.atom,0L,(long) MagickPathExtent,MagickFalse,(Atom)
15965 AnyPropertyType,&type,&format,&length,&after,&data);
15966 if ((status != Success) || (length == 0))
15967 break;
15968 if (LocaleCompare((char *) data,"-quit") == 0)
15969 {
15970 XClientMessage(display,windows->image.id,windows->im_protocols,
15971 windows->im_exit,CurrentTime);
15972 (void) XFree((void *) data);
15973 break;
15974 }
15975 (void) CopyMagickString(resource_info->image_info->filename,
15976 (char *) data,MagickPathExtent);
15977 (void) XFree((void *) data);
15978 nexus=ReadImage(resource_info->image_info,exception);
15979 CatchException(exception);
15980 if (nexus != (Image *) NULL)
15981 *state|=NextImageState | ExitState;
15982 break;
15983 }
15984 case ReparentNotify:
15985 {
15986 if (display_image->debug != MagickFalse )
15987 (void) LogMagickEvent(X11Event,GetMagickModule(),
15988 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent,
15989 event.xreparent.window);
15990 break;
15991 }
15992 case UnmapNotify:
15993 {
15994 if (display_image->debug != MagickFalse )
15995 (void) LogMagickEvent(X11Event,GetMagickModule(),
15996 "Unmap Notify: 0x%lx",event.xunmap.window);
15997 if (event.xunmap.window == windows->backdrop.id)
15998 {
15999 windows->backdrop.mapped=MagickFalse;
16000 break;
16001 }
16002 if (event.xunmap.window == windows->image.id)
16003 {
16004 windows->image.mapped=MagickFalse;
16005 break;
16006 }
16007 if (event.xunmap.window == windows->magnify.id)
16008 {
16009 windows->magnify.mapped=MagickFalse;
16010 break;
16011 }
16012 if (event.xunmap.window == windows->pan.id)
16013 {
16014 windows->pan.mapped=MagickFalse;
16015 break;
16016 }
16017 if (event.xunmap.window == windows->info.id)
16018 {
16019 windows->info.mapped=MagickFalse;
16020 break;
16021 }
16022 if (event.xunmap.window == windows->icon.id)
16023 {
16024 if (map_info->colormap == icon_map->colormap)
16025 XConfigureImageColormap(display,resource_info,windows,
16026 display_image,exception);
16027 (void) XFreeStandardColormap(display,icon_visual,icon_map,
16028 icon_pixel);
16029 windows->icon.mapped=MagickFalse;
16030 break;
16031 }
16032 if (event.xunmap.window == windows->command.id)
16033 {
16034 windows->command.mapped=MagickFalse;
16035 break;
16036 }
16037 if (event.xunmap.window == windows->popup.id)
16038 {
16039 if (windows->backdrop.id != (Window) NULL)
16040 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
16041 CurrentTime);
16042 windows->popup.mapped=MagickFalse;
16043 break;
16044 }
16045 if (event.xunmap.window == windows->widget.id)
16046 {
16047 if (windows->backdrop.id != (Window) NULL)
16048 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
16049 CurrentTime);
16050 windows->widget.mapped=MagickFalse;
16051 break;
16052 }
16053 break;
16054 }
16055 default:
16056 {
16057 if (display_image->debug != MagickFalse )
16058 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
16059 event.type);
16060 break;
16061 }
16062 }
16063 } while (!(*state & ExitState));
16064 if ((*state & ExitState) == 0)
16065 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand,
16066 &display_image,exception);
16067 else
16068 if (resource_info->confirm_edit != MagickFalse )
16069 {
16070 /*
16071 Query user if image has changed.
16072 */
16073 if ((resource_info->immutable == MagickFalse) &&
16074 display_image->taint != MagickFalse)
16075 {
16076 int
16077 status;
16078
16079 status=XConfirmWidget(display,windows,"Your image changed.",
16080 "Do you want to save it");
16081 if (status == 0)
16082 *state&=(~ExitState);
16083 else
16084 if (status > 0)
16085 (void) XMagickCommand(display,resource_info,windows,SaveCommand,
16086 &display_image,exception);
16087 }
16088 }
16089 if ((windows->visual_info->klass == GrayScale) ||
16090 (windows->visual_info->klass == PseudoColor) ||
16091 (windows->visual_info->klass == DirectColor))
16092 {
16093 /*
16094 Withdraw pan and Magnify window.
16095 */
16096 if (windows->info.mapped != MagickFalse )
16097 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
16098 if (windows->magnify.mapped != MagickFalse )
16099 (void) XWithdrawWindow(display,windows->magnify.id,
16100 windows->magnify.screen);
16101 if (windows->command.mapped != MagickFalse )
16102 (void) XWithdrawWindow(display,windows->command.id,
16103 windows->command.screen);
16104 }
16105 if (windows->pan.mapped != MagickFalse )
16106 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen);
16107 if (resource_info->backdrop == MagickFalse)
16108 if (windows->backdrop.mapped)
16109 {
16110 (void) XWithdrawWindow(display,windows->backdrop.id,
16111 windows->backdrop.screen);
16112 (void) XDestroyWindow(display,windows->backdrop.id);
16113 windows->backdrop.id=(Window) NULL;
16114 (void) XWithdrawWindow(display,windows->image.id,
16115 windows->image.screen);
16116 (void) XDestroyWindow(display,windows->image.id);
16117 windows->image.id=(Window) NULL;
16118 }
16119 XSetCursorState(display,windows,MagickTrue);
16120 XCheckRefreshWindows(display,windows);
16121 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0))
16122 *state&=(~ExitState);
16123 if (*state & ExitState)
16124 {
16125 /*
16126 Free Standard Colormap.
16127 */
16128 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel);
16129 if (resource_info->map_type == (char *) NULL)
16130 (void) XFreeStandardColormap(display,visual_info,map_info,pixel);
16131 /*
16132 Free X resources.
16133 */
16134 if (resource_info->copy_image != (Image *) NULL)
16135 {
16136 resource_info->copy_image=DestroyImage(resource_info->copy_image);
16137 resource_info->copy_image=NewImageList();
16138 }
16139 DestroyXResources();
16140 }
16141 (void) XSync(display,MagickFalse);
16142 /*
16143 Restore our progress monitor and warning handlers.
16144 */
16145 (void) SetErrorHandler(warning_handler);
16146 (void) SetWarningHandler(warning_handler);
16147 /*
16148 Change to home directory.
16149 */
16150 directory=getcwd(working_directory,MagickPathExtent);
16151 (void) directory;
16152 {
16153 int
16154 status;
16155
16156 if (*resource_info->home_directory == '\0')
16157 (void) CopyMagickString(resource_info->home_directory,".",MagickPathExtent);
16158 status=chdir(resource_info->home_directory);
16159 if (status == -1)
16160 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
16161 "UnableToOpenFile","%s",resource_info->home_directory);
16162 }
16163 *image=display_image;
16164 return(nexus);
16165 }
16166 #else
16167
16168 /*
16169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16170 % %
16171 % %
16172 % %
16173 + D i s p l a y I m a g e s %
16174 % %
16175 % %
16176 % %
16177 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16178 %
16179 % DisplayImages() displays an image sequence to any X window screen. It
16180 % returns a value other than 0 if successful. Check the exception member
16181 % of image to determine the reason for any failure.
16182 %
16183 % The format of the DisplayImages method is:
16184 %
16185 % MagickBooleanType DisplayImages(const ImageInfo *image_info,
16186 % Image *images,ExceptionInfo *exception)
16187 %
16188 % A description of each parameter follows:
16189 %
16190 % o image_info: the image info.
16191 %
16192 % o image: the image.
16193 %
16194 % o exception: return any errors or warnings in this structure.
16195 %
16196 */
DisplayImages(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)16197 MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
16198 Image *image,ExceptionInfo *exception)
16199 {
16200 assert(image_info != (const ImageInfo *) NULL);
16201 assert(image_info->signature == MagickCoreSignature);
16202 assert(image != (Image *) NULL);
16203 assert(image->signature == MagickCoreSignature);
16204 (void) image_info;
16205 if (image->debug != MagickFalse )
16206 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
16207 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
16208 "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image->filename);
16209 return(MagickFalse);
16210 }
16211
16212 /*
16213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16214 % %
16215 % %
16216 % %
16217 + R e m o t e D i s p l a y C o m m a n d %
16218 % %
16219 % %
16220 % %
16221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16222 %
16223 % RemoteDisplayCommand() encourages a remote display program to display the
16224 % specified image filename.
16225 %
16226 % The format of the RemoteDisplayCommand method is:
16227 %
16228 % MagickBooleanType RemoteDisplayCommand(const ImageInfo *image,
16229 % const char *window,const char *filename,ExceptionInfo *exception)
16230 %
16231 % A description of each parameter follows:
16232 %
16233 % o image_info: the image info.
16234 %
16235 % o window: Specifies the name or id of an X window.
16236 %
16237 % o filename: the name of the image filename to display.
16238 %
16239 % o exception: return any errors or warnings in this structure.
16240 %
16241 */
RemoteDisplayCommand(const ImageInfo * image_info,const char * window,const char * filename,ExceptionInfo * exception)16242 MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
16243 const char *window,const char *filename,ExceptionInfo *exception)
16244 {
16245 assert(image_info != (const ImageInfo *) NULL);
16246 assert(image_info->signature == MagickCoreSignature);
16247 assert(filename != (char *) NULL);
16248 (void) window;
16249 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
16250 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
16251 "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image_info->filename);
16252 return(MagickFalse);
16253 }
16254 #endif
16255