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-2019 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/script/license.php %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38
39 /*
40 Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/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) memset(&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) memset(&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,
5750 MagickPathExtent,"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,
7534 MagickPathExtent,"%ux%u%+d%+d",width,height,(int) (*image)->columns-
7535 (int) width-x,y);
7536 }
7537 if (windows->image.orphan != MagickFalse )
7538 break;
7539 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7540 break;
7541 }
7542 case FlipCommand:
7543 {
7544 Image
7545 *flip_image;
7546
7547 /*
7548 Flip image scanlines.
7549 */
7550 XSetCursorState(display,windows,MagickTrue);
7551 XCheckRefreshWindows(display,windows);
7552 flip_image=FlipImage(*image,exception);
7553 if (flip_image != (Image *) NULL)
7554 {
7555 *image=DestroyImage(*image);
7556 *image=flip_image;
7557 }
7558 CatchException(exception);
7559 XSetCursorState(display,windows,MagickFalse);
7560 if (windows->image.crop_geometry != (char *) NULL)
7561 {
7562 /*
7563 Flip crop geometry.
7564 */
7565 width=(unsigned int) (*image)->columns;
7566 height=(unsigned int) (*image)->rows;
7567 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7568 &width,&height);
7569 (void) FormatLocaleString(windows->image.crop_geometry,
7570 MagickPathExtent,"%ux%u%+d%+d",width,height,x,(int) (*image)->rows-
7571 (int) height-y);
7572 }
7573 if (windows->image.orphan != MagickFalse )
7574 break;
7575 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7576 break;
7577 }
7578 case RotateRightCommand:
7579 {
7580 /*
7581 Rotate image 90 degrees clockwise.
7582 */
7583 status=XRotateImage(display,resource_info,windows,90.0,image,exception);
7584 if (status == MagickFalse)
7585 {
7586 XNoticeWidget(display,windows,"Unable to rotate X image",
7587 (*image)->filename);
7588 break;
7589 }
7590 break;
7591 }
7592 case RotateLeftCommand:
7593 {
7594 /*
7595 Rotate image 90 degrees counter-clockwise.
7596 */
7597 status=XRotateImage(display,resource_info,windows,-90.0,image,exception);
7598 if (status == MagickFalse)
7599 {
7600 XNoticeWidget(display,windows,"Unable to rotate X image",
7601 (*image)->filename);
7602 break;
7603 }
7604 break;
7605 }
7606 case RotateCommand:
7607 {
7608 /*
7609 Rotate image.
7610 */
7611 status=XRotateImage(display,resource_info,windows,0.0,image,exception);
7612 if (status == MagickFalse)
7613 {
7614 XNoticeWidget(display,windows,"Unable to rotate X image",
7615 (*image)->filename);
7616 break;
7617 }
7618 break;
7619 }
7620 case ShearCommand:
7621 {
7622 Image
7623 *shear_image;
7624
7625 static char
7626 geometry[MagickPathExtent] = "45.0x45.0";
7627
7628 /*
7629 Query user for shear color and geometry.
7630 */
7631 XColorBrowserWidget(display,windows,"Select",color);
7632 if (*color == '\0')
7633 break;
7634 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:",
7635 geometry);
7636 if (*geometry == '\0')
7637 break;
7638 /*
7639 Shear image.
7640 */
7641 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
7642 exception);
7643 XSetCursorState(display,windows,MagickTrue);
7644 XCheckRefreshWindows(display,windows);
7645 (void) QueryColorCompliance(color,AllCompliance,
7646 &(*image)->background_color,exception);
7647 flags=ParseGeometry(geometry,&geometry_info);
7648 if ((flags & SigmaValue) == 0)
7649 geometry_info.sigma=geometry_info.rho;
7650 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma,
7651 exception);
7652 if (shear_image != (Image *) NULL)
7653 {
7654 *image=DestroyImage(*image);
7655 *image=shear_image;
7656 }
7657 CatchException(exception);
7658 XSetCursorState(display,windows,MagickFalse);
7659 if (windows->image.orphan != MagickFalse )
7660 break;
7661 windows->image.window_changes.width=(int) (*image)->columns;
7662 windows->image.window_changes.height=(int) (*image)->rows;
7663 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7664 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7665 break;
7666 }
7667 case RollCommand:
7668 {
7669 Image
7670 *roll_image;
7671
7672 static char
7673 geometry[MagickPathExtent] = "+2+2";
7674
7675 /*
7676 Query user for the roll geometry.
7677 */
7678 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:",
7679 geometry);
7680 if (*geometry == '\0')
7681 break;
7682 /*
7683 Roll image.
7684 */
7685 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
7686 exception);
7687 XSetCursorState(display,windows,MagickTrue);
7688 XCheckRefreshWindows(display,windows);
7689 (void) ParsePageGeometry(*image,geometry,&page_geometry,
7690 exception);
7691 roll_image=RollImage(*image,page_geometry.x,page_geometry.y,
7692 exception);
7693 if (roll_image != (Image *) NULL)
7694 {
7695 *image=DestroyImage(*image);
7696 *image=roll_image;
7697 }
7698 CatchException(exception);
7699 XSetCursorState(display,windows,MagickFalse);
7700 if (windows->image.orphan != MagickFalse )
7701 break;
7702 windows->image.window_changes.width=(int) (*image)->columns;
7703 windows->image.window_changes.height=(int) (*image)->rows;
7704 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7705 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7706 break;
7707 }
7708 case TrimCommand:
7709 {
7710 static char
7711 fuzz[MagickPathExtent];
7712
7713 /*
7714 Query user for the fuzz factor.
7715 */
7716 (void) FormatLocaleString(fuzz,MagickPathExtent,"%g%%",100.0*
7717 (*image)->fuzz/(QuantumRange+1.0));
7718 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz);
7719 if (*fuzz == '\0')
7720 break;
7721 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+1.0);
7722 /*
7723 Trim image.
7724 */
7725 status=XTrimImage(display,resource_info,windows,*image,exception);
7726 if (status == MagickFalse)
7727 {
7728 XNoticeWidget(display,windows,"Unable to trim X image",
7729 (*image)->filename);
7730 break;
7731 }
7732 break;
7733 }
7734 case HueCommand:
7735 {
7736 static char
7737 hue_percent[MagickPathExtent] = "110";
7738
7739 /*
7740 Query user for percent hue change.
7741 */
7742 (void) XDialogWidget(display,windows,"Apply",
7743 "Enter percent change in image hue (0-200):",hue_percent);
7744 if (*hue_percent == '\0')
7745 break;
7746 /*
7747 Vary the image hue.
7748 */
7749 XSetCursorState(display,windows,MagickTrue);
7750 XCheckRefreshWindows(display,windows);
7751 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MagickPathExtent);
7752 (void) ConcatenateMagickString(modulate_factors,hue_percent,
7753 MagickPathExtent);
7754 (void) ModulateImage(*image,modulate_factors,exception);
7755 XSetCursorState(display,windows,MagickFalse);
7756 if (windows->image.orphan != MagickFalse )
7757 break;
7758 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7759 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7760 break;
7761 }
7762 case SaturationCommand:
7763 {
7764 static char
7765 saturation_percent[MagickPathExtent] = "110";
7766
7767 /*
7768 Query user for percent saturation change.
7769 */
7770 (void) XDialogWidget(display,windows,"Apply",
7771 "Enter percent change in color saturation (0-200):",saturation_percent);
7772 if (*saturation_percent == '\0')
7773 break;
7774 /*
7775 Vary color saturation.
7776 */
7777 XSetCursorState(display,windows,MagickTrue);
7778 XCheckRefreshWindows(display,windows);
7779 (void) CopyMagickString(modulate_factors,"100.0/",MagickPathExtent);
7780 (void) ConcatenateMagickString(modulate_factors,saturation_percent,
7781 MagickPathExtent);
7782 (void) ModulateImage(*image,modulate_factors,exception);
7783 XSetCursorState(display,windows,MagickFalse);
7784 if (windows->image.orphan != MagickFalse )
7785 break;
7786 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7787 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7788 break;
7789 }
7790 case BrightnessCommand:
7791 {
7792 static char
7793 brightness_percent[MagickPathExtent] = "110";
7794
7795 /*
7796 Query user for percent brightness change.
7797 */
7798 (void) XDialogWidget(display,windows,"Apply",
7799 "Enter percent change in color brightness (0-200):",brightness_percent);
7800 if (*brightness_percent == '\0')
7801 break;
7802 /*
7803 Vary the color brightness.
7804 */
7805 XSetCursorState(display,windows,MagickTrue);
7806 XCheckRefreshWindows(display,windows);
7807 (void) CopyMagickString(modulate_factors,brightness_percent,
7808 MagickPathExtent);
7809 (void) ModulateImage(*image,modulate_factors,exception);
7810 XSetCursorState(display,windows,MagickFalse);
7811 if (windows->image.orphan != MagickFalse )
7812 break;
7813 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7814 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7815 break;
7816 }
7817 case GammaCommand:
7818 {
7819 static char
7820 factor[MagickPathExtent] = "1.6";
7821
7822 /*
7823 Query user for gamma value.
7824 */
7825 (void) XDialogWidget(display,windows,"Gamma",
7826 "Enter gamma value (e.g. 1.2):",factor);
7827 if (*factor == '\0')
7828 break;
7829 /*
7830 Gamma correct image.
7831 */
7832 XSetCursorState(display,windows,MagickTrue);
7833 XCheckRefreshWindows(display,windows);
7834 (void) GammaImage(*image,strtod(factor,(char **) NULL),exception);
7835 XSetCursorState(display,windows,MagickFalse);
7836 if (windows->image.orphan != MagickFalse )
7837 break;
7838 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7839 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7840 break;
7841 }
7842 case SpiffCommand:
7843 {
7844 /*
7845 Sharpen the image contrast.
7846 */
7847 XSetCursorState(display,windows,MagickTrue);
7848 XCheckRefreshWindows(display,windows);
7849 (void) ContrastImage(*image,MagickTrue,exception);
7850 XSetCursorState(display,windows,MagickFalse);
7851 if (windows->image.orphan != MagickFalse )
7852 break;
7853 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7854 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7855 break;
7856 }
7857 case DullCommand:
7858 {
7859 /*
7860 Dull the image contrast.
7861 */
7862 XSetCursorState(display,windows,MagickTrue);
7863 XCheckRefreshWindows(display,windows);
7864 (void) ContrastImage(*image,MagickFalse,exception);
7865 XSetCursorState(display,windows,MagickFalse);
7866 if (windows->image.orphan != MagickFalse )
7867 break;
7868 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7869 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7870 break;
7871 }
7872 case ContrastStretchCommand:
7873 {
7874 double
7875 black_point,
7876 white_point;
7877
7878 static char
7879 levels[MagickPathExtent] = "1%";
7880
7881 /*
7882 Query user for gamma value.
7883 */
7884 (void) XDialogWidget(display,windows,"Contrast Stretch",
7885 "Enter black and white points:",levels);
7886 if (*levels == '\0')
7887 break;
7888 /*
7889 Contrast stretch image.
7890 */
7891 XSetCursorState(display,windows,MagickTrue);
7892 XCheckRefreshWindows(display,windows);
7893 flags=ParseGeometry(levels,&geometry_info);
7894 black_point=geometry_info.rho;
7895 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point;
7896 if ((flags & PercentValue) != 0)
7897 {
7898 black_point*=(double) (*image)->columns*(*image)->rows/100.0;
7899 white_point*=(double) (*image)->columns*(*image)->rows/100.0;
7900 }
7901 white_point=(double) (*image)->columns*(*image)->rows-white_point;
7902 (void) ContrastStretchImage(*image,black_point,white_point,
7903 exception);
7904 XSetCursorState(display,windows,MagickFalse);
7905 if (windows->image.orphan != MagickFalse )
7906 break;
7907 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7908 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7909 break;
7910 }
7911 case SigmoidalContrastCommand:
7912 {
7913 GeometryInfo
7914 geometry_info;
7915
7916 MagickStatusType
7917 flags;
7918
7919 static char
7920 levels[MagickPathExtent] = "3x50%";
7921
7922 /*
7923 Query user for gamma value.
7924 */
7925 (void) XDialogWidget(display,windows,"Sigmoidal Contrast",
7926 "Enter contrast and midpoint:",levels);
7927 if (*levels == '\0')
7928 break;
7929 /*
7930 Contrast stretch image.
7931 */
7932 XSetCursorState(display,windows,MagickTrue);
7933 XCheckRefreshWindows(display,windows);
7934 flags=ParseGeometry(levels,&geometry_info);
7935 if ((flags & SigmaValue) == 0)
7936 geometry_info.sigma=1.0*QuantumRange/2.0;
7937 if ((flags & PercentValue) != 0)
7938 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0;
7939 (void) SigmoidalContrastImage(*image,MagickTrue,geometry_info.rho,
7940 geometry_info.sigma,exception);
7941 XSetCursorState(display,windows,MagickFalse);
7942 if (windows->image.orphan != MagickFalse )
7943 break;
7944 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7945 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7946 break;
7947 }
7948 case NormalizeCommand:
7949 {
7950 /*
7951 Perform histogram normalization on the image.
7952 */
7953 XSetCursorState(display,windows,MagickTrue);
7954 XCheckRefreshWindows(display,windows);
7955 (void) NormalizeImage(*image,exception);
7956 XSetCursorState(display,windows,MagickFalse);
7957 if (windows->image.orphan != MagickFalse )
7958 break;
7959 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7960 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7961 break;
7962 }
7963 case EqualizeCommand:
7964 {
7965 /*
7966 Perform histogram equalization on the image.
7967 */
7968 XSetCursorState(display,windows,MagickTrue);
7969 XCheckRefreshWindows(display,windows);
7970 (void) EqualizeImage(*image,exception);
7971 XSetCursorState(display,windows,MagickFalse);
7972 if (windows->image.orphan != MagickFalse )
7973 break;
7974 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7975 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7976 break;
7977 }
7978 case NegateCommand:
7979 {
7980 /*
7981 Negate colors in image.
7982 */
7983 XSetCursorState(display,windows,MagickTrue);
7984 XCheckRefreshWindows(display,windows);
7985 (void) NegateImage(*image,MagickFalse,exception);
7986 XSetCursorState(display,windows,MagickFalse);
7987 if (windows->image.orphan != MagickFalse )
7988 break;
7989 XConfigureImageColormap(display,resource_info,windows,*image,exception);
7990 (void) XConfigureImage(display,resource_info,windows,*image,exception);
7991 break;
7992 }
7993 case GrayscaleCommand:
7994 {
7995 /*
7996 Convert image to grayscale.
7997 */
7998 XSetCursorState(display,windows,MagickTrue);
7999 XCheckRefreshWindows(display,windows);
8000 (void) SetImageType(*image,(*image)->alpha_trait == UndefinedPixelTrait ?
8001 GrayscaleType : GrayscaleAlphaType,exception);
8002 XSetCursorState(display,windows,MagickFalse);
8003 if (windows->image.orphan != MagickFalse )
8004 break;
8005 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8006 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8007 break;
8008 }
8009 case MapCommand:
8010 {
8011 Image
8012 *affinity_image;
8013
8014 static char
8015 filename[MagickPathExtent] = "\0";
8016
8017 /*
8018 Request image file name from user.
8019 */
8020 XFileBrowserWidget(display,windows,"Map",filename);
8021 if (*filename == '\0')
8022 break;
8023 /*
8024 Map image.
8025 */
8026 XSetCursorState(display,windows,MagickTrue);
8027 XCheckRefreshWindows(display,windows);
8028 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
8029 affinity_image=ReadImage(image_info,exception);
8030 if (affinity_image != (Image *) NULL)
8031 {
8032 (void) RemapImage(&quantize_info,*image,affinity_image,exception);
8033 affinity_image=DestroyImage(affinity_image);
8034 }
8035 CatchException(exception);
8036 XSetCursorState(display,windows,MagickFalse);
8037 if (windows->image.orphan != MagickFalse )
8038 break;
8039 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8040 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8041 break;
8042 }
8043 case QuantizeCommand:
8044 {
8045 int
8046 status;
8047
8048 static char
8049 colors[MagickPathExtent] = "256";
8050
8051 /*
8052 Query user for maximum number of colors.
8053 */
8054 status=XDialogWidget(display,windows,"Quantize",
8055 "Maximum number of colors:",colors);
8056 if (*colors == '\0')
8057 break;
8058 /*
8059 Color reduce the image.
8060 */
8061 XSetCursorState(display,windows,MagickTrue);
8062 XCheckRefreshWindows(display,windows);
8063 quantize_info.number_colors=StringToUnsignedLong(colors);
8064 quantize_info.dither_method=status != 0 ? RiemersmaDitherMethod :
8065 NoDitherMethod;
8066 (void) QuantizeImage(&quantize_info,*image,exception);
8067 XSetCursorState(display,windows,MagickFalse);
8068 if (windows->image.orphan != MagickFalse )
8069 break;
8070 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8071 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8072 break;
8073 }
8074 case DespeckleCommand:
8075 {
8076 Image
8077 *despeckle_image;
8078
8079 /*
8080 Despeckle image.
8081 */
8082 XSetCursorState(display,windows,MagickTrue);
8083 XCheckRefreshWindows(display,windows);
8084 despeckle_image=DespeckleImage(*image,exception);
8085 if (despeckle_image != (Image *) NULL)
8086 {
8087 *image=DestroyImage(*image);
8088 *image=despeckle_image;
8089 }
8090 CatchException(exception);
8091 XSetCursorState(display,windows,MagickFalse);
8092 if (windows->image.orphan != MagickFalse )
8093 break;
8094 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8095 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8096 break;
8097 }
8098 case EmbossCommand:
8099 {
8100 Image
8101 *emboss_image;
8102
8103 static char
8104 radius[MagickPathExtent] = "0.0x1.0";
8105
8106 /*
8107 Query user for emboss radius.
8108 */
8109 (void) XDialogWidget(display,windows,"Emboss",
8110 "Enter the emboss radius and standard deviation:",radius);
8111 if (*radius == '\0')
8112 break;
8113 /*
8114 Reduce noise in the image.
8115 */
8116 XSetCursorState(display,windows,MagickTrue);
8117 XCheckRefreshWindows(display,windows);
8118 flags=ParseGeometry(radius,&geometry_info);
8119 if ((flags & SigmaValue) == 0)
8120 geometry_info.sigma=1.0;
8121 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma,
8122 exception);
8123 if (emboss_image != (Image *) NULL)
8124 {
8125 *image=DestroyImage(*image);
8126 *image=emboss_image;
8127 }
8128 CatchException(exception);
8129 XSetCursorState(display,windows,MagickFalse);
8130 if (windows->image.orphan != MagickFalse )
8131 break;
8132 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8133 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8134 break;
8135 }
8136 case ReduceNoiseCommand:
8137 {
8138 Image
8139 *noise_image;
8140
8141 static char
8142 radius[MagickPathExtent] = "0";
8143
8144 /*
8145 Query user for noise radius.
8146 */
8147 (void) XDialogWidget(display,windows,"Reduce Noise",
8148 "Enter the noise radius:",radius);
8149 if (*radius == '\0')
8150 break;
8151 /*
8152 Reduce noise in the image.
8153 */
8154 XSetCursorState(display,windows,MagickTrue);
8155 XCheckRefreshWindows(display,windows);
8156 flags=ParseGeometry(radius,&geometry_info);
8157 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t)
8158 geometry_info.rho,(size_t) geometry_info.rho,exception);
8159 if (noise_image != (Image *) NULL)
8160 {
8161 *image=DestroyImage(*image);
8162 *image=noise_image;
8163 }
8164 CatchException(exception);
8165 XSetCursorState(display,windows,MagickFalse);
8166 if (windows->image.orphan != MagickFalse )
8167 break;
8168 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8169 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8170 break;
8171 }
8172 case AddNoiseCommand:
8173 {
8174 char
8175 **noises;
8176
8177 Image
8178 *noise_image;
8179
8180 static char
8181 noise_type[MagickPathExtent] = "Gaussian";
8182
8183 /*
8184 Add noise to the image.
8185 */
8186 noises=GetCommandOptions(MagickNoiseOptions);
8187 if (noises == (char **) NULL)
8188 break;
8189 XListBrowserWidget(display,windows,&windows->widget,
8190 (const char **) noises,"Add Noise",
8191 "Select a type of noise to add to your image:",noise_type);
8192 noises=DestroyStringList(noises);
8193 if (*noise_type == '\0')
8194 break;
8195 XSetCursorState(display,windows,MagickTrue);
8196 XCheckRefreshWindows(display,windows);
8197 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption(
8198 MagickNoiseOptions,MagickFalse,noise_type),1.0,exception);
8199 if (noise_image != (Image *) NULL)
8200 {
8201 *image=DestroyImage(*image);
8202 *image=noise_image;
8203 }
8204 CatchException(exception);
8205 XSetCursorState(display,windows,MagickFalse);
8206 if (windows->image.orphan != MagickFalse )
8207 break;
8208 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8209 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8210 break;
8211 }
8212 case SharpenCommand:
8213 {
8214 Image
8215 *sharp_image;
8216
8217 static char
8218 radius[MagickPathExtent] = "0.0x1.0";
8219
8220 /*
8221 Query user for sharpen radius.
8222 */
8223 (void) XDialogWidget(display,windows,"Sharpen",
8224 "Enter the sharpen radius and standard deviation:",radius);
8225 if (*radius == '\0')
8226 break;
8227 /*
8228 Sharpen image scanlines.
8229 */
8230 XSetCursorState(display,windows,MagickTrue);
8231 XCheckRefreshWindows(display,windows);
8232 flags=ParseGeometry(radius,&geometry_info);
8233 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma,
8234 exception);
8235 if (sharp_image != (Image *) NULL)
8236 {
8237 *image=DestroyImage(*image);
8238 *image=sharp_image;
8239 }
8240 CatchException(exception);
8241 XSetCursorState(display,windows,MagickFalse);
8242 if (windows->image.orphan != MagickFalse )
8243 break;
8244 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8245 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8246 break;
8247 }
8248 case BlurCommand:
8249 {
8250 Image
8251 *blur_image;
8252
8253 static char
8254 radius[MagickPathExtent] = "0.0x1.0";
8255
8256 /*
8257 Query user for blur radius.
8258 */
8259 (void) XDialogWidget(display,windows,"Blur",
8260 "Enter the blur radius and standard deviation:",radius);
8261 if (*radius == '\0')
8262 break;
8263 /*
8264 Blur an image.
8265 */
8266 XSetCursorState(display,windows,MagickTrue);
8267 XCheckRefreshWindows(display,windows);
8268 flags=ParseGeometry(radius,&geometry_info);
8269 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma,
8270 exception);
8271 if (blur_image != (Image *) NULL)
8272 {
8273 *image=DestroyImage(*image);
8274 *image=blur_image;
8275 }
8276 CatchException(exception);
8277 XSetCursorState(display,windows,MagickFalse);
8278 if (windows->image.orphan != MagickFalse )
8279 break;
8280 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8281 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8282 break;
8283 }
8284 case ThresholdCommand:
8285 {
8286 double
8287 threshold;
8288
8289 static char
8290 factor[MagickPathExtent] = "128";
8291
8292 /*
8293 Query user for threshold value.
8294 */
8295 (void) XDialogWidget(display,windows,"Threshold",
8296 "Enter threshold value:",factor);
8297 if (*factor == '\0')
8298 break;
8299 /*
8300 Gamma correct image.
8301 */
8302 XSetCursorState(display,windows,MagickTrue);
8303 XCheckRefreshWindows(display,windows);
8304 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
8305 (void) BilevelImage(*image,threshold,exception);
8306 XSetCursorState(display,windows,MagickFalse);
8307 if (windows->image.orphan != MagickFalse )
8308 break;
8309 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8310 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8311 break;
8312 }
8313 case EdgeDetectCommand:
8314 {
8315 Image
8316 *edge_image;
8317
8318 static char
8319 radius[MagickPathExtent] = "0";
8320
8321 /*
8322 Query user for edge factor.
8323 */
8324 (void) XDialogWidget(display,windows,"Detect Edges",
8325 "Enter the edge detect radius:",radius);
8326 if (*radius == '\0')
8327 break;
8328 /*
8329 Detect edge in image.
8330 */
8331 XSetCursorState(display,windows,MagickTrue);
8332 XCheckRefreshWindows(display,windows);
8333 flags=ParseGeometry(radius,&geometry_info);
8334 edge_image=EdgeImage(*image,geometry_info.rho,exception);
8335 if (edge_image != (Image *) NULL)
8336 {
8337 *image=DestroyImage(*image);
8338 *image=edge_image;
8339 }
8340 CatchException(exception);
8341 XSetCursorState(display,windows,MagickFalse);
8342 if (windows->image.orphan != MagickFalse )
8343 break;
8344 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8345 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8346 break;
8347 }
8348 case SpreadCommand:
8349 {
8350 Image
8351 *spread_image;
8352
8353 static char
8354 amount[MagickPathExtent] = "2";
8355
8356 /*
8357 Query user for spread amount.
8358 */
8359 (void) XDialogWidget(display,windows,"Spread",
8360 "Enter the displacement amount:",amount);
8361 if (*amount == '\0')
8362 break;
8363 /*
8364 Displace image pixels by a random amount.
8365 */
8366 XSetCursorState(display,windows,MagickTrue);
8367 XCheckRefreshWindows(display,windows);
8368 flags=ParseGeometry(amount,&geometry_info);
8369 spread_image=EdgeImage(*image,geometry_info.rho,exception);
8370 if (spread_image != (Image *) NULL)
8371 {
8372 *image=DestroyImage(*image);
8373 *image=spread_image;
8374 }
8375 CatchException(exception);
8376 XSetCursorState(display,windows,MagickFalse);
8377 if (windows->image.orphan != MagickFalse )
8378 break;
8379 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8380 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8381 break;
8382 }
8383 case ShadeCommand:
8384 {
8385 Image
8386 *shade_image;
8387
8388 int
8389 status;
8390
8391 static char
8392 geometry[MagickPathExtent] = "30x30";
8393
8394 /*
8395 Query user for the shade geometry.
8396 */
8397 status=XDialogWidget(display,windows,"Shade",
8398 "Enter the azimuth and elevation of the light source:",geometry);
8399 if (*geometry == '\0')
8400 break;
8401 /*
8402 Shade image pixels.
8403 */
8404 XSetCursorState(display,windows,MagickTrue);
8405 XCheckRefreshWindows(display,windows);
8406 flags=ParseGeometry(geometry,&geometry_info);
8407 if ((flags & SigmaValue) == 0)
8408 geometry_info.sigma=1.0;
8409 shade_image=ShadeImage(*image,status != 0 ? MagickTrue : MagickFalse,
8410 geometry_info.rho,geometry_info.sigma,exception);
8411 if (shade_image != (Image *) NULL)
8412 {
8413 *image=DestroyImage(*image);
8414 *image=shade_image;
8415 }
8416 CatchException(exception);
8417 XSetCursorState(display,windows,MagickFalse);
8418 if (windows->image.orphan != MagickFalse )
8419 break;
8420 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8421 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8422 break;
8423 }
8424 case RaiseCommand:
8425 {
8426 static char
8427 bevel_width[MagickPathExtent] = "10";
8428
8429 /*
8430 Query user for bevel width.
8431 */
8432 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width);
8433 if (*bevel_width == '\0')
8434 break;
8435 /*
8436 Raise an image.
8437 */
8438 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8439 exception);
8440 XSetCursorState(display,windows,MagickTrue);
8441 XCheckRefreshWindows(display,windows);
8442 (void) ParsePageGeometry(*image,bevel_width,&page_geometry,
8443 exception);
8444 (void) RaiseImage(*image,&page_geometry,MagickTrue,exception);
8445 XSetCursorState(display,windows,MagickFalse);
8446 if (windows->image.orphan != MagickFalse )
8447 break;
8448 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8449 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8450 break;
8451 }
8452 case SegmentCommand:
8453 {
8454 static char
8455 threshold[MagickPathExtent] = "1.0x1.5";
8456
8457 /*
8458 Query user for smoothing threshold.
8459 */
8460 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:",
8461 threshold);
8462 if (*threshold == '\0')
8463 break;
8464 /*
8465 Segment an image.
8466 */
8467 XSetCursorState(display,windows,MagickTrue);
8468 XCheckRefreshWindows(display,windows);
8469 flags=ParseGeometry(threshold,&geometry_info);
8470 if ((flags & SigmaValue) == 0)
8471 geometry_info.sigma=1.0;
8472 (void) SegmentImage(*image,sRGBColorspace,MagickFalse,geometry_info.rho,
8473 geometry_info.sigma,exception);
8474 XSetCursorState(display,windows,MagickFalse);
8475 if (windows->image.orphan != MagickFalse )
8476 break;
8477 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8478 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8479 break;
8480 }
8481 case SepiaToneCommand:
8482 {
8483 double
8484 threshold;
8485
8486 Image
8487 *sepia_image;
8488
8489 static char
8490 factor[MagickPathExtent] = "80%";
8491
8492 /*
8493 Query user for sepia-tone factor.
8494 */
8495 (void) XDialogWidget(display,windows,"Sepia Tone",
8496 "Enter the sepia tone factor (0 - 99.9%):",factor);
8497 if (*factor == '\0')
8498 break;
8499 /*
8500 Sepia tone image pixels.
8501 */
8502 XSetCursorState(display,windows,MagickTrue);
8503 XCheckRefreshWindows(display,windows);
8504 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
8505 sepia_image=SepiaToneImage(*image,threshold,exception);
8506 if (sepia_image != (Image *) NULL)
8507 {
8508 *image=DestroyImage(*image);
8509 *image=sepia_image;
8510 }
8511 CatchException(exception);
8512 XSetCursorState(display,windows,MagickFalse);
8513 if (windows->image.orphan != MagickFalse )
8514 break;
8515 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8516 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8517 break;
8518 }
8519 case SolarizeCommand:
8520 {
8521 double
8522 threshold;
8523
8524 static char
8525 factor[MagickPathExtent] = "60%";
8526
8527 /*
8528 Query user for solarize factor.
8529 */
8530 (void) XDialogWidget(display,windows,"Solarize",
8531 "Enter the solarize factor (0 - 99.9%):",factor);
8532 if (*factor == '\0')
8533 break;
8534 /*
8535 Solarize image pixels.
8536 */
8537 XSetCursorState(display,windows,MagickTrue);
8538 XCheckRefreshWindows(display,windows);
8539 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
8540 (void) SolarizeImage(*image,threshold,exception);
8541 XSetCursorState(display,windows,MagickFalse);
8542 if (windows->image.orphan != MagickFalse )
8543 break;
8544 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8545 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8546 break;
8547 }
8548 case SwirlCommand:
8549 {
8550 Image
8551 *swirl_image;
8552
8553 static char
8554 degrees[MagickPathExtent] = "60";
8555
8556 /*
8557 Query user for swirl angle.
8558 */
8559 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:",
8560 degrees);
8561 if (*degrees == '\0')
8562 break;
8563 /*
8564 Swirl image pixels about the center.
8565 */
8566 XSetCursorState(display,windows,MagickTrue);
8567 XCheckRefreshWindows(display,windows);
8568 flags=ParseGeometry(degrees,&geometry_info);
8569 swirl_image=SwirlImage(*image,geometry_info.rho,(*image)->interpolate,
8570 exception);
8571 if (swirl_image != (Image *) NULL)
8572 {
8573 *image=DestroyImage(*image);
8574 *image=swirl_image;
8575 }
8576 CatchException(exception);
8577 XSetCursorState(display,windows,MagickFalse);
8578 if (windows->image.orphan != MagickFalse )
8579 break;
8580 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8581 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8582 break;
8583 }
8584 case ImplodeCommand:
8585 {
8586 Image
8587 *implode_image;
8588
8589 static char
8590 factor[MagickPathExtent] = "0.3";
8591
8592 /*
8593 Query user for implode factor.
8594 */
8595 (void) XDialogWidget(display,windows,"Implode",
8596 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor);
8597 if (*factor == '\0')
8598 break;
8599 /*
8600 Implode image pixels about the center.
8601 */
8602 XSetCursorState(display,windows,MagickTrue);
8603 XCheckRefreshWindows(display,windows);
8604 flags=ParseGeometry(factor,&geometry_info);
8605 implode_image=ImplodeImage(*image,geometry_info.rho,(*image)->interpolate,
8606 exception);
8607 if (implode_image != (Image *) NULL)
8608 {
8609 *image=DestroyImage(*image);
8610 *image=implode_image;
8611 }
8612 CatchException(exception);
8613 XSetCursorState(display,windows,MagickFalse);
8614 if (windows->image.orphan != MagickFalse )
8615 break;
8616 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8617 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8618 break;
8619 }
8620 case VignetteCommand:
8621 {
8622 Image
8623 *vignette_image;
8624
8625 static char
8626 geometry[MagickPathExtent] = "0x20";
8627
8628 /*
8629 Query user for the vignette geometry.
8630 */
8631 (void) XDialogWidget(display,windows,"Vignette",
8632 "Enter the radius, sigma, and x and y offsets:",geometry);
8633 if (*geometry == '\0')
8634 break;
8635 /*
8636 Soften the edges of the image in vignette style
8637 */
8638 XSetCursorState(display,windows,MagickTrue);
8639 XCheckRefreshWindows(display,windows);
8640 flags=ParseGeometry(geometry,&geometry_info);
8641 if ((flags & SigmaValue) == 0)
8642 geometry_info.sigma=1.0;
8643 if ((flags & XiValue) == 0)
8644 geometry_info.xi=0.1*(*image)->columns;
8645 if ((flags & PsiValue) == 0)
8646 geometry_info.psi=0.1*(*image)->rows;
8647 vignette_image=VignetteImage(*image,geometry_info.rho,0.0,(ssize_t)
8648 ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-0.5),
8649 exception);
8650 if (vignette_image != (Image *) NULL)
8651 {
8652 *image=DestroyImage(*image);
8653 *image=vignette_image;
8654 }
8655 CatchException(exception);
8656 XSetCursorState(display,windows,MagickFalse);
8657 if (windows->image.orphan != MagickFalse )
8658 break;
8659 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8660 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8661 break;
8662 }
8663 case WaveCommand:
8664 {
8665 Image
8666 *wave_image;
8667
8668 static char
8669 geometry[MagickPathExtent] = "25x150";
8670
8671 /*
8672 Query user for the wave geometry.
8673 */
8674 (void) XDialogWidget(display,windows,"Wave",
8675 "Enter the amplitude and length of the wave:",geometry);
8676 if (*geometry == '\0')
8677 break;
8678 /*
8679 Alter an image along a sine wave.
8680 */
8681 XSetCursorState(display,windows,MagickTrue);
8682 XCheckRefreshWindows(display,windows);
8683 flags=ParseGeometry(geometry,&geometry_info);
8684 if ((flags & SigmaValue) == 0)
8685 geometry_info.sigma=1.0;
8686 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma,
8687 (*image)->interpolate,exception);
8688 if (wave_image != (Image *) NULL)
8689 {
8690 *image=DestroyImage(*image);
8691 *image=wave_image;
8692 }
8693 CatchException(exception);
8694 XSetCursorState(display,windows,MagickFalse);
8695 if (windows->image.orphan != MagickFalse )
8696 break;
8697 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8698 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8699 break;
8700 }
8701 case OilPaintCommand:
8702 {
8703 Image
8704 *paint_image;
8705
8706 static char
8707 radius[MagickPathExtent] = "0";
8708
8709 /*
8710 Query user for circular neighborhood radius.
8711 */
8712 (void) XDialogWidget(display,windows,"Oil Paint",
8713 "Enter the mask radius:",radius);
8714 if (*radius == '\0')
8715 break;
8716 /*
8717 OilPaint image scanlines.
8718 */
8719 XSetCursorState(display,windows,MagickTrue);
8720 XCheckRefreshWindows(display,windows);
8721 flags=ParseGeometry(radius,&geometry_info);
8722 paint_image=OilPaintImage(*image,geometry_info.rho,geometry_info.sigma,
8723 exception);
8724 if (paint_image != (Image *) NULL)
8725 {
8726 *image=DestroyImage(*image);
8727 *image=paint_image;
8728 }
8729 CatchException(exception);
8730 XSetCursorState(display,windows,MagickFalse);
8731 if (windows->image.orphan != MagickFalse )
8732 break;
8733 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8734 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8735 break;
8736 }
8737 case CharcoalDrawCommand:
8738 {
8739 Image
8740 *charcoal_image;
8741
8742 static char
8743 radius[MagickPathExtent] = "0x1";
8744
8745 /*
8746 Query user for charcoal radius.
8747 */
8748 (void) XDialogWidget(display,windows,"Charcoal Draw",
8749 "Enter the charcoal radius and sigma:",radius);
8750 if (*radius == '\0')
8751 break;
8752 /*
8753 Charcoal the image.
8754 */
8755 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8756 exception);
8757 XSetCursorState(display,windows,MagickTrue);
8758 XCheckRefreshWindows(display,windows);
8759 flags=ParseGeometry(radius,&geometry_info);
8760 if ((flags & SigmaValue) == 0)
8761 geometry_info.sigma=geometry_info.rho;
8762 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma,
8763 exception);
8764 if (charcoal_image != (Image *) NULL)
8765 {
8766 *image=DestroyImage(*image);
8767 *image=charcoal_image;
8768 }
8769 CatchException(exception);
8770 XSetCursorState(display,windows,MagickFalse);
8771 if (windows->image.orphan != MagickFalse )
8772 break;
8773 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8774 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8775 break;
8776 }
8777 case AnnotateCommand:
8778 {
8779 /*
8780 Annotate the image with text.
8781 */
8782 status=XAnnotateEditImage(display,resource_info,windows,*image,exception);
8783 if (status == MagickFalse)
8784 {
8785 XNoticeWidget(display,windows,"Unable to annotate X image",
8786 (*image)->filename);
8787 break;
8788 }
8789 break;
8790 }
8791 case DrawCommand:
8792 {
8793 /*
8794 Draw image.
8795 */
8796 status=XDrawEditImage(display,resource_info,windows,image,exception);
8797 if (status == MagickFalse)
8798 {
8799 XNoticeWidget(display,windows,"Unable to draw on the X image",
8800 (*image)->filename);
8801 break;
8802 }
8803 break;
8804 }
8805 case ColorCommand:
8806 {
8807 /*
8808 Color edit.
8809 */
8810 status=XColorEditImage(display,resource_info,windows,image,exception);
8811 if (status == MagickFalse)
8812 {
8813 XNoticeWidget(display,windows,"Unable to pixel edit X image",
8814 (*image)->filename);
8815 break;
8816 }
8817 break;
8818 }
8819 case MatteCommand:
8820 {
8821 /*
8822 Matte edit.
8823 */
8824 status=XMatteEditImage(display,resource_info,windows,image,exception);
8825 if (status == MagickFalse)
8826 {
8827 XNoticeWidget(display,windows,"Unable to matte edit X image",
8828 (*image)->filename);
8829 break;
8830 }
8831 break;
8832 }
8833 case CompositeCommand:
8834 {
8835 /*
8836 Composite image.
8837 */
8838 status=XCompositeImage(display,resource_info,windows,*image,
8839 exception);
8840 if (status == MagickFalse)
8841 {
8842 XNoticeWidget(display,windows,"Unable to composite X image",
8843 (*image)->filename);
8844 break;
8845 }
8846 break;
8847 }
8848 case AddBorderCommand:
8849 {
8850 Image
8851 *border_image;
8852
8853 static char
8854 geometry[MagickPathExtent] = "6x6";
8855
8856 /*
8857 Query user for border color and geometry.
8858 */
8859 XColorBrowserWidget(display,windows,"Select",color);
8860 if (*color == '\0')
8861 break;
8862 (void) XDialogWidget(display,windows,"Add Border",
8863 "Enter border geometry:",geometry);
8864 if (*geometry == '\0')
8865 break;
8866 /*
8867 Add a border to the image.
8868 */
8869 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8870 exception);
8871 XSetCursorState(display,windows,MagickTrue);
8872 XCheckRefreshWindows(display,windows);
8873 (void) QueryColorCompliance(color,AllCompliance,&(*image)->border_color,
8874 exception);
8875 (void) ParsePageGeometry(*image,geometry,&page_geometry,
8876 exception);
8877 border_image=BorderImage(*image,&page_geometry,(*image)->compose,
8878 exception);
8879 if (border_image != (Image *) NULL)
8880 {
8881 *image=DestroyImage(*image);
8882 *image=border_image;
8883 }
8884 CatchException(exception);
8885 XSetCursorState(display,windows,MagickFalse);
8886 if (windows->image.orphan != MagickFalse )
8887 break;
8888 windows->image.window_changes.width=(int) (*image)->columns;
8889 windows->image.window_changes.height=(int) (*image)->rows;
8890 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8891 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8892 break;
8893 }
8894 case AddFrameCommand:
8895 {
8896 FrameInfo
8897 frame_info;
8898
8899 Image
8900 *frame_image;
8901
8902 static char
8903 geometry[MagickPathExtent] = "6x6";
8904
8905 /*
8906 Query user for frame color and geometry.
8907 */
8908 XColorBrowserWidget(display,windows,"Select",color);
8909 if (*color == '\0')
8910 break;
8911 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:",
8912 geometry);
8913 if (*geometry == '\0')
8914 break;
8915 /*
8916 Surround image with an ornamental border.
8917 */
8918 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8919 exception);
8920 XSetCursorState(display,windows,MagickTrue);
8921 XCheckRefreshWindows(display,windows);
8922 (void) QueryColorCompliance(color,AllCompliance,&(*image)->matte_color,
8923 exception);
8924 (void) ParsePageGeometry(*image,geometry,&page_geometry,
8925 exception);
8926 frame_info.width=page_geometry.width;
8927 frame_info.height=page_geometry.height;
8928 frame_info.outer_bevel=page_geometry.x;
8929 frame_info.inner_bevel=page_geometry.y;
8930 frame_info.x=(ssize_t) frame_info.width;
8931 frame_info.y=(ssize_t) frame_info.height;
8932 frame_info.width=(*image)->columns+2*frame_info.width;
8933 frame_info.height=(*image)->rows+2*frame_info.height;
8934 frame_image=FrameImage(*image,&frame_info,(*image)->compose,exception);
8935 if (frame_image != (Image *) NULL)
8936 {
8937 *image=DestroyImage(*image);
8938 *image=frame_image;
8939 }
8940 CatchException(exception);
8941 XSetCursorState(display,windows,MagickFalse);
8942 if (windows->image.orphan != MagickFalse )
8943 break;
8944 windows->image.window_changes.width=(int) (*image)->columns;
8945 windows->image.window_changes.height=(int) (*image)->rows;
8946 XConfigureImageColormap(display,resource_info,windows,*image,exception);
8947 (void) XConfigureImage(display,resource_info,windows,*image,exception);
8948 break;
8949 }
8950 case CommentCommand:
8951 {
8952 const char
8953 *value;
8954
8955 FILE
8956 *file;
8957
8958 int
8959 unique_file;
8960
8961 /*
8962 Edit image comment.
8963 */
8964 unique_file=AcquireUniqueFileResource(image_info->filename);
8965 if (unique_file == -1)
8966 XNoticeWidget(display,windows,"Unable to edit image comment",
8967 image_info->filename);
8968 value=GetImageProperty(*image,"comment",exception);
8969 if (value == (char *) NULL)
8970 unique_file=close(unique_file)-1;
8971 else
8972 {
8973 register const char
8974 *p;
8975
8976 file=fdopen(unique_file,"w");
8977 if (file == (FILE *) NULL)
8978 {
8979 XNoticeWidget(display,windows,"Unable to edit image comment",
8980 image_info->filename);
8981 break;
8982 }
8983 for (p=value; *p != '\0'; p++)
8984 (void) fputc((int) *p,file);
8985 (void) fputc('\n',file);
8986 (void) fclose(file);
8987 }
8988 XSetCursorState(display,windows,MagickTrue);
8989 XCheckRefreshWindows(display,windows);
8990 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL,
8991 exception);
8992 if (status == MagickFalse)
8993 XNoticeWidget(display,windows,"Unable to edit image comment",
8994 (char *) NULL);
8995 else
8996 {
8997 char
8998 *comment;
8999
9000 comment=FileToString(image_info->filename,~0UL,exception);
9001 if (comment != (char *) NULL)
9002 {
9003 (void) SetImageProperty(*image,"comment",comment,exception);
9004 (*image)->taint=MagickTrue;
9005 }
9006 }
9007 (void) RelinquishUniqueFileResource(image_info->filename);
9008 XSetCursorState(display,windows,MagickFalse);
9009 break;
9010 }
9011 case LaunchCommand:
9012 {
9013 /*
9014 Launch program.
9015 */
9016 XSetCursorState(display,windows,MagickTrue);
9017 XCheckRefreshWindows(display,windows);
9018 (void) AcquireUniqueFilename(filename);
9019 (void) FormatLocaleString((*image)->filename,MagickPathExtent,"launch:%s",
9020 filename);
9021 status=WriteImage(image_info,*image,exception);
9022 if (status == MagickFalse)
9023 XNoticeWidget(display,windows,"Unable to launch image editor",
9024 (char *) NULL);
9025 else
9026 {
9027 nexus=ReadImage(resource_info->image_info,exception);
9028 CatchException(exception);
9029 XClientMessage(display,windows->image.id,windows->im_protocols,
9030 windows->im_next_image,CurrentTime);
9031 }
9032 (void) RelinquishUniqueFileResource(filename);
9033 XSetCursorState(display,windows,MagickFalse);
9034 break;
9035 }
9036 case RegionofInterestCommand:
9037 {
9038 /*
9039 Apply an image processing technique to a region of interest.
9040 */
9041 (void) XROIImage(display,resource_info,windows,image,exception);
9042 break;
9043 }
9044 case InfoCommand:
9045 break;
9046 case ZoomCommand:
9047 {
9048 /*
9049 Zoom image.
9050 */
9051 if (windows->magnify.mapped != MagickFalse )
9052 (void) XRaiseWindow(display,windows->magnify.id);
9053 else
9054 {
9055 /*
9056 Make magnify image.
9057 */
9058 XSetCursorState(display,windows,MagickTrue);
9059 (void) XMapRaised(display,windows->magnify.id);
9060 XSetCursorState(display,windows,MagickFalse);
9061 }
9062 break;
9063 }
9064 case ShowPreviewCommand:
9065 {
9066 char
9067 **previews,
9068 value[MagickPathExtent];
9069
9070 Image
9071 *preview_image;
9072
9073 PreviewType
9074 preview;
9075
9076 static char
9077 preview_type[MagickPathExtent] = "Gamma";
9078
9079 /*
9080 Select preview type from menu.
9081 */
9082 previews=GetCommandOptions(MagickPreviewOptions);
9083 if (previews == (char **) NULL)
9084 break;
9085 XListBrowserWidget(display,windows,&windows->widget,
9086 (const char **) previews,"Preview",
9087 "Select an enhancement, effect, or F/X:",preview_type);
9088 previews=DestroyStringList(previews);
9089 if (*preview_type == '\0')
9090 break;
9091 /*
9092 Show image preview.
9093 */
9094 XSetCursorState(display,windows,MagickTrue);
9095 XCheckRefreshWindows(display,windows);
9096 preview=(PreviewType) ParseCommandOption(MagickPreviewOptions,
9097 MagickFalse,preview_type);
9098 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
9099 windows->image.id);
9100 (void) SetImageProperty(*image,"group",value,exception);
9101 (void) DeleteImageProperty(*image,"label");
9102 (void) SetImageProperty(*image,"label","Preview",exception);
9103 preview_image=PreviewImage(*image,preview,exception);
9104 if (preview_image == (Image *) NULL)
9105 break;
9106 (void) AcquireUniqueFilename(filename);
9107 (void) FormatLocaleString(preview_image->filename,MagickPathExtent,
9108 "show:%s",filename);
9109 status=WriteImage(image_info,preview_image,exception);
9110 (void) RelinquishUniqueFileResource(filename);
9111 preview_image=DestroyImage(preview_image);
9112 if (status == MagickFalse)
9113 XNoticeWidget(display,windows,"Unable to show image preview",
9114 (*image)->filename);
9115 XDelay(display,1500);
9116 XSetCursorState(display,windows,MagickFalse);
9117 break;
9118 }
9119 case ShowHistogramCommand:
9120 {
9121 char
9122 value[MagickPathExtent];
9123
9124 Image
9125 *histogram_image;
9126
9127 /*
9128 Show image histogram.
9129 */
9130 XSetCursorState(display,windows,MagickTrue);
9131 XCheckRefreshWindows(display,windows);
9132 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
9133 windows->image.id);
9134 (void) SetImageProperty(*image,"group",value,exception);
9135 (void) DeleteImageProperty(*image,"label");
9136 (void) SetImageProperty(*image,"label","Histogram",exception);
9137 (void) AcquireUniqueFilename(filename);
9138 (void) FormatLocaleString((*image)->filename,MagickPathExtent,
9139 "histogram:%s",filename);
9140 status=WriteImage(image_info,*image,exception);
9141 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
9142 histogram_image=ReadImage(image_info,exception);
9143 (void) RelinquishUniqueFileResource(filename);
9144 if (histogram_image == (Image *) NULL)
9145 break;
9146 (void) FormatLocaleString(histogram_image->filename,MagickPathExtent,
9147 "show:%s",filename);
9148 status=WriteImage(image_info,histogram_image,exception);
9149 histogram_image=DestroyImage(histogram_image);
9150 if (status == MagickFalse)
9151 XNoticeWidget(display,windows,"Unable to show histogram",
9152 (*image)->filename);
9153 XDelay(display,1500);
9154 XSetCursorState(display,windows,MagickFalse);
9155 break;
9156 }
9157 case ShowMatteCommand:
9158 {
9159 char
9160 value[MagickPathExtent];
9161
9162 Image
9163 *matte_image;
9164
9165 if ((*image)->alpha_trait == UndefinedPixelTrait)
9166 {
9167 XNoticeWidget(display,windows,
9168 "Image does not have any matte information",(*image)->filename);
9169 break;
9170 }
9171 /*
9172 Show image matte.
9173 */
9174 XSetCursorState(display,windows,MagickTrue);
9175 XCheckRefreshWindows(display,windows);
9176 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
9177 windows->image.id);
9178 (void) SetImageProperty(*image,"group",value,exception);
9179 (void) DeleteImageProperty(*image,"label");
9180 (void) SetImageProperty(*image,"label","Matte",exception);
9181 (void) AcquireUniqueFilename(filename);
9182 (void) FormatLocaleString((*image)->filename,MagickPathExtent,"matte:%s",
9183 filename);
9184 status=WriteImage(image_info,*image,exception);
9185 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
9186 matte_image=ReadImage(image_info,exception);
9187 (void) RelinquishUniqueFileResource(filename);
9188 if (matte_image == (Image *) NULL)
9189 break;
9190 (void) FormatLocaleString(matte_image->filename,MagickPathExtent,"show:%s",
9191 filename);
9192 status=WriteImage(image_info,matte_image,exception);
9193 matte_image=DestroyImage(matte_image);
9194 if (status == MagickFalse)
9195 XNoticeWidget(display,windows,"Unable to show matte",
9196 (*image)->filename);
9197 XDelay(display,1500);
9198 XSetCursorState(display,windows,MagickFalse);
9199 break;
9200 }
9201 case BackgroundCommand:
9202 {
9203 /*
9204 Background image.
9205 */
9206 status=XBackgroundImage(display,resource_info,windows,image,exception);
9207 if (status == MagickFalse)
9208 break;
9209 nexus=CloneImage(*image,0,0,MagickTrue,exception);
9210 if (nexus != (Image *) NULL)
9211 XClientMessage(display,windows->image.id,windows->im_protocols,
9212 windows->im_next_image,CurrentTime);
9213 break;
9214 }
9215 case SlideShowCommand:
9216 {
9217 static char
9218 delay[MagickPathExtent] = "5";
9219
9220 /*
9221 Display next image after pausing.
9222 */
9223 (void) XDialogWidget(display,windows,"Slide Show",
9224 "Pause how many 1/100ths of a second between images:",delay);
9225 if (*delay == '\0')
9226 break;
9227 resource_info->delay=StringToUnsignedLong(delay);
9228 XClientMessage(display,windows->image.id,windows->im_protocols,
9229 windows->im_next_image,CurrentTime);
9230 break;
9231 }
9232 case PreferencesCommand:
9233 {
9234 /*
9235 Set user preferences.
9236 */
9237 status=XPreferencesWidget(display,resource_info,windows);
9238 if (status == MagickFalse)
9239 break;
9240 nexus=CloneImage(*image,0,0,MagickTrue,exception);
9241 if (nexus != (Image *) NULL)
9242 XClientMessage(display,windows->image.id,windows->im_protocols,
9243 windows->im_next_image,CurrentTime);
9244 break;
9245 }
9246 case HelpCommand:
9247 {
9248 /*
9249 User requested help.
9250 */
9251 XTextViewWidget(display,resource_info,windows,MagickFalse,
9252 "Help Viewer - Display",DisplayHelp);
9253 break;
9254 }
9255 case BrowseDocumentationCommand:
9256 {
9257 Atom
9258 mozilla_atom;
9259
9260 Window
9261 mozilla_window,
9262 root_window;
9263
9264 /*
9265 Browse the ImageMagick documentation.
9266 */
9267 root_window=XRootWindow(display,XDefaultScreen(display));
9268 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse);
9269 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom);
9270 if (mozilla_window != (Window) NULL)
9271 {
9272 char
9273 command[MagickPathExtent],
9274 *url;
9275
9276 /*
9277 Display documentation using Netscape remote control.
9278 */
9279 url=GetMagickHomeURL();
9280 (void) FormatLocaleString(command,MagickPathExtent,
9281 "openurl(%s,new-tab)",url);
9282 url=DestroyString(url);
9283 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse);
9284 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING,
9285 8,PropModeReplace,(unsigned char *) command,(int) strlen(command));
9286 XSetCursorState(display,windows,MagickFalse);
9287 break;
9288 }
9289 XSetCursorState(display,windows,MagickTrue);
9290 XCheckRefreshWindows(display,windows);
9291 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL,
9292 exception);
9293 if (status == MagickFalse)
9294 XNoticeWidget(display,windows,"Unable to browse documentation",
9295 (char *) NULL);
9296 XDelay(display,1500);
9297 XSetCursorState(display,windows,MagickFalse);
9298 break;
9299 }
9300 case VersionCommand:
9301 {
9302 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL),
9303 GetMagickCopyright());
9304 break;
9305 }
9306 case SaveToUndoBufferCommand:
9307 break;
9308 default:
9309 {
9310 (void) XBell(display,0);
9311 break;
9312 }
9313 }
9314 image_info=DestroyImageInfo(image_info);
9315 return(nexus);
9316 }
9317
9318 /*
9319 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9320 % %
9321 % %
9322 % %
9323 + X M a g n i f y I m a g e %
9324 % %
9325 % %
9326 % %
9327 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9328 %
9329 % XMagnifyImage() magnifies portions of the image as indicated by the pointer.
9330 % The magnified portion is displayed in a separate window.
9331 %
9332 % The format of the XMagnifyImage method is:
9333 %
9334 % void XMagnifyImage(Display *display,XWindows *windows,XEvent *event,
9335 % ExceptionInfo *exception)
9336 %
9337 % A description of each parameter follows:
9338 %
9339 % o display: Specifies a connection to an X server; returned from
9340 % XOpenDisplay.
9341 %
9342 % o windows: Specifies a pointer to a XWindows structure.
9343 %
9344 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
9345 % the entire image is refreshed.
9346 %
9347 % o exception: return any errors or warnings in this structure.
9348 %
9349 */
XMagnifyImage(Display * display,XWindows * windows,XEvent * event,ExceptionInfo * exception)9350 static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event,
9351 ExceptionInfo *exception)
9352 {
9353 char
9354 text[MagickPathExtent];
9355
9356 register int
9357 x,
9358 y;
9359
9360 size_t
9361 state;
9362
9363 /*
9364 Update magnified image until the mouse button is released.
9365 */
9366 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor);
9367 state=DefaultState;
9368 x=event->xbutton.x;
9369 y=event->xbutton.y;
9370 windows->magnify.x=(int) windows->image.x+x;
9371 windows->magnify.y=(int) windows->image.y+y;
9372 do
9373 {
9374 /*
9375 Map and unmap Info widget as text cursor crosses its boundaries.
9376 */
9377 if (windows->info.mapped != MagickFalse )
9378 {
9379 if ((x < (int) (windows->info.x+windows->info.width)) &&
9380 (y < (int) (windows->info.y+windows->info.height)))
9381 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
9382 }
9383 else
9384 if ((x > (int) (windows->info.x+windows->info.width)) ||
9385 (y > (int) (windows->info.y+windows->info.height)))
9386 (void) XMapWindow(display,windows->info.id);
9387 if (windows->info.mapped != MagickFalse )
9388 {
9389 /*
9390 Display pointer position.
9391 */
9392 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ",
9393 windows->magnify.x,windows->magnify.y);
9394 XInfoWidget(display,windows,text);
9395 }
9396 /*
9397 Wait for next event.
9398 */
9399 XScreenEvent(display,windows,event,exception);
9400 switch (event->type)
9401 {
9402 case ButtonPress:
9403 break;
9404 case ButtonRelease:
9405 {
9406 /*
9407 User has finished magnifying image.
9408 */
9409 x=event->xbutton.x;
9410 y=event->xbutton.y;
9411 state|=ExitState;
9412 break;
9413 }
9414 case Expose:
9415 break;
9416 case MotionNotify:
9417 {
9418 x=event->xmotion.x;
9419 y=event->xmotion.y;
9420 break;
9421 }
9422 default:
9423 break;
9424 }
9425 /*
9426 Check boundary conditions.
9427 */
9428 if (x < 0)
9429 x=0;
9430 else
9431 if (x >= (int) windows->image.width)
9432 x=(int) windows->image.width-1;
9433 if (y < 0)
9434 y=0;
9435 else
9436 if (y >= (int) windows->image.height)
9437 y=(int) windows->image.height-1;
9438 } while ((state & ExitState) == 0);
9439 /*
9440 Display magnified image.
9441 */
9442 XSetCursorState(display,windows,MagickFalse);
9443 }
9444
9445 /*
9446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9447 % %
9448 % %
9449 % %
9450 + X M a g n i f y W i n d o w C o m m a n d %
9451 % %
9452 % %
9453 % %
9454 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9455 %
9456 % XMagnifyWindowCommand() moves the image within an Magnify window by one
9457 % pixel as specified by the key symbol.
9458 %
9459 % The format of the XMagnifyWindowCommand method is:
9460 %
9461 % void XMagnifyWindowCommand(Display *display,XWindows *windows,
9462 % const MagickStatusType state,const KeySym key_symbol,
9463 % ExceptionInfo *exception)
9464 %
9465 % A description of each parameter follows:
9466 %
9467 % o display: Specifies a connection to an X server; returned from
9468 % XOpenDisplay.
9469 %
9470 % o windows: Specifies a pointer to a XWindows structure.
9471 %
9472 % o state: key mask.
9473 %
9474 % o key_symbol: Specifies a KeySym which indicates which side of the image
9475 % to trim.
9476 %
9477 % o exception: return any errors or warnings in this structure.
9478 %
9479 */
XMagnifyWindowCommand(Display * display,XWindows * windows,const MagickStatusType state,const KeySym key_symbol,ExceptionInfo * exception)9480 static void XMagnifyWindowCommand(Display *display,XWindows *windows,
9481 const MagickStatusType state,const KeySym key_symbol,ExceptionInfo *exception)
9482 {
9483 unsigned int
9484 quantum;
9485
9486 /*
9487 User specified a magnify factor or position.
9488 */
9489 quantum=1;
9490 if ((state & Mod1Mask) != 0)
9491 quantum=10;
9492 switch ((int) key_symbol)
9493 {
9494 case QuitCommand:
9495 {
9496 (void) XWithdrawWindow(display,windows->magnify.id,
9497 windows->magnify.screen);
9498 break;
9499 }
9500 case XK_Home:
9501 case XK_KP_Home:
9502 {
9503 windows->magnify.x=(int) windows->image.width/2;
9504 windows->magnify.y=(int) windows->image.height/2;
9505 break;
9506 }
9507 case XK_Left:
9508 case XK_KP_Left:
9509 {
9510 if (windows->magnify.x > 0)
9511 windows->magnify.x-=quantum;
9512 break;
9513 }
9514 case XK_Up:
9515 case XK_KP_Up:
9516 {
9517 if (windows->magnify.y > 0)
9518 windows->magnify.y-=quantum;
9519 break;
9520 }
9521 case XK_Right:
9522 case XK_KP_Right:
9523 {
9524 if (windows->magnify.x < (int) (windows->image.ximage->width-1))
9525 windows->magnify.x+=quantum;
9526 break;
9527 }
9528 case XK_Down:
9529 case XK_KP_Down:
9530 {
9531 if (windows->magnify.y < (int) (windows->image.ximage->height-1))
9532 windows->magnify.y+=quantum;
9533 break;
9534 }
9535 case XK_0:
9536 case XK_1:
9537 case XK_2:
9538 case XK_3:
9539 case XK_4:
9540 case XK_5:
9541 case XK_6:
9542 case XK_7:
9543 case XK_8:
9544 case XK_9:
9545 {
9546 windows->magnify.data=(key_symbol-XK_0);
9547 break;
9548 }
9549 case XK_KP_0:
9550 case XK_KP_1:
9551 case XK_KP_2:
9552 case XK_KP_3:
9553 case XK_KP_4:
9554 case XK_KP_5:
9555 case XK_KP_6:
9556 case XK_KP_7:
9557 case XK_KP_8:
9558 case XK_KP_9:
9559 {
9560 windows->magnify.data=(key_symbol-XK_KP_0);
9561 break;
9562 }
9563 default:
9564 break;
9565 }
9566 XMakeMagnifyImage(display,windows,exception);
9567 }
9568
9569 /*
9570 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9571 % %
9572 % %
9573 % %
9574 + X M a k e P a n I m a g e %
9575 % %
9576 % %
9577 % %
9578 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9579 %
9580 % XMakePanImage() creates a thumbnail of the image and displays it in the Pan
9581 % icon window.
9582 %
9583 % The format of the XMakePanImage method is:
9584 %
9585 % void XMakePanImage(Display *display,XResourceInfo *resource_info,
9586 % XWindows *windows,Image *image,ExceptionInfo *exception)
9587 %
9588 % A description of each parameter follows:
9589 %
9590 % o display: Specifies a connection to an X server; returned from
9591 % XOpenDisplay.
9592 %
9593 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9594 %
9595 % o windows: Specifies a pointer to a XWindows structure.
9596 %
9597 % o image: the image.
9598 %
9599 % o exception: return any errors or warnings in this structure.
9600 %
9601 */
XMakePanImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,ExceptionInfo * exception)9602 static void XMakePanImage(Display *display,XResourceInfo *resource_info,
9603 XWindows *windows,Image *image,ExceptionInfo *exception)
9604 {
9605 MagickStatusType
9606 status;
9607
9608 /*
9609 Create and display image for panning icon.
9610 */
9611 XSetCursorState(display,windows,MagickTrue);
9612 XCheckRefreshWindows(display,windows);
9613 windows->pan.x=(int) windows->image.x;
9614 windows->pan.y=(int) windows->image.y;
9615 status=XMakeImage(display,resource_info,&windows->pan,image,
9616 windows->pan.width,windows->pan.height,exception);
9617 if (status == MagickFalse)
9618 ThrowXWindowException(ResourceLimitError,
9619 "MemoryAllocationFailed",image->filename);
9620 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
9621 windows->pan.pixmap);
9622 (void) XClearWindow(display,windows->pan.id);
9623 XDrawPanRectangle(display,windows);
9624 XSetCursorState(display,windows,MagickFalse);
9625 }
9626
9627 /*
9628 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9629 % %
9630 % %
9631 % %
9632 + X M a t t a E d i t I m a g e %
9633 % %
9634 % %
9635 % %
9636 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9637 %
9638 % XMatteEditImage() allows the user to interactively change the Matte channel
9639 % of an image. If the image is PseudoClass it is promoted to DirectClass
9640 % before the matte information is stored.
9641 %
9642 % The format of the XMatteEditImage method is:
9643 %
9644 % MagickBooleanType XMatteEditImage(Display *display,
9645 % XResourceInfo *resource_info,XWindows *windows,Image **image,
9646 % ExceptionInfo *exception)
9647 %
9648 % A description of each parameter follows:
9649 %
9650 % o display: Specifies a connection to an X server; returned from
9651 % XOpenDisplay.
9652 %
9653 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9654 %
9655 % o windows: Specifies a pointer to a XWindows structure.
9656 %
9657 % o image: the image; returned from ReadImage.
9658 %
9659 % o exception: return any errors or warnings in this structure.
9660 %
9661 */
XMatteEditImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image ** image,ExceptionInfo * exception)9662 static MagickBooleanType XMatteEditImage(Display *display,
9663 XResourceInfo *resource_info,XWindows *windows,Image **image,
9664 ExceptionInfo *exception)
9665 {
9666 static char
9667 matte[MagickPathExtent] = "0";
9668
9669 static const char
9670 *MatteEditMenu[] =
9671 {
9672 "Method",
9673 "Border Color",
9674 "Fuzz",
9675 "Matte Value",
9676 "Undo",
9677 "Help",
9678 "Dismiss",
9679 (char *) NULL
9680 };
9681
9682 static const ModeType
9683 MatteEditCommands[] =
9684 {
9685 MatteEditMethod,
9686 MatteEditBorderCommand,
9687 MatteEditFuzzCommand,
9688 MatteEditValueCommand,
9689 MatteEditUndoCommand,
9690 MatteEditHelpCommand,
9691 MatteEditDismissCommand
9692 };
9693
9694 static PaintMethod
9695 method = PointMethod;
9696
9697 static XColor
9698 border_color = { 0, 0, 0, 0, 0, 0 };
9699
9700 char
9701 command[MagickPathExtent],
9702 text[MagickPathExtent];
9703
9704 Cursor
9705 cursor;
9706
9707 int
9708 entry,
9709 id,
9710 x,
9711 x_offset,
9712 y,
9713 y_offset;
9714
9715 register int
9716 i;
9717
9718 register Quantum
9719 *q;
9720
9721 unsigned int
9722 height,
9723 width;
9724
9725 size_t
9726 state;
9727
9728 XEvent
9729 event;
9730
9731 /*
9732 Map Command widget.
9733 */
9734 (void) CloneString(&windows->command.name,"Matte Edit");
9735 windows->command.data=4;
9736 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL);
9737 (void) XMapRaised(display,windows->command.id);
9738 XClientMessage(display,windows->image.id,windows->im_protocols,
9739 windows->im_update_widget,CurrentTime);
9740 /*
9741 Make cursor.
9742 */
9743 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
9744 resource_info->background_color,resource_info->foreground_color);
9745 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9746 /*
9747 Track pointer until button 1 is pressed.
9748 */
9749 XQueryPosition(display,windows->image.id,&x,&y);
9750 (void) XSelectInput(display,windows->image.id,
9751 windows->image.attributes.event_mask | PointerMotionMask);
9752 state=DefaultState;
9753 do
9754 {
9755 if (windows->info.mapped != MagickFalse )
9756 {
9757 /*
9758 Display pointer position.
9759 */
9760 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ",
9761 x+windows->image.x,y+windows->image.y);
9762 XInfoWidget(display,windows,text);
9763 }
9764 /*
9765 Wait for next event.
9766 */
9767 XScreenEvent(display,windows,&event,exception);
9768 if (event.xany.window == windows->command.id)
9769 {
9770 /*
9771 Select a command from the Command widget.
9772 */
9773 id=XCommandWidget(display,windows,MatteEditMenu,&event);
9774 if (id < 0)
9775 {
9776 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9777 continue;
9778 }
9779 switch (MatteEditCommands[id])
9780 {
9781 case MatteEditMethod:
9782 {
9783 char
9784 **methods;
9785
9786 /*
9787 Select a method from the pop-up menu.
9788 */
9789 methods=GetCommandOptions(MagickMethodOptions);
9790 if (methods == (char **) NULL)
9791 break;
9792 entry=XMenuWidget(display,windows,MatteEditMenu[id],
9793 (const char **) methods,command);
9794 if (entry >= 0)
9795 method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
9796 MagickFalse,methods[entry]);
9797 methods=DestroyStringList(methods);
9798 break;
9799 }
9800 case MatteEditBorderCommand:
9801 {
9802 const char
9803 *ColorMenu[MaxNumberPens];
9804
9805 int
9806 pen_number;
9807
9808 /*
9809 Initialize menu selections.
9810 */
9811 for (i=0; i < (int) (MaxNumberPens-2); i++)
9812 ColorMenu[i]=resource_info->pen_colors[i];
9813 ColorMenu[MaxNumberPens-2]="Browser...";
9814 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
9815 /*
9816 Select a pen color from the pop-up menu.
9817 */
9818 pen_number=XMenuWidget(display,windows,MatteEditMenu[id],
9819 (const char **) ColorMenu,command);
9820 if (pen_number < 0)
9821 break;
9822 if (pen_number == (MaxNumberPens-2))
9823 {
9824 static char
9825 color_name[MagickPathExtent] = "gray";
9826
9827 /*
9828 Select a pen color from a dialog.
9829 */
9830 resource_info->pen_colors[pen_number]=color_name;
9831 XColorBrowserWidget(display,windows,"Select",color_name);
9832 if (*color_name == '\0')
9833 break;
9834 }
9835 /*
9836 Set border color.
9837 */
9838 (void) XParseColor(display,windows->map_info->colormap,
9839 resource_info->pen_colors[pen_number],&border_color);
9840 break;
9841 }
9842 case MatteEditFuzzCommand:
9843 {
9844 static char
9845 fuzz[MagickPathExtent];
9846
9847 static const char
9848 *FuzzMenu[] =
9849 {
9850 "0%",
9851 "2%",
9852 "5%",
9853 "10%",
9854 "15%",
9855 "Dialog...",
9856 (char *) NULL,
9857 };
9858
9859 /*
9860 Select a command from the pop-up menu.
9861 */
9862 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu,
9863 command);
9864 if (entry < 0)
9865 break;
9866 if (entry != 5)
9867 {
9868 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double)
9869 QuantumRange+1.0);
9870 break;
9871 }
9872 (void) CopyMagickString(fuzz,"20%",MagickPathExtent);
9873 (void) XDialogWidget(display,windows,"Ok",
9874 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
9875 if (*fuzz == '\0')
9876 break;
9877 (void) ConcatenateMagickString(fuzz,"%",MagickPathExtent);
9878 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+
9879 1.0);
9880 break;
9881 }
9882 case MatteEditValueCommand:
9883 {
9884 static char
9885 message[MagickPathExtent];
9886
9887 static const char
9888 *MatteMenu[] =
9889 {
9890 "Opaque",
9891 "Transparent",
9892 "Dialog...",
9893 (char *) NULL,
9894 };
9895
9896 /*
9897 Select a command from the pop-up menu.
9898 */
9899 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu,
9900 command);
9901 if (entry < 0)
9902 break;
9903 if (entry != 2)
9904 {
9905 (void) FormatLocaleString(matte,MagickPathExtent,QuantumFormat,
9906 OpaqueAlpha);
9907 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0)
9908 (void) FormatLocaleString(matte,MagickPathExtent,
9909 QuantumFormat,(Quantum) TransparentAlpha);
9910 break;
9911 }
9912 (void) FormatLocaleString(message,MagickPathExtent,
9913 "Enter matte value (0 - " QuantumFormat "):",(Quantum)
9914 QuantumRange);
9915 (void) XDialogWidget(display,windows,"Matte",message,matte);
9916 if (*matte == '\0')
9917 break;
9918 break;
9919 }
9920 case MatteEditUndoCommand:
9921 {
9922 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
9923 image,exception);
9924 break;
9925 }
9926 case MatteEditHelpCommand:
9927 {
9928 XTextViewWidget(display,resource_info,windows,MagickFalse,
9929 "Help Viewer - Matte Edit",ImageMatteEditHelp);
9930 break;
9931 }
9932 case MatteEditDismissCommand:
9933 {
9934 /*
9935 Prematurely exit.
9936 */
9937 state|=EscapeState;
9938 state|=ExitState;
9939 break;
9940 }
9941 default:
9942 break;
9943 }
9944 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9945 continue;
9946 }
9947 switch (event.type)
9948 {
9949 case ButtonPress:
9950 {
9951 if (event.xbutton.button != Button1)
9952 break;
9953 if ((event.xbutton.window != windows->image.id) &&
9954 (event.xbutton.window != windows->magnify.id))
9955 break;
9956 /*
9957 Update matte data.
9958 */
9959 x=event.xbutton.x;
9960 y=event.xbutton.y;
9961 (void) XMagickCommand(display,resource_info,windows,
9962 SaveToUndoBufferCommand,image,exception);
9963 state|=UpdateConfigurationState;
9964 break;
9965 }
9966 case ButtonRelease:
9967 {
9968 if (event.xbutton.button != Button1)
9969 break;
9970 if ((event.xbutton.window != windows->image.id) &&
9971 (event.xbutton.window != windows->magnify.id))
9972 break;
9973 /*
9974 Update colormap information.
9975 */
9976 x=event.xbutton.x;
9977 y=event.xbutton.y;
9978 XConfigureImageColormap(display,resource_info,windows,*image,exception);
9979 (void) XConfigureImage(display,resource_info,windows,*image,exception);
9980 XInfoWidget(display,windows,text);
9981 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9982 state&=(~UpdateConfigurationState);
9983 break;
9984 }
9985 case Expose:
9986 break;
9987 case KeyPress:
9988 {
9989 char
9990 command[MagickPathExtent];
9991
9992 KeySym
9993 key_symbol;
9994
9995 if (event.xkey.window == windows->magnify.id)
9996 {
9997 Window
9998 window;
9999
10000 window=windows->magnify.id;
10001 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
10002 }
10003 if (event.xkey.window != windows->image.id)
10004 break;
10005 /*
10006 Respond to a user key press.
10007 */
10008 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
10009 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
10010 switch ((int) key_symbol)
10011 {
10012 case XK_Escape:
10013 case XK_F20:
10014 {
10015 /*
10016 Prematurely exit.
10017 */
10018 state|=ExitState;
10019 break;
10020 }
10021 case XK_F1:
10022 case XK_Help:
10023 {
10024 XTextViewWidget(display,resource_info,windows,MagickFalse,
10025 "Help Viewer - Matte Edit",ImageMatteEditHelp);
10026 break;
10027 }
10028 default:
10029 {
10030 (void) XBell(display,0);
10031 break;
10032 }
10033 }
10034 break;
10035 }
10036 case MotionNotify:
10037 {
10038 /*
10039 Map and unmap Info widget as cursor crosses its boundaries.
10040 */
10041 x=event.xmotion.x;
10042 y=event.xmotion.y;
10043 if (windows->info.mapped != MagickFalse )
10044 {
10045 if ((x < (int) (windows->info.x+windows->info.width)) &&
10046 (y < (int) (windows->info.y+windows->info.height)))
10047 (void) XWithdrawWindow(display,windows->info.id,
10048 windows->info.screen);
10049 }
10050 else
10051 if ((x > (int) (windows->info.x+windows->info.width)) ||
10052 (y > (int) (windows->info.y+windows->info.height)))
10053 (void) XMapWindow(display,windows->info.id);
10054 break;
10055 }
10056 default:
10057 break;
10058 }
10059 if (event.xany.window == windows->magnify.id)
10060 {
10061 x=windows->magnify.x-windows->image.x;
10062 y=windows->magnify.y-windows->image.y;
10063 }
10064 x_offset=x;
10065 y_offset=y;
10066 if ((state & UpdateConfigurationState) != 0)
10067 {
10068 CacheView
10069 *image_view;
10070
10071 int
10072 x,
10073 y;
10074
10075 /*
10076 Matte edit is relative to image configuration.
10077 */
10078 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
10079 MagickTrue);
10080 XPutPixel(windows->image.ximage,x_offset,y_offset,
10081 windows->pixel_info->background_color.pixel);
10082 width=(unsigned int) (*image)->columns;
10083 height=(unsigned int) (*image)->rows;
10084 x=0;
10085 y=0;
10086 if (windows->image.crop_geometry != (char *) NULL)
10087 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,
10088 &height);
10089 x_offset=(int) (width*(windows->image.x+x_offset)/
10090 windows->image.ximage->width+x);
10091 y_offset=(int) (height*(windows->image.y+y_offset)/
10092 windows->image.ximage->height+y);
10093 if ((x_offset < 0) || (y_offset < 0))
10094 continue;
10095 if ((x_offset >= (int) (*image)->columns) ||
10096 (y_offset >= (int) (*image)->rows))
10097 continue;
10098 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
10099 return(MagickFalse);
10100 if ((*image)->alpha_trait == UndefinedPixelTrait)
10101 (void) SetImageAlphaChannel(*image,OpaqueAlphaChannel,exception);
10102 image_view=AcquireAuthenticCacheView(*image,exception);
10103 switch (method)
10104 {
10105 case PointMethod:
10106 default:
10107 {
10108 /*
10109 Update matte information using point algorithm.
10110 */
10111 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,
10112 (ssize_t) y_offset,1,1,exception);
10113 if (q == (Quantum *) NULL)
10114 break;
10115 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
10116 (void) SyncCacheViewAuthenticPixels(image_view,exception);
10117 break;
10118 }
10119 case ReplaceMethod:
10120 {
10121 PixelInfo
10122 pixel,
10123 target;
10124
10125 /*
10126 Update matte information using replace algorithm.
10127 */
10128 (void) GetOneCacheViewVirtualPixelInfo(image_view,(ssize_t)
10129 x_offset,(ssize_t) y_offset,&target,exception);
10130 for (y=0; y < (int) (*image)->rows; y++)
10131 {
10132 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
10133 (*image)->columns,1,exception);
10134 if (q == (Quantum *) NULL)
10135 break;
10136 for (x=0; x < (int) (*image)->columns; x++)
10137 {
10138 GetPixelInfoPixel(*image,q,&pixel);
10139 if (IsFuzzyEquivalencePixelInfo(&pixel,&target))
10140 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
10141 q+=GetPixelChannels(*image);
10142 }
10143 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
10144 break;
10145 }
10146 break;
10147 }
10148 case FloodfillMethod:
10149 case FillToBorderMethod:
10150 {
10151 ChannelType
10152 channel_mask;
10153
10154 DrawInfo
10155 *draw_info;
10156
10157 PixelInfo
10158 target;
10159
10160 /*
10161 Update matte information using floodfill algorithm.
10162 */
10163 (void) GetOneVirtualPixelInfo(*image,
10164 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t)
10165 y_offset,&target,exception);
10166 if (method == FillToBorderMethod)
10167 {
10168 target.red=(double) ScaleShortToQuantum(
10169 border_color.red);
10170 target.green=(double) ScaleShortToQuantum(
10171 border_color.green);
10172 target.blue=(double) ScaleShortToQuantum(
10173 border_color.blue);
10174 }
10175 draw_info=CloneDrawInfo(resource_info->image_info,
10176 (DrawInfo *) NULL);
10177 draw_info->fill.alpha=(double) ClampToQuantum(
10178 StringToDouble(matte,(char **) NULL));
10179 channel_mask=SetImageChannelMask(*image,AlphaChannel);
10180 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t)
10181 x_offset,(ssize_t) y_offset,
10182 method != FloodfillMethod ? MagickTrue : MagickFalse,exception);
10183 (void) SetPixelChannelMask(*image,channel_mask);
10184 draw_info=DestroyDrawInfo(draw_info);
10185 break;
10186 }
10187 case ResetMethod:
10188 {
10189 /*
10190 Update matte information using reset algorithm.
10191 */
10192 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse)
10193 return(MagickFalse);
10194 for (y=0; y < (int) (*image)->rows; y++)
10195 {
10196 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
10197 (*image)->columns,1,exception);
10198 if (q == (Quantum *) NULL)
10199 break;
10200 for (x=0; x < (int) (*image)->columns; x++)
10201 {
10202 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
10203 q+=GetPixelChannels(*image);
10204 }
10205 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
10206 break;
10207 }
10208 if (StringToLong(matte) == (long) OpaqueAlpha)
10209 (*image)->alpha_trait=UndefinedPixelTrait;
10210 break;
10211 }
10212 }
10213 image_view=DestroyCacheView(image_view);
10214 state&=(~UpdateConfigurationState);
10215 }
10216 } while ((state & ExitState) == 0);
10217 (void) XSelectInput(display,windows->image.id,
10218 windows->image.attributes.event_mask);
10219 XSetCursorState(display,windows,MagickFalse);
10220 (void) XFreeCursor(display,cursor);
10221 return(MagickTrue);
10222 }
10223
10224 /*
10225 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10226 % %
10227 % %
10228 % %
10229 + X O p e n I m a g e %
10230 % %
10231 % %
10232 % %
10233 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10234 %
10235 % XOpenImage() loads an image from a file.
10236 %
10237 % The format of the XOpenImage method is:
10238 %
10239 % Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10240 % XWindows *windows,const unsigned int command)
10241 %
10242 % A description of each parameter follows:
10243 %
10244 % o display: Specifies a connection to an X server; returned from
10245 % XOpenDisplay.
10246 %
10247 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10248 %
10249 % o windows: Specifies a pointer to a XWindows structure.
10250 %
10251 % o command: A value other than zero indicates that the file is selected
10252 % from the command line argument list.
10253 %
10254 */
XOpenImage(Display * display,XResourceInfo * resource_info,XWindows * windows,const MagickBooleanType command)10255 static Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10256 XWindows *windows,const MagickBooleanType command)
10257 {
10258 const MagickInfo
10259 *magick_info;
10260
10261 ExceptionInfo
10262 *exception;
10263
10264 Image
10265 *nexus;
10266
10267 ImageInfo
10268 *image_info;
10269
10270 static char
10271 filename[MagickPathExtent] = "\0";
10272
10273 /*
10274 Request file name from user.
10275 */
10276 if (command == MagickFalse)
10277 XFileBrowserWidget(display,windows,"Open",filename);
10278 else
10279 {
10280 char
10281 **filelist,
10282 **files;
10283
10284 int
10285 count,
10286 status;
10287
10288 register int
10289 i,
10290 j;
10291
10292 /*
10293 Select next image from the command line.
10294 */
10295 status=XGetCommand(display,windows->image.id,&files,&count);
10296 if (status == 0)
10297 {
10298 ThrowXWindowException(XServerError,"UnableToGetProperty","...");
10299 return((Image *) NULL);
10300 }
10301 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist));
10302 if (filelist == (char **) NULL)
10303 {
10304 ThrowXWindowException(ResourceLimitError,
10305 "MemoryAllocationFailed","...");
10306 (void) XFreeStringList(files);
10307 return((Image *) NULL);
10308 }
10309 j=0;
10310 for (i=1; i < count; i++)
10311 if (*files[i] != '-')
10312 filelist[j++]=files[i];
10313 filelist[j]=(char *) NULL;
10314 XListBrowserWidget(display,windows,&windows->widget,
10315 (const char **) filelist,"Load","Select Image to Load:",filename);
10316 filelist=(char **) RelinquishMagickMemory(filelist);
10317 (void) XFreeStringList(files);
10318 }
10319 if (*filename == '\0')
10320 return((Image *) NULL);
10321 image_info=CloneImageInfo(resource_info->image_info);
10322 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL,
10323 (void *) NULL);
10324 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
10325 exception=AcquireExceptionInfo();
10326 (void) SetImageInfo(image_info,0,exception);
10327 if (LocaleCompare(image_info->magick,"X") == 0)
10328 {
10329 char
10330 seconds[MagickPathExtent];
10331
10332 /*
10333 User may want to delay the X server screen grab.
10334 */
10335 (void) CopyMagickString(seconds,"0",MagickPathExtent);
10336 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:",
10337 seconds);
10338 if (*seconds == '\0')
10339 return((Image *) NULL);
10340 XDelay(display,(size_t) (1000*StringToLong(seconds)));
10341 }
10342 magick_info=GetMagickInfo(image_info->magick,exception);
10343 if ((magick_info != (const MagickInfo *) NULL) &&
10344 GetMagickRawSupport(magick_info) == MagickTrue)
10345 {
10346 char
10347 geometry[MagickPathExtent];
10348
10349 /*
10350 Request image size from the user.
10351 */
10352 (void) CopyMagickString(geometry,"512x512",MagickPathExtent);
10353 if (image_info->size != (char *) NULL)
10354 (void) CopyMagickString(geometry,image_info->size,MagickPathExtent);
10355 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:",
10356 geometry);
10357 (void) CloneString(&image_info->size,geometry);
10358 }
10359 /*
10360 Load the image.
10361 */
10362 XSetCursorState(display,windows,MagickTrue);
10363 XCheckRefreshWindows(display,windows);
10364 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
10365 nexus=ReadImage(image_info,exception);
10366 CatchException(exception);
10367 XSetCursorState(display,windows,MagickFalse);
10368 if (nexus != (Image *) NULL)
10369 XClientMessage(display,windows->image.id,windows->im_protocols,
10370 windows->im_next_image,CurrentTime);
10371 else
10372 {
10373 char
10374 *text,
10375 **textlist;
10376
10377 /*
10378 Unknown image format.
10379 */
10380 text=FileToString(filename,~0UL,exception);
10381 if (text == (char *) NULL)
10382 return((Image *) NULL);
10383 textlist=StringToList(text);
10384 if (textlist != (char **) NULL)
10385 {
10386 char
10387 title[MagickPathExtent];
10388
10389 register int
10390 i;
10391
10392 (void) FormatLocaleString(title,MagickPathExtent,
10393 "Unknown format: %s",filename);
10394 XTextViewWidget(display,resource_info,windows,MagickTrue,title,
10395 (const char **) textlist);
10396 for (i=0; textlist[i] != (char *) NULL; i++)
10397 textlist[i]=DestroyString(textlist[i]);
10398 textlist=(char **) RelinquishMagickMemory(textlist);
10399 }
10400 text=DestroyString(text);
10401 }
10402 exception=DestroyExceptionInfo(exception);
10403 image_info=DestroyImageInfo(image_info);
10404 return(nexus);
10405 }
10406
10407 /*
10408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10409 % %
10410 % %
10411 % %
10412 + X P a n I m a g e %
10413 % %
10414 % %
10415 % %
10416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10417 %
10418 % XPanImage() pans the image until the mouse button is released.
10419 %
10420 % The format of the XPanImage method is:
10421 %
10422 % void XPanImage(Display *display,XWindows *windows,XEvent *event,
10423 % ExceptionInfo *exception)
10424 %
10425 % A description of each parameter follows:
10426 %
10427 % o display: Specifies a connection to an X server; returned from
10428 % XOpenDisplay.
10429 %
10430 % o windows: Specifies a pointer to a XWindows structure.
10431 %
10432 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
10433 % the entire image is refreshed.
10434 %
10435 % o exception: return any errors or warnings in this structure.
10436 %
10437 */
XPanImage(Display * display,XWindows * windows,XEvent * event,ExceptionInfo * exception)10438 static void XPanImage(Display *display,XWindows *windows,XEvent *event,
10439 ExceptionInfo *exception)
10440 {
10441 char
10442 text[MagickPathExtent];
10443
10444 Cursor
10445 cursor;
10446
10447 double
10448 x_factor,
10449 y_factor;
10450
10451 RectangleInfo
10452 pan_info;
10453
10454 size_t
10455 state;
10456
10457 /*
10458 Define cursor.
10459 */
10460 if ((windows->image.ximage->width > (int) windows->image.width) &&
10461 (windows->image.ximage->height > (int) windows->image.height))
10462 cursor=XCreateFontCursor(display,XC_fleur);
10463 else
10464 if (windows->image.ximage->width > (int) windows->image.width)
10465 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow);
10466 else
10467 if (windows->image.ximage->height > (int) windows->image.height)
10468 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow);
10469 else
10470 cursor=XCreateFontCursor(display,XC_arrow);
10471 (void) XCheckDefineCursor(display,windows->pan.id,cursor);
10472 /*
10473 Pan image as pointer moves until the mouse button is released.
10474 */
10475 x_factor=(double) windows->image.ximage->width/windows->pan.width;
10476 y_factor=(double) windows->image.ximage->height/windows->pan.height;
10477 pan_info.width=windows->pan.width*windows->image.width/
10478 windows->image.ximage->width;
10479 pan_info.height=windows->pan.height*windows->image.height/
10480 windows->image.ximage->height;
10481 pan_info.x=0;
10482 pan_info.y=0;
10483 state=UpdateConfigurationState;
10484 do
10485 {
10486 switch (event->type)
10487 {
10488 case ButtonPress:
10489 {
10490 /*
10491 User choose an initial pan location.
10492 */
10493 pan_info.x=(ssize_t) event->xbutton.x;
10494 pan_info.y=(ssize_t) event->xbutton.y;
10495 state|=UpdateConfigurationState;
10496 break;
10497 }
10498 case ButtonRelease:
10499 {
10500 /*
10501 User has finished panning the image.
10502 */
10503 pan_info.x=(ssize_t) event->xbutton.x;
10504 pan_info.y=(ssize_t) event->xbutton.y;
10505 state|=UpdateConfigurationState | ExitState;
10506 break;
10507 }
10508 case MotionNotify:
10509 {
10510 pan_info.x=(ssize_t) event->xmotion.x;
10511 pan_info.y=(ssize_t) event->xmotion.y;
10512 state|=UpdateConfigurationState;
10513 }
10514 default:
10515 break;
10516 }
10517 if ((state & UpdateConfigurationState) != 0)
10518 {
10519 /*
10520 Check boundary conditions.
10521 */
10522 if (pan_info.x < (ssize_t) (pan_info.width/2))
10523 pan_info.x=0;
10524 else
10525 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2)));
10526 if (pan_info.x < 0)
10527 pan_info.x=0;
10528 else
10529 if ((int) (pan_info.x+windows->image.width) >
10530 windows->image.ximage->width)
10531 pan_info.x=(ssize_t)
10532 (windows->image.ximage->width-windows->image.width);
10533 if (pan_info.y < (ssize_t) (pan_info.height/2))
10534 pan_info.y=0;
10535 else
10536 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2)));
10537 if (pan_info.y < 0)
10538 pan_info.y=0;
10539 else
10540 if ((int) (pan_info.y+windows->image.height) >
10541 windows->image.ximage->height)
10542 pan_info.y=(ssize_t)
10543 (windows->image.ximage->height-windows->image.height);
10544 if ((windows->image.x != (int) pan_info.x) ||
10545 (windows->image.y != (int) pan_info.y))
10546 {
10547 /*
10548 Display image pan offset.
10549 */
10550 windows->image.x=(int) pan_info.x;
10551 windows->image.y=(int) pan_info.y;
10552 (void) FormatLocaleString(text,MagickPathExtent," %ux%u%+d%+d ",
10553 windows->image.width,windows->image.height,windows->image.x,
10554 windows->image.y);
10555 XInfoWidget(display,windows,text);
10556 /*
10557 Refresh Image window.
10558 */
10559 XDrawPanRectangle(display,windows);
10560 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
10561 }
10562 state&=(~UpdateConfigurationState);
10563 }
10564 /*
10565 Wait for next event.
10566 */
10567 if ((state & ExitState) == 0)
10568 XScreenEvent(display,windows,event,exception);
10569 } while ((state & ExitState) == 0);
10570 /*
10571 Restore cursor.
10572 */
10573 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor);
10574 (void) XFreeCursor(display,cursor);
10575 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
10576 }
10577
10578 /*
10579 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10580 % %
10581 % %
10582 % %
10583 + X P a s t e I m a g e %
10584 % %
10585 % %
10586 % %
10587 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10588 %
10589 % XPasteImage() pastes an image previously saved with XCropImage in the X
10590 % window image at a location the user chooses with the pointer.
10591 %
10592 % The format of the XPasteImage method is:
10593 %
10594 % MagickBooleanType XPasteImage(Display *display,
10595 % XResourceInfo *resource_info,XWindows *windows,Image *image,
10596 % ExceptionInfo *exception)
10597 %
10598 % A description of each parameter follows:
10599 %
10600 % o display: Specifies a connection to an X server; returned from
10601 % XOpenDisplay.
10602 %
10603 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10604 %
10605 % o windows: Specifies a pointer to a XWindows structure.
10606 %
10607 % o image: the image; returned from ReadImage.
10608 %
10609 % o exception: return any errors or warnings in this structure.
10610 %
10611 */
XPasteImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,ExceptionInfo * exception)10612 static MagickBooleanType XPasteImage(Display *display,
10613 XResourceInfo *resource_info,XWindows *windows,Image *image,
10614 ExceptionInfo *exception)
10615 {
10616 static const char
10617 *PasteMenu[] =
10618 {
10619 "Operator",
10620 "Help",
10621 "Dismiss",
10622 (char *) NULL
10623 };
10624
10625 static const ModeType
10626 PasteCommands[] =
10627 {
10628 PasteOperatorsCommand,
10629 PasteHelpCommand,
10630 PasteDismissCommand
10631 };
10632
10633 static CompositeOperator
10634 compose = CopyCompositeOp;
10635
10636 char
10637 text[MagickPathExtent];
10638
10639 Cursor
10640 cursor;
10641
10642 Image
10643 *paste_image;
10644
10645 int
10646 entry,
10647 id,
10648 x,
10649 y;
10650
10651 double
10652 scale_factor;
10653
10654 RectangleInfo
10655 highlight_info,
10656 paste_info;
10657
10658 unsigned int
10659 height,
10660 width;
10661
10662 size_t
10663 state;
10664
10665 XEvent
10666 event;
10667
10668 /*
10669 Copy image.
10670 */
10671 if (resource_info->copy_image == (Image *) NULL)
10672 return(MagickFalse);
10673 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,exception);
10674 if (paste_image == (Image *) NULL)
10675 return(MagickFalse);
10676 /*
10677 Map Command widget.
10678 */
10679 (void) CloneString(&windows->command.name,"Paste");
10680 windows->command.data=1;
10681 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL);
10682 (void) XMapRaised(display,windows->command.id);
10683 XClientMessage(display,windows->image.id,windows->im_protocols,
10684 windows->im_update_widget,CurrentTime);
10685 /*
10686 Track pointer until button 1 is pressed.
10687 */
10688 XSetCursorState(display,windows,MagickFalse);
10689 XQueryPosition(display,windows->image.id,&x,&y);
10690 (void) XSelectInput(display,windows->image.id,
10691 windows->image.attributes.event_mask | PointerMotionMask);
10692 paste_info.x=(ssize_t) windows->image.x+x;
10693 paste_info.y=(ssize_t) windows->image.y+y;
10694 paste_info.width=0;
10695 paste_info.height=0;
10696 cursor=XCreateFontCursor(display,XC_ul_angle);
10697 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
10698 state=DefaultState;
10699 do
10700 {
10701 if (windows->info.mapped != MagickFalse )
10702 {
10703 /*
10704 Display pointer position.
10705 */
10706 (void) FormatLocaleString(text,MagickPathExtent," %+ld%+ld ",
10707 (long) paste_info.x,(long) paste_info.y);
10708 XInfoWidget(display,windows,text);
10709 }
10710 highlight_info=paste_info;
10711 highlight_info.x=paste_info.x-windows->image.x;
10712 highlight_info.y=paste_info.y-windows->image.y;
10713 XHighlightRectangle(display,windows->image.id,
10714 windows->image.highlight_context,&highlight_info);
10715 /*
10716 Wait for next event.
10717 */
10718 XScreenEvent(display,windows,&event,exception);
10719 XHighlightRectangle(display,windows->image.id,
10720 windows->image.highlight_context,&highlight_info);
10721 if (event.xany.window == windows->command.id)
10722 {
10723 /*
10724 Select a command from the Command widget.
10725 */
10726 id=XCommandWidget(display,windows,PasteMenu,&event);
10727 if (id < 0)
10728 continue;
10729 switch (PasteCommands[id])
10730 {
10731 case PasteOperatorsCommand:
10732 {
10733 char
10734 command[MagickPathExtent],
10735 **operators;
10736
10737 /*
10738 Select a command from the pop-up menu.
10739 */
10740 operators=GetCommandOptions(MagickComposeOptions);
10741 if (operators == (char **) NULL)
10742 break;
10743 entry=XMenuWidget(display,windows,PasteMenu[id],
10744 (const char **) operators,command);
10745 if (entry >= 0)
10746 compose=(CompositeOperator) ParseCommandOption(
10747 MagickComposeOptions,MagickFalse,operators[entry]);
10748 operators=DestroyStringList(operators);
10749 break;
10750 }
10751 case PasteHelpCommand:
10752 {
10753 XTextViewWidget(display,resource_info,windows,MagickFalse,
10754 "Help Viewer - Image Composite",ImagePasteHelp);
10755 break;
10756 }
10757 case PasteDismissCommand:
10758 {
10759 /*
10760 Prematurely exit.
10761 */
10762 state|=EscapeState;
10763 state|=ExitState;
10764 break;
10765 }
10766 default:
10767 break;
10768 }
10769 continue;
10770 }
10771 switch (event.type)
10772 {
10773 case ButtonPress:
10774 {
10775 if (image->debug != MagickFalse )
10776 (void) LogMagickEvent(X11Event,GetMagickModule(),
10777 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
10778 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10779 if (event.xbutton.button != Button1)
10780 break;
10781 if (event.xbutton.window != windows->image.id)
10782 break;
10783 /*
10784 Paste rectangle is relative to image configuration.
10785 */
10786 width=(unsigned int) image->columns;
10787 height=(unsigned int) image->rows;
10788 x=0;
10789 y=0;
10790 if (windows->image.crop_geometry != (char *) NULL)
10791 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
10792 &width,&height);
10793 scale_factor=(double) windows->image.ximage->width/width;
10794 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5);
10795 scale_factor=(double) windows->image.ximage->height/height;
10796 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5);
10797 (void) XCheckDefineCursor(display,windows->image.id,cursor);
10798 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10799 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
10800 break;
10801 }
10802 case ButtonRelease:
10803 {
10804 if (image->debug != MagickFalse )
10805 (void) LogMagickEvent(X11Event,GetMagickModule(),
10806 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
10807 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10808 if (event.xbutton.button != Button1)
10809 break;
10810 if (event.xbutton.window != windows->image.id)
10811 break;
10812 if ((paste_info.width != 0) && (paste_info.height != 0))
10813 {
10814 /*
10815 User has selected the location of the paste image.
10816 */
10817 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10818 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
10819 state|=ExitState;
10820 }
10821 break;
10822 }
10823 case Expose:
10824 break;
10825 case KeyPress:
10826 {
10827 char
10828 command[MagickPathExtent];
10829
10830 KeySym
10831 key_symbol;
10832
10833 int
10834 length;
10835
10836 if (event.xkey.window != windows->image.id)
10837 break;
10838 /*
10839 Respond to a user key press.
10840 */
10841 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
10842 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
10843 *(command+length)='\0';
10844 if (image->debug != MagickFalse )
10845 (void) LogMagickEvent(X11Event,GetMagickModule(),
10846 "Key press: 0x%lx (%s)",(long) key_symbol,command);
10847 switch ((int) key_symbol)
10848 {
10849 case XK_Escape:
10850 case XK_F20:
10851 {
10852 /*
10853 Prematurely exit.
10854 */
10855 paste_image=DestroyImage(paste_image);
10856 state|=EscapeState;
10857 state|=ExitState;
10858 break;
10859 }
10860 case XK_F1:
10861 case XK_Help:
10862 {
10863 (void) XSetFunction(display,windows->image.highlight_context,
10864 GXcopy);
10865 XTextViewWidget(display,resource_info,windows,MagickFalse,
10866 "Help Viewer - Image Composite",ImagePasteHelp);
10867 (void) XSetFunction(display,windows->image.highlight_context,
10868 GXinvert);
10869 break;
10870 }
10871 default:
10872 {
10873 (void) XBell(display,0);
10874 break;
10875 }
10876 }
10877 break;
10878 }
10879 case MotionNotify:
10880 {
10881 /*
10882 Map and unmap Info widget as text cursor crosses its boundaries.
10883 */
10884 x=event.xmotion.x;
10885 y=event.xmotion.y;
10886 if (windows->info.mapped != MagickFalse )
10887 {
10888 if ((x < (int) (windows->info.x+windows->info.width)) &&
10889 (y < (int) (windows->info.y+windows->info.height)))
10890 (void) XWithdrawWindow(display,windows->info.id,
10891 windows->info.screen);
10892 }
10893 else
10894 if ((x > (int) (windows->info.x+windows->info.width)) ||
10895 (y > (int) (windows->info.y+windows->info.height)))
10896 (void) XMapWindow(display,windows->info.id);
10897 paste_info.x=(ssize_t) windows->image.x+x;
10898 paste_info.y=(ssize_t) windows->image.y+y;
10899 break;
10900 }
10901 default:
10902 {
10903 if (image->debug != MagickFalse )
10904 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
10905 event.type);
10906 break;
10907 }
10908 }
10909 } while ((state & ExitState) == 0);
10910 (void) XSelectInput(display,windows->image.id,
10911 windows->image.attributes.event_mask);
10912 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
10913 XSetCursorState(display,windows,MagickFalse);
10914 (void) XFreeCursor(display,cursor);
10915 if ((state & EscapeState) != 0)
10916 return(MagickTrue);
10917 /*
10918 Image pasting is relative to image configuration.
10919 */
10920 XSetCursorState(display,windows,MagickTrue);
10921 XCheckRefreshWindows(display,windows);
10922 width=(unsigned int) image->columns;
10923 height=(unsigned int) image->rows;
10924 x=0;
10925 y=0;
10926 if (windows->image.crop_geometry != (char *) NULL)
10927 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
10928 scale_factor=(double) width/windows->image.ximage->width;
10929 paste_info.x+=x;
10930 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5);
10931 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5);
10932 scale_factor=(double) height/windows->image.ximage->height;
10933 paste_info.y+=y;
10934 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5);
10935 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5);
10936 /*
10937 Paste image with X Image window.
10938 */
10939 (void) CompositeImage(image,paste_image,compose,MagickTrue,paste_info.x,
10940 paste_info.y,exception);
10941 paste_image=DestroyImage(paste_image);
10942 XSetCursorState(display,windows,MagickFalse);
10943 /*
10944 Update image colormap.
10945 */
10946 XConfigureImageColormap(display,resource_info,windows,image,exception);
10947 (void) XConfigureImage(display,resource_info,windows,image,exception);
10948 return(MagickTrue);
10949 }
10950
10951 /*
10952 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10953 % %
10954 % %
10955 % %
10956 + X P r i n t I m a g e %
10957 % %
10958 % %
10959 % %
10960 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10961 %
10962 % XPrintImage() prints an image to a Postscript printer.
10963 %
10964 % The format of the XPrintImage method is:
10965 %
10966 % MagickBooleanType XPrintImage(Display *display,
10967 % XResourceInfo *resource_info,XWindows *windows,Image *image,
10968 % ExceptionInfo *exception)
10969 %
10970 % A description of each parameter follows:
10971 %
10972 % o display: Specifies a connection to an X server; returned from
10973 % XOpenDisplay.
10974 %
10975 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10976 %
10977 % o windows: Specifies a pointer to a XWindows structure.
10978 %
10979 % o image: the image.
10980 %
10981 % o exception: return any errors or warnings in this structure.
10982 %
10983 */
XPrintImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,ExceptionInfo * exception)10984 static MagickBooleanType XPrintImage(Display *display,
10985 XResourceInfo *resource_info,XWindows *windows,Image *image,
10986 ExceptionInfo *exception)
10987 {
10988 char
10989 filename[MagickPathExtent],
10990 geometry[MagickPathExtent];
10991
10992 Image
10993 *print_image;
10994
10995 ImageInfo
10996 *image_info;
10997
10998 MagickStatusType
10999 status;
11000
11001 /*
11002 Request Postscript page geometry from user.
11003 */
11004 image_info=CloneImageInfo(resource_info->image_info);
11005 (void) FormatLocaleString(geometry,MagickPathExtent,"Letter");
11006 if (image_info->page != (char *) NULL)
11007 (void) CopyMagickString(geometry,image_info->page,MagickPathExtent);
11008 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
11009 "Select Postscript Page Geometry:",geometry);
11010 if (*geometry == '\0')
11011 return(MagickTrue);
11012 image_info->page=GetPageGeometry(geometry);
11013 /*
11014 Apply image transforms.
11015 */
11016 XSetCursorState(display,windows,MagickTrue);
11017 XCheckRefreshWindows(display,windows);
11018 print_image=CloneImage(image,0,0,MagickTrue,exception);
11019 if (print_image == (Image *) NULL)
11020 return(MagickFalse);
11021 (void) FormatLocaleString(geometry,MagickPathExtent,"%dx%d!",
11022 windows->image.ximage->width,windows->image.ximage->height);
11023 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry,
11024 exception);
11025 /*
11026 Print image.
11027 */
11028 (void) AcquireUniqueFilename(filename);
11029 (void) FormatLocaleString(print_image->filename,MagickPathExtent,"print:%s",
11030 filename);
11031 status=WriteImage(image_info,print_image,exception);
11032 (void) RelinquishUniqueFileResource(filename);
11033 print_image=DestroyImage(print_image);
11034 image_info=DestroyImageInfo(image_info);
11035 XSetCursorState(display,windows,MagickFalse);
11036 return(status != 0 ? MagickTrue : MagickFalse);
11037 }
11038
11039 /*
11040 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11041 % %
11042 % %
11043 % %
11044 + X R O I I m a g e %
11045 % %
11046 % %
11047 % %
11048 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11049 %
11050 % XROIImage() applies an image processing technique to a region of interest.
11051 %
11052 % The format of the XROIImage method is:
11053 %
11054 % MagickBooleanType XROIImage(Display *display,
11055 % XResourceInfo *resource_info,XWindows *windows,Image **image,
11056 % ExceptionInfo *exception)
11057 %
11058 % A description of each parameter follows:
11059 %
11060 % o display: Specifies a connection to an X server; returned from
11061 % XOpenDisplay.
11062 %
11063 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
11064 %
11065 % o windows: Specifies a pointer to a XWindows structure.
11066 %
11067 % o image: the image; returned from ReadImage.
11068 %
11069 % o exception: return any errors or warnings in this structure.
11070 %
11071 */
XROIImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image ** image,ExceptionInfo * exception)11072 static MagickBooleanType XROIImage(Display *display,
11073 XResourceInfo *resource_info,XWindows *windows,Image **image,
11074 ExceptionInfo *exception)
11075 {
11076 #define ApplyMenus 7
11077
11078 static const char
11079 *ROIMenu[] =
11080 {
11081 "Help",
11082 "Dismiss",
11083 (char *) NULL
11084 },
11085 *ApplyMenu[] =
11086 {
11087 "File",
11088 "Edit",
11089 "Transform",
11090 "Enhance",
11091 "Effects",
11092 "F/X",
11093 "Miscellany",
11094 "Help",
11095 "Dismiss",
11096 (char *) NULL
11097 },
11098 *FileMenu[] =
11099 {
11100 "Save...",
11101 "Print...",
11102 (char *) NULL
11103 },
11104 *EditMenu[] =
11105 {
11106 "Undo",
11107 "Redo",
11108 (char *) NULL
11109 },
11110 *TransformMenu[] =
11111 {
11112 "Flop",
11113 "Flip",
11114 "Rotate Right",
11115 "Rotate Left",
11116 (char *) NULL
11117 },
11118 *EnhanceMenu[] =
11119 {
11120 "Hue...",
11121 "Saturation...",
11122 "Brightness...",
11123 "Gamma...",
11124 "Spiff",
11125 "Dull",
11126 "Contrast Stretch...",
11127 "Sigmoidal Contrast...",
11128 "Normalize",
11129 "Equalize",
11130 "Negate",
11131 "Grayscale",
11132 "Map...",
11133 "Quantize...",
11134 (char *) NULL
11135 },
11136 *EffectsMenu[] =
11137 {
11138 "Despeckle",
11139 "Emboss",
11140 "Reduce Noise",
11141 "Add Noise",
11142 "Sharpen...",
11143 "Blur...",
11144 "Threshold...",
11145 "Edge Detect...",
11146 "Spread...",
11147 "Shade...",
11148 "Raise...",
11149 "Segment...",
11150 (char *) NULL
11151 },
11152 *FXMenu[] =
11153 {
11154 "Solarize...",
11155 "Sepia Tone...",
11156 "Swirl...",
11157 "Implode...",
11158 "Vignette...",
11159 "Wave...",
11160 "Oil Paint...",
11161 "Charcoal Draw...",
11162 (char *) NULL
11163 },
11164 *MiscellanyMenu[] =
11165 {
11166 "Image Info",
11167 "Zoom Image",
11168 "Show Preview...",
11169 "Show Histogram",
11170 "Show Matte",
11171 (char *) NULL
11172 };
11173
11174 static const char
11175 **Menus[ApplyMenus] =
11176 {
11177 FileMenu,
11178 EditMenu,
11179 TransformMenu,
11180 EnhanceMenu,
11181 EffectsMenu,
11182 FXMenu,
11183 MiscellanyMenu
11184 };
11185
11186 static const CommandType
11187 ApplyCommands[] =
11188 {
11189 NullCommand,
11190 NullCommand,
11191 NullCommand,
11192 NullCommand,
11193 NullCommand,
11194 NullCommand,
11195 NullCommand,
11196 HelpCommand,
11197 QuitCommand
11198 },
11199 FileCommands[] =
11200 {
11201 SaveCommand,
11202 PrintCommand
11203 },
11204 EditCommands[] =
11205 {
11206 UndoCommand,
11207 RedoCommand
11208 },
11209 TransformCommands[] =
11210 {
11211 FlopCommand,
11212 FlipCommand,
11213 RotateRightCommand,
11214 RotateLeftCommand
11215 },
11216 EnhanceCommands[] =
11217 {
11218 HueCommand,
11219 SaturationCommand,
11220 BrightnessCommand,
11221 GammaCommand,
11222 SpiffCommand,
11223 DullCommand,
11224 ContrastStretchCommand,
11225 SigmoidalContrastCommand,
11226 NormalizeCommand,
11227 EqualizeCommand,
11228 NegateCommand,
11229 GrayscaleCommand,
11230 MapCommand,
11231 QuantizeCommand
11232 },
11233 EffectsCommands[] =
11234 {
11235 DespeckleCommand,
11236 EmbossCommand,
11237 ReduceNoiseCommand,
11238 AddNoiseCommand,
11239 SharpenCommand,
11240 BlurCommand,
11241 EdgeDetectCommand,
11242 SpreadCommand,
11243 ShadeCommand,
11244 RaiseCommand,
11245 SegmentCommand
11246 },
11247 FXCommands[] =
11248 {
11249 SolarizeCommand,
11250 SepiaToneCommand,
11251 SwirlCommand,
11252 ImplodeCommand,
11253 VignetteCommand,
11254 WaveCommand,
11255 OilPaintCommand,
11256 CharcoalDrawCommand
11257 },
11258 MiscellanyCommands[] =
11259 {
11260 InfoCommand,
11261 ZoomCommand,
11262 ShowPreviewCommand,
11263 ShowHistogramCommand,
11264 ShowMatteCommand
11265 },
11266 ROICommands[] =
11267 {
11268 ROIHelpCommand,
11269 ROIDismissCommand
11270 };
11271
11272 static const CommandType
11273 *Commands[ApplyMenus] =
11274 {
11275 FileCommands,
11276 EditCommands,
11277 TransformCommands,
11278 EnhanceCommands,
11279 EffectsCommands,
11280 FXCommands,
11281 MiscellanyCommands
11282 };
11283
11284 char
11285 command[MagickPathExtent],
11286 text[MagickPathExtent];
11287
11288 CommandType
11289 command_type;
11290
11291 Cursor
11292 cursor;
11293
11294 Image
11295 *roi_image;
11296
11297 int
11298 entry,
11299 id,
11300 x,
11301 y;
11302
11303 double
11304 scale_factor;
11305
11306 MagickProgressMonitor
11307 progress_monitor;
11308
11309 RectangleInfo
11310 crop_info,
11311 highlight_info,
11312 roi_info;
11313
11314 unsigned int
11315 height,
11316 width;
11317
11318 size_t
11319 state;
11320
11321 XEvent
11322 event;
11323
11324 /*
11325 Map Command widget.
11326 */
11327 (void) CloneString(&windows->command.name,"ROI");
11328 windows->command.data=0;
11329 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL);
11330 (void) XMapRaised(display,windows->command.id);
11331 XClientMessage(display,windows->image.id,windows->im_protocols,
11332 windows->im_update_widget,CurrentTime);
11333 /*
11334 Track pointer until button 1 is pressed.
11335 */
11336 XQueryPosition(display,windows->image.id,&x,&y);
11337 (void) XSelectInput(display,windows->image.id,
11338 windows->image.attributes.event_mask | PointerMotionMask);
11339 roi_info.x=(ssize_t) windows->image.x+x;
11340 roi_info.y=(ssize_t) windows->image.y+y;
11341 roi_info.width=0;
11342 roi_info.height=0;
11343 cursor=XCreateFontCursor(display,XC_fleur);
11344 state=DefaultState;
11345 do
11346 {
11347 if (windows->info.mapped != MagickFalse )
11348 {
11349 /*
11350 Display pointer position.
11351 */
11352 (void) FormatLocaleString(text,MagickPathExtent," %+ld%+ld ",
11353 (long) roi_info.x,(long) roi_info.y);
11354 XInfoWidget(display,windows,text);
11355 }
11356 /*
11357 Wait for next event.
11358 */
11359 XScreenEvent(display,windows,&event,exception);
11360 if (event.xany.window == windows->command.id)
11361 {
11362 /*
11363 Select a command from the Command widget.
11364 */
11365 id=XCommandWidget(display,windows,ROIMenu,&event);
11366 if (id < 0)
11367 continue;
11368 switch (ROICommands[id])
11369 {
11370 case ROIHelpCommand:
11371 {
11372 XTextViewWidget(display,resource_info,windows,MagickFalse,
11373 "Help Viewer - Region of Interest",ImageROIHelp);
11374 break;
11375 }
11376 case ROIDismissCommand:
11377 {
11378 /*
11379 Prematurely exit.
11380 */
11381 state|=EscapeState;
11382 state|=ExitState;
11383 break;
11384 }
11385 default:
11386 break;
11387 }
11388 continue;
11389 }
11390 switch (event.type)
11391 {
11392 case ButtonPress:
11393 {
11394 if (event.xbutton.button != Button1)
11395 break;
11396 if (event.xbutton.window != windows->image.id)
11397 break;
11398 /*
11399 Note first corner of region of interest rectangle-- exit loop.
11400 */
11401 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11402 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11403 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11404 state|=ExitState;
11405 break;
11406 }
11407 case ButtonRelease:
11408 break;
11409 case Expose:
11410 break;
11411 case KeyPress:
11412 {
11413 KeySym
11414 key_symbol;
11415
11416 if (event.xkey.window != windows->image.id)
11417 break;
11418 /*
11419 Respond to a user key press.
11420 */
11421 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11422 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11423 switch ((int) key_symbol)
11424 {
11425 case XK_Escape:
11426 case XK_F20:
11427 {
11428 /*
11429 Prematurely exit.
11430 */
11431 state|=EscapeState;
11432 state|=ExitState;
11433 break;
11434 }
11435 case XK_F1:
11436 case XK_Help:
11437 {
11438 XTextViewWidget(display,resource_info,windows,MagickFalse,
11439 "Help Viewer - Region of Interest",ImageROIHelp);
11440 break;
11441 }
11442 default:
11443 {
11444 (void) XBell(display,0);
11445 break;
11446 }
11447 }
11448 break;
11449 }
11450 case MotionNotify:
11451 {
11452 /*
11453 Map and unmap Info widget as text cursor crosses its boundaries.
11454 */
11455 x=event.xmotion.x;
11456 y=event.xmotion.y;
11457 if (windows->info.mapped != MagickFalse )
11458 {
11459 if ((x < (int) (windows->info.x+windows->info.width)) &&
11460 (y < (int) (windows->info.y+windows->info.height)))
11461 (void) XWithdrawWindow(display,windows->info.id,
11462 windows->info.screen);
11463 }
11464 else
11465 if ((x > (int) (windows->info.x+windows->info.width)) ||
11466 (y > (int) (windows->info.y+windows->info.height)))
11467 (void) XMapWindow(display,windows->info.id);
11468 roi_info.x=(ssize_t) windows->image.x+x;
11469 roi_info.y=(ssize_t) windows->image.y+y;
11470 break;
11471 }
11472 default:
11473 break;
11474 }
11475 } while ((state & ExitState) == 0);
11476 (void) XSelectInput(display,windows->image.id,
11477 windows->image.attributes.event_mask);
11478 if ((state & EscapeState) != 0)
11479 {
11480 /*
11481 User want to exit without region of interest.
11482 */
11483 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11484 (void) XFreeCursor(display,cursor);
11485 return(MagickTrue);
11486 }
11487 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
11488 do
11489 {
11490 /*
11491 Size rectangle as pointer moves until the mouse button is released.
11492 */
11493 x=(int) roi_info.x;
11494 y=(int) roi_info.y;
11495 roi_info.width=0;
11496 roi_info.height=0;
11497 state=DefaultState;
11498 do
11499 {
11500 highlight_info=roi_info;
11501 highlight_info.x=roi_info.x-windows->image.x;
11502 highlight_info.y=roi_info.y-windows->image.y;
11503 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11504 {
11505 /*
11506 Display info and draw region of interest rectangle.
11507 */
11508 if (windows->info.mapped == MagickFalse)
11509 (void) XMapWindow(display,windows->info.id);
11510 (void) FormatLocaleString(text,MagickPathExtent,
11511 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11512 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11513 XInfoWidget(display,windows,text);
11514 XHighlightRectangle(display,windows->image.id,
11515 windows->image.highlight_context,&highlight_info);
11516 }
11517 else
11518 if (windows->info.mapped != MagickFalse )
11519 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11520 /*
11521 Wait for next event.
11522 */
11523 XScreenEvent(display,windows,&event,exception);
11524 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11525 XHighlightRectangle(display,windows->image.id,
11526 windows->image.highlight_context,&highlight_info);
11527 switch (event.type)
11528 {
11529 case ButtonPress:
11530 {
11531 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11532 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11533 break;
11534 }
11535 case ButtonRelease:
11536 {
11537 /*
11538 User has committed to region of interest rectangle.
11539 */
11540 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11541 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
11542 XSetCursorState(display,windows,MagickFalse);
11543 state|=ExitState;
11544 if (LocaleCompare(windows->command.name,"Apply") == 0)
11545 break;
11546 (void) CloneString(&windows->command.name,"Apply");
11547 windows->command.data=ApplyMenus;
11548 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL);
11549 break;
11550 }
11551 case Expose:
11552 break;
11553 case MotionNotify:
11554 {
11555 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11556 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
11557 }
11558 default:
11559 break;
11560 }
11561 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) ||
11562 ((state & ExitState) != 0))
11563 {
11564 /*
11565 Check boundary conditions.
11566 */
11567 if (roi_info.x < 0)
11568 roi_info.x=0;
11569 else
11570 if (roi_info.x > (ssize_t) windows->image.ximage->width)
11571 roi_info.x=(ssize_t) windows->image.ximage->width;
11572 if ((int) roi_info.x < x)
11573 roi_info.width=(unsigned int) (x-roi_info.x);
11574 else
11575 {
11576 roi_info.width=(unsigned int) (roi_info.x-x);
11577 roi_info.x=(ssize_t) x;
11578 }
11579 if (roi_info.y < 0)
11580 roi_info.y=0;
11581 else
11582 if (roi_info.y > (ssize_t) windows->image.ximage->height)
11583 roi_info.y=(ssize_t) windows->image.ximage->height;
11584 if ((int) roi_info.y < y)
11585 roi_info.height=(unsigned int) (y-roi_info.y);
11586 else
11587 {
11588 roi_info.height=(unsigned int) (roi_info.y-y);
11589 roi_info.y=(ssize_t) y;
11590 }
11591 }
11592 } while ((state & ExitState) == 0);
11593 /*
11594 Wait for user to grab a corner of the rectangle or press return.
11595 */
11596 state=DefaultState;
11597 command_type=NullCommand;
11598 crop_info.x=0;
11599 crop_info.y=0;
11600 (void) XMapWindow(display,windows->info.id);
11601 do
11602 {
11603 if (windows->info.mapped != MagickFalse )
11604 {
11605 /*
11606 Display pointer position.
11607 */
11608 (void) FormatLocaleString(text,MagickPathExtent,
11609 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11610 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11611 XInfoWidget(display,windows,text);
11612 }
11613 highlight_info=roi_info;
11614 highlight_info.x=roi_info.x-windows->image.x;
11615 highlight_info.y=roi_info.y-windows->image.y;
11616 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
11617 {
11618 state|=EscapeState;
11619 state|=ExitState;
11620 break;
11621 }
11622 if ((state & UpdateRegionState) != 0)
11623 {
11624 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11625 switch (command_type)
11626 {
11627 case UndoCommand:
11628 case RedoCommand:
11629 {
11630 (void) XMagickCommand(display,resource_info,windows,command_type,
11631 image,exception);
11632 break;
11633 }
11634 default:
11635 {
11636 /*
11637 Region of interest is relative to image configuration.
11638 */
11639 progress_monitor=SetImageProgressMonitor(*image,
11640 (MagickProgressMonitor) NULL,(*image)->client_data);
11641 crop_info=roi_info;
11642 width=(unsigned int) (*image)->columns;
11643 height=(unsigned int) (*image)->rows;
11644 x=0;
11645 y=0;
11646 if (windows->image.crop_geometry != (char *) NULL)
11647 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
11648 &width,&height);
11649 scale_factor=(double) width/windows->image.ximage->width;
11650 crop_info.x+=x;
11651 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
11652 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
11653 scale_factor=(double)
11654 height/windows->image.ximage->height;
11655 crop_info.y+=y;
11656 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
11657 crop_info.height=(unsigned int)
11658 (scale_factor*crop_info.height+0.5);
11659 roi_image=CropImage(*image,&crop_info,exception);
11660 (void) SetImageProgressMonitor(*image,progress_monitor,
11661 (*image)->client_data);
11662 if (roi_image == (Image *) NULL)
11663 continue;
11664 /*
11665 Apply image processing technique to the region of interest.
11666 */
11667 windows->image.orphan=MagickTrue;
11668 (void) XMagickCommand(display,resource_info,windows,command_type,
11669 &roi_image,exception);
11670 progress_monitor=SetImageProgressMonitor(*image,
11671 (MagickProgressMonitor) NULL,(*image)->client_data);
11672 (void) XMagickCommand(display,resource_info,windows,
11673 SaveToUndoBufferCommand,image,exception);
11674 windows->image.orphan=MagickFalse;
11675 (void) CompositeImage(*image,roi_image,CopyCompositeOp,
11676 MagickTrue,crop_info.x,crop_info.y,exception);
11677 roi_image=DestroyImage(roi_image);
11678 (void) SetImageProgressMonitor(*image,progress_monitor,
11679 (*image)->client_data);
11680 break;
11681 }
11682 }
11683 if (command_type != InfoCommand)
11684 {
11685 XConfigureImageColormap(display,resource_info,windows,*image,
11686 exception);
11687 (void) XConfigureImage(display,resource_info,windows,*image,
11688 exception);
11689 }
11690 XCheckRefreshWindows(display,windows);
11691 XInfoWidget(display,windows,text);
11692 (void) XSetFunction(display,windows->image.highlight_context,
11693 GXinvert);
11694 state&=(~UpdateRegionState);
11695 }
11696 XHighlightRectangle(display,windows->image.id,
11697 windows->image.highlight_context,&highlight_info);
11698 XScreenEvent(display,windows,&event,exception);
11699 if (event.xany.window == windows->command.id)
11700 {
11701 /*
11702 Select a command from the Command widget.
11703 */
11704 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11705 command_type=NullCommand;
11706 id=XCommandWidget(display,windows,ApplyMenu,&event);
11707 if (id >= 0)
11708 {
11709 (void) CopyMagickString(command,ApplyMenu[id],MagickPathExtent);
11710 command_type=ApplyCommands[id];
11711 if (id < ApplyMenus)
11712 {
11713 /*
11714 Select a command from a pop-up menu.
11715 */
11716 entry=XMenuWidget(display,windows,ApplyMenu[id],
11717 (const char **) Menus[id],command);
11718 if (entry >= 0)
11719 {
11720 (void) CopyMagickString(command,Menus[id][entry],
11721 MagickPathExtent);
11722 command_type=Commands[id][entry];
11723 }
11724 }
11725 }
11726 (void) XSetFunction(display,windows->image.highlight_context,
11727 GXinvert);
11728 XHighlightRectangle(display,windows->image.id,
11729 windows->image.highlight_context,&highlight_info);
11730 if (command_type == HelpCommand)
11731 {
11732 (void) XSetFunction(display,windows->image.highlight_context,
11733 GXcopy);
11734 XTextViewWidget(display,resource_info,windows,MagickFalse,
11735 "Help Viewer - Region of Interest",ImageROIHelp);
11736 (void) XSetFunction(display,windows->image.highlight_context,
11737 GXinvert);
11738 continue;
11739 }
11740 if (command_type == QuitCommand)
11741 {
11742 /*
11743 exit.
11744 */
11745 state|=EscapeState;
11746 state|=ExitState;
11747 continue;
11748 }
11749 if (command_type != NullCommand)
11750 state|=UpdateRegionState;
11751 continue;
11752 }
11753 XHighlightRectangle(display,windows->image.id,
11754 windows->image.highlight_context,&highlight_info);
11755 switch (event.type)
11756 {
11757 case ButtonPress:
11758 {
11759 x=windows->image.x;
11760 y=windows->image.y;
11761 if (event.xbutton.button != Button1)
11762 break;
11763 if (event.xbutton.window != windows->image.id)
11764 break;
11765 x=windows->image.x+event.xbutton.x;
11766 y=windows->image.y+event.xbutton.y;
11767 if ((x < (int) (roi_info.x+RoiDelta)) &&
11768 (x > (int) (roi_info.x-RoiDelta)) &&
11769 (y < (int) (roi_info.y+RoiDelta)) &&
11770 (y > (int) (roi_info.y-RoiDelta)))
11771 {
11772 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
11773 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
11774 state|=UpdateConfigurationState;
11775 break;
11776 }
11777 if ((x < (int) (roi_info.x+RoiDelta)) &&
11778 (x > (int) (roi_info.x-RoiDelta)) &&
11779 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11780 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11781 {
11782 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
11783 state|=UpdateConfigurationState;
11784 break;
11785 }
11786 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11787 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11788 (y < (int) (roi_info.y+RoiDelta)) &&
11789 (y > (int) (roi_info.y-RoiDelta)))
11790 {
11791 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
11792 state|=UpdateConfigurationState;
11793 break;
11794 }
11795 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11796 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11797 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11798 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11799 {
11800 state|=UpdateConfigurationState;
11801 break;
11802 }
11803 }
11804 case ButtonRelease:
11805 {
11806 if (event.xbutton.window == windows->pan.id)
11807 if ((highlight_info.x != crop_info.x-windows->image.x) ||
11808 (highlight_info.y != crop_info.y-windows->image.y))
11809 XHighlightRectangle(display,windows->image.id,
11810 windows->image.highlight_context,&highlight_info);
11811 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11812 event.xbutton.time);
11813 break;
11814 }
11815 case Expose:
11816 {
11817 if (event.xexpose.window == windows->image.id)
11818 if (event.xexpose.count == 0)
11819 {
11820 event.xexpose.x=(int) highlight_info.x;
11821 event.xexpose.y=(int) highlight_info.y;
11822 event.xexpose.width=(int) highlight_info.width;
11823 event.xexpose.height=(int) highlight_info.height;
11824 XRefreshWindow(display,&windows->image,&event);
11825 }
11826 if (event.xexpose.window == windows->info.id)
11827 if (event.xexpose.count == 0)
11828 XInfoWidget(display,windows,text);
11829 break;
11830 }
11831 case KeyPress:
11832 {
11833 KeySym
11834 key_symbol;
11835
11836 if (event.xkey.window != windows->image.id)
11837 break;
11838 /*
11839 Respond to a user key press.
11840 */
11841 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11842 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11843 switch ((int) key_symbol)
11844 {
11845 case XK_Shift_L:
11846 case XK_Shift_R:
11847 break;
11848 case XK_Escape:
11849 case XK_F20:
11850 state|=EscapeState;
11851 case XK_Return:
11852 {
11853 state|=ExitState;
11854 break;
11855 }
11856 case XK_Home:
11857 case XK_KP_Home:
11858 {
11859 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L);
11860 roi_info.y=(ssize_t) (windows->image.height/2L-
11861 roi_info.height/2L);
11862 break;
11863 }
11864 case XK_Left:
11865 case XK_KP_Left:
11866 {
11867 roi_info.x--;
11868 break;
11869 }
11870 case XK_Up:
11871 case XK_KP_Up:
11872 case XK_Next:
11873 {
11874 roi_info.y--;
11875 break;
11876 }
11877 case XK_Right:
11878 case XK_KP_Right:
11879 {
11880 roi_info.x++;
11881 break;
11882 }
11883 case XK_Prior:
11884 case XK_Down:
11885 case XK_KP_Down:
11886 {
11887 roi_info.y++;
11888 break;
11889 }
11890 case XK_F1:
11891 case XK_Help:
11892 {
11893 (void) XSetFunction(display,windows->image.highlight_context,
11894 GXcopy);
11895 XTextViewWidget(display,resource_info,windows,MagickFalse,
11896 "Help Viewer - Region of Interest",ImageROIHelp);
11897 (void) XSetFunction(display,windows->image.highlight_context,
11898 GXinvert);
11899 break;
11900 }
11901 default:
11902 {
11903 command_type=XImageWindowCommand(display,resource_info,windows,
11904 event.xkey.state,key_symbol,image,exception);
11905 if (command_type != NullCommand)
11906 state|=UpdateRegionState;
11907 break;
11908 }
11909 }
11910 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11911 event.xkey.time);
11912 break;
11913 }
11914 case KeyRelease:
11915 break;
11916 case MotionNotify:
11917 {
11918 if (event.xbutton.window != windows->image.id)
11919 break;
11920 /*
11921 Map and unmap Info widget as text cursor crosses its boundaries.
11922 */
11923 x=event.xmotion.x;
11924 y=event.xmotion.y;
11925 if (windows->info.mapped != MagickFalse )
11926 {
11927 if ((x < (int) (windows->info.x+windows->info.width)) &&
11928 (y < (int) (windows->info.y+windows->info.height)))
11929 (void) XWithdrawWindow(display,windows->info.id,
11930 windows->info.screen);
11931 }
11932 else
11933 if ((x > (int) (windows->info.x+windows->info.width)) ||
11934 (y > (int) (windows->info.y+windows->info.height)))
11935 (void) XMapWindow(display,windows->info.id);
11936 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11937 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
11938 break;
11939 }
11940 case SelectionRequest:
11941 {
11942 XSelectionEvent
11943 notify;
11944
11945 XSelectionRequestEvent
11946 *request;
11947
11948 /*
11949 Set primary selection.
11950 */
11951 (void) FormatLocaleString(text,MagickPathExtent,
11952 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
11953 roi_info.height,(double) roi_info.x,(double) roi_info.y);
11954 request=(&(event.xselectionrequest));
11955 (void) XChangeProperty(request->display,request->requestor,
11956 request->property,request->target,8,PropModeReplace,
11957 (unsigned char *) text,(int) strlen(text));
11958 notify.type=SelectionNotify;
11959 notify.display=request->display;
11960 notify.requestor=request->requestor;
11961 notify.selection=request->selection;
11962 notify.target=request->target;
11963 notify.time=request->time;
11964 if (request->property == None)
11965 notify.property=request->target;
11966 else
11967 notify.property=request->property;
11968 (void) XSendEvent(request->display,request->requestor,False,0,
11969 (XEvent *) ¬ify);
11970 }
11971 default:
11972 break;
11973 }
11974 if ((state & UpdateConfigurationState) != 0)
11975 {
11976 (void) XPutBackEvent(display,&event);
11977 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11978 break;
11979 }
11980 } while ((state & ExitState) == 0);
11981 } while ((state & ExitState) == 0);
11982 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11983 XSetCursorState(display,windows,MagickFalse);
11984 if ((state & EscapeState) != 0)
11985 return(MagickTrue);
11986 return(MagickTrue);
11987 }
11988
11989 /*
11990 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11991 % %
11992 % %
11993 % %
11994 + X R o t a t e I m a g e %
11995 % %
11996 % %
11997 % %
11998 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11999 %
12000 % XRotateImage() rotates the X image. If the degrees parameter if zero, the
12001 % rotation angle is computed from the slope of a line drawn by the user.
12002 %
12003 % The format of the XRotateImage method is:
12004 %
12005 % MagickBooleanType XRotateImage(Display *display,
12006 % XResourceInfo *resource_info,XWindows *windows,double degrees,
12007 % Image **image,ExceptionInfo *exception)
12008 %
12009 % A description of each parameter follows:
12010 %
12011 % o display: Specifies a connection to an X server; returned from
12012 % XOpenDisplay.
12013 %
12014 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12015 %
12016 % o windows: Specifies a pointer to a XWindows structure.
12017 %
12018 % o degrees: Specifies the number of degrees to rotate the image.
12019 %
12020 % o image: the image.
12021 %
12022 % o exception: return any errors or warnings in this structure.
12023 %
12024 */
XRotateImage(Display * display,XResourceInfo * resource_info,XWindows * windows,double degrees,Image ** image,ExceptionInfo * exception)12025 static MagickBooleanType XRotateImage(Display *display,
12026 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image,
12027 ExceptionInfo *exception)
12028 {
12029 static const char
12030 *RotateMenu[] =
12031 {
12032 "Pixel Color",
12033 "Direction",
12034 "Help",
12035 "Dismiss",
12036 (char *) NULL
12037 };
12038
12039 static ModeType
12040 direction = HorizontalRotateCommand;
12041
12042 static const ModeType
12043 DirectionCommands[] =
12044 {
12045 HorizontalRotateCommand,
12046 VerticalRotateCommand
12047 },
12048 RotateCommands[] =
12049 {
12050 RotateColorCommand,
12051 RotateDirectionCommand,
12052 RotateHelpCommand,
12053 RotateDismissCommand
12054 };
12055
12056 static unsigned int
12057 pen_id = 0;
12058
12059 char
12060 command[MagickPathExtent],
12061 text[MagickPathExtent];
12062
12063 Image
12064 *rotate_image;
12065
12066 int
12067 id,
12068 x,
12069 y;
12070
12071 double
12072 normalized_degrees;
12073
12074 register int
12075 i;
12076
12077 unsigned int
12078 height,
12079 rotations,
12080 width;
12081
12082 if (degrees == 0.0)
12083 {
12084 unsigned int
12085 distance;
12086
12087 size_t
12088 state;
12089
12090 XEvent
12091 event;
12092
12093 XSegment
12094 rotate_info;
12095
12096 /*
12097 Map Command widget.
12098 */
12099 (void) CloneString(&windows->command.name,"Rotate");
12100 windows->command.data=2;
12101 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL);
12102 (void) XMapRaised(display,windows->command.id);
12103 XClientMessage(display,windows->image.id,windows->im_protocols,
12104 windows->im_update_widget,CurrentTime);
12105 /*
12106 Wait for first button press.
12107 */
12108 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
12109 XQueryPosition(display,windows->image.id,&x,&y);
12110 rotate_info.x1=x;
12111 rotate_info.y1=y;
12112 rotate_info.x2=x;
12113 rotate_info.y2=y;
12114 state=DefaultState;
12115 do
12116 {
12117 XHighlightLine(display,windows->image.id,
12118 windows->image.highlight_context,&rotate_info);
12119 /*
12120 Wait for next event.
12121 */
12122 XScreenEvent(display,windows,&event,exception);
12123 XHighlightLine(display,windows->image.id,
12124 windows->image.highlight_context,&rotate_info);
12125 if (event.xany.window == windows->command.id)
12126 {
12127 /*
12128 Select a command from the Command widget.
12129 */
12130 id=XCommandWidget(display,windows,RotateMenu,&event);
12131 if (id < 0)
12132 continue;
12133 (void) XSetFunction(display,windows->image.highlight_context,
12134 GXcopy);
12135 switch (RotateCommands[id])
12136 {
12137 case RotateColorCommand:
12138 {
12139 const char
12140 *ColorMenu[MaxNumberPens];
12141
12142 int
12143 pen_number;
12144
12145 XColor
12146 color;
12147
12148 /*
12149 Initialize menu selections.
12150 */
12151 for (i=0; i < (int) (MaxNumberPens-2); i++)
12152 ColorMenu[i]=resource_info->pen_colors[i];
12153 ColorMenu[MaxNumberPens-2]="Browser...";
12154 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
12155 /*
12156 Select a pen color from the pop-up menu.
12157 */
12158 pen_number=XMenuWidget(display,windows,RotateMenu[id],
12159 (const char **) ColorMenu,command);
12160 if (pen_number < 0)
12161 break;
12162 if (pen_number == (MaxNumberPens-2))
12163 {
12164 static char
12165 color_name[MagickPathExtent] = "gray";
12166
12167 /*
12168 Select a pen color from a dialog.
12169 */
12170 resource_info->pen_colors[pen_number]=color_name;
12171 XColorBrowserWidget(display,windows,"Select",color_name);
12172 if (*color_name == '\0')
12173 break;
12174 }
12175 /*
12176 Set pen color.
12177 */
12178 (void) XParseColor(display,windows->map_info->colormap,
12179 resource_info->pen_colors[pen_number],&color);
12180 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
12181 (unsigned int) MaxColors,&color);
12182 windows->pixel_info->pen_colors[pen_number]=color;
12183 pen_id=(unsigned int) pen_number;
12184 break;
12185 }
12186 case RotateDirectionCommand:
12187 {
12188 static const char
12189 *Directions[] =
12190 {
12191 "horizontal",
12192 "vertical",
12193 (char *) NULL,
12194 };
12195
12196 /*
12197 Select a command from the pop-up menu.
12198 */
12199 id=XMenuWidget(display,windows,RotateMenu[id],
12200 Directions,command);
12201 if (id >= 0)
12202 direction=DirectionCommands[id];
12203 break;
12204 }
12205 case RotateHelpCommand:
12206 {
12207 XTextViewWidget(display,resource_info,windows,MagickFalse,
12208 "Help Viewer - Image Rotation",ImageRotateHelp);
12209 break;
12210 }
12211 case RotateDismissCommand:
12212 {
12213 /*
12214 Prematurely exit.
12215 */
12216 state|=EscapeState;
12217 state|=ExitState;
12218 break;
12219 }
12220 default:
12221 break;
12222 }
12223 (void) XSetFunction(display,windows->image.highlight_context,
12224 GXinvert);
12225 continue;
12226 }
12227 switch (event.type)
12228 {
12229 case ButtonPress:
12230 {
12231 if (event.xbutton.button != Button1)
12232 break;
12233 if (event.xbutton.window != windows->image.id)
12234 break;
12235 /*
12236 exit loop.
12237 */
12238 (void) XSetFunction(display,windows->image.highlight_context,
12239 GXcopy);
12240 rotate_info.x1=event.xbutton.x;
12241 rotate_info.y1=event.xbutton.y;
12242 state|=ExitState;
12243 break;
12244 }
12245 case ButtonRelease:
12246 break;
12247 case Expose:
12248 break;
12249 case KeyPress:
12250 {
12251 char
12252 command[MagickPathExtent];
12253
12254 KeySym
12255 key_symbol;
12256
12257 if (event.xkey.window != windows->image.id)
12258 break;
12259 /*
12260 Respond to a user key press.
12261 */
12262 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
12263 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12264 switch ((int) key_symbol)
12265 {
12266 case XK_Escape:
12267 case XK_F20:
12268 {
12269 /*
12270 Prematurely exit.
12271 */
12272 state|=EscapeState;
12273 state|=ExitState;
12274 break;
12275 }
12276 case XK_F1:
12277 case XK_Help:
12278 {
12279 (void) XSetFunction(display,windows->image.highlight_context,
12280 GXcopy);
12281 XTextViewWidget(display,resource_info,windows,MagickFalse,
12282 "Help Viewer - Image Rotation",ImageRotateHelp);
12283 (void) XSetFunction(display,windows->image.highlight_context,
12284 GXinvert);
12285 break;
12286 }
12287 default:
12288 {
12289 (void) XBell(display,0);
12290 break;
12291 }
12292 }
12293 break;
12294 }
12295 case MotionNotify:
12296 {
12297 rotate_info.x1=event.xmotion.x;
12298 rotate_info.y1=event.xmotion.y;
12299 }
12300 }
12301 rotate_info.x2=rotate_info.x1;
12302 rotate_info.y2=rotate_info.y1;
12303 if (direction == HorizontalRotateCommand)
12304 rotate_info.x2+=32;
12305 else
12306 rotate_info.y2-=32;
12307 } while ((state & ExitState) == 0);
12308 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12309 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12310 if ((state & EscapeState) != 0)
12311 return(MagickTrue);
12312 /*
12313 Draw line as pointer moves until the mouse button is released.
12314 */
12315 distance=0;
12316 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
12317 state=DefaultState;
12318 do
12319 {
12320 if (distance > 9)
12321 {
12322 /*
12323 Display info and draw rotation line.
12324 */
12325 if (windows->info.mapped == MagickFalse)
12326 (void) XMapWindow(display,windows->info.id);
12327 (void) FormatLocaleString(text,MagickPathExtent," %g",
12328 direction == VerticalRotateCommand ? degrees-90.0 : degrees);
12329 XInfoWidget(display,windows,text);
12330 XHighlightLine(display,windows->image.id,
12331 windows->image.highlight_context,&rotate_info);
12332 }
12333 else
12334 if (windows->info.mapped != MagickFalse )
12335 (void) XWithdrawWindow(display,windows->info.id,
12336 windows->info.screen);
12337 /*
12338 Wait for next event.
12339 */
12340 XScreenEvent(display,windows,&event,exception);
12341 if (distance > 9)
12342 XHighlightLine(display,windows->image.id,
12343 windows->image.highlight_context,&rotate_info);
12344 switch (event.type)
12345 {
12346 case ButtonPress:
12347 break;
12348 case ButtonRelease:
12349 {
12350 /*
12351 User has committed to rotation line.
12352 */
12353 rotate_info.x2=event.xbutton.x;
12354 rotate_info.y2=event.xbutton.y;
12355 state|=ExitState;
12356 break;
12357 }
12358 case Expose:
12359 break;
12360 case MotionNotify:
12361 {
12362 rotate_info.x2=event.xmotion.x;
12363 rotate_info.y2=event.xmotion.y;
12364 }
12365 default:
12366 break;
12367 }
12368 /*
12369 Check boundary conditions.
12370 */
12371 if (rotate_info.x2 < 0)
12372 rotate_info.x2=0;
12373 else
12374 if (rotate_info.x2 > (int) windows->image.width)
12375 rotate_info.x2=(short) windows->image.width;
12376 if (rotate_info.y2 < 0)
12377 rotate_info.y2=0;
12378 else
12379 if (rotate_info.y2 > (int) windows->image.height)
12380 rotate_info.y2=(short) windows->image.height;
12381 /*
12382 Compute rotation angle from the slope of the line.
12383 */
12384 degrees=0.0;
12385 distance=(unsigned int)
12386 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+
12387 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1));
12388 if (distance > 9)
12389 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2-
12390 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1)));
12391 } while ((state & ExitState) == 0);
12392 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12393 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12394 if (distance <= 9)
12395 return(MagickTrue);
12396 }
12397 if (direction == VerticalRotateCommand)
12398 degrees-=90.0;
12399 if (degrees == 0.0)
12400 return(MagickTrue);
12401 /*
12402 Rotate image.
12403 */
12404 normalized_degrees=degrees;
12405 while (normalized_degrees < -45.0)
12406 normalized_degrees+=360.0;
12407 for (rotations=0; normalized_degrees > 45.0; rotations++)
12408 normalized_degrees-=90.0;
12409 if (normalized_degrees != 0.0)
12410 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
12411 exception);
12412 XSetCursorState(display,windows,MagickTrue);
12413 XCheckRefreshWindows(display,windows);
12414 (*image)->background_color.red=(double) ScaleShortToQuantum(
12415 windows->pixel_info->pen_colors[pen_id].red);
12416 (*image)->background_color.green=(double) ScaleShortToQuantum(
12417 windows->pixel_info->pen_colors[pen_id].green);
12418 (*image)->background_color.blue=(double) ScaleShortToQuantum(
12419 windows->pixel_info->pen_colors[pen_id].blue);
12420 rotate_image=RotateImage(*image,degrees,exception);
12421 XSetCursorState(display,windows,MagickFalse);
12422 if (rotate_image == (Image *) NULL)
12423 return(MagickFalse);
12424 *image=DestroyImage(*image);
12425 *image=rotate_image;
12426 if (windows->image.crop_geometry != (char *) NULL)
12427 {
12428 /*
12429 Rotate crop geometry.
12430 */
12431 width=(unsigned int) (*image)->columns;
12432 height=(unsigned int) (*image)->rows;
12433 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12434 switch (rotations % 4)
12435 {
12436 default:
12437 case 0:
12438 break;
12439 case 1:
12440 {
12441 /*
12442 Rotate 90 degrees.
12443 */
12444 (void) FormatLocaleString(windows->image.crop_geometry,
12445 MagickPathExtent,"%ux%u%+d%+d",height,width,(int) (*image)->columns-
12446 (int) height-y,x);
12447 break;
12448 }
12449 case 2:
12450 {
12451 /*
12452 Rotate 180 degrees.
12453 */
12454 (void) FormatLocaleString(windows->image.crop_geometry,
12455 MagickPathExtent,"%ux%u%+d%+d",width,height,(int) width-x,(int)
12456 height-y);
12457 break;
12458 }
12459 case 3:
12460 {
12461 /*
12462 Rotate 270 degrees.
12463 */
12464 (void) FormatLocaleString(windows->image.crop_geometry,
12465 MagickPathExtent,"%ux%u%+d%+d",height,width,y,(int) (*image)->rows-
12466 (int) width-x);
12467 break;
12468 }
12469 }
12470 }
12471 if (windows->image.orphan != MagickFalse )
12472 return(MagickTrue);
12473 if (normalized_degrees != 0.0)
12474 {
12475 /*
12476 Update image colormap.
12477 */
12478 windows->image.window_changes.width=(int) (*image)->columns;
12479 windows->image.window_changes.height=(int) (*image)->rows;
12480 if (windows->image.crop_geometry != (char *) NULL)
12481 {
12482 /*
12483 Obtain dimensions of image from crop geometry.
12484 */
12485 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
12486 &width,&height);
12487 windows->image.window_changes.width=(int) width;
12488 windows->image.window_changes.height=(int) height;
12489 }
12490 XConfigureImageColormap(display,resource_info,windows,*image,exception);
12491 }
12492 else
12493 if (((rotations % 4) == 1) || ((rotations % 4) == 3))
12494 {
12495 windows->image.window_changes.width=windows->image.ximage->height;
12496 windows->image.window_changes.height=windows->image.ximage->width;
12497 }
12498 /*
12499 Update image configuration.
12500 */
12501 (void) XConfigureImage(display,resource_info,windows,*image,exception);
12502 return(MagickTrue);
12503 }
12504
12505 /*
12506 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12507 % %
12508 % %
12509 % %
12510 + X S a v e I m a g e %
12511 % %
12512 % %
12513 % %
12514 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12515 %
12516 % XSaveImage() saves an image to a file.
12517 %
12518 % The format of the XSaveImage method is:
12519 %
12520 % MagickBooleanType XSaveImage(Display *display,
12521 % XResourceInfo *resource_info,XWindows *windows,Image *image,
12522 % ExceptionInfo *exception)
12523 %
12524 % A description of each parameter follows:
12525 %
12526 % o display: Specifies a connection to an X server; returned from
12527 % XOpenDisplay.
12528 %
12529 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12530 %
12531 % o windows: Specifies a pointer to a XWindows structure.
12532 %
12533 % o image: the image.
12534 %
12535 % o exception: return any errors or warnings in this structure.
12536 %
12537 */
XSaveImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,ExceptionInfo * exception)12538 static MagickBooleanType XSaveImage(Display *display,
12539 XResourceInfo *resource_info,XWindows *windows,Image *image,
12540 ExceptionInfo *exception)
12541 {
12542 char
12543 filename[MagickPathExtent],
12544 geometry[MagickPathExtent];
12545
12546 Image
12547 *save_image;
12548
12549 ImageInfo
12550 *image_info;
12551
12552 MagickStatusType
12553 status;
12554
12555 /*
12556 Request file name from user.
12557 */
12558 if (resource_info->write_filename != (char *) NULL)
12559 (void) CopyMagickString(filename,resource_info->write_filename,
12560 MagickPathExtent);
12561 else
12562 {
12563 char
12564 path[MagickPathExtent];
12565
12566 int
12567 status;
12568
12569 GetPathComponent(image->filename,HeadPath,path);
12570 GetPathComponent(image->filename,TailPath,filename);
12571 if (*path != '\0')
12572 {
12573 status=chdir(path);
12574 if (status == -1)
12575 (void) ThrowMagickException(exception,GetMagickModule(),
12576 FileOpenError,"UnableToOpenFile","%s",path);
12577 }
12578 }
12579 XFileBrowserWidget(display,windows,"Save",filename);
12580 if (*filename == '\0')
12581 return(MagickTrue);
12582 if (IsPathAccessible(filename) != MagickFalse )
12583 {
12584 int
12585 status;
12586
12587 /*
12588 File exists-- seek user's permission before overwriting.
12589 */
12590 status=XConfirmWidget(display,windows,"Overwrite",filename);
12591 if (status <= 0)
12592 return(MagickTrue);
12593 }
12594 image_info=CloneImageInfo(resource_info->image_info);
12595 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
12596 (void) SetImageInfo(image_info,1,exception);
12597 if ((LocaleCompare(image_info->magick,"JPEG") == 0) ||
12598 (LocaleCompare(image_info->magick,"JPG") == 0))
12599 {
12600 char
12601 quality[MagickPathExtent];
12602
12603 int
12604 status;
12605
12606 /*
12607 Request JPEG quality from user.
12608 */
12609 (void) FormatLocaleString(quality,MagickPathExtent,"%.20g",(double)
12610 image->quality);
12611 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
12612 quality);
12613 if (*quality == '\0')
12614 return(MagickTrue);
12615 image->quality=StringToUnsignedLong(quality);
12616 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace;
12617 }
12618 if ((LocaleCompare(image_info->magick,"EPS") == 0) ||
12619 (LocaleCompare(image_info->magick,"PDF") == 0) ||
12620 (LocaleCompare(image_info->magick,"PS") == 0) ||
12621 (LocaleCompare(image_info->magick,"PS2") == 0))
12622 {
12623 char
12624 geometry[MagickPathExtent];
12625
12626 /*
12627 Request page geometry from user.
12628 */
12629 (void) CopyMagickString(geometry,PSPageGeometry,MagickPathExtent);
12630 if (LocaleCompare(image_info->magick,"PDF") == 0)
12631 (void) CopyMagickString(geometry,PSPageGeometry,MagickPathExtent);
12632 if (image_info->page != (char *) NULL)
12633 (void) CopyMagickString(geometry,image_info->page,MagickPathExtent);
12634 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
12635 "Select page geometry:",geometry);
12636 if (*geometry != '\0')
12637 image_info->page=GetPageGeometry(geometry);
12638 }
12639 /*
12640 Apply image transforms.
12641 */
12642 XSetCursorState(display,windows,MagickTrue);
12643 XCheckRefreshWindows(display,windows);
12644 save_image=CloneImage(image,0,0,MagickTrue,exception);
12645 if (save_image == (Image *) NULL)
12646 return(MagickFalse);
12647 (void) FormatLocaleString(geometry,MagickPathExtent,"%dx%d!",
12648 windows->image.ximage->width,windows->image.ximage->height);
12649 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry,
12650 exception);
12651 /*
12652 Write image.
12653 */
12654 (void) CopyMagickString(save_image->filename,filename,MagickPathExtent);
12655 status=WriteImage(image_info,save_image,exception);
12656 if (status != MagickFalse )
12657 image->taint=MagickFalse;
12658 save_image=DestroyImage(save_image);
12659 image_info=DestroyImageInfo(image_info);
12660 XSetCursorState(display,windows,MagickFalse);
12661 return(status != 0 ? MagickTrue : MagickFalse);
12662 }
12663
12664 /*
12665 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12666 % %
12667 % %
12668 % %
12669 + X S c r e e n E v e n t %
12670 % %
12671 % %
12672 % %
12673 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12674 %
12675 % XScreenEvent() handles global events associated with the Pan and Magnify
12676 % windows.
12677 %
12678 % The format of the XScreenEvent function is:
12679 %
12680 % void XScreenEvent(Display *display,XWindows *windows,XEvent *event,
12681 % ExceptionInfo *exception)
12682 %
12683 % A description of each parameter follows:
12684 %
12685 % o display: Specifies a pointer to the Display structure; returned from
12686 % XOpenDisplay.
12687 %
12688 % o windows: Specifies a pointer to a XWindows structure.
12689 %
12690 % o event: Specifies a pointer to a X11 XEvent structure.
12691 %
12692 % o exception: return any errors or warnings in this structure.
12693 %
12694 */
12695
12696 #if defined(__cplusplus) || defined(c_plusplus)
12697 extern "C" {
12698 #endif
12699
XPredicate(Display * magick_unused (display),XEvent * event,char * data)12700 static int XPredicate(Display *magick_unused(display),XEvent *event,char *data)
12701 {
12702 register XWindows
12703 *windows;
12704
12705 windows=(XWindows *) data;
12706 if ((event->type == ClientMessage) &&
12707 (event->xclient.window == windows->image.id))
12708 return(MagickFalse);
12709 return(MagickTrue);
12710 }
12711
12712 #if defined(__cplusplus) || defined(c_plusplus)
12713 }
12714 #endif
12715
XScreenEvent(Display * display,XWindows * windows,XEvent * event,ExceptionInfo * exception)12716 static void XScreenEvent(Display *display,XWindows *windows,XEvent *event,
12717 ExceptionInfo *exception)
12718 {
12719 register int
12720 x,
12721 y;
12722
12723 (void) XIfEvent(display,event,XPredicate,(char *) windows);
12724 if (event->xany.window == windows->command.id)
12725 return;
12726 switch (event->type)
12727 {
12728 case ButtonPress:
12729 case ButtonRelease:
12730 {
12731 if ((event->xbutton.button == Button3) &&
12732 (event->xbutton.state & Mod1Mask))
12733 {
12734 /*
12735 Convert Alt-Button3 to Button2.
12736 */
12737 event->xbutton.button=Button2;
12738 event->xbutton.state&=(~Mod1Mask);
12739 }
12740 if (event->xbutton.window == windows->backdrop.id)
12741 {
12742 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent,
12743 event->xbutton.time);
12744 break;
12745 }
12746 if (event->xbutton.window == windows->pan.id)
12747 {
12748 XPanImage(display,windows,event,exception);
12749 break;
12750 }
12751 if (event->xbutton.window == windows->image.id)
12752 if (event->xbutton.button == Button2)
12753 {
12754 /*
12755 Update magnified image.
12756 */
12757 x=event->xbutton.x;
12758 y=event->xbutton.y;
12759 if (x < 0)
12760 x=0;
12761 else
12762 if (x >= (int) windows->image.width)
12763 x=(int) (windows->image.width-1);
12764 windows->magnify.x=(int) windows->image.x+x;
12765 if (y < 0)
12766 y=0;
12767 else
12768 if (y >= (int) windows->image.height)
12769 y=(int) (windows->image.height-1);
12770 windows->magnify.y=windows->image.y+y;
12771 if (windows->magnify.mapped == MagickFalse)
12772 (void) XMapRaised(display,windows->magnify.id);
12773 XMakeMagnifyImage(display,windows,exception);
12774 if (event->type == ButtonRelease)
12775 (void) XWithdrawWindow(display,windows->info.id,
12776 windows->info.screen);
12777 break;
12778 }
12779 break;
12780 }
12781 case ClientMessage:
12782 {
12783 /*
12784 If client window delete message, exit.
12785 */
12786 if (event->xclient.message_type != windows->wm_protocols)
12787 break;
12788 if (*event->xclient.data.l != (long) windows->wm_delete_window)
12789 break;
12790 if (event->xclient.window == windows->magnify.id)
12791 {
12792 (void) XWithdrawWindow(display,windows->magnify.id,
12793 windows->magnify.screen);
12794 break;
12795 }
12796 break;
12797 }
12798 case ConfigureNotify:
12799 {
12800 if (event->xconfigure.window == windows->magnify.id)
12801 {
12802 unsigned int
12803 magnify;
12804
12805 /*
12806 Magnify window has a new configuration.
12807 */
12808 windows->magnify.width=(unsigned int) event->xconfigure.width;
12809 windows->magnify.height=(unsigned int) event->xconfigure.height;
12810 if (windows->magnify.mapped == MagickFalse)
12811 break;
12812 magnify=1;
12813 while ((int) magnify <= event->xconfigure.width)
12814 magnify<<=1;
12815 while ((int) magnify <= event->xconfigure.height)
12816 magnify<<=1;
12817 magnify>>=1;
12818 if (((int) magnify != event->xconfigure.width) ||
12819 ((int) magnify != event->xconfigure.height))
12820 {
12821 XWindowChanges
12822 window_changes;
12823
12824 window_changes.width=(int) magnify;
12825 window_changes.height=(int) magnify;
12826 (void) XReconfigureWMWindow(display,windows->magnify.id,
12827 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
12828 &window_changes);
12829 break;
12830 }
12831 XMakeMagnifyImage(display,windows,exception);
12832 break;
12833 }
12834 break;
12835 }
12836 case Expose:
12837 {
12838 if (event->xexpose.window == windows->image.id)
12839 {
12840 XRefreshWindow(display,&windows->image,event);
12841 break;
12842 }
12843 if (event->xexpose.window == windows->pan.id)
12844 if (event->xexpose.count == 0)
12845 {
12846 XDrawPanRectangle(display,windows);
12847 break;
12848 }
12849 if (event->xexpose.window == windows->magnify.id)
12850 if (event->xexpose.count == 0)
12851 {
12852 XMakeMagnifyImage(display,windows,exception);
12853 break;
12854 }
12855 break;
12856 }
12857 case KeyPress:
12858 {
12859 char
12860 command[MagickPathExtent];
12861
12862 KeySym
12863 key_symbol;
12864
12865 if (event->xkey.window != windows->magnify.id)
12866 break;
12867 /*
12868 Respond to a user key press.
12869 */
12870 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int)
12871 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12872 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol,
12873 exception);
12874 break;
12875 }
12876 case MapNotify:
12877 {
12878 if (event->xmap.window == windows->magnify.id)
12879 {
12880 windows->magnify.mapped=MagickTrue;
12881 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12882 break;
12883 }
12884 if (event->xmap.window == windows->info.id)
12885 {
12886 windows->info.mapped=MagickTrue;
12887 break;
12888 }
12889 break;
12890 }
12891 case MotionNotify:
12892 {
12893 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ;
12894 if (event->xmotion.window == windows->image.id)
12895 if (windows->magnify.mapped != MagickFalse )
12896 {
12897 /*
12898 Update magnified image.
12899 */
12900 x=event->xmotion.x;
12901 y=event->xmotion.y;
12902 if (x < 0)
12903 x=0;
12904 else
12905 if (x >= (int) windows->image.width)
12906 x=(int) (windows->image.width-1);
12907 windows->magnify.x=(int) windows->image.x+x;
12908 if (y < 0)
12909 y=0;
12910 else
12911 if (y >= (int) windows->image.height)
12912 y=(int) (windows->image.height-1);
12913 windows->magnify.y=windows->image.y+y;
12914 XMakeMagnifyImage(display,windows,exception);
12915 }
12916 break;
12917 }
12918 case UnmapNotify:
12919 {
12920 if (event->xunmap.window == windows->magnify.id)
12921 {
12922 windows->magnify.mapped=MagickFalse;
12923 break;
12924 }
12925 if (event->xunmap.window == windows->info.id)
12926 {
12927 windows->info.mapped=MagickFalse;
12928 break;
12929 }
12930 break;
12931 }
12932 default:
12933 break;
12934 }
12935 }
12936
12937 /*
12938 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12939 % %
12940 % %
12941 % %
12942 + X S e t C r o p G e o m e t r y %
12943 % %
12944 % %
12945 % %
12946 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12947 %
12948 % XSetCropGeometry() accepts a cropping geometry relative to the Image window
12949 % and translates it to a cropping geometry relative to the image.
12950 %
12951 % The format of the XSetCropGeometry method is:
12952 %
12953 % void XSetCropGeometry(Display *display,XWindows *windows,
12954 % RectangleInfo *crop_info,Image *image)
12955 %
12956 % A description of each parameter follows:
12957 %
12958 % o display: Specifies a connection to an X server; returned from
12959 % XOpenDisplay.
12960 %
12961 % o windows: Specifies a pointer to a XWindows structure.
12962 %
12963 % o crop_info: A pointer to a RectangleInfo that defines a region of the
12964 % Image window to crop.
12965 %
12966 % o image: the image.
12967 %
12968 */
XSetCropGeometry(Display * display,XWindows * windows,RectangleInfo * crop_info,Image * image)12969 static void XSetCropGeometry(Display *display,XWindows *windows,
12970 RectangleInfo *crop_info,Image *image)
12971 {
12972 char
12973 text[MagickPathExtent];
12974
12975 int
12976 x,
12977 y;
12978
12979 double
12980 scale_factor;
12981
12982 unsigned int
12983 height,
12984 width;
12985
12986 if (windows->info.mapped != MagickFalse )
12987 {
12988 /*
12989 Display info on cropping rectangle.
12990 */
12991 (void) FormatLocaleString(text,MagickPathExtent," %.20gx%.20g%+.20g%+.20g",
12992 (double) crop_info->width,(double) crop_info->height,(double)
12993 crop_info->x,(double) crop_info->y);
12994 XInfoWidget(display,windows,text);
12995 }
12996 /*
12997 Cropping geometry is relative to any previous crop geometry.
12998 */
12999 x=0;
13000 y=0;
13001 width=(unsigned int) image->columns;
13002 height=(unsigned int) image->rows;
13003 if (windows->image.crop_geometry != (char *) NULL)
13004 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
13005 else
13006 windows->image.crop_geometry=AcquireString((char *) NULL);
13007 /*
13008 Define the crop geometry string from the cropping rectangle.
13009 */
13010 scale_factor=(double) width/windows->image.ximage->width;
13011 if (crop_info->x > 0)
13012 x+=(int) (scale_factor*crop_info->x+0.5);
13013 width=(unsigned int) (scale_factor*crop_info->width+0.5);
13014 if (width == 0)
13015 width=1;
13016 scale_factor=(double) height/windows->image.ximage->height;
13017 if (crop_info->y > 0)
13018 y+=(int) (scale_factor*crop_info->y+0.5);
13019 height=(unsigned int) (scale_factor*crop_info->height+0.5);
13020 if (height == 0)
13021 height=1;
13022 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent,
13023 "%ux%u%+d%+d",width,height,x,y);
13024 }
13025
13026 /*
13027 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13028 % %
13029 % %
13030 % %
13031 + X T i l e I m a g e %
13032 % %
13033 % %
13034 % %
13035 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13036 %
13037 % XTileImage() loads or deletes a selected tile from a visual image directory.
13038 % The load or delete command is chosen from a menu.
13039 %
13040 % The format of the XTileImage method is:
13041 %
13042 % Image *XTileImage(Display *display,XResourceInfo *resource_info,
13043 % XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception)
13044 %
13045 % A description of each parameter follows:
13046 %
13047 % o tile_image: XTileImage reads or deletes the tile image
13048 % and returns it. A null image is returned if an error occurs.
13049 %
13050 % o display: Specifies a connection to an X server; returned from
13051 % XOpenDisplay.
13052 %
13053 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13054 %
13055 % o windows: Specifies a pointer to a XWindows structure.
13056 %
13057 % o image: the image; returned from ReadImage.
13058 %
13059 % o event: Specifies a pointer to a XEvent structure. If it is NULL,
13060 % the entire image is refreshed.
13061 %
13062 % o exception: return any errors or warnings in this structure.
13063 %
13064 */
XTileImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,XEvent * event,ExceptionInfo * exception)13065 static Image *XTileImage(Display *display,XResourceInfo *resource_info,
13066 XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception)
13067 {
13068 static const char
13069 *VerbMenu[] =
13070 {
13071 "Load",
13072 "Next",
13073 "Former",
13074 "Delete",
13075 "Update",
13076 (char *) NULL,
13077 };
13078
13079 static const ModeType
13080 TileCommands[] =
13081 {
13082 TileLoadCommand,
13083 TileNextCommand,
13084 TileFormerCommand,
13085 TileDeleteCommand,
13086 TileUpdateCommand
13087 };
13088
13089 char
13090 command[MagickPathExtent],
13091 filename[MagickPathExtent];
13092
13093 Image
13094 *tile_image;
13095
13096 int
13097 id,
13098 status,
13099 tile,
13100 x,
13101 y;
13102
13103 double
13104 scale_factor;
13105
13106 register char
13107 *p,
13108 *q;
13109
13110 register int
13111 i;
13112
13113 unsigned int
13114 height,
13115 width;
13116
13117 /*
13118 Tile image is relative to montage image configuration.
13119 */
13120 x=0;
13121 y=0;
13122 width=(unsigned int) image->columns;
13123 height=(unsigned int) image->rows;
13124 if (windows->image.crop_geometry != (char *) NULL)
13125 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
13126 scale_factor=(double) width/windows->image.ximage->width;
13127 event->xbutton.x+=windows->image.x;
13128 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5);
13129 scale_factor=(double) height/windows->image.ximage->height;
13130 event->xbutton.y+=windows->image.y;
13131 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5);
13132 /*
13133 Determine size and location of each tile in the visual image directory.
13134 */
13135 width=(unsigned int) image->columns;
13136 height=(unsigned int) image->rows;
13137 x=0;
13138 y=0;
13139 (void) XParseGeometry(image->montage,&x,&y,&width,&height);
13140 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+
13141 (event->xbutton.x-x)/width;
13142 if (tile < 0)
13143 {
13144 /*
13145 Button press is outside any tile.
13146 */
13147 (void) XBell(display,0);
13148 return((Image *) NULL);
13149 }
13150 /*
13151 Determine file name from the tile directory.
13152 */
13153 p=image->directory;
13154 for (i=tile; (i != 0) && (*p != '\0'); )
13155 {
13156 if (*p == '\xff')
13157 i--;
13158 p++;
13159 }
13160 if (*p == '\0')
13161 {
13162 /*
13163 Button press is outside any tile.
13164 */
13165 (void) XBell(display,0);
13166 return((Image *) NULL);
13167 }
13168 /*
13169 Select a command from the pop-up menu.
13170 */
13171 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command);
13172 if (id < 0)
13173 return((Image *) NULL);
13174 q=p;
13175 while ((*q != '\n') && (*q != '\0'))
13176 q++;
13177 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13178 /*
13179 Perform command for the selected tile.
13180 */
13181 XSetCursorState(display,windows,MagickTrue);
13182 XCheckRefreshWindows(display,windows);
13183 tile_image=NewImageList();
13184 switch (TileCommands[id])
13185 {
13186 case TileLoadCommand:
13187 {
13188 /*
13189 Load tile image.
13190 */
13191 XCheckRefreshWindows(display,windows);
13192 (void) CopyMagickString(resource_info->image_info->magick,"MIFF",
13193 MagickPathExtent);
13194 (void) CopyMagickString(resource_info->image_info->filename,filename,
13195 MagickPathExtent);
13196 tile_image=ReadImage(resource_info->image_info,exception);
13197 CatchException(exception);
13198 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13199 break;
13200 }
13201 case TileNextCommand:
13202 {
13203 /*
13204 Display next image.
13205 */
13206 XClientMessage(display,windows->image.id,windows->im_protocols,
13207 windows->im_next_image,CurrentTime);
13208 break;
13209 }
13210 case TileFormerCommand:
13211 {
13212 /*
13213 Display former image.
13214 */
13215 XClientMessage(display,windows->image.id,windows->im_protocols,
13216 windows->im_former_image,CurrentTime);
13217 break;
13218 }
13219 case TileDeleteCommand:
13220 {
13221 /*
13222 Delete tile image.
13223 */
13224 if (IsPathAccessible(filename) == MagickFalse)
13225 {
13226 XNoticeWidget(display,windows,"Image file does not exist:",filename);
13227 break;
13228 }
13229 status=XConfirmWidget(display,windows,"Really delete tile",filename);
13230 if (status <= 0)
13231 break;
13232 status=ShredFile(filename);
13233 if (status != MagickFalse )
13234 {
13235 XNoticeWidget(display,windows,"Unable to delete image file:",
13236 filename);
13237 break;
13238 }
13239 }
13240 case TileUpdateCommand:
13241 {
13242 int
13243 x_offset,
13244 y_offset;
13245
13246 PixelInfo
13247 pixel;
13248
13249 register int
13250 j;
13251
13252 register Quantum
13253 *s;
13254
13255 /*
13256 Ensure all the images exist.
13257 */
13258 tile=0;
13259 GetPixelInfo(image,&pixel);
13260 for (p=image->directory; *p != '\0'; p++)
13261 {
13262 CacheView
13263 *image_view;
13264
13265 q=p;
13266 while ((*q != '\xff') && (*q != '\0'))
13267 q++;
13268 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13269 p=q;
13270 if (IsPathAccessible(filename) != MagickFalse )
13271 {
13272 tile++;
13273 continue;
13274 }
13275 /*
13276 Overwrite tile with background color.
13277 */
13278 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x);
13279 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y);
13280 image_view=AcquireAuthenticCacheView(image,exception);
13281 (void) GetOneCacheViewVirtualPixelInfo(image_view,0,0,&pixel,exception);
13282 for (i=0; i < (int) height; i++)
13283 {
13284 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t)
13285 y_offset+i,width,1,exception);
13286 if (s == (Quantum *) NULL)
13287 break;
13288 for (j=0; j < (int) width; j++)
13289 {
13290 SetPixelViaPixelInfo(image,&pixel,s);
13291 s+=GetPixelChannels(image);
13292 }
13293 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
13294 break;
13295 }
13296 image_view=DestroyCacheView(image_view);
13297 tile++;
13298 }
13299 windows->image.window_changes.width=(int) image->columns;
13300 windows->image.window_changes.height=(int) image->rows;
13301 XConfigureImageColormap(display,resource_info,windows,image,exception);
13302 (void) XConfigureImage(display,resource_info,windows,image,exception);
13303 break;
13304 }
13305 default:
13306 break;
13307 }
13308 XSetCursorState(display,windows,MagickFalse);
13309 return(tile_image);
13310 }
13311
13312 /*
13313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13314 % %
13315 % %
13316 % %
13317 + X T r a n s l a t e I m a g e %
13318 % %
13319 % %
13320 % %
13321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13322 %
13323 % XTranslateImage() translates the image within an Image window by one pixel
13324 % as specified by the key symbol. If the image has a montage string the
13325 % translation is respect to the width and height contained within the string.
13326 %
13327 % The format of the XTranslateImage method is:
13328 %
13329 % void XTranslateImage(Display *display,XWindows *windows,
13330 % Image *image,const KeySym key_symbol)
13331 %
13332 % A description of each parameter follows:
13333 %
13334 % o display: Specifies a connection to an X server; returned from
13335 % XOpenDisplay.
13336 %
13337 % o windows: Specifies a pointer to a XWindows structure.
13338 %
13339 % o image: the image.
13340 %
13341 % o key_symbol: Specifies a KeySym which indicates which side of the image
13342 % to trim.
13343 %
13344 */
XTranslateImage(Display * display,XWindows * windows,Image * image,const KeySym key_symbol)13345 static void XTranslateImage(Display *display,XWindows *windows,
13346 Image *image,const KeySym key_symbol)
13347 {
13348 char
13349 text[MagickPathExtent];
13350
13351 int
13352 x,
13353 y;
13354
13355 unsigned int
13356 x_offset,
13357 y_offset;
13358
13359 /*
13360 User specified a pan position offset.
13361 */
13362 x_offset=windows->image.width;
13363 y_offset=windows->image.height;
13364 if (image->montage != (char *) NULL)
13365 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset);
13366 switch ((int) key_symbol)
13367 {
13368 case XK_Home:
13369 case XK_KP_Home:
13370 {
13371 windows->image.x=(int) windows->image.width/2;
13372 windows->image.y=(int) windows->image.height/2;
13373 break;
13374 }
13375 case XK_Left:
13376 case XK_KP_Left:
13377 {
13378 windows->image.x-=x_offset;
13379 break;
13380 }
13381 case XK_Next:
13382 case XK_Up:
13383 case XK_KP_Up:
13384 {
13385 windows->image.y-=y_offset;
13386 break;
13387 }
13388 case XK_Right:
13389 case XK_KP_Right:
13390 {
13391 windows->image.x+=x_offset;
13392 break;
13393 }
13394 case XK_Prior:
13395 case XK_Down:
13396 case XK_KP_Down:
13397 {
13398 windows->image.y+=y_offset;
13399 break;
13400 }
13401 default:
13402 return;
13403 }
13404 /*
13405 Check boundary conditions.
13406 */
13407 if (windows->image.x < 0)
13408 windows->image.x=0;
13409 else
13410 if ((int) (windows->image.x+windows->image.width) >
13411 windows->image.ximage->width)
13412 windows->image.x=(int) windows->image.ximage->width-windows->image.width;
13413 if (windows->image.y < 0)
13414 windows->image.y=0;
13415 else
13416 if ((int) (windows->image.y+windows->image.height) >
13417 windows->image.ximage->height)
13418 windows->image.y=(int) windows->image.ximage->height-windows->image.height;
13419 /*
13420 Refresh Image window.
13421 */
13422 (void) FormatLocaleString(text,MagickPathExtent," %ux%u%+d%+d ",
13423 windows->image.width,windows->image.height,windows->image.x,
13424 windows->image.y);
13425 XInfoWidget(display,windows,text);
13426 XCheckRefreshWindows(display,windows);
13427 XDrawPanRectangle(display,windows);
13428 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
13429 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13430 }
13431
13432 /*
13433 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13434 % %
13435 % %
13436 % %
13437 + X T r i m I m a g e %
13438 % %
13439 % %
13440 % %
13441 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13442 %
13443 % XTrimImage() trims the edges from the Image window.
13444 %
13445 % The format of the XTrimImage method is:
13446 %
13447 % MagickBooleanType XTrimImage(Display *display,
13448 % XResourceInfo *resource_info,XWindows *windows,Image *image,
13449 % ExceptionInfo *exception)
13450 %
13451 % A description of each parameter follows:
13452 %
13453 % o display: Specifies a connection to an X server; returned from
13454 % XOpenDisplay.
13455 %
13456 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13457 %
13458 % o windows: Specifies a pointer to a XWindows structure.
13459 %
13460 % o image: the image.
13461 %
13462 % o exception: return any errors or warnings in this structure.
13463 %
13464 */
XTrimImage(Display * display,XResourceInfo * resource_info,XWindows * windows,Image * image,ExceptionInfo * exception)13465 static MagickBooleanType XTrimImage(Display *display,
13466 XResourceInfo *resource_info,XWindows *windows,Image *image,
13467 ExceptionInfo *exception)
13468 {
13469 RectangleInfo
13470 trim_info;
13471
13472 register int
13473 x,
13474 y;
13475
13476 size_t
13477 background,
13478 pixel;
13479
13480 /*
13481 Trim edges from image.
13482 */
13483 XSetCursorState(display,windows,MagickTrue);
13484 XCheckRefreshWindows(display,windows);
13485 /*
13486 Crop the left edge.
13487 */
13488 background=XGetPixel(windows->image.ximage,0,0);
13489 trim_info.width=(size_t) windows->image.ximage->width;
13490 for (x=0; x < windows->image.ximage->width; x++)
13491 {
13492 for (y=0; y < windows->image.ximage->height; y++)
13493 {
13494 pixel=XGetPixel(windows->image.ximage,x,y);
13495 if (pixel != background)
13496 break;
13497 }
13498 if (y < windows->image.ximage->height)
13499 break;
13500 }
13501 trim_info.x=(ssize_t) x;
13502 if (trim_info.x == (ssize_t) windows->image.ximage->width)
13503 {
13504 XSetCursorState(display,windows,MagickFalse);
13505 return(MagickFalse);
13506 }
13507 /*
13508 Crop the right edge.
13509 */
13510 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0);
13511 for (x=windows->image.ximage->width-1; x != 0; x--)
13512 {
13513 for (y=0; y < windows->image.ximage->height; y++)
13514 {
13515 pixel=XGetPixel(windows->image.ximage,x,y);
13516 if (pixel != background)
13517 break;
13518 }
13519 if (y < windows->image.ximage->height)
13520 break;
13521 }
13522 trim_info.width=(size_t) (x-trim_info.x+1);
13523 /*
13524 Crop the top edge.
13525 */
13526 background=XGetPixel(windows->image.ximage,0,0);
13527 trim_info.height=(size_t) windows->image.ximage->height;
13528 for (y=0; y < windows->image.ximage->height; y++)
13529 {
13530 for (x=0; x < windows->image.ximage->width; x++)
13531 {
13532 pixel=XGetPixel(windows->image.ximage,x,y);
13533 if (pixel != background)
13534 break;
13535 }
13536 if (x < windows->image.ximage->width)
13537 break;
13538 }
13539 trim_info.y=(ssize_t) y;
13540 /*
13541 Crop the bottom edge.
13542 */
13543 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1);
13544 for (y=windows->image.ximage->height-1; y != 0; y--)
13545 {
13546 for (x=0; x < windows->image.ximage->width; x++)
13547 {
13548 pixel=XGetPixel(windows->image.ximage,x,y);
13549 if (pixel != background)
13550 break;
13551 }
13552 if (x < windows->image.ximage->width)
13553 break;
13554 }
13555 trim_info.height=(size_t) y-trim_info.y+1;
13556 if (((unsigned int) trim_info.width != windows->image.width) ||
13557 ((unsigned int) trim_info.height != windows->image.height))
13558 {
13559 /*
13560 Reconfigure Image window as defined by the trimming rectangle.
13561 */
13562 XSetCropGeometry(display,windows,&trim_info,image);
13563 windows->image.window_changes.width=(int) trim_info.width;
13564 windows->image.window_changes.height=(int) trim_info.height;
13565 (void) XConfigureImage(display,resource_info,windows,image,exception);
13566 }
13567 XSetCursorState(display,windows,MagickFalse);
13568 return(MagickTrue);
13569 }
13570
13571 /*
13572 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13573 % %
13574 % %
13575 % %
13576 + X V i s u a l D i r e c t o r y I m a g e %
13577 % %
13578 % %
13579 % %
13580 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13581 %
13582 % XVisualDirectoryImage() creates a Visual Image Directory.
13583 %
13584 % The format of the XVisualDirectoryImage method is:
13585 %
13586 % Image *XVisualDirectoryImage(Display *display,
13587 % XResourceInfo *resource_info,XWindows *windows,
13588 % ExceptionInfo *exception)
13589 %
13590 % A description of each parameter follows:
13591 %
13592 % o display: Specifies a connection to an X server; returned from
13593 % XOpenDisplay.
13594 %
13595 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13596 %
13597 % o windows: Specifies a pointer to a XWindows structure.
13598 %
13599 % o exception: return any errors or warnings in this structure.
13600 %
13601 */
XVisualDirectoryImage(Display * display,XResourceInfo * resource_info,XWindows * windows,ExceptionInfo * exception)13602 static Image *XVisualDirectoryImage(Display *display,
13603 XResourceInfo *resource_info,XWindows *windows,ExceptionInfo *exception)
13604 {
13605 #define TileImageTag "Scale/Image"
13606 #define XClientName "montage"
13607
13608 char
13609 **filelist;
13610
13611 Image
13612 *images,
13613 *montage_image,
13614 *next_image,
13615 *thumbnail_image;
13616
13617 ImageInfo
13618 *read_info;
13619
13620 int
13621 number_files;
13622
13623 MagickBooleanType
13624 backdrop;
13625
13626 MagickStatusType
13627 status;
13628
13629 MontageInfo
13630 *montage_info;
13631
13632 RectangleInfo
13633 geometry;
13634
13635 register int
13636 i;
13637
13638 static char
13639 filename[MagickPathExtent] = "\0",
13640 filenames[MagickPathExtent] = "*";
13641
13642 XResourceInfo
13643 background_resources;
13644
13645 /*
13646 Request file name from user.
13647 */
13648 XFileBrowserWidget(display,windows,"Directory",filenames);
13649 if (*filenames == '\0')
13650 return((Image *) NULL);
13651 /*
13652 Expand the filenames.
13653 */
13654 filelist=(char **) AcquireMagickMemory(sizeof(*filelist));
13655 if (filelist == (char **) NULL)
13656 {
13657 ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
13658 filenames);
13659 return((Image *) NULL);
13660 }
13661 number_files=1;
13662 filelist[0]=filenames;
13663 status=ExpandFilenames(&number_files,&filelist);
13664 if ((status == MagickFalse) || (number_files == 0))
13665 {
13666 if (number_files == 0)
13667 ThrowXWindowException(ImageError,"NoImagesWereFound",filenames)
13668 else
13669 ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
13670 filenames);
13671 return((Image *) NULL);
13672 }
13673 /*
13674 Set image background resources.
13675 */
13676 background_resources=(*resource_info);
13677 background_resources.window_id=AcquireString("");
13678 (void) FormatLocaleString(background_resources.window_id,MagickPathExtent,
13679 "0x%lx",windows->image.id);
13680 background_resources.backdrop=MagickTrue;
13681 /*
13682 Read each image and convert them to a tile.
13683 */
13684 backdrop=((windows->visual_info->klass == TrueColor) ||
13685 (windows->visual_info->klass == DirectColor)) ? MagickTrue : MagickFalse;
13686 read_info=CloneImageInfo(resource_info->image_info);
13687 (void) SetImageOption(read_info,"jpeg:size","120x120");
13688 (void) CloneString(&read_info->size,DefaultTileGeometry);
13689 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL,
13690 (void *) NULL);
13691 images=NewImageList();
13692 XSetCursorState(display,windows,MagickTrue);
13693 XCheckRefreshWindows(display,windows);
13694 for (i=0; i < (int) number_files; i++)
13695 {
13696 (void) CopyMagickString(read_info->filename,filelist[i],MagickPathExtent);
13697 filelist[i]=DestroyString(filelist[i]);
13698 *read_info->magick='\0';
13699 next_image=ReadImage(read_info,exception);
13700 CatchException(exception);
13701 if (next_image != (Image *) NULL)
13702 {
13703 (void) DeleteImageProperty(next_image,"label");
13704 (void) SetImageProperty(next_image,"label",InterpretImageProperties(
13705 read_info,next_image,DefaultTileLabel,exception),exception);
13706 (void) ParseRegionGeometry(next_image,read_info->size,&geometry,
13707 exception);
13708 thumbnail_image=ThumbnailImage(next_image,geometry.width,
13709 geometry.height,exception);
13710 if (thumbnail_image != (Image *) NULL)
13711 {
13712 next_image=DestroyImage(next_image);
13713 next_image=thumbnail_image;
13714 }
13715 if (backdrop)
13716 {
13717 (void) XDisplayBackgroundImage(display,&background_resources,
13718 next_image,exception);
13719 XSetCursorState(display,windows,MagickTrue);
13720 }
13721 AppendImageToList(&images,next_image);
13722 if (images->progress_monitor != (MagickProgressMonitor) NULL)
13723 {
13724 MagickBooleanType
13725 proceed;
13726
13727 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i,
13728 (MagickSizeType) number_files);
13729 if (proceed == MagickFalse)
13730 break;
13731 }
13732 }
13733 }
13734 filelist=(char **) RelinquishMagickMemory(filelist);
13735 if (images == (Image *) NULL)
13736 {
13737 read_info=DestroyImageInfo(read_info);
13738 XSetCursorState(display,windows,MagickFalse);
13739 ThrowXWindowException(ImageError,"NoImagesWereLoaded",filenames);
13740 return((Image *) NULL);
13741 }
13742 /*
13743 Create the Visual Image Directory.
13744 */
13745 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL);
13746 montage_info->pointsize=10;
13747 if (resource_info->font != (char *) NULL)
13748 (void) CloneString(&montage_info->font,resource_info->font);
13749 (void) CopyMagickString(montage_info->filename,filename,MagickPathExtent);
13750 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList(
13751 images),exception);
13752 images=DestroyImageList(images);
13753 montage_info=DestroyMontageInfo(montage_info);
13754 read_info=DestroyImageInfo(read_info);
13755 XSetCursorState(display,windows,MagickFalse);
13756 if (montage_image == (Image *) NULL)
13757 return(montage_image);
13758 XClientMessage(display,windows->image.id,windows->im_protocols,
13759 windows->im_next_image,CurrentTime);
13760 return(montage_image);
13761 }
13762
13763 /*
13764 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13765 % %
13766 % %
13767 % %
13768 % X D i s p l a y B a c k g r o u n d I m a g e %
13769 % %
13770 % %
13771 % %
13772 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13773 %
13774 % XDisplayBackgroundImage() displays an image in the background of a window.
13775 %
13776 % The format of the XDisplayBackgroundImage method is:
13777 %
13778 % MagickBooleanType XDisplayBackgroundImage(Display *display,
13779 % XResourceInfo *resource_info,Image *image,ExceptionInfo *exception)
13780 %
13781 % A description of each parameter follows:
13782 %
13783 % o display: Specifies a connection to an X server; returned from
13784 % XOpenDisplay.
13785 %
13786 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13787 %
13788 % o image: the image.
13789 %
13790 % o exception: return any errors or warnings in this structure.
13791 %
13792 */
XDisplayBackgroundImage(Display * display,XResourceInfo * resource_info,Image * image,ExceptionInfo * exception)13793 MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display,
13794 XResourceInfo *resource_info,Image *image,ExceptionInfo *exception)
13795 {
13796 char
13797 geometry[MagickPathExtent],
13798 visual_type[MagickPathExtent];
13799
13800 int
13801 height,
13802 status,
13803 width;
13804
13805 RectangleInfo
13806 geometry_info;
13807
13808 static XPixelInfo
13809 pixel;
13810
13811 static XStandardColormap
13812 *map_info;
13813
13814 static XVisualInfo
13815 *visual_info = (XVisualInfo *) NULL;
13816
13817 static XWindowInfo
13818 window_info;
13819
13820 size_t
13821 delay;
13822
13823 Window
13824 root_window;
13825
13826 XGCValues
13827 context_values;
13828
13829 XResourceInfo
13830 resources;
13831
13832 XWindowAttributes
13833 window_attributes;
13834
13835 /*
13836 Determine target window.
13837 */
13838 assert(image != (Image *) NULL);
13839 assert(image->signature == MagickCoreSignature);
13840 if (image->debug != MagickFalse )
13841 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
13842 resources=(*resource_info);
13843 window_info.id=(Window) NULL;
13844 root_window=XRootWindow(display,XDefaultScreen(display));
13845 if (LocaleCompare(resources.window_id,"root") == 0)
13846 window_info.id=root_window;
13847 else
13848 {
13849 if (isdigit((int) ((unsigned char) *resources.window_id)) != 0)
13850 window_info.id=XWindowByID(display,root_window,
13851 (Window) strtol((char *) resources.window_id,(char **) NULL,0));
13852 if (window_info.id == (Window) NULL)
13853 window_info.id=XWindowByName(display,root_window,resources.window_id);
13854 }
13855 if (window_info.id == (Window) NULL)
13856 {
13857 ThrowXWindowException(XServerError,"NoWindowWithSpecifiedIDExists",
13858 resources.window_id);
13859 return(MagickFalse);
13860 }
13861 /*
13862 Determine window visual id.
13863 */
13864 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display));
13865 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display));
13866 (void) CopyMagickString(visual_type,"default",MagickPathExtent);
13867 status=XGetWindowAttributes(display,window_info.id,&window_attributes);
13868 if (status != 0)
13869 (void) FormatLocaleString(visual_type,MagickPathExtent,"0x%lx",
13870 XVisualIDFromVisual(window_attributes.visual));
13871 if (visual_info == (XVisualInfo *) NULL)
13872 {
13873 /*
13874 Allocate standard colormap.
13875 */
13876 map_info=XAllocStandardColormap();
13877 if (map_info == (XStandardColormap *) NULL)
13878 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
13879 image->filename);
13880 map_info->colormap=(Colormap) NULL;
13881 pixel.pixels=(unsigned long *) NULL;
13882 /*
13883 Initialize visual info.
13884 */
13885 resources.map_type=(char *) NULL;
13886 resources.visual_type=visual_type;
13887 visual_info=XBestVisualInfo(display,map_info,&resources);
13888 if (visual_info == (XVisualInfo *) NULL)
13889 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual",
13890 resources.visual_type);
13891 /*
13892 Initialize window info.
13893 */
13894 window_info.ximage=(XImage *) NULL;
13895 window_info.matte_image=(XImage *) NULL;
13896 window_info.pixmap=(Pixmap) NULL;
13897 window_info.matte_pixmap=(Pixmap) NULL;
13898 }
13899 /*
13900 Free previous root colors.
13901 */
13902 if (window_info.id == root_window)
13903 (void) XDestroyWindowColors(display,root_window);
13904 /*
13905 Initialize Standard Colormap.
13906 */
13907 resources.colormap=SharedColormap;
13908 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel,
13909 exception);
13910 /*
13911 Graphic context superclass.
13912 */
13913 context_values.background=pixel.background_color.pixel;
13914 context_values.foreground=pixel.foreground_color.pixel;
13915 pixel.annotate_context=XCreateGC(display,window_info.id,
13916 (size_t) (GCBackground | GCForeground),&context_values);
13917 if (pixel.annotate_context == (GC) NULL)
13918 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
13919 image->filename);
13920 /*
13921 Initialize Image window attributes.
13922 */
13923 window_info.name=AcquireString("\0");
13924 window_info.icon_name=AcquireString("\0");
13925 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL,
13926 &resources,&window_info);
13927 /*
13928 Create the X image.
13929 */
13930 window_info.width=(unsigned int) image->columns;
13931 window_info.height=(unsigned int) image->rows;
13932 if ((image->columns != window_info.width) ||
13933 (image->rows != window_info.height))
13934 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13935 image->filename);
13936 (void) FormatLocaleString(geometry,MagickPathExtent,"%ux%u+0+0>",
13937 window_attributes.width,window_attributes.height);
13938 geometry_info.width=window_info.width;
13939 geometry_info.height=window_info.height;
13940 geometry_info.x=(ssize_t) window_info.x;
13941 geometry_info.y=(ssize_t) window_info.y;
13942 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
13943 &geometry_info.width,&geometry_info.height);
13944 window_info.width=(unsigned int) geometry_info.width;
13945 window_info.height=(unsigned int) geometry_info.height;
13946 window_info.x=(int) geometry_info.x;
13947 window_info.y=(int) geometry_info.y;
13948 status=XMakeImage(display,&resources,&window_info,image,window_info.width,
13949 window_info.height,exception);
13950 if (status == MagickFalse)
13951 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13952 image->filename);
13953 window_info.x=0;
13954 window_info.y=0;
13955 if (image->debug != MagickFalse )
13956 {
13957 (void) LogMagickEvent(X11Event,GetMagickModule(),
13958 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene,
13959 (double) image->columns,(double) image->rows);
13960 if (image->colors != 0)
13961 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
13962 image->colors);
13963 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick);
13964 }
13965 /*
13966 Adjust image dimensions as specified by backdrop or geometry options.
13967 */
13968 width=(int) window_info.width;
13969 height=(int) window_info.height;
13970 if (resources.backdrop != MagickFalse )
13971 {
13972 /*
13973 Center image on window.
13974 */
13975 window_info.x=(window_attributes.width/2)-
13976 (window_info.ximage->width/2);
13977 window_info.y=(window_attributes.height/2)-
13978 (window_info.ximage->height/2);
13979 width=window_attributes.width;
13980 height=window_attributes.height;
13981 }
13982 if ((resources.image_geometry != (char *) NULL) &&
13983 (*resources.image_geometry != '\0'))
13984 {
13985 char
13986 default_geometry[MagickPathExtent];
13987
13988 int
13989 flags,
13990 gravity;
13991
13992 XSizeHints
13993 *size_hints;
13994
13995 /*
13996 User specified geometry.
13997 */
13998 size_hints=XAllocSizeHints();
13999 if (size_hints == (XSizeHints *) NULL)
14000 ThrowXWindowFatalException(ResourceLimitFatalError,
14001 "MemoryAllocationFailed",image->filename);
14002 size_hints->flags=0L;
14003 (void) FormatLocaleString(default_geometry,MagickPathExtent,"%dx%d",
14004 width,height);
14005 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry,
14006 default_geometry,window_info.border_width,size_hints,&window_info.x,
14007 &window_info.y,&width,&height,&gravity);
14008 if (flags & (XValue | YValue))
14009 {
14010 width=window_attributes.width;
14011 height=window_attributes.height;
14012 }
14013 (void) XFree((void *) size_hints);
14014 }
14015 /*
14016 Create the X pixmap.
14017 */
14018 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width,
14019 (unsigned int) height,window_info.depth);
14020 if (window_info.pixmap == (Pixmap) NULL)
14021 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
14022 image->filename);
14023 /*
14024 Display pixmap on the window.
14025 */
14026 if (((unsigned int) width > window_info.width) ||
14027 ((unsigned int) height > window_info.height))
14028 (void) XFillRectangle(display,window_info.pixmap,
14029 window_info.annotate_context,0,0,(unsigned int) width,
14030 (unsigned int) height);
14031 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
14032 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int)
14033 window_info.width,(unsigned int) window_info.height);
14034 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
14035 (void) XClearWindow(display,window_info.id);
14036 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L);
14037 XDelay(display,delay == 0UL ? 10UL : delay);
14038 (void) XSync(display,MagickFalse);
14039 return(window_info.id == root_window ? MagickTrue : MagickFalse);
14040 }
14041
14042 /*
14043 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14044 % %
14045 % %
14046 % %
14047 + X D i s p l a y I m a g e %
14048 % %
14049 % %
14050 % %
14051 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14052 %
14053 % XDisplayImage() displays an image via X11. A new image is created and
14054 % returned if the user interactively transforms the displayed image.
14055 %
14056 % The format of the XDisplayImage method is:
14057 %
14058 % Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
14059 % char **argv,int argc,Image **image,size_t *state,
14060 % ExceptionInfo *exception)
14061 %
14062 % A description of each parameter follows:
14063 %
14064 % o nexus: Method XDisplayImage returns an image when the
14065 % user chooses 'Open Image' from the command menu or picks a tile
14066 % from the image directory. Otherwise a null image is returned.
14067 %
14068 % o display: Specifies a connection to an X server; returned from
14069 % XOpenDisplay.
14070 %
14071 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
14072 %
14073 % o argv: Specifies the application's argument list.
14074 %
14075 % o argc: Specifies the number of arguments.
14076 %
14077 % o image: Specifies an address to an address of an Image structure;
14078 %
14079 % o exception: return any errors or warnings in this structure.
14080 %
14081 */
XDisplayImage(Display * display,XResourceInfo * resource_info,char ** argv,int argc,Image ** image,size_t * state,ExceptionInfo * exception)14082 MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
14083 char **argv,int argc,Image **image,size_t *state,ExceptionInfo *exception)
14084 {
14085 #define MagnifySize 256 /* must be a power of 2 */
14086 #define MagickMenus 10
14087 #define MagickTitle "Commands"
14088
14089 static const char
14090 *CommandMenu[] =
14091 {
14092 "File",
14093 "Edit",
14094 "View",
14095 "Transform",
14096 "Enhance",
14097 "Effects",
14098 "F/X",
14099 "Image Edit",
14100 "Miscellany",
14101 "Help",
14102 (char *) NULL
14103 },
14104 *FileMenu[] =
14105 {
14106 "Open...",
14107 "Next",
14108 "Former",
14109 "Select...",
14110 "Save...",
14111 "Print...",
14112 "Delete...",
14113 "New...",
14114 "Visual Directory...",
14115 "Quit",
14116 (char *) NULL
14117 },
14118 *EditMenu[] =
14119 {
14120 "Undo",
14121 "Redo",
14122 "Cut",
14123 "Copy",
14124 "Paste",
14125 (char *) NULL
14126 },
14127 *ViewMenu[] =
14128 {
14129 "Half Size",
14130 "Original Size",
14131 "Double Size",
14132 "Resize...",
14133 "Apply",
14134 "Refresh",
14135 "Restore",
14136 (char *) NULL
14137 },
14138 *TransformMenu[] =
14139 {
14140 "Crop",
14141 "Chop",
14142 "Flop",
14143 "Flip",
14144 "Rotate Right",
14145 "Rotate Left",
14146 "Rotate...",
14147 "Shear...",
14148 "Roll...",
14149 "Trim Edges",
14150 (char *) NULL
14151 },
14152 *EnhanceMenu[] =
14153 {
14154 "Hue...",
14155 "Saturation...",
14156 "Brightness...",
14157 "Gamma...",
14158 "Spiff",
14159 "Dull",
14160 "Contrast Stretch...",
14161 "Sigmoidal Contrast...",
14162 "Normalize",
14163 "Equalize",
14164 "Negate",
14165 "Grayscale",
14166 "Map...",
14167 "Quantize...",
14168 (char *) NULL
14169 },
14170 *EffectsMenu[] =
14171 {
14172 "Despeckle",
14173 "Emboss",
14174 "Reduce Noise",
14175 "Add Noise...",
14176 "Sharpen...",
14177 "Blur...",
14178 "Threshold...",
14179 "Edge Detect...",
14180 "Spread...",
14181 "Shade...",
14182 "Raise...",
14183 "Segment...",
14184 (char *) NULL
14185 },
14186 *FXMenu[] =
14187 {
14188 "Solarize...",
14189 "Sepia Tone...",
14190 "Swirl...",
14191 "Implode...",
14192 "Vignette...",
14193 "Wave...",
14194 "Oil Paint...",
14195 "Charcoal Draw...",
14196 (char *) NULL
14197 },
14198 *ImageEditMenu[] =
14199 {
14200 "Annotate...",
14201 "Draw...",
14202 "Color...",
14203 "Matte...",
14204 "Composite...",
14205 "Add Border...",
14206 "Add Frame...",
14207 "Comment...",
14208 "Launch...",
14209 "Region of Interest...",
14210 (char *) NULL
14211 },
14212 *MiscellanyMenu[] =
14213 {
14214 "Image Info",
14215 "Zoom Image",
14216 "Show Preview...",
14217 "Show Histogram",
14218 "Show Matte",
14219 "Background...",
14220 "Slide Show...",
14221 "Preferences...",
14222 (char *) NULL
14223 },
14224 *HelpMenu[] =
14225 {
14226 "Overview",
14227 "Browse Documentation",
14228 "About Display",
14229 (char *) NULL
14230 },
14231 *ShortCutsMenu[] =
14232 {
14233 "Next",
14234 "Former",
14235 "Open...",
14236 "Save...",
14237 "Print...",
14238 "Undo",
14239 "Restore",
14240 "Image Info",
14241 "Quit",
14242 (char *) NULL
14243 },
14244 *VirtualMenu[] =
14245 {
14246 "Image Info",
14247 "Print",
14248 "Next",
14249 "Quit",
14250 (char *) NULL
14251 };
14252
14253 static const char
14254 **Menus[MagickMenus] =
14255 {
14256 FileMenu,
14257 EditMenu,
14258 ViewMenu,
14259 TransformMenu,
14260 EnhanceMenu,
14261 EffectsMenu,
14262 FXMenu,
14263 ImageEditMenu,
14264 MiscellanyMenu,
14265 HelpMenu
14266 };
14267
14268 static CommandType
14269 CommandMenus[] =
14270 {
14271 NullCommand,
14272 NullCommand,
14273 NullCommand,
14274 NullCommand,
14275 NullCommand,
14276 NullCommand,
14277 NullCommand,
14278 NullCommand,
14279 NullCommand,
14280 NullCommand,
14281 },
14282 FileCommands[] =
14283 {
14284 OpenCommand,
14285 NextCommand,
14286 FormerCommand,
14287 SelectCommand,
14288 SaveCommand,
14289 PrintCommand,
14290 DeleteCommand,
14291 NewCommand,
14292 VisualDirectoryCommand,
14293 QuitCommand
14294 },
14295 EditCommands[] =
14296 {
14297 UndoCommand,
14298 RedoCommand,
14299 CutCommand,
14300 CopyCommand,
14301 PasteCommand
14302 },
14303 ViewCommands[] =
14304 {
14305 HalfSizeCommand,
14306 OriginalSizeCommand,
14307 DoubleSizeCommand,
14308 ResizeCommand,
14309 ApplyCommand,
14310 RefreshCommand,
14311 RestoreCommand
14312 },
14313 TransformCommands[] =
14314 {
14315 CropCommand,
14316 ChopCommand,
14317 FlopCommand,
14318 FlipCommand,
14319 RotateRightCommand,
14320 RotateLeftCommand,
14321 RotateCommand,
14322 ShearCommand,
14323 RollCommand,
14324 TrimCommand
14325 },
14326 EnhanceCommands[] =
14327 {
14328 HueCommand,
14329 SaturationCommand,
14330 BrightnessCommand,
14331 GammaCommand,
14332 SpiffCommand,
14333 DullCommand,
14334 ContrastStretchCommand,
14335 SigmoidalContrastCommand,
14336 NormalizeCommand,
14337 EqualizeCommand,
14338 NegateCommand,
14339 GrayscaleCommand,
14340 MapCommand,
14341 QuantizeCommand
14342 },
14343 EffectsCommands[] =
14344 {
14345 DespeckleCommand,
14346 EmbossCommand,
14347 ReduceNoiseCommand,
14348 AddNoiseCommand,
14349 SharpenCommand,
14350 BlurCommand,
14351 ThresholdCommand,
14352 EdgeDetectCommand,
14353 SpreadCommand,
14354 ShadeCommand,
14355 RaiseCommand,
14356 SegmentCommand
14357 },
14358 FXCommands[] =
14359 {
14360 SolarizeCommand,
14361 SepiaToneCommand,
14362 SwirlCommand,
14363 ImplodeCommand,
14364 VignetteCommand,
14365 WaveCommand,
14366 OilPaintCommand,
14367 CharcoalDrawCommand
14368 },
14369 ImageEditCommands[] =
14370 {
14371 AnnotateCommand,
14372 DrawCommand,
14373 ColorCommand,
14374 MatteCommand,
14375 CompositeCommand,
14376 AddBorderCommand,
14377 AddFrameCommand,
14378 CommentCommand,
14379 LaunchCommand,
14380 RegionofInterestCommand
14381 },
14382 MiscellanyCommands[] =
14383 {
14384 InfoCommand,
14385 ZoomCommand,
14386 ShowPreviewCommand,
14387 ShowHistogramCommand,
14388 ShowMatteCommand,
14389 BackgroundCommand,
14390 SlideShowCommand,
14391 PreferencesCommand
14392 },
14393 HelpCommands[] =
14394 {
14395 HelpCommand,
14396 BrowseDocumentationCommand,
14397 VersionCommand
14398 },
14399 ShortCutsCommands[] =
14400 {
14401 NextCommand,
14402 FormerCommand,
14403 OpenCommand,
14404 SaveCommand,
14405 PrintCommand,
14406 UndoCommand,
14407 RestoreCommand,
14408 InfoCommand,
14409 QuitCommand
14410 },
14411 VirtualCommands[] =
14412 {
14413 InfoCommand,
14414 PrintCommand,
14415 NextCommand,
14416 QuitCommand
14417 };
14418
14419 static CommandType
14420 *Commands[MagickMenus] =
14421 {
14422 FileCommands,
14423 EditCommands,
14424 ViewCommands,
14425 TransformCommands,
14426 EnhanceCommands,
14427 EffectsCommands,
14428 FXCommands,
14429 ImageEditCommands,
14430 MiscellanyCommands,
14431 HelpCommands
14432 };
14433
14434 char
14435 command[MagickPathExtent],
14436 *directory,
14437 geometry[MagickPathExtent],
14438 resource_name[MagickPathExtent];
14439
14440 CommandType
14441 command_type;
14442
14443 Image
14444 *display_image,
14445 *nexus;
14446
14447 int
14448 entry,
14449 id;
14450
14451 KeySym
14452 key_symbol;
14453
14454 MagickStatusType
14455 context_mask,
14456 status;
14457
14458 RectangleInfo
14459 geometry_info;
14460
14461 register int
14462 i;
14463
14464 static char
14465 working_directory[MagickPathExtent];
14466
14467 static XPoint
14468 vid_info;
14469
14470 static XWindowInfo
14471 *magick_windows[MaxXWindows];
14472
14473 static unsigned int
14474 number_windows;
14475
14476 struct stat
14477 attributes;
14478
14479 time_t
14480 timer,
14481 timestamp,
14482 update_time;
14483
14484 unsigned int
14485 height,
14486 width;
14487
14488 size_t
14489 delay;
14490
14491 WarningHandler
14492 warning_handler;
14493
14494 Window
14495 root_window;
14496
14497 XClassHint
14498 *class_hints;
14499
14500 XEvent
14501 event;
14502
14503 XFontStruct
14504 *font_info;
14505
14506 XGCValues
14507 context_values;
14508
14509 XPixelInfo
14510 *icon_pixel,
14511 *pixel;
14512
14513 XResourceInfo
14514 *icon_resources;
14515
14516 XStandardColormap
14517 *icon_map,
14518 *map_info;
14519
14520 XVisualInfo
14521 *icon_visual,
14522 *visual_info;
14523
14524 XWindowChanges
14525 window_changes;
14526
14527 XWindows
14528 *windows;
14529
14530 XWMHints
14531 *manager_hints;
14532
14533 assert(image != (Image **) NULL);
14534 assert((*image)->signature == MagickCoreSignature);
14535 if ((*image)->debug != MagickFalse )
14536 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
14537 display_image=(*image);
14538 warning_handler=(WarningHandler) NULL;
14539 windows=XSetWindows((XWindows *) ~0);
14540 if (windows != (XWindows *) NULL)
14541 {
14542 int
14543 status;
14544
14545 if (*working_directory == '\0')
14546 (void) CopyMagickString(working_directory,".",MagickPathExtent);
14547 status=chdir(working_directory);
14548 if (status == -1)
14549 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
14550 "UnableToOpenFile","%s",working_directory);
14551 warning_handler=resource_info->display_warnings ?
14552 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
14553 warning_handler=resource_info->display_warnings ?
14554 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
14555 }
14556 else
14557 {
14558 /*
14559 Allocate windows structure.
14560 */
14561 resource_info->colors=display_image->colors;
14562 windows=XSetWindows(XInitializeWindows(display,resource_info));
14563 if (windows == (XWindows *) NULL)
14564 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow",
14565 (*image)->filename);
14566 /*
14567 Initialize window id's.
14568 */
14569 number_windows=0;
14570 magick_windows[number_windows++]=(&windows->icon);
14571 magick_windows[number_windows++]=(&windows->backdrop);
14572 magick_windows[number_windows++]=(&windows->image);
14573 magick_windows[number_windows++]=(&windows->info);
14574 magick_windows[number_windows++]=(&windows->command);
14575 magick_windows[number_windows++]=(&windows->widget);
14576 magick_windows[number_windows++]=(&windows->popup);
14577 magick_windows[number_windows++]=(&windows->magnify);
14578 magick_windows[number_windows++]=(&windows->pan);
14579 for (i=0; i < (int) number_windows; i++)
14580 magick_windows[i]->id=(Window) NULL;
14581 vid_info.x=0;
14582 vid_info.y=0;
14583 }
14584 /*
14585 Initialize font info.
14586 */
14587 if (windows->font_info != (XFontStruct *) NULL)
14588 (void) XFreeFont(display,windows->font_info);
14589 windows->font_info=XBestFont(display,resource_info,MagickFalse);
14590 if (windows->font_info == (XFontStruct *) NULL)
14591 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont",
14592 resource_info->font);
14593 /*
14594 Initialize Standard Colormap.
14595 */
14596 map_info=windows->map_info;
14597 icon_map=windows->icon_map;
14598 visual_info=windows->visual_info;
14599 icon_visual=windows->icon_visual;
14600 pixel=windows->pixel_info;
14601 icon_pixel=windows->icon_pixel;
14602 font_info=windows->font_info;
14603 icon_resources=windows->icon_resources;
14604 class_hints=windows->class_hints;
14605 manager_hints=windows->manager_hints;
14606 root_window=XRootWindow(display,visual_info->screen);
14607 nexus=NewImageList();
14608 if (display_image->debug != MagickFalse )
14609 {
14610 (void) LogMagickEvent(X11Event,GetMagickModule(),
14611 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename,
14612 (double) display_image->scene,(double) display_image->columns,
14613 (double) display_image->rows);
14614 if (display_image->colors != 0)
14615 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
14616 display_image->colors);
14617 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
14618 display_image->magick);
14619 }
14620 XMakeStandardColormap(display,visual_info,resource_info,display_image,
14621 map_info,pixel,exception);
14622 display_image->taint=MagickFalse;
14623 /*
14624 Initialize graphic context.
14625 */
14626 windows->context.id=(Window) NULL;
14627 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14628 resource_info,&windows->context);
14629 (void) CloneString(&class_hints->res_name,resource_info->client_name);
14630 (void) CloneString(&class_hints->res_class,resource_info->client_name);
14631 class_hints->res_class[0]=(char) LocaleUppercase((int)
14632 class_hints->res_class[0]);
14633 manager_hints->flags=InputHint | StateHint;
14634 manager_hints->input=MagickFalse;
14635 manager_hints->initial_state=WithdrawnState;
14636 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14637 &windows->context);
14638 if (display_image->debug != MagickFalse )
14639 (void) LogMagickEvent(X11Event,GetMagickModule(),
14640 "Window id: 0x%lx (context)",windows->context.id);
14641 context_values.background=pixel->background_color.pixel;
14642 context_values.font=font_info->fid;
14643 context_values.foreground=pixel->foreground_color.pixel;
14644 context_values.graphics_exposures=MagickFalse;
14645 context_mask=(MagickStatusType)
14646 (GCBackground | GCFont | GCForeground | GCGraphicsExposures);
14647 if (pixel->annotate_context != (GC) NULL)
14648 (void) XFreeGC(display,pixel->annotate_context);
14649 pixel->annotate_context=XCreateGC(display,windows->context.id,
14650 context_mask,&context_values);
14651 if (pixel->annotate_context == (GC) NULL)
14652 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14653 display_image->filename);
14654 context_values.background=pixel->depth_color.pixel;
14655 if (pixel->widget_context != (GC) NULL)
14656 (void) XFreeGC(display,pixel->widget_context);
14657 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask,
14658 &context_values);
14659 if (pixel->widget_context == (GC) NULL)
14660 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14661 display_image->filename);
14662 context_values.background=pixel->foreground_color.pixel;
14663 context_values.foreground=pixel->background_color.pixel;
14664 context_values.plane_mask=context_values.background ^
14665 context_values.foreground;
14666 if (pixel->highlight_context != (GC) NULL)
14667 (void) XFreeGC(display,pixel->highlight_context);
14668 pixel->highlight_context=XCreateGC(display,windows->context.id,
14669 (size_t) (context_mask | GCPlaneMask),&context_values);
14670 if (pixel->highlight_context == (GC) NULL)
14671 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14672 display_image->filename);
14673 (void) XDestroyWindow(display,windows->context.id);
14674 /*
14675 Initialize icon window.
14676 */
14677 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL,
14678 icon_resources,&windows->icon);
14679 windows->icon.geometry=resource_info->icon_geometry;
14680 XBestIconSize(display,&windows->icon,display_image);
14681 windows->icon.attributes.colormap=XDefaultColormap(display,
14682 icon_visual->screen);
14683 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask;
14684 manager_hints->flags=InputHint | StateHint;
14685 manager_hints->input=MagickFalse;
14686 manager_hints->initial_state=IconicState;
14687 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14688 &windows->icon);
14689 if (display_image->debug != MagickFalse )
14690 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)",
14691 windows->icon.id);
14692 /*
14693 Initialize graphic context for icon window.
14694 */
14695 if (icon_pixel->annotate_context != (GC) NULL)
14696 (void) XFreeGC(display,icon_pixel->annotate_context);
14697 context_values.background=icon_pixel->background_color.pixel;
14698 context_values.foreground=icon_pixel->foreground_color.pixel;
14699 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id,
14700 (size_t) (GCBackground | GCForeground),&context_values);
14701 if (icon_pixel->annotate_context == (GC) NULL)
14702 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14703 display_image->filename);
14704 windows->icon.annotate_context=icon_pixel->annotate_context;
14705 /*
14706 Initialize Image window.
14707 */
14708 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14709 &windows->image);
14710 windows->image.shape=MagickTrue; /* non-rectangular shape hint */
14711 if (resource_info->use_shared_memory == MagickFalse)
14712 windows->image.shared_memory=MagickFalse;
14713 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState))
14714 {
14715 char
14716 *title;
14717
14718 title=InterpretImageProperties(resource_info->image_info,display_image,
14719 resource_info->title,exception);
14720 (void) CopyMagickString(windows->image.name,title,MagickPathExtent);
14721 (void) CopyMagickString(windows->image.icon_name,title,MagickPathExtent);
14722 title=DestroyString(title);
14723 }
14724 else
14725 {
14726 char
14727 filename[MagickPathExtent];
14728
14729 /*
14730 Window name is the base of the filename.
14731 */
14732 GetPathComponent(display_image->magick_filename,TailPath,filename);
14733 if (display_image->scene == 0)
14734 (void) FormatLocaleString(windows->image.name,MagickPathExtent,
14735 "%s: %s",MagickPackageName,filename);
14736 else
14737 (void) FormatLocaleString(windows->image.name,MagickPathExtent,
14738 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename,
14739 (double) display_image->scene,(double) GetImageListLength(
14740 display_image));
14741 (void) CopyMagickString(windows->image.icon_name,filename,
14742 MagickPathExtent);
14743 }
14744 if (resource_info->immutable)
14745 windows->image.immutable=MagickTrue;
14746 windows->image.use_pixmap=resource_info->use_pixmap;
14747 windows->image.geometry=resource_info->image_geometry;
14748 (void) FormatLocaleString(geometry,MagickPathExtent,"%ux%u+0+0>!",
14749 XDisplayWidth(display,visual_info->screen),
14750 XDisplayHeight(display,visual_info->screen));
14751 geometry_info.width=display_image->columns;
14752 geometry_info.height=display_image->rows;
14753 geometry_info.x=0;
14754 geometry_info.y=0;
14755 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
14756 &geometry_info.width,&geometry_info.height);
14757 windows->image.width=(unsigned int) geometry_info.width;
14758 windows->image.height=(unsigned int) geometry_info.height;
14759 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14760 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14761 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14762 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask;
14763 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14764 resource_info,&windows->backdrop);
14765 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL))
14766 {
14767 /*
14768 Initialize backdrop window.
14769 */
14770 windows->backdrop.x=0;
14771 windows->backdrop.y=0;
14772 (void) CloneString(&windows->backdrop.name,"Backdrop");
14773 windows->backdrop.flags=(size_t) (USSize | USPosition);
14774 windows->backdrop.width=(unsigned int)
14775 XDisplayWidth(display,visual_info->screen);
14776 windows->backdrop.height=(unsigned int)
14777 XDisplayHeight(display,visual_info->screen);
14778 windows->backdrop.border_width=0;
14779 windows->backdrop.immutable=MagickTrue;
14780 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask |
14781 ButtonReleaseMask;
14782 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask |
14783 StructureNotifyMask;
14784 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14785 manager_hints->icon_window=windows->icon.id;
14786 manager_hints->input=MagickTrue;
14787 manager_hints->initial_state=resource_info->iconic ? IconicState :
14788 NormalState;
14789 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14790 &windows->backdrop);
14791 if (display_image->debug != MagickFalse )
14792 (void) LogMagickEvent(X11Event,GetMagickModule(),
14793 "Window id: 0x%lx (backdrop)",windows->backdrop.id);
14794 (void) XMapWindow(display,windows->backdrop.id);
14795 (void) XClearWindow(display,windows->backdrop.id);
14796 if (windows->image.id != (Window) NULL)
14797 {
14798 (void) XDestroyWindow(display,windows->image.id);
14799 windows->image.id=(Window) NULL;
14800 }
14801 /*
14802 Position image in the center the backdrop.
14803 */
14804 windows->image.flags|=USPosition;
14805 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)-
14806 (windows->image.width/2);
14807 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)-
14808 (windows->image.height/2);
14809 }
14810 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14811 manager_hints->icon_window=windows->icon.id;
14812 manager_hints->input=MagickTrue;
14813 manager_hints->initial_state=resource_info->iconic ? IconicState :
14814 NormalState;
14815 if (windows->group_leader.id != (Window) NULL)
14816 {
14817 /*
14818 Follow the leader.
14819 */
14820 manager_hints->flags|=WindowGroupHint;
14821 manager_hints->window_group=windows->group_leader.id;
14822 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask);
14823 if (display_image->debug != MagickFalse )
14824 (void) LogMagickEvent(X11Event,GetMagickModule(),
14825 "Window id: 0x%lx (group leader)",windows->group_leader.id);
14826 }
14827 XMakeWindow(display,
14828 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window),
14829 argv,argc,class_hints,manager_hints,&windows->image);
14830 (void) XChangeProperty(display,windows->image.id,windows->im_protocols,
14831 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0);
14832 if (windows->group_leader.id != (Window) NULL)
14833 (void) XSetTransientForHint(display,windows->image.id,
14834 windows->group_leader.id);
14835 if (display_image->debug != MagickFalse )
14836 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)",
14837 windows->image.id);
14838 /*
14839 Initialize Info widget.
14840 */
14841 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14842 &windows->info);
14843 (void) CloneString(&windows->info.name,"Info");
14844 (void) CloneString(&windows->info.icon_name,"Info");
14845 windows->info.border_width=1;
14846 windows->info.x=2;
14847 windows->info.y=2;
14848 windows->info.flags|=PPosition;
14849 windows->info.attributes.win_gravity=UnmapGravity;
14850 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask |
14851 StructureNotifyMask;
14852 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14853 manager_hints->input=MagickFalse;
14854 manager_hints->initial_state=NormalState;
14855 manager_hints->window_group=windows->image.id;
14856 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints,
14857 &windows->info);
14858 windows->info.highlight_stipple=XCreateBitmapFromData(display,
14859 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14860 windows->info.shadow_stipple=XCreateBitmapFromData(display,
14861 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14862 (void) XSetTransientForHint(display,windows->info.id,windows->image.id);
14863 if (windows->image.mapped != MagickFalse )
14864 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
14865 if (display_image->debug != MagickFalse )
14866 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)",
14867 windows->info.id);
14868 /*
14869 Initialize Command widget.
14870 */
14871 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14872 resource_info,&windows->command);
14873 windows->command.data=MagickMenus;
14874 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL);
14875 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.command",
14876 resource_info->client_name);
14877 windows->command.geometry=XGetResourceClass(resource_info->resource_database,
14878 resource_name,"geometry",(char *) NULL);
14879 (void) CloneString(&windows->command.name,MagickTitle);
14880 windows->command.border_width=0;
14881 windows->command.flags|=PPosition;
14882 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14883 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask |
14884 OwnerGrabButtonMask | StructureNotifyMask;
14885 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14886 manager_hints->input=MagickTrue;
14887 manager_hints->initial_state=NormalState;
14888 manager_hints->window_group=windows->image.id;
14889 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14890 &windows->command);
14891 windows->command.highlight_stipple=XCreateBitmapFromData(display,
14892 windows->command.id,(char *) HighlightBitmap,HighlightWidth,
14893 HighlightHeight);
14894 windows->command.shadow_stipple=XCreateBitmapFromData(display,
14895 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14896 (void) XSetTransientForHint(display,windows->command.id,windows->image.id);
14897 if (windows->command.mapped != MagickFalse )
14898 (void) XMapRaised(display,windows->command.id);
14899 if (display_image->debug != MagickFalse )
14900 (void) LogMagickEvent(X11Event,GetMagickModule(),
14901 "Window id: 0x%lx (command)",windows->command.id);
14902 /*
14903 Initialize Widget window.
14904 */
14905 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14906 resource_info,&windows->widget);
14907 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.widget",
14908 resource_info->client_name);
14909 windows->widget.geometry=XGetResourceClass(resource_info->resource_database,
14910 resource_name,"geometry",(char *) NULL);
14911 windows->widget.border_width=0;
14912 windows->widget.flags|=PPosition;
14913 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14914 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14915 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14916 StructureNotifyMask;
14917 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14918 manager_hints->input=MagickTrue;
14919 manager_hints->initial_state=NormalState;
14920 manager_hints->window_group=windows->image.id;
14921 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14922 &windows->widget);
14923 windows->widget.highlight_stipple=XCreateBitmapFromData(display,
14924 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14925 windows->widget.shadow_stipple=XCreateBitmapFromData(display,
14926 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14927 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id);
14928 if (display_image->debug != MagickFalse )
14929 (void) LogMagickEvent(X11Event,GetMagickModule(),
14930 "Window id: 0x%lx (widget)",windows->widget.id);
14931 /*
14932 Initialize popup window.
14933 */
14934 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14935 resource_info,&windows->popup);
14936 windows->popup.border_width=0;
14937 windows->popup.flags|=PPosition;
14938 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14939 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14940 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask;
14941 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14942 manager_hints->input=MagickTrue;
14943 manager_hints->initial_state=NormalState;
14944 manager_hints->window_group=windows->image.id;
14945 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14946 &windows->popup);
14947 windows->popup.highlight_stipple=XCreateBitmapFromData(display,
14948 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14949 windows->popup.shadow_stipple=XCreateBitmapFromData(display,
14950 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14951 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id);
14952 if (display_image->debug != MagickFalse )
14953 (void) LogMagickEvent(X11Event,GetMagickModule(),
14954 "Window id: 0x%lx (pop up)",windows->popup.id);
14955 /*
14956 Initialize Magnify window and cursor.
14957 */
14958 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14959 resource_info,&windows->magnify);
14960 if (resource_info->use_shared_memory == MagickFalse)
14961 windows->magnify.shared_memory=MagickFalse;
14962 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.magnify",
14963 resource_info->client_name);
14964 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database,
14965 resource_name,"geometry",(char *) NULL);
14966 (void) FormatLocaleString(windows->magnify.name,MagickPathExtent,"Magnify %uX",
14967 resource_info->magnify);
14968 if (windows->magnify.cursor != (Cursor) NULL)
14969 (void) XFreeCursor(display,windows->magnify.cursor);
14970 windows->magnify.cursor=XMakeCursor(display,windows->image.id,
14971 map_info->colormap,resource_info->background_color,
14972 resource_info->foreground_color);
14973 if (windows->magnify.cursor == (Cursor) NULL)
14974 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor",
14975 display_image->filename);
14976 windows->magnify.width=MagnifySize;
14977 windows->magnify.height=MagnifySize;
14978 windows->magnify.flags|=PPosition;
14979 windows->magnify.min_width=MagnifySize;
14980 windows->magnify.min_height=MagnifySize;
14981 windows->magnify.width_inc=MagnifySize;
14982 windows->magnify.height_inc=MagnifySize;
14983 windows->magnify.data=resource_info->magnify;
14984 windows->magnify.attributes.cursor=windows->magnify.cursor;
14985 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask |
14986 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask |
14987 StructureNotifyMask;
14988 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14989 manager_hints->input=MagickTrue;
14990 manager_hints->initial_state=NormalState;
14991 manager_hints->window_group=windows->image.id;
14992 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14993 &windows->magnify);
14994 if (display_image->debug != MagickFalse )
14995 (void) LogMagickEvent(X11Event,GetMagickModule(),
14996 "Window id: 0x%lx (magnify)",windows->magnify.id);
14997 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id);
14998 /*
14999 Initialize panning window.
15000 */
15001 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
15002 resource_info,&windows->pan);
15003 (void) CloneString(&windows->pan.name,"Pan Icon");
15004 windows->pan.width=windows->icon.width;
15005 windows->pan.height=windows->icon.height;
15006 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.pan",
15007 resource_info->client_name);
15008 windows->pan.geometry=XGetResourceClass(resource_info->resource_database,
15009 resource_name,"geometry",(char *) NULL);
15010 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
15011 &windows->pan.width,&windows->pan.height);
15012 windows->pan.flags|=PPosition;
15013 windows->pan.immutable=MagickTrue;
15014 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
15015 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask |
15016 StructureNotifyMask;
15017 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
15018 manager_hints->input=MagickFalse;
15019 manager_hints->initial_state=NormalState;
15020 manager_hints->window_group=windows->image.id;
15021 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
15022 &windows->pan);
15023 if (display_image->debug != MagickFalse )
15024 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)",
15025 windows->pan.id);
15026 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id);
15027 if (windows->info.mapped != MagickFalse )
15028 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
15029 if ((windows->image.mapped == MagickFalse) ||
15030 (windows->backdrop.id != (Window) NULL))
15031 (void) XMapWindow(display,windows->image.id);
15032 /*
15033 Set our progress monitor and warning handlers.
15034 */
15035 if (warning_handler == (WarningHandler) NULL)
15036 {
15037 warning_handler=resource_info->display_warnings ?
15038 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
15039 warning_handler=resource_info->display_warnings ?
15040 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
15041 }
15042 /*
15043 Initialize Image and Magnify X images.
15044 */
15045 windows->image.x=0;
15046 windows->image.y=0;
15047 windows->magnify.shape=MagickFalse;
15048 width=(unsigned int) display_image->columns;
15049 height=(unsigned int) display_image->rows;
15050 if ((display_image->columns != width) || (display_image->rows != height))
15051 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
15052 display_image->filename);
15053 status=XMakeImage(display,resource_info,&windows->image,display_image,
15054 width,height,exception);
15055 if (status == MagickFalse)
15056 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
15057 display_image->filename);
15058 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL,
15059 windows->magnify.width,windows->magnify.height,exception);
15060 if (status == MagickFalse)
15061 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
15062 display_image->filename);
15063 if (windows->magnify.mapped != MagickFalse )
15064 (void) XMapRaised(display,windows->magnify.id);
15065 if (windows->pan.mapped != MagickFalse )
15066 (void) XMapRaised(display,windows->pan.id);
15067 windows->image.window_changes.width=(int) display_image->columns;
15068 windows->image.window_changes.height=(int) display_image->rows;
15069 (void) XConfigureImage(display,resource_info,windows,display_image,exception);
15070 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
15071 (void) XSync(display,MagickFalse);
15072 /*
15073 Respond to events.
15074 */
15075 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L);
15076 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15077 update_time=0;
15078 if (resource_info->update != MagickFalse )
15079 {
15080 MagickBooleanType
15081 status;
15082
15083 /*
15084 Determine when file data was last modified.
15085 */
15086 status=GetPathAttributes(display_image->filename,&attributes);
15087 if (status != MagickFalse )
15088 update_time=attributes.st_mtime;
15089 }
15090 *state&=(~FormerImageState);
15091 *state&=(~MontageImageState);
15092 *state&=(~NextImageState);
15093 do
15094 {
15095 /*
15096 Handle a window event.
15097 */
15098 if (windows->image.mapped != MagickFalse )
15099 if ((display_image->delay != 0) || (resource_info->update != 0))
15100 {
15101 if (timer < time((time_t *) NULL))
15102 {
15103 if (resource_info->update == MagickFalse)
15104 *state|=NextImageState | ExitState;
15105 else
15106 {
15107 MagickBooleanType
15108 status;
15109
15110 /*
15111 Determine if image file was modified.
15112 */
15113 status=GetPathAttributes(display_image->filename,&attributes);
15114 if (status != MagickFalse )
15115 if (update_time != attributes.st_mtime)
15116 {
15117 /*
15118 Redisplay image.
15119 */
15120 (void) FormatLocaleString(
15121 resource_info->image_info->filename,MagickPathExtent,
15122 "%s:%s",display_image->magick,
15123 display_image->filename);
15124 nexus=ReadImage(resource_info->image_info,exception);
15125 if (nexus != (Image *) NULL)
15126 *state|=NextImageState | ExitState;
15127 }
15128 delay=display_image->delay/MagickMax(
15129 display_image->ticks_per_second,1L);
15130 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15131 }
15132 }
15133 if (XEventsQueued(display,QueuedAfterFlush) == 0)
15134 {
15135 /*
15136 Do not block if delay > 0.
15137 */
15138 XDelay(display,SuspendTime << 2);
15139 continue;
15140 }
15141 }
15142 timestamp=time((time_t *) NULL);
15143 (void) XNextEvent(display,&event);
15144 if ((windows->image.stasis == MagickFalse) ||
15145 (windows->magnify.stasis == MagickFalse))
15146 {
15147 if ((time((time_t *) NULL)-timestamp) > 0)
15148 {
15149 windows->image.stasis=MagickTrue;
15150 windows->magnify.stasis=MagickTrue;
15151 }
15152 }
15153 if (event.xany.window == windows->command.id)
15154 {
15155 /*
15156 Select a command from the Command widget.
15157 */
15158 id=XCommandWidget(display,windows,CommandMenu,&event);
15159 if (id < 0)
15160 continue;
15161 (void) CopyMagickString(command,CommandMenu[id],MagickPathExtent);
15162 command_type=CommandMenus[id];
15163 if (id < MagickMenus)
15164 {
15165 /*
15166 Select a command from a pop-up menu.
15167 */
15168 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id],
15169 command);
15170 if (entry < 0)
15171 continue;
15172 (void) CopyMagickString(command,Menus[id][entry],MagickPathExtent);
15173 command_type=Commands[id][entry];
15174 }
15175 if (command_type != NullCommand)
15176 nexus=XMagickCommand(display,resource_info,windows,command_type,
15177 &display_image,exception);
15178 continue;
15179 }
15180 switch (event.type)
15181 {
15182 case ButtonPress:
15183 {
15184 if (display_image->debug != MagickFalse )
15185 (void) LogMagickEvent(X11Event,GetMagickModule(),
15186 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
15187 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15188 if ((event.xbutton.button == Button3) &&
15189 (event.xbutton.state & Mod1Mask))
15190 {
15191 /*
15192 Convert Alt-Button3 to Button2.
15193 */
15194 event.xbutton.button=Button2;
15195 event.xbutton.state&=(~Mod1Mask);
15196 }
15197 if (event.xbutton.window == windows->backdrop.id)
15198 {
15199 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent,
15200 event.xbutton.time);
15201 break;
15202 }
15203 if (event.xbutton.window == windows->image.id)
15204 {
15205 switch (event.xbutton.button)
15206 {
15207 case Button1:
15208 {
15209 if (resource_info->immutable)
15210 {
15211 /*
15212 Select a command from the Virtual menu.
15213 */
15214 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15215 command);
15216 if (entry >= 0)
15217 nexus=XMagickCommand(display,resource_info,windows,
15218 VirtualCommands[entry],&display_image,exception);
15219 break;
15220 }
15221 /*
15222 Map/unmap Command widget.
15223 */
15224 if (windows->command.mapped != MagickFalse )
15225 (void) XWithdrawWindow(display,windows->command.id,
15226 windows->command.screen);
15227 else
15228 {
15229 (void) XCommandWidget(display,windows,CommandMenu,
15230 (XEvent *) NULL);
15231 (void) XMapRaised(display,windows->command.id);
15232 }
15233 break;
15234 }
15235 case Button2:
15236 {
15237 /*
15238 User pressed the image magnify button.
15239 */
15240 (void) XMagickCommand(display,resource_info,windows,ZoomCommand,
15241 &display_image,exception);
15242 XMagnifyImage(display,windows,&event,exception);
15243 break;
15244 }
15245 case Button3:
15246 {
15247 if (resource_info->immutable)
15248 {
15249 /*
15250 Select a command from the Virtual menu.
15251 */
15252 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15253 command);
15254 if (entry >= 0)
15255 nexus=XMagickCommand(display,resource_info,windows,
15256 VirtualCommands[entry],&display_image,exception);
15257 break;
15258 }
15259 if (display_image->montage != (char *) NULL)
15260 {
15261 /*
15262 Open or delete a tile from a visual image directory.
15263 */
15264 nexus=XTileImage(display,resource_info,windows,
15265 display_image,&event,exception);
15266 if (nexus != (Image *) NULL)
15267 *state|=MontageImageState | NextImageState | ExitState;
15268 vid_info.x=(short int) windows->image.x;
15269 vid_info.y=(short int) windows->image.y;
15270 break;
15271 }
15272 /*
15273 Select a command from the Short Cuts menu.
15274 */
15275 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu,
15276 command);
15277 if (entry >= 0)
15278 nexus=XMagickCommand(display,resource_info,windows,
15279 ShortCutsCommands[entry],&display_image,exception);
15280 break;
15281 }
15282 case Button4:
15283 {
15284 /*
15285 Wheel up.
15286 */
15287 XTranslateImage(display,windows,*image,XK_Up);
15288 break;
15289 }
15290 case Button5:
15291 {
15292 /*
15293 Wheel down.
15294 */
15295 XTranslateImage(display,windows,*image,XK_Down);
15296 break;
15297 }
15298 default:
15299 break;
15300 }
15301 break;
15302 }
15303 if (event.xbutton.window == windows->magnify.id)
15304 {
15305 int
15306 factor;
15307
15308 static const char
15309 *MagnifyMenu[] =
15310 {
15311 "2",
15312 "4",
15313 "5",
15314 "6",
15315 "7",
15316 "8",
15317 "9",
15318 "3",
15319 (char *) NULL,
15320 };
15321
15322 static KeySym
15323 MagnifyCommands[] =
15324 {
15325 XK_2,
15326 XK_4,
15327 XK_5,
15328 XK_6,
15329 XK_7,
15330 XK_8,
15331 XK_9,
15332 XK_3
15333 };
15334
15335 /*
15336 Select a magnify factor from the pop-up menu.
15337 */
15338 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command);
15339 if (factor >= 0)
15340 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor],
15341 exception);
15342 break;
15343 }
15344 if (event.xbutton.window == windows->pan.id)
15345 {
15346 switch (event.xbutton.button)
15347 {
15348 case Button4:
15349 {
15350 /*
15351 Wheel up.
15352 */
15353 XTranslateImage(display,windows,*image,XK_Up);
15354 break;
15355 }
15356 case Button5:
15357 {
15358 /*
15359 Wheel down.
15360 */
15361 XTranslateImage(display,windows,*image,XK_Down);
15362 break;
15363 }
15364 default:
15365 {
15366 XPanImage(display,windows,&event,exception);
15367 break;
15368 }
15369 }
15370 break;
15371 }
15372 delay=display_image->delay/MagickMax(display_image->ticks_per_second,
15373 1L);
15374 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15375 break;
15376 }
15377 case ButtonRelease:
15378 {
15379 if (display_image->debug != MagickFalse )
15380 (void) LogMagickEvent(X11Event,GetMagickModule(),
15381 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
15382 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15383 break;
15384 }
15385 case ClientMessage:
15386 {
15387 if (display_image->debug != MagickFalse )
15388 (void) LogMagickEvent(X11Event,GetMagickModule(),
15389 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window,
15390 event.xclient.message_type,event.xclient.format,(unsigned long)
15391 event.xclient.data.l[0]);
15392 if (event.xclient.message_type == windows->im_protocols)
15393 {
15394 if (*event.xclient.data.l == (long) windows->im_update_widget)
15395 {
15396 (void) CloneString(&windows->command.name,MagickTitle);
15397 windows->command.data=MagickMenus;
15398 (void) XCommandWidget(display,windows,CommandMenu,
15399 (XEvent *) NULL);
15400 break;
15401 }
15402 if (*event.xclient.data.l == (long) windows->im_update_colormap)
15403 {
15404 /*
15405 Update graphic context and window colormap.
15406 */
15407 for (i=0; i < (int) number_windows; i++)
15408 {
15409 if (magick_windows[i]->id == windows->icon.id)
15410 continue;
15411 context_values.background=pixel->background_color.pixel;
15412 context_values.foreground=pixel->foreground_color.pixel;
15413 (void) XChangeGC(display,magick_windows[i]->annotate_context,
15414 context_mask,&context_values);
15415 (void) XChangeGC(display,magick_windows[i]->widget_context,
15416 context_mask,&context_values);
15417 context_values.background=pixel->foreground_color.pixel;
15418 context_values.foreground=pixel->background_color.pixel;
15419 context_values.plane_mask=context_values.background ^
15420 context_values.foreground;
15421 (void) XChangeGC(display,magick_windows[i]->highlight_context,
15422 (size_t) (context_mask | GCPlaneMask),
15423 &context_values);
15424 magick_windows[i]->attributes.background_pixel=
15425 pixel->background_color.pixel;
15426 magick_windows[i]->attributes.border_pixel=
15427 pixel->border_color.pixel;
15428 magick_windows[i]->attributes.colormap=map_info->colormap;
15429 (void) XChangeWindowAttributes(display,magick_windows[i]->id,
15430 (unsigned long) magick_windows[i]->mask,
15431 &magick_windows[i]->attributes);
15432 }
15433 if (windows->pan.mapped != MagickFalse )
15434 {
15435 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
15436 windows->pan.pixmap);
15437 (void) XClearWindow(display,windows->pan.id);
15438 XDrawPanRectangle(display,windows);
15439 }
15440 if (windows->backdrop.id != (Window) NULL)
15441 (void) XInstallColormap(display,map_info->colormap);
15442 break;
15443 }
15444 if (*event.xclient.data.l == (long) windows->im_former_image)
15445 {
15446 *state|=FormerImageState | ExitState;
15447 break;
15448 }
15449 if (*event.xclient.data.l == (long) windows->im_next_image)
15450 {
15451 *state|=NextImageState | ExitState;
15452 break;
15453 }
15454 if (*event.xclient.data.l == (long) windows->im_retain_colors)
15455 {
15456 *state|=RetainColorsState;
15457 break;
15458 }
15459 if (*event.xclient.data.l == (long) windows->im_exit)
15460 {
15461 *state|=ExitState;
15462 break;
15463 }
15464 break;
15465 }
15466 if (event.xclient.message_type == windows->dnd_protocols)
15467 {
15468 Atom
15469 selection,
15470 type;
15471
15472 int
15473 format,
15474 status;
15475
15476 unsigned char
15477 *data;
15478
15479 unsigned long
15480 after,
15481 length;
15482
15483 /*
15484 Display image named by the Drag-and-Drop selection.
15485 */
15486 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128))
15487 break;
15488 selection=XInternAtom(display,"DndSelection",MagickFalse);
15489 status=XGetWindowProperty(display,root_window,selection,0L,(long)
15490 MagickPathExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format,
15491 &length,&after,&data);
15492 if ((status != Success) || (length == 0))
15493 break;
15494 if (*event.xclient.data.l == 2)
15495 {
15496 /*
15497 Offix DND.
15498 */
15499 (void) CopyMagickString(resource_info->image_info->filename,
15500 (char *) data,MagickPathExtent);
15501 }
15502 else
15503 {
15504 /*
15505 XDND.
15506 */
15507 if (strncmp((char *) data, "file:", 5) != 0)
15508 {
15509 (void) XFree((void *) data);
15510 break;
15511 }
15512 (void) CopyMagickString(resource_info->image_info->filename,
15513 ((char *) data)+5,MagickPathExtent);
15514 }
15515 nexus=ReadImage(resource_info->image_info,exception);
15516 CatchException(exception);
15517 if (nexus != (Image *) NULL)
15518 *state|=NextImageState | ExitState;
15519 (void) XFree((void *) data);
15520 break;
15521 }
15522 /*
15523 If client window delete message, exit.
15524 */
15525 if (event.xclient.message_type != windows->wm_protocols)
15526 break;
15527 if (*event.xclient.data.l != (long) windows->wm_delete_window)
15528 break;
15529 (void) XWithdrawWindow(display,event.xclient.window,
15530 visual_info->screen);
15531 if (event.xclient.window == windows->image.id)
15532 {
15533 *state|=ExitState;
15534 break;
15535 }
15536 if (event.xclient.window == windows->pan.id)
15537 {
15538 /*
15539 Restore original image size when pan window is deleted.
15540 */
15541 windows->image.window_changes.width=windows->image.ximage->width;
15542 windows->image.window_changes.height=windows->image.ximage->height;
15543 (void) XConfigureImage(display,resource_info,windows,
15544 display_image,exception);
15545 }
15546 break;
15547 }
15548 case ConfigureNotify:
15549 {
15550 if (display_image->debug != MagickFalse )
15551 (void) LogMagickEvent(X11Event,GetMagickModule(),
15552 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window,
15553 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x,
15554 event.xconfigure.y,event.xconfigure.send_event);
15555 if (event.xconfigure.window == windows->image.id)
15556 {
15557 /*
15558 Image window has a new configuration.
15559 */
15560 if (event.xconfigure.send_event != 0)
15561 {
15562 XWindowChanges
15563 window_changes;
15564
15565 /*
15566 Position the transient windows relative of the Image window.
15567 */
15568 if (windows->command.geometry == (char *) NULL)
15569 if (windows->command.mapped == MagickFalse)
15570 {
15571 windows->command.x=event.xconfigure.x-
15572 windows->command.width-25;
15573 windows->command.y=event.xconfigure.y;
15574 XConstrainWindowPosition(display,&windows->command);
15575 window_changes.x=windows->command.x;
15576 window_changes.y=windows->command.y;
15577 (void) XReconfigureWMWindow(display,windows->command.id,
15578 windows->command.screen,(unsigned int) (CWX | CWY),
15579 &window_changes);
15580 }
15581 if (windows->widget.geometry == (char *) NULL)
15582 if (windows->widget.mapped == MagickFalse)
15583 {
15584 windows->widget.x=event.xconfigure.x+
15585 event.xconfigure.width/10;
15586 windows->widget.y=event.xconfigure.y+
15587 event.xconfigure.height/10;
15588 XConstrainWindowPosition(display,&windows->widget);
15589 window_changes.x=windows->widget.x;
15590 window_changes.y=windows->widget.y;
15591 (void) XReconfigureWMWindow(display,windows->widget.id,
15592 windows->widget.screen,(unsigned int) (CWX | CWY),
15593 &window_changes);
15594 }
15595 if (windows->magnify.geometry == (char *) NULL)
15596 if (windows->magnify.mapped == MagickFalse)
15597 {
15598 windows->magnify.x=event.xconfigure.x+
15599 event.xconfigure.width+25;
15600 windows->magnify.y=event.xconfigure.y;
15601 XConstrainWindowPosition(display,&windows->magnify);
15602 window_changes.x=windows->magnify.x;
15603 window_changes.y=windows->magnify.y;
15604 (void) XReconfigureWMWindow(display,windows->magnify.id,
15605 windows->magnify.screen,(unsigned int) (CWX | CWY),
15606 &window_changes);
15607 }
15608 if (windows->pan.geometry == (char *) NULL)
15609 if (windows->pan.mapped == MagickFalse)
15610 {
15611 windows->pan.x=event.xconfigure.x+
15612 event.xconfigure.width+25;
15613 windows->pan.y=event.xconfigure.y+
15614 windows->magnify.height+50;
15615 XConstrainWindowPosition(display,&windows->pan);
15616 window_changes.x=windows->pan.x;
15617 window_changes.y=windows->pan.y;
15618 (void) XReconfigureWMWindow(display,windows->pan.id,
15619 windows->pan.screen,(unsigned int) (CWX | CWY),
15620 &window_changes);
15621 }
15622 }
15623 if ((event.xconfigure.width == (int) windows->image.width) &&
15624 (event.xconfigure.height == (int) windows->image.height))
15625 break;
15626 windows->image.width=(unsigned int) event.xconfigure.width;
15627 windows->image.height=(unsigned int) event.xconfigure.height;
15628 windows->image.x=0;
15629 windows->image.y=0;
15630 if (display_image->montage != (char *) NULL)
15631 {
15632 windows->image.x=vid_info.x;
15633 windows->image.y=vid_info.y;
15634 }
15635 if (windows->image.mapped != MagickFalse &&
15636 windows->image.stasis != MagickFalse )
15637 {
15638 /*
15639 Update image window configuration.
15640 */
15641 windows->image.window_changes.width=event.xconfigure.width;
15642 windows->image.window_changes.height=event.xconfigure.height;
15643 (void) XConfigureImage(display,resource_info,windows,
15644 display_image,exception);
15645 }
15646 /*
15647 Update pan window configuration.
15648 */
15649 if ((event.xconfigure.width < windows->image.ximage->width) ||
15650 (event.xconfigure.height < windows->image.ximage->height))
15651 {
15652 (void) XMapRaised(display,windows->pan.id);
15653 XDrawPanRectangle(display,windows);
15654 }
15655 else
15656 if (windows->pan.mapped != MagickFalse )
15657 (void) XWithdrawWindow(display,windows->pan.id,
15658 windows->pan.screen);
15659 break;
15660 }
15661 if (event.xconfigure.window == windows->magnify.id)
15662 {
15663 unsigned int
15664 magnify;
15665
15666 /*
15667 Magnify window has a new configuration.
15668 */
15669 windows->magnify.width=(unsigned int) event.xconfigure.width;
15670 windows->magnify.height=(unsigned int) event.xconfigure.height;
15671 if (windows->magnify.mapped == MagickFalse)
15672 break;
15673 magnify=1;
15674 while ((int) magnify <= event.xconfigure.width)
15675 magnify<<=1;
15676 while ((int) magnify <= event.xconfigure.height)
15677 magnify<<=1;
15678 magnify>>=1;
15679 if (((int) magnify != event.xconfigure.width) ||
15680 ((int) magnify != event.xconfigure.height))
15681 {
15682 window_changes.width=(int) magnify;
15683 window_changes.height=(int) magnify;
15684 (void) XReconfigureWMWindow(display,windows->magnify.id,
15685 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
15686 &window_changes);
15687 break;
15688 }
15689 if (windows->magnify.mapped != MagickFalse &&
15690 windows->magnify.stasis != MagickFalse )
15691 {
15692 status=XMakeImage(display,resource_info,&windows->magnify,
15693 display_image,windows->magnify.width,windows->magnify.height,
15694 exception);
15695 XMakeMagnifyImage(display,windows,exception);
15696 }
15697 break;
15698 }
15699 if (windows->magnify.mapped != MagickFalse &&
15700 (event.xconfigure.window == windows->pan.id))
15701 {
15702 /*
15703 Pan icon window has a new configuration.
15704 */
15705 if (event.xconfigure.send_event != 0)
15706 {
15707 windows->pan.x=event.xconfigure.x;
15708 windows->pan.y=event.xconfigure.y;
15709 }
15710 windows->pan.width=(unsigned int) event.xconfigure.width;
15711 windows->pan.height=(unsigned int) event.xconfigure.height;
15712 break;
15713 }
15714 if (event.xconfigure.window == windows->icon.id)
15715 {
15716 /*
15717 Icon window has a new configuration.
15718 */
15719 windows->icon.width=(unsigned int) event.xconfigure.width;
15720 windows->icon.height=(unsigned int) event.xconfigure.height;
15721 break;
15722 }
15723 break;
15724 }
15725 case DestroyNotify:
15726 {
15727 /*
15728 Group leader has exited.
15729 */
15730 if (display_image->debug != MagickFalse )
15731 (void) LogMagickEvent(X11Event,GetMagickModule(),
15732 "Destroy Notify: 0x%lx",event.xdestroywindow.window);
15733 if (event.xdestroywindow.window == windows->group_leader.id)
15734 {
15735 *state|=ExitState;
15736 break;
15737 }
15738 break;
15739 }
15740 case EnterNotify:
15741 {
15742 /*
15743 Selectively install colormap.
15744 */
15745 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15746 if (event.xcrossing.mode != NotifyUngrab)
15747 XInstallColormap(display,map_info->colormap);
15748 break;
15749 }
15750 case Expose:
15751 {
15752 if (display_image->debug != MagickFalse )
15753 (void) LogMagickEvent(X11Event,GetMagickModule(),
15754 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window,
15755 event.xexpose.width,event.xexpose.height,event.xexpose.x,
15756 event.xexpose.y);
15757 /*
15758 Refresh windows that are now exposed.
15759 */
15760 if ((event.xexpose.window == windows->image.id) &&
15761 windows->image.mapped != MagickFalse )
15762 {
15763 XRefreshWindow(display,&windows->image,&event);
15764 delay=display_image->delay/MagickMax(
15765 display_image->ticks_per_second,1L);
15766 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15767 break;
15768 }
15769 if ((event.xexpose.window == windows->magnify.id) &&
15770 windows->magnify.mapped != MagickFalse)
15771 {
15772 XMakeMagnifyImage(display,windows,exception);
15773 break;
15774 }
15775 if (event.xexpose.window == windows->pan.id)
15776 {
15777 XDrawPanRectangle(display,windows);
15778 break;
15779 }
15780 if (event.xexpose.window == windows->icon.id)
15781 {
15782 XRefreshWindow(display,&windows->icon,&event);
15783 break;
15784 }
15785 break;
15786 }
15787 case KeyPress:
15788 {
15789 int
15790 length;
15791
15792 /*
15793 Respond to a user key press.
15794 */
15795 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
15796 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15797 *(command+length)='\0';
15798 if (display_image->debug != MagickFalse )
15799 (void) LogMagickEvent(X11Event,GetMagickModule(),
15800 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long)
15801 key_symbol,command);
15802 if (event.xkey.window == windows->image.id)
15803 {
15804 command_type=XImageWindowCommand(display,resource_info,windows,
15805 event.xkey.state,key_symbol,&display_image,exception);
15806 if (command_type != NullCommand)
15807 nexus=XMagickCommand(display,resource_info,windows,command_type,
15808 &display_image,exception);
15809 }
15810 if (event.xkey.window == windows->magnify.id)
15811 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol,
15812 exception);
15813 if (event.xkey.window == windows->pan.id)
15814 {
15815 if ((key_symbol == XK_q) || (key_symbol == XK_Escape))
15816 (void) XWithdrawWindow(display,windows->pan.id,
15817 windows->pan.screen);
15818 else
15819 if ((key_symbol == XK_F1) || (key_symbol == XK_Help))
15820 XTextViewWidget(display,resource_info,windows,MagickFalse,
15821 "Help Viewer - Image Pan",ImagePanHelp);
15822 else
15823 XTranslateImage(display,windows,*image,key_symbol);
15824 }
15825 delay=display_image->delay/MagickMax(
15826 display_image->ticks_per_second,1L);
15827 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15828 break;
15829 }
15830 case KeyRelease:
15831 {
15832 /*
15833 Respond to a user key release.
15834 */
15835 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
15836 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15837 if (display_image->debug != MagickFalse )
15838 (void) LogMagickEvent(X11Event,GetMagickModule(),
15839 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command);
15840 break;
15841 }
15842 case LeaveNotify:
15843 {
15844 /*
15845 Selectively uninstall colormap.
15846 */
15847 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15848 if (event.xcrossing.mode != NotifyUngrab)
15849 XUninstallColormap(display,map_info->colormap);
15850 break;
15851 }
15852 case MapNotify:
15853 {
15854 if (display_image->debug != MagickFalse )
15855 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx",
15856 event.xmap.window);
15857 if (event.xmap.window == windows->backdrop.id)
15858 {
15859 (void) XSetInputFocus(display,event.xmap.window,RevertToParent,
15860 CurrentTime);
15861 windows->backdrop.mapped=MagickTrue;
15862 break;
15863 }
15864 if (event.xmap.window == windows->image.id)
15865 {
15866 if (windows->backdrop.id != (Window) NULL)
15867 (void) XInstallColormap(display,map_info->colormap);
15868 if (LocaleCompare(display_image->magick,"LOGO") == 0)
15869 {
15870 if (LocaleCompare(display_image->filename,"LOGO") == 0)
15871 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
15872 }
15873 if (((int) windows->image.width < windows->image.ximage->width) ||
15874 ((int) windows->image.height < windows->image.ximage->height))
15875 (void) XMapRaised(display,windows->pan.id);
15876 windows->image.mapped=MagickTrue;
15877 break;
15878 }
15879 if (event.xmap.window == windows->magnify.id)
15880 {
15881 XMakeMagnifyImage(display,windows,exception);
15882 windows->magnify.mapped=MagickTrue;
15883 (void) XWithdrawWindow(display,windows->info.id,
15884 windows->info.screen);
15885 break;
15886 }
15887 if (event.xmap.window == windows->pan.id)
15888 {
15889 XMakePanImage(display,resource_info,windows,display_image,
15890 exception);
15891 windows->pan.mapped=MagickTrue;
15892 break;
15893 }
15894 if (event.xmap.window == windows->info.id)
15895 {
15896 windows->info.mapped=MagickTrue;
15897 break;
15898 }
15899 if (event.xmap.window == windows->icon.id)
15900 {
15901 MagickBooleanType
15902 taint;
15903
15904 /*
15905 Create an icon image.
15906 */
15907 taint=display_image->taint;
15908 XMakeStandardColormap(display,icon_visual,icon_resources,
15909 display_image,icon_map,icon_pixel,exception);
15910 (void) XMakeImage(display,icon_resources,&windows->icon,
15911 display_image,windows->icon.width,windows->icon.height,
15912 exception);
15913 display_image->taint=taint;
15914 (void) XSetWindowBackgroundPixmap(display,windows->icon.id,
15915 windows->icon.pixmap);
15916 (void) XClearWindow(display,windows->icon.id);
15917 (void) XWithdrawWindow(display,windows->info.id,
15918 windows->info.screen);
15919 windows->icon.mapped=MagickTrue;
15920 break;
15921 }
15922 if (event.xmap.window == windows->command.id)
15923 {
15924 windows->command.mapped=MagickTrue;
15925 break;
15926 }
15927 if (event.xmap.window == windows->popup.id)
15928 {
15929 windows->popup.mapped=MagickTrue;
15930 break;
15931 }
15932 if (event.xmap.window == windows->widget.id)
15933 {
15934 windows->widget.mapped=MagickTrue;
15935 break;
15936 }
15937 break;
15938 }
15939 case MappingNotify:
15940 {
15941 (void) XRefreshKeyboardMapping(&event.xmapping);
15942 break;
15943 }
15944 case NoExpose:
15945 break;
15946 case PropertyNotify:
15947 {
15948 Atom
15949 type;
15950
15951 int
15952 format,
15953 status;
15954
15955 unsigned char
15956 *data;
15957
15958 unsigned long
15959 after,
15960 length;
15961
15962 if (display_image->debug != MagickFalse )
15963 (void) LogMagickEvent(X11Event,GetMagickModule(),
15964 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window,
15965 event.xproperty.atom,event.xproperty.state);
15966 if (event.xproperty.atom != windows->im_remote_command)
15967 break;
15968 /*
15969 Display image named by the remote command protocol.
15970 */
15971 status=XGetWindowProperty(display,event.xproperty.window,
15972 event.xproperty.atom,0L,(long) MagickPathExtent,MagickFalse,(Atom)
15973 AnyPropertyType,&type,&format,&length,&after,&data);
15974 if ((status != Success) || (length == 0))
15975 break;
15976 if (LocaleCompare((char *) data,"-quit") == 0)
15977 {
15978 XClientMessage(display,windows->image.id,windows->im_protocols,
15979 windows->im_exit,CurrentTime);
15980 (void) XFree((void *) data);
15981 break;
15982 }
15983 (void) CopyMagickString(resource_info->image_info->filename,
15984 (char *) data,MagickPathExtent);
15985 (void) XFree((void *) data);
15986 nexus=ReadImage(resource_info->image_info,exception);
15987 CatchException(exception);
15988 if (nexus != (Image *) NULL)
15989 *state|=NextImageState | ExitState;
15990 break;
15991 }
15992 case ReparentNotify:
15993 {
15994 if (display_image->debug != MagickFalse )
15995 (void) LogMagickEvent(X11Event,GetMagickModule(),
15996 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent,
15997 event.xreparent.window);
15998 break;
15999 }
16000 case UnmapNotify:
16001 {
16002 if (display_image->debug != MagickFalse )
16003 (void) LogMagickEvent(X11Event,GetMagickModule(),
16004 "Unmap Notify: 0x%lx",event.xunmap.window);
16005 if (event.xunmap.window == windows->backdrop.id)
16006 {
16007 windows->backdrop.mapped=MagickFalse;
16008 break;
16009 }
16010 if (event.xunmap.window == windows->image.id)
16011 {
16012 windows->image.mapped=MagickFalse;
16013 break;
16014 }
16015 if (event.xunmap.window == windows->magnify.id)
16016 {
16017 windows->magnify.mapped=MagickFalse;
16018 break;
16019 }
16020 if (event.xunmap.window == windows->pan.id)
16021 {
16022 windows->pan.mapped=MagickFalse;
16023 break;
16024 }
16025 if (event.xunmap.window == windows->info.id)
16026 {
16027 windows->info.mapped=MagickFalse;
16028 break;
16029 }
16030 if (event.xunmap.window == windows->icon.id)
16031 {
16032 if (map_info->colormap == icon_map->colormap)
16033 XConfigureImageColormap(display,resource_info,windows,
16034 display_image,exception);
16035 (void) XFreeStandardColormap(display,icon_visual,icon_map,
16036 icon_pixel);
16037 windows->icon.mapped=MagickFalse;
16038 break;
16039 }
16040 if (event.xunmap.window == windows->command.id)
16041 {
16042 windows->command.mapped=MagickFalse;
16043 break;
16044 }
16045 if (event.xunmap.window == windows->popup.id)
16046 {
16047 if (windows->backdrop.id != (Window) NULL)
16048 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
16049 CurrentTime);
16050 windows->popup.mapped=MagickFalse;
16051 break;
16052 }
16053 if (event.xunmap.window == windows->widget.id)
16054 {
16055 if (windows->backdrop.id != (Window) NULL)
16056 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
16057 CurrentTime);
16058 windows->widget.mapped=MagickFalse;
16059 break;
16060 }
16061 break;
16062 }
16063 default:
16064 {
16065 if (display_image->debug != MagickFalse )
16066 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
16067 event.type);
16068 break;
16069 }
16070 }
16071 } while (!(*state & ExitState));
16072 if ((*state & ExitState) == 0)
16073 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand,
16074 &display_image,exception);
16075 else
16076 if (resource_info->confirm_edit != MagickFalse )
16077 {
16078 /*
16079 Query user if image has changed.
16080 */
16081 if ((resource_info->immutable == MagickFalse) &&
16082 display_image->taint != MagickFalse)
16083 {
16084 int
16085 status;
16086
16087 status=XConfirmWidget(display,windows,"Your image changed.",
16088 "Do you want to save it");
16089 if (status == 0)
16090 *state&=(~ExitState);
16091 else
16092 if (status > 0)
16093 (void) XMagickCommand(display,resource_info,windows,SaveCommand,
16094 &display_image,exception);
16095 }
16096 }
16097 if ((windows->visual_info->klass == GrayScale) ||
16098 (windows->visual_info->klass == PseudoColor) ||
16099 (windows->visual_info->klass == DirectColor))
16100 {
16101 /*
16102 Withdraw pan and Magnify window.
16103 */
16104 if (windows->info.mapped != MagickFalse )
16105 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
16106 if (windows->magnify.mapped != MagickFalse )
16107 (void) XWithdrawWindow(display,windows->magnify.id,
16108 windows->magnify.screen);
16109 if (windows->command.mapped != MagickFalse )
16110 (void) XWithdrawWindow(display,windows->command.id,
16111 windows->command.screen);
16112 }
16113 if (windows->pan.mapped != MagickFalse )
16114 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen);
16115 if (resource_info->backdrop == MagickFalse)
16116 if (windows->backdrop.mapped)
16117 {
16118 (void) XWithdrawWindow(display,windows->backdrop.id,
16119 windows->backdrop.screen);
16120 (void) XDestroyWindow(display,windows->backdrop.id);
16121 windows->backdrop.id=(Window) NULL;
16122 (void) XWithdrawWindow(display,windows->image.id,
16123 windows->image.screen);
16124 (void) XDestroyWindow(display,windows->image.id);
16125 windows->image.id=(Window) NULL;
16126 }
16127 XSetCursorState(display,windows,MagickTrue);
16128 XCheckRefreshWindows(display,windows);
16129 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0))
16130 *state&=(~ExitState);
16131 if (*state & ExitState)
16132 {
16133 /*
16134 Free Standard Colormap.
16135 */
16136 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel);
16137 if (resource_info->map_type == (char *) NULL)
16138 (void) XFreeStandardColormap(display,visual_info,map_info,pixel);
16139 /*
16140 Free X resources.
16141 */
16142 if (resource_info->copy_image != (Image *) NULL)
16143 {
16144 resource_info->copy_image=DestroyImage(resource_info->copy_image);
16145 resource_info->copy_image=NewImageList();
16146 }
16147 DestroyXResources();
16148 }
16149 (void) XSync(display,MagickFalse);
16150 /*
16151 Restore our progress monitor and warning handlers.
16152 */
16153 (void) SetErrorHandler(warning_handler);
16154 (void) SetWarningHandler(warning_handler);
16155 /*
16156 Change to home directory.
16157 */
16158 directory=getcwd(working_directory,MagickPathExtent);
16159 (void) directory;
16160 {
16161 int
16162 status;
16163
16164 if (*resource_info->home_directory == '\0')
16165 (void) CopyMagickString(resource_info->home_directory,".",MagickPathExtent);
16166 status=chdir(resource_info->home_directory);
16167 if (status == -1)
16168 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
16169 "UnableToOpenFile","%s",resource_info->home_directory);
16170 }
16171 *image=display_image;
16172 return(nexus);
16173 }
16174 #else
16175
16176 /*
16177 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16178 % %
16179 % %
16180 % %
16181 + D i s p l a y I m a g e s %
16182 % %
16183 % %
16184 % %
16185 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16186 %
16187 % DisplayImages() displays an image sequence to any X window screen. It
16188 % returns a value other than 0 if successful. Check the exception member
16189 % of image to determine the reason for any failure.
16190 %
16191 % The format of the DisplayImages method is:
16192 %
16193 % MagickBooleanType DisplayImages(const ImageInfo *image_info,
16194 % Image *images,ExceptionInfo *exception)
16195 %
16196 % A description of each parameter follows:
16197 %
16198 % o image_info: the image info.
16199 %
16200 % o image: the image.
16201 %
16202 % o exception: return any errors or warnings in this structure.
16203 %
16204 */
DisplayImages(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)16205 MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
16206 Image *image,ExceptionInfo *exception)
16207 {
16208 assert(image_info != (const ImageInfo *) NULL);
16209 assert(image_info->signature == MagickCoreSignature);
16210 assert(image != (Image *) NULL);
16211 assert(image->signature == MagickCoreSignature);
16212 (void) image_info;
16213 if (image->debug != MagickFalse )
16214 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
16215 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
16216 "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image->filename);
16217 return(MagickFalse);
16218 }
16219
16220 /*
16221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16222 % %
16223 % %
16224 % %
16225 + R e m o t e D i s p l a y C o m m a n d %
16226 % %
16227 % %
16228 % %
16229 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16230 %
16231 % RemoteDisplayCommand() encourages a remote display program to display the
16232 % specified image filename.
16233 %
16234 % The format of the RemoteDisplayCommand method is:
16235 %
16236 % MagickBooleanType RemoteDisplayCommand(const ImageInfo *image,
16237 % const char *window,const char *filename,ExceptionInfo *exception)
16238 %
16239 % A description of each parameter follows:
16240 %
16241 % o image_info: the image info.
16242 %
16243 % o window: Specifies the name or id of an X window.
16244 %
16245 % o filename: the name of the image filename to display.
16246 %
16247 % o exception: return any errors or warnings in this structure.
16248 %
16249 */
RemoteDisplayCommand(const ImageInfo * image_info,const char * window,const char * filename,ExceptionInfo * exception)16250 MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
16251 const char *window,const char *filename,ExceptionInfo *exception)
16252 {
16253 assert(image_info != (const ImageInfo *) NULL);
16254 assert(image_info->signature == MagickCoreSignature);
16255 assert(filename != (char *) NULL);
16256 (void) window;
16257 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
16258 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
16259 "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image_info->filename);
16260 return(MagickFalse);
16261 }
16262 #endif
16263