blob: 7f3bf7aef64c260471f47bab47f58292f3dc1355 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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 %
cristyde984cd2013-12-01 14:49:27 +000016% Cristy %
cristy3ed852e2009-09-05 21:47:34 +000017% July 1992 %
18% %
19% %
cristyb56bb242014-11-25 17:12:48 +000020% Copyright 1999-2015 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37*/
38
39/*
40 Include declarations.
41*/
cristy4c08aed2011-07-01 19:47:50 +000042#include "MagickCore/studio.h"
43#include "MagickCore/artifact.h"
cristy8941c702012-06-21 01:30:15 +000044#include "MagickCore/attribute.h"
cristy4c08aed2011-07-01 19:47:50 +000045#include "MagickCore/blob.h"
46#include "MagickCore/cache.h"
cristy52010022011-10-21 18:07:37 +000047#include "MagickCore/cache-private.h"
cristy6a2180c2013-05-27 10:28:36 +000048#include "MagickCore/channel.h"
cristy4c08aed2011-07-01 19:47:50 +000049#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"
cristyc53413d2011-11-17 13:04:26 +000058#include "MagickCore/distort.h"
cristy4c08aed2011-07-01 19:47:50 +000059#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"
cristy1e37e8f2014-02-21 17:05:37 +000075#include "MagickCore/nt-base-private.h"
cristy4c08aed2011-07-01 19:47:50 +000076#include "MagickCore/option.h"
77#include "MagickCore/paint.h"
78#include "MagickCore/pixel.h"
79#include "MagickCore/pixel-accessor.h"
80#include "MagickCore/PreRvIcccm.h"
81#include "MagickCore/property.h"
82#include "MagickCore/quantum.h"
83#include "MagickCore/quantum-private.h"
84#include "MagickCore/resize.h"
85#include "MagickCore/resource_.h"
86#include "MagickCore/shear.h"
87#include "MagickCore/segment.h"
cristy7497f482011-12-08 01:57:31 +000088#include "MagickCore/statistic.h"
cristy4c08aed2011-07-01 19:47:50 +000089#include "MagickCore/string_.h"
90#include "MagickCore/string-private.h"
91#include "MagickCore/transform.h"
92#include "MagickCore/threshold.h"
93#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000094#include "MagickCore/utility-private.h"
cristy4c08aed2011-07-01 19:47:50 +000095#include "MagickCore/version.h"
96#include "MagickCore/widget.h"
cristybcbda3f2011-09-03 13:01:22 +000097#include "MagickCore/widget-private.h"
98#include "MagickCore/xwindow.h"
cristy4c08aed2011-07-01 19:47:50 +000099#include "MagickCore/xwindow-private.h"
cristy3ed852e2009-09-05 21:47:34 +0000100
101#if defined(MAGICKCORE_X11_DELEGATE)
102/*
103 Define declarations.
104*/
cristy49e2d862010-11-12 02:50:30 +0000105#define MaxColors MagickMin((ssize_t) windows->visual_info->colormap_size,256L)
cristy3ed852e2009-09-05 21:47:34 +0000106
107/*
108 Constant declarations.
109*/
110static const unsigned char
111 HighlightBitmap[8] =
112 {
113 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55
114 },
cristydd05beb2010-11-21 21:23:39 +0000115 OpaqueBitmap[8] =
116 {
117 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
118 },
cristy3ed852e2009-09-05 21:47:34 +0000119 ShadowBitmap[8] =
120 {
121 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
122 };
123
124static 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*/
147static 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 "",
cristycee97112010-05-28 00:44:52 +0000948 " Meta-W Press to alter an image along a sine wave.",
cristy3ed852e2009-09-05 21:47:34 +0000949 "",
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*/
1341typedef enum
1342{
1343 CopyMode,
1344 CropMode,
1345 CutMode
1346} ClipboardMode;
1347
1348typedef 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
1444typedef 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
cristydd05beb2010-11-21 21:23:39 +00001517#define OpaqueWidth 8
1518#define OpaqueHeight 8
cristy3ed852e2009-09-05 21:47:34 +00001519#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*/
1531static const int
1532 RoiDelta = 8;
1533
1534static 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*/
1571static CommandType
1572 XImageWindowCommand(Display *,XResourceInfo *,XWindows *,
cristy051718b2011-08-28 22:49:25 +00001573 const MagickStatusType,KeySym,Image **,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +00001574
1575static Image
1576 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType,
cristy051718b2011-08-28 22:49:25 +00001577 Image **,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +00001578 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType),
cristy051718b2011-08-28 22:49:25 +00001579 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *,
1580 ExceptionInfo *),
1581 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *,
1582 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +00001583
1584static MagickBooleanType
cristy051718b2011-08-28 22:49:25 +00001585 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 *);
cristy3ed852e2009-09-05 21:47:34 +00001609
1610static void
1611 XDrawPanRectangle(Display *,XWindows *),
cristy051718b2011-08-28 22:49:25 +00001612 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **,
1613 ExceptionInfo *),
cristy6710d842011-10-20 23:23:00 +00001614 XMagnifyImage(Display *,XWindows *,XEvent *,ExceptionInfo *),
cristy051718b2011-08-28 22:49:25 +00001615 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
cristy6710d842011-10-20 23:23:00 +00001616 XPanImage(Display *,XWindows *,XEvent *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +00001617 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType,
cristy6710d842011-10-20 23:23:00 +00001618 const KeySym,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +00001619 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *),
cristy6710d842011-10-20 23:23:00 +00001620 XScreenEvent(Display *,XWindows *,XEvent *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +00001621 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,
cristy051718b2011-08-28 22:49:25 +00001641% Image *images,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001642%
1643% A description of each parameter follows:
1644%
1645% o image_info: the image info.
1646%
1647% o image: the image.
1648%
cristy051718b2011-08-28 22:49:25 +00001649% o exception: return any errors or warnings in this structure.
1650%
cristy3ed852e2009-09-05 21:47:34 +00001651*/
1652MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
cristy051718b2011-08-28 22:49:25 +00001653 Image *images,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001654{
1655 char
1656 *argv[1];
1657
1658 Display
1659 *display;
1660
1661 Image
1662 *image;
1663
cristybb503372010-05-27 20:51:26 +00001664 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001665 i;
1666
cristybb503372010-05-27 20:51:26 +00001667 size_t
cristy3ed852e2009-09-05 21:47:34 +00001668 state;
1669
1670 XrmDatabase
1671 resource_database;
1672
1673 XResourceInfo
1674 resource_info;
1675
1676 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001677 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001678 assert(images != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001679 assert(images->signature == MagickCoreSignature);
cristy59864562013-04-18 11:47:41 +00001680 if (IfMagickTrue(images->debug) )
cristy3ed852e2009-09-05 21:47:34 +00001681 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
1682 display=XOpenDisplay(image_info->server_name);
1683 if (display == (Display *) NULL)
1684 {
cristy051718b2011-08-28 22:49:25 +00001685 (void) ThrowMagickException(exception,GetMagickModule(),XServerError,
cristyefe601c2013-01-05 17:51:12 +00001686 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name));
cristy3ed852e2009-09-05 21:47:34 +00001687 return(MagickFalse);
1688 }
cristy051718b2011-08-28 22:49:25 +00001689 if (exception->severity != UndefinedException)
1690 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00001691 (void) XSetErrorHandler(XError);
1692 resource_database=XGetResourceDatabase(display,GetClientName());
1693 (void) ResetMagickMemory(&resource_info,0,sizeof(resource_info));
1694 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info);
1695 if (image_info->page != (char *) NULL)
1696 resource_info.image_geometry=AcquireString(image_info->page);
1697 resource_info.immutable=MagickTrue;
1698 argv[0]=AcquireString(GetClientName());
1699 state=DefaultState;
1700 for (i=0; (state & ExitState) == 0; i++)
1701 {
cristybb503372010-05-27 20:51:26 +00001702 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations))
cristy3ed852e2009-09-05 21:47:34 +00001703 break;
1704 image=GetImageFromList(images,i % GetImageListLength(images));
cristy051718b2011-08-28 22:49:25 +00001705 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state,exception);
cristy3ed852e2009-09-05 21:47:34 +00001706 }
cristye42f6582012-02-11 17:59:50 +00001707 (void) SetErrorHandler((ErrorHandler) NULL);
1708 (void) SetWarningHandler((WarningHandler) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001709 argv[0]=DestroyString(argv[0]);
1710 (void) XCloseDisplay(display);
1711 XDestroyResourceInfo(&resource_info);
cristy051718b2011-08-28 22:49:25 +00001712 if (exception->severity != UndefinedException)
cristy3ed852e2009-09-05 21:47:34 +00001713 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*/
1747MagickExport 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);
cristye1c94d92015-06-28 12:16:33 +00001757 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001758 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,
cristyefe601c2013-01-05 17:51:12 +00001764 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name));
cristy3ed852e2009-09-05 21:47:34 +00001765 return(MagickFalse);
1766 }
1767 (void) XSetErrorHandler(XError);
1768 status=XRemoteCommand(display,window,filename);
1769 (void) XCloseDisplay(display);
dirkb9dbc292015-07-26 09:50:00 +00001770 return(status != 0 ? MagickTrue : MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00001771}
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,
cristy051718b2011-08-28 22:49:25 +00001789% XResourceInfo *resource_info,XWindows *windows,Image *image,
1790% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001791%
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
cristy3ed852e2009-09-05 21:47:34 +00001805static MagickBooleanType XAnnotateEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00001806 XResourceInfo *resource_info,XWindows *windows,Image *image,
1807 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001808{
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
cristya19f1d72012-08-07 18:24:38 +00001847 static double
cristy3ed852e2009-09-05 21:47:34 +00001848 degrees = 0.0;
1849
1850 static unsigned int
1851 box_id = MaxNumberPens-2,
1852 font_id = 0,
1853 pen_id = 0;
1854
1855 char
cristy151b66d2015-04-15 10:50:31 +00001856 command[MagickPathExtent],
1857 text[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00001858
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
cristybb503372010-05-27 20:51:26 +00001881 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001882 i;
1883
1884 unsigned int
1885 height,
1886 width;
1887
cristybb503372010-05-27 20:51:26 +00001888 size_t
cristy3ed852e2009-09-05 21:47:34 +00001889 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 {
cristy59864562013-04-18 11:47:41 +00001925 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00001926 {
1927 /*
1928 Display pointer position.
1929 */
cristy151b66d2015-04-15 10:50:31 +00001930 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +00001931 x+windows->image.x,y+windows->image.y);
1932 XInfoWidget(display,windows,text);
1933 }
1934 /*
1935 Wait for next event.
1936 */
cristy6710d842011-10-20 23:23:00 +00001937 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00001938 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
cristy151b66d2015-04-15 10:50:31 +00001974 font_name[MagickPathExtent] = "fixed";
cristy3ed852e2009-09-05 21:47:34 +00001975
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;
cristy59864562013-04-18 11:47:41 +00002018 if (IfMagickTrue(transparent_pen) )
cristy3ed852e2009-09-05 21:47:34 +00002019 break;
2020 if (pen_number == (MaxNumberPens-1))
2021 {
2022 static char
cristy151b66d2015-04-15 10:50:31 +00002023 color_name[MagickPathExtent] = "gray";
cristy3ed852e2009-09-05 21:47:34 +00002024
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;
cristy59864562013-04-18 11:47:41 +00002063 if (IfMagickTrue(transparent_box) )
cristy3ed852e2009-09-05 21:47:34 +00002064 break;
2065 if (pen_number == (MaxNumberPens-1))
2066 {
2067 static char
cristy151b66d2015-04-15 10:50:31 +00002068 color_name[MagickPathExtent] = "gray";
cristy3ed852e2009-09-05 21:47:34 +00002069
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
cristy151b66d2015-04-15 10:50:31 +00002095 angle[MagickPathExtent] = "30.0";
cristy3ed852e2009-09-05 21:47:34 +00002096
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 {
cristydbdd0e32011-11-04 23:29:40 +00002121 degrees=StringToDouble(RotateMenu[entry],(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002122 break;
2123 }
2124 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:",
2125 angle);
2126 if (*angle == '\0')
2127 break;
cristydbdd0e32011-11-04 23:29:40 +00002128 degrees=StringToDouble(angle,(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002129 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;
cristy59864562013-04-18 11:47:41 +00002214 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00002215 {
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 */
cristy73bd4a52010-10-05 11:24:23 +00002256 annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info));
cristy3ed852e2009-09-05 21:47:34 +00002257 if (annotate_info == (XAnnotateInfo *) NULL)
2258 return(MagickFalse);
2259 XGetAnnotateInfo(annotate_info);
2260 annotate_info->x=x;
2261 annotate_info->y=y;
cristy59864562013-04-18 11:47:41 +00002262 if (IfMagickFalse(transparent_box) && IfMagickFalse(transparent_pen))
cristy3ed852e2009-09-05 21:47:34 +00002263 annotate_info->stencil=OpaqueStencil;
2264 else
cristy59864562013-04-18 11:47:41 +00002265 if (IfMagickFalse(transparent_box) )
cristy3ed852e2009-09-05 21:47:34 +00002266 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)
cristy49e2d862010-11-12 02:50:30 +00002273 windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL,
cristy3ed852e2009-09-05 21:47:34 +00002274 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 */
cristy6710d842011-10-20 23:23:00 +00002310 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00002311 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)
cristy49e2d862010-11-12 02:50:30 +00002547 windows->image.width/MagickMax((ssize_t)
2548 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text));
cristy3ed852e2009-09-05 21:47:34 +00002549 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
cristyf2faecf2010-05-28 19:19:36 +00002584 unsigned long
cristy3ed852e2009-09-05 21:47:34 +00002585 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,
cristy151b66d2015-04-15 10:50:31 +00002594 event.xselection.property,0L,(long) MagickPathExtent,True,XA_STRING,
cristy3ed852e2009-09-05 21:47:34 +00002595 &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 */
cristybb503372010-05-27 20:51:26 +00002602 for (i=0; i < (ssize_t) length; i++)
cristy3ed852e2009-09-05 21:47:34 +00002603 {
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)
cristy49e2d862010-11-12 02:50:30 +00002642 windows->image.width/MagickMax((ssize_t)
2643 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text));
cristy3ed852e2009-09-05 21:47:34 +00002644 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)
cristybb503372010-05-27 20:51:26 +00002695 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00002696 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)
cristybb503372010-05-27 20:51:26 +00002704 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00002705 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;
cristy151b66d2015-04-15 10:50:31 +00002718 (void) FormatLocaleString(annotate_info->geometry,MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +00002719 "%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 */
cristy7c3af952011-10-20 16:04:16 +00002725 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image,
2726 exception);
cristy3ed852e2009-09-05 21:47:34 +00002727 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 */
cristy6710d842011-10-20 23:23:00 +00002747 XConfigureImageColormap(display,resource_info,windows,image,exception);
cristy051718b2011-08-28 22:49:25 +00002748 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00002749 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,
cristy051718b2011-08-28 22:49:25 +00002768% XResourceInfo *resource_info,XWindows *windows,Image **image,
2769% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002770%
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%
cristy051718b2011-08-28 22:49:25 +00002782% o exception: return any errors or warnings in this structure.
2783%
cristy3ed852e2009-09-05 21:47:34 +00002784*/
2785static MagickBooleanType XBackgroundImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00002786 XResourceInfo *resource_info,XWindows *windows,Image **image,
2787 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002788{
2789#define BackgroundImageTag "Background/Image"
2790
2791 int
2792 status;
2793
2794 static char
cristy151b66d2015-04-15 10:50:31 +00002795 window_id[MagickPathExtent] = "root";
cristy3ed852e2009-09-05 21:47:34 +00002796
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);
cristy051718b2011-08-28 22:49:25 +00002807 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
2808 exception);
cristy3ed852e2009-09-05 21:47:34 +00002809 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;
dirkb9dbc292015-07-26 09:50:00 +00002814 background_resources.backdrop=status != 0 ? MagickTrue : MagickFalse;
cristy051718b2011-08-28 22:49:25 +00002815 status=XDisplayBackgroundImage(display,&background_resources,*image,
2816 exception);
anthony11d32022012-11-17 05:31:33 +00002817 if (IfMagickTrue(status))
cristy3ed852e2009-09-05 21:47:34 +00002818 XClientMessage(display,windows->image.id,windows->im_protocols,
2819 windows->im_retain_colors,CurrentTime);
2820 XSetCursorState(display,windows,MagickFalse);
cristy051718b2011-08-28 22:49:25 +00002821 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image,
2822 exception);
cristy3ed852e2009-09-05 21:47:34 +00002823 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,
cristy051718b2011-08-28 22:49:25 +00002842% XWindows *windows,Image **image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002843%
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%
cristy051718b2011-08-28 22:49:25 +00002855% o exception: return any errors or warnings in this structure.
2856%
cristy3ed852e2009-09-05 21:47:34 +00002857*/
2858static MagickBooleanType XChopImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00002859 XResourceInfo *resource_info,XWindows *windows,Image **image,
2860 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002861{
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
cristy151b66d2015-04-15 10:50:31 +00002888 text[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00002889
2890 Image
2891 *chop_image;
2892
2893 int
2894 id,
2895 x,
2896 y;
2897
cristya19f1d72012-08-07 18:24:38 +00002898 double
cristy3ed852e2009-09-05 21:47:34 +00002899 scale_factor;
2900
2901 RectangleInfo
2902 chop_info;
2903
2904 unsigned int
2905 distance,
2906 height,
2907 width;
2908
cristybb503372010-05-27 20:51:26 +00002909 size_t
cristy3ed852e2009-09-05 21:47:34 +00002910 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;
cristyffc870d2015-06-28 12:52:22 +00002934 (void) ResetMagickMemory(&segment_info,0,sizeof(segment_info));
cristy3ed852e2009-09-05 21:47:34 +00002935 do
2936 {
cristy59864562013-04-18 11:47:41 +00002937 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00002938 {
2939 /*
2940 Display pointer position.
2941 */
cristy151b66d2015-04-15 10:50:31 +00002942 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +00002943 x+windows->image.x,y+windows->image.y);
2944 XInfoWidget(display,windows,text);
2945 }
2946 /*
2947 Wait for next event.
2948 */
cristy6710d842011-10-20 23:23:00 +00002949 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00002950 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
cristy151b66d2015-04-15 10:50:31 +00002963 command[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00002964
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
cristy151b66d2015-04-15 10:50:31 +00003026 command[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00003027
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;
cristy59864562013-04-18 11:47:41 +00003076 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00003077 {
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 */
cristy59864562013-04-18 11:47:41 +00003112 if (IfMagickFalse(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00003113 (void) XMapWindow(display,windows->info.id);
cristy151b66d2015-04-15 10:50:31 +00003114 (void) FormatLocaleString(text,MagickPathExtent,
cristy6d8abba2010-06-03 01:10:47 +00003115 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +00003116 chop_info.height,(double) chop_info.x,(double) chop_info.y);
cristy3ed852e2009-09-05 21:47:34 +00003117 XInfoWidget(display,windows,text);
3118 XHighlightLine(display,windows->image.id,
3119 windows->image.highlight_context,&segment_info);
3120 }
3121 else
cristy59864562013-04-18 11:47:41 +00003122 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00003123 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3124 /*
3125 Wait for next event.
3126 */
cristy6710d842011-10-20 23:23:00 +00003127 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00003128 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 {
cristybb503372010-05-27 20:51:26 +00003180 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1);
cristy49e2d862010-11-12 02:50:30 +00003181 chop_info.x=(ssize_t) windows->image.x+segment_info.x1;
cristy3ed852e2009-09-05 21:47:34 +00003182 chop_info.height=0;
3183 chop_info.y=0;
3184 if (segment_info.x1 > (int) segment_info.x2)
3185 {
cristybb503372010-05-27 20:51:26 +00003186 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1);
cristy49e2d862010-11-12 02:50:30 +00003187 chop_info.x=(ssize_t) windows->image.x+segment_info.x2;
cristy3ed852e2009-09-05 21:47:34 +00003188 }
3189 }
3190 else
3191 {
3192 chop_info.width=0;
cristybb503372010-05-27 20:51:26 +00003193 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1);
cristy3ed852e2009-09-05 21:47:34 +00003194 chop_info.x=0;
cristy49e2d862010-11-12 02:50:30 +00003195 chop_info.y=(ssize_t) windows->image.y+segment_info.y1;
cristy3ed852e2009-09-05 21:47:34 +00003196 if (segment_info.y1 > segment_info.y2)
3197 {
cristy49e2d862010-11-12 02:50:30 +00003198 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1);
3199 chop_info.y=(ssize_t) windows->image.y+segment_info.y2;
cristy3ed852e2009-09-05 21:47:34 +00003200 }
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 */
cristy051718b2011-08-28 22:49:25 +00003210 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
3211 exception);
cristy3ed852e2009-09-05 21:47:34 +00003212 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);
cristya19f1d72012-08-07 18:24:38 +00003224 scale_factor=(double) width/windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +00003225 chop_info.x+=x;
cristy49e2d862010-11-12 02:50:30 +00003226 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +00003227 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5);
cristya19f1d72012-08-07 18:24:38 +00003228 scale_factor=(double) height/windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +00003229 chop_info.y+=y;
cristy49e2d862010-11-12 02:50:30 +00003230 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +00003231 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5);
3232 /*
3233 Chop image.
3234 */
cristy051718b2011-08-28 22:49:25 +00003235 chop_image=ChopImage(*image,&chop_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003236 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 */
cristy6710d842011-10-20 23:23:00 +00003244 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00003245 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00003246 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,
cristy051718b2011-08-28 22:49:25 +00003266% XResourceInfo *resource_info,XWindows *windows,Image **image,
3267% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003268%
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%
cristy051718b2011-08-28 22:49:25 +00003280% o exception: return any errors or warnings in this structure.
3281%
cristy3ed852e2009-09-05 21:47:34 +00003282*/
cristy3ed852e2009-09-05 21:47:34 +00003283static MagickBooleanType XColorEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00003284 XResourceInfo *resource_info,XWindows *windows,Image **image,
3285 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003286{
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
cristy151b66d2015-04-15 10:50:31 +00003322 command[MagickPathExtent],
3323 text[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00003324
3325 Cursor
3326 cursor;
3327
cristy3ed852e2009-09-05 21:47:34 +00003328 int
3329 entry,
3330 id,
3331 x,
3332 x_offset,
3333 y,
3334 y_offset;
3335
cristy4c08aed2011-07-01 19:47:50 +00003336 register Quantum
cristy3ed852e2009-09-05 21:47:34 +00003337 *q;
3338
cristybb503372010-05-27 20:51:26 +00003339 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003340 i;
3341
3342 unsigned int
3343 height,
3344 width;
3345
cristybb503372010-05-27 20:51:26 +00003346 size_t
cristy3ed852e2009-09-05 21:47:34 +00003347 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 {
cristy59864562013-04-18 11:47:41 +00003379 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00003380 {
3381 /*
3382 Display pointer position.
3383 */
cristy151b66d2015-04-15 10:50:31 +00003384 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +00003385 x+windows->image.x,y+windows->image.y);
3386 XInfoWidget(display,windows,text);
3387 }
3388 /*
3389 Wait for next event.
3390 */
cristy6710d842011-10-20 23:23:00 +00003391 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00003392 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 */
cristy042ee782011-04-22 18:48:30 +00003413 methods=(char **) GetCommandOptions(MagickMethodOptions);
cristy3ed852e2009-09-05 21:47:34 +00003414 if (methods == (char **) NULL)
3415 break;
3416 entry=XMenuWidget(display,windows,ColorEditMenu[id],
3417 (const char **) methods,command);
3418 if (entry >= 0)
cristy042ee782011-04-22 18:48:30 +00003419 method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
cristy3ed852e2009-09-05 21:47:34 +00003420 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
cristy151b66d2015-04-15 10:50:31 +00003449 color_name[MagickPathExtent] = "gray";
cristy3ed852e2009-09-05 21:47:34 +00003450
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
cristy151b66d2015-04-15 10:50:31 +00003495 color_name[MagickPathExtent] = "gray";
cristy3ed852e2009-09-05 21:47:34 +00003496
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
cristy151b66d2015-04-15 10:50:31 +00003515 fuzz[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00003516
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 {
cristydbdd0e32011-11-04 23:29:40 +00003538 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double)
cristy40a08ad2010-02-09 02:27:44 +00003539 QuantumRange+1.0);
cristy3ed852e2009-09-05 21:47:34 +00003540 break;
3541 }
cristy151b66d2015-04-15 10:50:31 +00003542 (void) (void) CopyMagickString(fuzz,"20%",MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00003543 (void) XDialogWidget(display,windows,"Ok",
3544 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
3545 if (*fuzz == '\0')
3546 break;
cristy151b66d2015-04-15 10:50:31 +00003547 (void) ConcatenateMagickString(fuzz,"%",MagickPathExtent);
cristy9b34e302011-11-05 02:15:45 +00003548 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+
3549 1.0);
cristy3ed852e2009-09-05 21:47:34 +00003550 break;
3551 }
3552 case ColorEditUndoCommand:
3553 {
3554 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
cristy051718b2011-08-28 22:49:25 +00003555 image,exception);
cristy3ed852e2009-09-05 21:47:34 +00003556 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,
cristy051718b2011-08-28 22:49:25 +00003593 SaveToUndoBufferCommand,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00003594 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;
cristy6710d842011-10-20 23:23:00 +00003609 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00003610 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00003611 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;
cristy59864562013-04-18 11:47:41 +00003671 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00003672 {
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 {
cristy49e2d862010-11-12 02:50:30 +00003696 CacheView
3697 *image_view;
3698
cristy3ed852e2009-09-05 21:47:34 +00003699 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;
cristy49e2d862010-11-12 02:50:30 +00003723 if ((x_offset >= (int) (*image)->columns) ||
3724 (y_offset >= (int) (*image)->rows))
cristy3ed852e2009-09-05 21:47:34 +00003725 continue;
cristy6f5395d2012-12-14 18:30:30 +00003726 image_view=AcquireAuthenticCacheView(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00003727 switch (method)
3728 {
3729 case PointMethod:
3730 default:
3731 {
3732 /*
3733 Update color information using point algorithm.
3734 */
cristy59864562013-04-18 11:47:41 +00003735 if (IfMagickFalse(SetImageStorageClass(*image,DirectClass,exception)) )
cristy3ed852e2009-09-05 21:47:34 +00003736 return(MagickFalse);
cristy49e2d862010-11-12 02:50:30 +00003737 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset,
cristy574cc262011-08-05 01:23:58 +00003738 (ssize_t) y_offset,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003739 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003740 break;
cristy4c08aed2011-07-01 19:47:50 +00003741 SetPixelRed(*image,ScaleShortToQuantum(color.red),q);
3742 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q);
3743 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q);
cristy051718b2011-08-28 22:49:25 +00003744 (void) SyncCacheViewAuthenticPixels(image_view,exception);
cristy3ed852e2009-09-05 21:47:34 +00003745 break;
3746 }
3747 case ReplaceMethod:
3748 {
cristy101ab702011-10-13 13:06:32 +00003749 PixelInfo
cristy4c08aed2011-07-01 19:47:50 +00003750 pixel,
cristy3ed852e2009-09-05 21:47:34 +00003751 target;
3752
3753 /*
3754 Update color information using replace algorithm.
3755 */
cristyf05d4942012-03-17 16:26:09 +00003756 (void) GetOneCacheViewVirtualPixelInfo(image_view,(ssize_t)
3757 x_offset,(ssize_t) y_offset,&target,exception);
cristy3ed852e2009-09-05 21:47:34 +00003758 if ((*image)->storage_class == DirectClass)
3759 {
cristy49e2d862010-11-12 02:50:30 +00003760 for (y=0; y < (int) (*image)->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003761 {
cristy49e2d862010-11-12 02:50:30 +00003762 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
3763 (*image)->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003764 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003765 break;
3766 for (x=0; x < (int) (*image)->columns; x++)
3767 {
cristy101ab702011-10-13 13:06:32 +00003768 GetPixelInfoPixel(*image,q,&pixel);
3769 if (IsFuzzyEquivalencePixelInfo(&pixel,&target))
cristy3ed852e2009-09-05 21:47:34 +00003770 {
cristy4c08aed2011-07-01 19:47:50 +00003771 SetPixelRed(*image,ScaleShortToQuantum(
3772 color.red),q);
3773 SetPixelGreen(*image,ScaleShortToQuantum(
3774 color.green),q);
3775 SetPixelBlue(*image,ScaleShortToQuantum(
3776 color.blue),q);
cristy3ed852e2009-09-05 21:47:34 +00003777 }
cristyed231572011-07-14 02:18:59 +00003778 q+=GetPixelChannels(*image);
cristy3ed852e2009-09-05 21:47:34 +00003779 }
cristy59864562013-04-18 11:47:41 +00003780 if (IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) )
cristy3ed852e2009-09-05 21:47:34 +00003781 break;
3782 }
3783 }
3784 else
3785 {
cristy49e2d862010-11-12 02:50:30 +00003786 for (i=0; i < (ssize_t) (*image)->colors; i++)
cristy101ab702011-10-13 13:06:32 +00003787 if (IsFuzzyEquivalencePixelInfo((*image)->colormap+i,&target))
cristy3ed852e2009-09-05 21:47:34 +00003788 {
cristye42f6582012-02-11 17:59:50 +00003789 (*image)->colormap[i].red=(double) ScaleShortToQuantum(
cristy4c08aed2011-07-01 19:47:50 +00003790 color.red);
cristye42f6582012-02-11 17:59:50 +00003791 (*image)->colormap[i].green=(double) ScaleShortToQuantum(
cristy3ed852e2009-09-05 21:47:34 +00003792 color.green);
cristye42f6582012-02-11 17:59:50 +00003793 (*image)->colormap[i].blue=(double) ScaleShortToQuantum(
cristy3ed852e2009-09-05 21:47:34 +00003794 color.blue);
3795 }
cristyea1a8aa2011-10-20 13:24:06 +00003796 (void) SyncImage(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00003797 }
3798 break;
3799 }
3800 case FloodfillMethod:
3801 case FillToBorderMethod:
3802 {
3803 DrawInfo
3804 *draw_info;
3805
cristy4c08aed2011-07-01 19:47:50 +00003806 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00003807 target;
3808
3809 /*
3810 Update color information using floodfill algorithm.
3811 */
cristy3aa93752011-12-18 15:54:24 +00003812 (void) GetOneVirtualPixelInfo(*image,
cristy52010022011-10-21 18:07:37 +00003813 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t)
3814 y_offset,&target,exception);
cristy3ed852e2009-09-05 21:47:34 +00003815 if (method == FillToBorderMethod)
3816 {
cristya19f1d72012-08-07 18:24:38 +00003817 target.red=(double)
cristy3ed852e2009-09-05 21:47:34 +00003818 ScaleShortToQuantum(border_color.red);
cristya19f1d72012-08-07 18:24:38 +00003819 target.green=(double)
cristy3ed852e2009-09-05 21:47:34 +00003820 ScaleShortToQuantum(border_color.green);
cristya19f1d72012-08-07 18:24:38 +00003821 target.blue=(double)
cristy3ed852e2009-09-05 21:47:34 +00003822 ScaleShortToQuantum(border_color.blue);
3823 }
3824 draw_info=CloneDrawInfo(resource_info->image_info,
3825 (DrawInfo *) NULL);
cristy9950d572011-10-01 18:22:35 +00003826 (void) QueryColorCompliance(resource_info->pen_colors[pen_id],
3827 AllCompliance,&draw_info->fill,exception);
anthony11d32022012-11-17 05:31:33 +00003828 (void) FloodfillPaintImage(*image,draw_info,&target,
3829 (ssize_t)x_offset,(ssize_t)y_offset,
dirkb9dbc292015-07-26 09:50:00 +00003830 method != FloodfillMethod ? MagickTrue : MagickFalse,exception);
cristy3ed852e2009-09-05 21:47:34 +00003831 draw_info=DestroyDrawInfo(draw_info);
3832 break;
3833 }
3834 case ResetMethod:
3835 {
3836 /*
3837 Update color information using reset algorithm.
3838 */
cristy59864562013-04-18 11:47:41 +00003839 if (IfMagickFalse(SetImageStorageClass(*image,DirectClass,exception)) )
cristy3ed852e2009-09-05 21:47:34 +00003840 return(MagickFalse);
cristy49e2d862010-11-12 02:50:30 +00003841 for (y=0; y < (int) (*image)->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003842 {
cristy49e2d862010-11-12 02:50:30 +00003843 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
3844 (*image)->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003845 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003846 break;
3847 for (x=0; x < (int) (*image)->columns; x++)
3848 {
cristy4c08aed2011-07-01 19:47:50 +00003849 SetPixelRed(*image,ScaleShortToQuantum(color.red),q);
3850 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q);
3851 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q);
cristyed231572011-07-14 02:18:59 +00003852 q+=GetPixelChannels(*image);
cristy3ed852e2009-09-05 21:47:34 +00003853 }
cristy59864562013-04-18 11:47:41 +00003854 if (IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) )
cristy3ed852e2009-09-05 21:47:34 +00003855 break;
3856 }
3857 break;
3858 }
3859 }
cristy49e2d862010-11-12 02:50:30 +00003860 image_view=DestroyCacheView(image_view);
cristy3ed852e2009-09-05 21:47:34 +00003861 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,
cristy051718b2011-08-28 22:49:25 +00003889% XResourceInfo *resource_info,XWindows *windows,Image *image,
3890% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003891%
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%
cristy051718b2011-08-28 22:49:25 +00003903% o exception: return any errors or warnings in this structure.
3904%
cristy3ed852e2009-09-05 21:47:34 +00003905*/
3906static MagickBooleanType XCompositeImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00003907 XResourceInfo *resource_info,XWindows *windows,Image *image,
3908 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003909{
3910 static char
cristy151b66d2015-04-15 10:50:31 +00003911 displacement_geometry[MagickPathExtent] = "30x30",
3912 filename[MagickPathExtent] = "\0";
cristy3ed852e2009-09-05 21:47:34 +00003913
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
cristy151b66d2015-04-15 10:50:31 +00003939 text[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00003940
3941 Cursor
3942 cursor;
3943
3944 Image
3945 *composite_image;
3946
3947 int
3948 entry,
3949 id,
3950 x,
3951 y;
3952
cristya19f1d72012-08-07 18:24:38 +00003953 double
cristy3ed852e2009-09-05 21:47:34 +00003954 blend,
3955 scale_factor;
3956
3957 RectangleInfo
3958 highlight_info,
3959 composite_info;
3960
3961 unsigned int
3962 height,
3963 width;
3964
cristybb503372010-05-27 20:51:26 +00003965 size_t
cristy3ed852e2009-09-05 21:47:34 +00003966 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,
cristy151b66d2015-04-15 10:50:31 +00003983 MagickPathExtent);
cristy051718b2011-08-28 22:49:25 +00003984 composite_image=ReadImage(resource_info->image_info,exception);
3985 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00003986 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);
cristy49e2d862010-11-12 02:50:30 +00004004 composite_info.x=(ssize_t) windows->image.x+x;
4005 composite_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +00004006 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 {
cristy59864562013-04-18 11:47:41 +00004014 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00004015 {
4016 /*
4017 Display pointer position.
4018 */
cristy151b66d2015-04-15 10:50:31 +00004019 (void) FormatLocaleString(text,MagickPathExtent," %+ld%+ld ",
cristyf2faecf2010-05-28 19:19:36 +00004020 (long) composite_info.x,(long) composite_info.y);
cristy3ed852e2009-09-05 21:47:34 +00004021 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 */
cristy6710d842011-10-20 23:23:00 +00004031 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00004032 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
cristy151b66d2015-04-15 10:50:31 +00004047 command[MagickPathExtent],
cristy3ed852e2009-09-05 21:47:34 +00004048 **operators;
4049
4050 /*
4051 Select a command from the pop-up menu.
4052 */
cristy042ee782011-04-22 18:48:30 +00004053 operators=GetCommandOptions(MagickComposeOptions);
cristy3ed852e2009-09-05 21:47:34 +00004054 if (operators == (char **) NULL)
4055 break;
4056 entry=XMenuWidget(display,windows,CompositeMenu[id],
4057 (const char **) operators,command);
4058 if (entry >= 0)
cristy042ee782011-04-22 18:48:30 +00004059 compose=(CompositeOperator) ParseCommandOption(
cristy3ed852e2009-09-05 21:47:34 +00004060 MagickComposeOptions,MagickFalse,operators[entry]);
4061 operators=DestroyStringList(operators);
4062 break;
4063 }
4064 case CompositeDissolveCommand:
4065 {
4066 static char
cristy151b66d2015-04-15 10:50:31 +00004067 factor[MagickPathExtent] = "20.0";
cristy3ed852e2009-09-05 21:47:34 +00004068
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;
cristydbdd0e32011-11-04 23:29:40 +00004080 blend=StringToDouble(factor,(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004081 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 {
cristy59864562013-04-18 11:47:41 +00004128 if (IfMagickTrue(image->debug) )
cristy3ed852e2009-09-05 21:47:34 +00004129 (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);
cristy49e2d862010-11-12 02:50:30 +00004142 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4143 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +00004144 break;
4145 }
4146 case ButtonRelease:
4147 {
cristy59864562013-04-18 11:47:41 +00004148 if (IfMagickTrue(image->debug) )
cristy3ed852e2009-09-05 21:47:34 +00004149 (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 */
cristy49e2d862010-11-12 02:50:30 +00004161 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4162 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +00004163 state|=ExitState;
4164 }
4165 break;
4166 }
4167 case Expose:
4168 break;
4169 case KeyPress:
4170 {
4171 char
cristy151b66d2015-04-15 10:50:31 +00004172 command[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00004173
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';
cristy59864562013-04-18 11:47:41 +00004188 if (IfMagickTrue(image->debug) )
cristy3ed852e2009-09-05 21:47:34 +00004189 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristyf2faecf2010-05-28 19:19:36 +00004190 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command);
cristy3ed852e2009-09-05 21:47:34 +00004191 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;
cristy59864562013-04-18 11:47:41 +00004230 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00004231 {
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);
cristy49e2d862010-11-12 02:50:30 +00004241 composite_info.x=(ssize_t) windows->image.x+x;
4242 composite_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +00004243 break;
4244 }
4245 default:
4246 {
cristy59864562013-04-18 11:47:41 +00004247 if (IfMagickTrue(image->debug) )
cristy3ed852e2009-09-05 21:47:34 +00004248 (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);
cristya19f1d72012-08-07 18:24:38 +00004272 scale_factor=(double) width/windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +00004273 composite_info.x+=x;
cristy49e2d862010-11-12 02:50:30 +00004274 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +00004275 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5);
cristya19f1d72012-08-07 18:24:38 +00004276 scale_factor=(double) height/windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +00004277 composite_info.y+=y;
cristy49e2d862010-11-12 02:50:30 +00004278 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +00004279 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 */
cristy15b98cd2010-09-12 19:42:50 +00004289 resize_image=ResizeImage(composite_image,composite_info.width,
cristyaa2c16c2012-03-25 22:21:35 +00004290 composite_info.height,composite_image->filter,exception);
cristy3ed852e2009-09-05 21:47:34 +00004291 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 {
cristy49e2d862010-11-12 02:50:30 +00004304 CacheView
4305 *image_view;
4306
cristy3ed852e2009-09-05 21:47:34 +00004307 int
4308 y;
4309
4310 Quantum
4311 opacity;
4312
4313 register int
4314 x;
4315
cristy4c08aed2011-07-01 19:47:50 +00004316 register Quantum
cristy3ed852e2009-09-05 21:47:34 +00004317 *q;
4318
4319 /*
4320 Create mattes for blending.
4321 */
cristy63240882011-08-05 19:05:27 +00004322 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel,exception);
cristy6e963d82012-06-19 15:23:24 +00004323 opacity=(Quantum) (ScaleQuantumToChar(QuantumRange)-
4324 ((ssize_t) ScaleQuantumToChar(QuantumRange)*blend)/100);
cristy59864562013-04-18 11:47:41 +00004325 if (IfMagickFalse(SetImageStorageClass(image,DirectClass,exception)) )
cristy3ed852e2009-09-05 21:47:34 +00004326 return(MagickFalse);
cristy8a46d822012-08-28 23:32:39 +00004327 image->alpha_trait=BlendPixelTrait;
cristy46ff2672012-12-14 15:32:26 +00004328 image_view=AcquireAuthenticCacheView(image,exception);
cristy49e2d862010-11-12 02:50:30 +00004329 for (y=0; y < (int) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004330 {
cristy49e2d862010-11-12 02:50:30 +00004331 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1,
4332 exception);
cristy4c08aed2011-07-01 19:47:50 +00004333 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004334 break;
4335 for (x=0; x < (int) image->columns; x++)
4336 {
cristy4c08aed2011-07-01 19:47:50 +00004337 SetPixelAlpha(image,opacity,q);
cristyed231572011-07-14 02:18:59 +00004338 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00004339 }
cristy59864562013-04-18 11:47:41 +00004340 if (IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) )
cristy3ed852e2009-09-05 21:47:34 +00004341 break;
4342 }
cristy49e2d862010-11-12 02:50:30 +00004343 image_view=DestroyCacheView(image_view);
cristy3ed852e2009-09-05 21:47:34 +00004344 }
4345 /*
4346 Composite image with X Image window.
4347 */
cristy39172402012-03-30 13:04:39 +00004348 (void) CompositeImage(image,composite_image,compose,MagickTrue,
cristyfeb3e962012-03-29 17:25:55 +00004349 composite_info.x,composite_info.y,exception);
cristy3ed852e2009-09-05 21:47:34 +00004350 composite_image=DestroyImage(composite_image);
4351 XSetCursorState(display,windows,MagickFalse);
4352 /*
4353 Update image configuration.
4354 */
cristy6710d842011-10-20 23:23:00 +00004355 XConfigureImageColormap(display,resource_info,windows,image,exception);
cristy051718b2011-08-28 22:49:25 +00004356 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00004357 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,
cristy051718b2011-08-28 22:49:25 +00004377% XResourceInfo *resource_info,XWindows *windows,Image *image,
4378% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004379%
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%
cristy051718b2011-08-28 22:49:25 +00004391% o exception: return any errors or warnings in this structure.
4392%
4393% o exception: return any errors or warnings in this structure.
cristy3ed852e2009-09-05 21:47:34 +00004394%
4395*/
4396static MagickBooleanType XConfigureImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00004397 XResourceInfo *resource_info,XWindows *windows,Image *image,
4398 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004399{
4400 char
cristy151b66d2015-04-15 10:50:31 +00004401 geometry[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00004402
cristy3ed852e2009-09-05 21:47:34 +00004403 MagickStatusType
4404 status;
4405
cristybb503372010-05-27 20:51:26 +00004406 size_t
cristy3ed852e2009-09-05 21:47:34 +00004407 mask,
4408 height,
4409 width;
4410
cristy9d314ff2011-03-09 01:30:28 +00004411 ssize_t
4412 x,
4413 y;
4414
cristy3ed852e2009-09-05 21:47:34 +00004415 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;
cristy59864562013-04-18 11:47:41 +00004426 if (IfMagickTrue(image->debug) )
cristy3ed852e2009-09-05 21:47:34 +00004427 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +00004428 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width,
4429 windows->image.ximage->height,(double) width,(double) height);
cristy3ed852e2009-09-05 21:47:34 +00004430 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,
cristy051718b2011-08-28 22:49:25 +00004450 (unsigned int) width,(unsigned int) height,exception);
cristy59864562013-04-18 11:47:41 +00004451 if (IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00004452 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)
cristy151b66d2015-04-15 10:50:31 +00004458 (void) FormatLocaleString(geometry,MagickPathExtent,"%s>!",
cristy3ed852e2009-09-05 21:47:34 +00004459 resource_info->image_geometry);
4460 else
cristy151b66d2015-04-15 10:50:31 +00004461 (void) FormatLocaleString(geometry,MagickPathExtent,"%ux%u+0+0>!",
cristy3ed852e2009-09-05 21:47:34 +00004462 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);
cristybb503372010-05-27 20:51:26 +00004471 mask=(size_t) (CWWidth | CWHeight);
cristy3ed852e2009-09-05 21:47:34 +00004472 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 */
cristy59864562013-04-18 11:47:41 +00004487 if (IfMagickTrue(windows->magnify.mapped) )
cristy6710d842011-10-20 23:23:00 +00004488 XMakeMagnifyImage(display,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +00004489 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);
dirkb9dbc292015-07-26 09:50:00 +00004530 return(status != 0 ? MagickTrue : MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00004531}
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,
cristy051718b2011-08-28 22:49:25 +00004552% const ClipboardMode mode,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004553%
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%
cristy051718b2011-08-28 22:49:25 +00004568% o exception: return any errors or warnings in this structure.
4569%
cristy3ed852e2009-09-05 21:47:34 +00004570*/
4571static MagickBooleanType XCropImage(Display *display,
4572 XResourceInfo *resource_info,XWindows *windows,Image *image,
cristy051718b2011-08-28 22:49:25 +00004573 const ClipboardMode mode,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004574{
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
cristy49e2d862010-11-12 02:50:30 +00004603 CacheView
4604 *image_view;
4605
cristy3ed852e2009-09-05 21:47:34 +00004606 char
cristy151b66d2015-04-15 10:50:31 +00004607 command[MagickPathExtent],
4608 text[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00004609
4610 Cursor
4611 cursor;
4612
cristy3ed852e2009-09-05 21:47:34 +00004613 int
4614 id,
4615 x,
4616 y;
4617
4618 KeySym
4619 key_symbol;
4620
4621 Image
4622 *crop_image;
4623
cristya19f1d72012-08-07 18:24:38 +00004624 double
cristy3ed852e2009-09-05 21:47:34 +00004625 scale_factor;
4626
4627 RectangleInfo
4628 crop_info,
4629 highlight_info;
4630
cristy4c08aed2011-07-01 19:47:50 +00004631 register Quantum
cristy3ed852e2009-09-05 21:47:34 +00004632 *q;
4633
4634 unsigned int
4635 height,
4636 width;
4637
cristybb503372010-05-27 20:51:26 +00004638 size_t
cristy3ed852e2009-09-05 21:47:34 +00004639 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);
cristy49e2d862010-11-12 02:50:30 +00004677 crop_info.x=(ssize_t) windows->image.x+x;
4678 crop_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +00004679 crop_info.width=0;
4680 crop_info.height=0;
4681 cursor=XCreateFontCursor(display,XC_fleur);
4682 state=DefaultState;
4683 do
4684 {
cristy59864562013-04-18 11:47:41 +00004685 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00004686 {
4687 /*
4688 Display pointer position.
4689 */
cristy151b66d2015-04-15 10:50:31 +00004690 (void) FormatLocaleString(text,MagickPathExtent," %+ld%+ld ",
cristyf2faecf2010-05-28 19:19:36 +00004691 (long) crop_info.x,(long) crop_info.y);
cristy3ed852e2009-09-05 21:47:34 +00004692 XInfoWidget(display,windows,text);
4693 }
4694 /*
4695 Wait for next event.
4696 */
cristy6710d842011-10-20 23:23:00 +00004697 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00004698 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);
cristy49e2d862010-11-12 02:50:30 +00004759 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4760 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +00004761 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;
cristy59864562013-04-18 11:47:41 +00004832 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00004833 {
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);
cristy49e2d862010-11-12 02:50:30 +00004843 crop_info.x=(ssize_t) windows->image.x+x;
4844 crop_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +00004845 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 */
cristy59864562013-04-18 11:47:41 +00004883 if (IfMagickFalse(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00004884 (void) XMapWindow(display,windows->info.id);
cristy151b66d2015-04-15 10:50:31 +00004885 (void) FormatLocaleString(text,MagickPathExtent,
cristy6d8abba2010-06-03 01:10:47 +00004886 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +00004887 crop_info.height,(double) crop_info.x,(double) crop_info.y);
cristy3ed852e2009-09-05 21:47:34 +00004888 XInfoWidget(display,windows,text);
4889 XHighlightRectangle(display,windows->image.id,
4890 windows->image.highlight_context,&highlight_info);
4891 }
4892 else
cristy59864562013-04-18 11:47:41 +00004893 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00004894 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
4895 /*
4896 Wait for next event.
4897 */
cristy6710d842011-10-20 23:23:00 +00004898 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00004899 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 {
cristy49e2d862010-11-12 02:50:30 +00004906 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4907 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +00004908 break;
4909 }
4910 case ButtonRelease:
4911 {
4912 /*
4913 User has committed to cropping rectangle.
4914 */
cristy49e2d862010-11-12 02:50:30 +00004915 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4916 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +00004917 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 {
cristy49e2d862010-11-12 02:50:30 +00004928 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x;
4929 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y;
cristy3ed852e2009-09-05 21:47:34 +00004930 }
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
cristy49e2d862010-11-12 02:50:30 +00004943 if (crop_info.x > (ssize_t) windows->image.ximage->width)
4944 crop_info.x=(ssize_t) windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +00004945 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);
cristy49e2d862010-11-12 02:50:30 +00004950 crop_info.x=(ssize_t) x;
cristy3ed852e2009-09-05 21:47:34 +00004951 }
4952 if (crop_info.y < 0)
4953 crop_info.y=0;
4954 else
cristy49e2d862010-11-12 02:50:30 +00004955 if (crop_info.y > (ssize_t) windows->image.ximage->height)
4956 crop_info.y=(ssize_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +00004957 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);
cristy49e2d862010-11-12 02:50:30 +00004962 crop_info.y=(ssize_t) y;
cristy3ed852e2009-09-05 21:47:34 +00004963 }
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 {
cristy59864562013-04-18 11:47:41 +00004973 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00004974 {
4975 /*
4976 Display pointer position.
4977 */
cristy151b66d2015-04-15 10:50:31 +00004978 (void) FormatLocaleString(text,MagickPathExtent,
cristy6d8abba2010-06-03 01:10:47 +00004979 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +00004980 crop_info.height,(double) crop_info.x,(double) crop_info.y);
cristy3ed852e2009-09-05 21:47:34 +00004981 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);
cristy6710d842011-10-20 23:23:00 +00004994 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00004995 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 {
cristybb503372010-05-27 20:51:26 +00005074 crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
5075 crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
cristy3ed852e2009-09-05 21:47:34 +00005076 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 {
cristybb503372010-05-27 20:51:26 +00005084 crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
cristy3ed852e2009-09-05 21:47:34 +00005085 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 {
cristybb503372010-05-27 20:51:26 +00005093 crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
cristy3ed852e2009-09-05 21:47:34 +00005094 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 {
cristyccdef732015-05-31 14:14:16 +00005155 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);
cristy3ed852e2009-09-05 21:47:34 +00005159 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;
cristy59864562013-04-18 11:47:41 +00005238 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00005239 {
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);
cristy49e2d862010-11-12 02:50:30 +00005249 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x;
5250 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y;
cristy3ed852e2009-09-05 21:47:34 +00005251 break;
5252 }
5253 case SelectionRequest:
5254 {
5255 XSelectionEvent
5256 notify;
5257
5258 XSelectionRequestEvent
5259 *request;
5260
5261 /*
5262 Set primary selection.
5263 */
cristy151b66d2015-04-15 10:50:31 +00005264 (void) FormatLocaleString(text,MagickPathExtent,
cristy6d8abba2010-06-03 01:10:47 +00005265 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +00005266 crop_info.height,(double) crop_info.x,(double) crop_info.y);
cristy3ed852e2009-09-05 21:47:34 +00005267 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 *) &notify);
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;
cristy051718b2011-08-28 22:49:25 +00005309 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00005310 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);
cristya19f1d72012-08-07 18:24:38 +00005323 scale_factor=(double) width/windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +00005324 crop_info.x+=x;
cristy49e2d862010-11-12 02:50:30 +00005325 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +00005326 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
cristya19f1d72012-08-07 18:24:38 +00005327 scale_factor=(double) height/windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +00005328 crop_info.y+=y;
cristy49e2d862010-11-12 02:50:30 +00005329 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +00005330 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5);
cristy051718b2011-08-28 22:49:25 +00005331 crop_image=CropImage(image,&crop_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00005332 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 {
cristy051718b2011-08-28 22:49:25 +00005340 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00005341 return(MagickTrue);
5342 }
5343 /*
5344 Cut image.
5345 */
cristy59864562013-04-18 11:47:41 +00005346 if (IfMagickFalse(SetImageStorageClass(image,DirectClass,exception)) )
cristy3ed852e2009-09-05 21:47:34 +00005347 return(MagickFalse);
cristy8a46d822012-08-28 23:32:39 +00005348 image->alpha_trait=BlendPixelTrait;
cristy46ff2672012-12-14 15:32:26 +00005349 image_view=AcquireAuthenticCacheView(image,exception);
cristy49e2d862010-11-12 02:50:30 +00005350 for (y=0; y < (int) crop_info.height; y++)
cristy3ed852e2009-09-05 21:47:34 +00005351 {
cristy49e2d862010-11-12 02:50:30 +00005352 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y,
5353 crop_info.width,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00005354 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00005355 break;
5356 for (x=0; x < (int) crop_info.width; x++)
5357 {
cristy4c08aed2011-07-01 19:47:50 +00005358 SetPixelAlpha(image,TransparentAlpha,q);
cristyed231572011-07-14 02:18:59 +00005359 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00005360 }
cristy59864562013-04-18 11:47:41 +00005361 if (IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) )
cristy3ed852e2009-09-05 21:47:34 +00005362 break;
5363 }
cristy49e2d862010-11-12 02:50:30 +00005364 image_view=DestroyCacheView(image_view);
cristy3ed852e2009-09-05 21:47:34 +00005365 /*
5366 Update image configuration.
5367 */
cristy6710d842011-10-20 23:23:00 +00005368 XConfigureImageColormap(display,resource_info,windows,image,exception);
cristy051718b2011-08-28 22:49:25 +00005369 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00005370 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,
cristy051718b2011-08-28 22:49:25 +00005390% XResourceInfo *resource_info,XWindows *windows,Image **image,
5391% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00005392%
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%
cristy051718b2011-08-28 22:49:25 +00005404% o exception: return any errors or warnings in this structure.
5405%
cristy3ed852e2009-09-05 21:47:34 +00005406*/
5407static MagickBooleanType XDrawEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00005408 XResourceInfo *resource_info,XWindows *windows,Image **image,
5409 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00005410{
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
cristy151b66d2015-04-15 10:50:31 +00005447 command[MagickPathExtent],
5448 text[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00005449
5450 Cursor
5451 cursor;
5452
5453 int
5454 entry,
5455 id,
5456 number_coordinates,
5457 x,
5458 y;
5459
cristya19f1d72012-08-07 18:24:38 +00005460 double
cristy3ed852e2009-09-05 21:47:34 +00005461 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
cristybb503372010-05-27 20:51:26 +00005478 size_t
cristy3ed852e2009-09-05 21:47:34 +00005479 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 {
cristy051718b2011-08-28 22:49:25 +00005504 (void) ThrowMagickException(exception,GetMagickModule(),
cristyefe601c2013-01-05 17:51:12 +00005505 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
cristy3ed852e2009-09-05 21:47:34 +00005506 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 {
cristy59864562013-04-18 11:47:41 +00005533 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00005534 {
5535 /*
5536 Display pointer position.
5537 */
cristy151b66d2015-04-15 10:50:31 +00005538 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +00005539 x+windows->image.x,y+windows->image.y);
5540 XInfoWidget(display,windows,text);
5541 }
5542 /*
5543 Wait for next event.
5544 */
cristy6710d842011-10-20 23:23:00 +00005545 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00005546 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;
cristy59864562013-04-18 11:47:41 +00005612 if (IfMagickTrue(transparent) )
cristy3ed852e2009-09-05 21:47:34 +00005613 {
5614 draw_info.stencil=TransparentStencil;
5615 break;
5616 }
5617 if (pen_number == (MaxNumberPens-1))
5618 {
5619 static char
cristy151b66d2015-04-15 10:50:31 +00005620 color_name[MagickPathExtent] = "gray";
cristy3ed852e2009-09-05 21:47:34 +00005621
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
cristy151b66d2015-04-15 10:50:31 +00005654 filename[MagickPathExtent] = "\0";
cristy3ed852e2009-09-05 21:47:34 +00005655
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;
cristy3ed852e2009-09-05 21:47:34 +00005681 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:
cristy3ed852e2009-09-05 21:47:34 +00005716 {
5717 stipple=XCreateBitmapFromData(display,root_window,
5718 (char *) HighlightBitmap,HighlightWidth,
5719 HighlightHeight);
5720 break;
5721 }
cristydd05beb2010-11-21 21:23:39 +00005722 case 6:
5723 default:
5724 {
5725 stipple=XCreateBitmapFromData(display,root_window,
5726 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight);
5727 break;
5728 }
cristy3ed852e2009-09-05 21:47:34 +00005729 }
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,
cristy151b66d2015-04-15 10:50:31 +00005742 MagickPathExtent);
cristy051718b2011-08-28 22:49:25 +00005743 stipple_image=ReadImage(image_info,exception);
5744 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00005745 XSetCursorState(display,windows,MagickFalse);
5746 if (stipple_image == (Image *) NULL)
5747 break;
5748 (void) AcquireUniqueFileResource(filename);
cristy151b66d2015-04-15 10:50:31 +00005749 (void) FormatLocaleString(stipple_image->filename,MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +00005750 "xbm:%s",filename);
cristy051718b2011-08-28 22:49:25 +00005751 (void) WriteImage(image_info,stipple_image,exception);
cristy3ed852e2009-09-05 21:47:34 +00005752 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
cristy151b66d2015-04-15 10:50:31 +00005765 width[MagickPathExtent] = "0";
cristy3ed852e2009-09-05 21:47:34 +00005766
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 {
cristydd05beb2010-11-21 21:23:39 +00005788 line_width=(unsigned int) StringToUnsignedLong(
5789 WidthsMenu[entry]);
cristy3ed852e2009-09-05 21:47:34 +00005790 break;
5791 }
5792 (void) XDialogWidget(display,windows,"Ok","Enter line width:",
5793 width);
5794 if (*width == '\0')
5795 break;
cristye27293e2009-12-18 02:53:20 +00005796 line_width=(unsigned int) StringToUnsignedLong(width);
cristy3ed852e2009-09-05 21:47:34 +00005797 break;
5798 }
5799 case DrawUndoCommand:
5800 {
5801 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
cristy051718b2011-08-28 22:49:25 +00005802 image,exception);
cristy3ed852e2009-09-05 21:47:34 +00005803 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;
cristy59864562013-04-18 11:47:41 +00005893 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00005894 {
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;
cristy49e2d862010-11-12 02:50:30 +00005922 rectangle_info.x=(ssize_t) x;
5923 rectangle_info.y=(ssize_t) y;
cristy3ed852e2009-09-05 21:47:34 +00005924 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);
cristy151b66d2015-04-15 10:50:31 +00005943 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d",
cristy3ed852e2009-09-05 21:47:34 +00005944 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)));
cristy151b66d2015-04-15 10:50:31 +00005959 (void) FormatLocaleString(text,MagickPathExtent," %g",
cristy3ed852e2009-09-05 21:47:34 +00005960 (double) degrees);
5961 XInfoWidget(display,windows,text);
5962 XHighlightLine(display,windows->image.id,
5963 windows->image.highlight_context,&line_info);
5964 }
5965 else
cristy59864562013-04-18 11:47:41 +00005966 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00005967 (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 */
cristy151b66d2015-04-15 10:50:31 +00005979 (void) FormatLocaleString(text,MagickPathExtent,
cristy6d8abba2010-06-03 01:10:47 +00005980 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
cristye8c25f92010-06-03 00:53:06 +00005981 (double) rectangle_info.height,(double) rectangle_info.x,
5982 (double) rectangle_info.y);
cristy3ed852e2009-09-05 21:47:34 +00005983 XInfoWidget(display,windows,text);
5984 XHighlightRectangle(display,windows->image.id,
5985 windows->image.highlight_context,&rectangle_info);
5986 }
5987 else
cristy59864562013-04-18 11:47:41 +00005988 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00005989 (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 */
cristy151b66d2015-04-15 10:50:31 +00006003 (void) FormatLocaleString(text,MagickPathExtent,
cristy6d8abba2010-06-03 01:10:47 +00006004 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
cristye8c25f92010-06-03 00:53:06 +00006005 (double) rectangle_info.height,(double) rectangle_info.x,
6006 (double) rectangle_info.y);
cristy3ed852e2009-09-05 21:47:34 +00006007 XInfoWidget(display,windows,text);
6008 XHighlightEllipse(display,windows->image.id,
6009 windows->image.highlight_context,&rectangle_info);
6010 }
6011 else
cristy59864562013-04-18 11:47:41 +00006012 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00006013 (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)));
cristy151b66d2015-04-15 10:50:31 +00006031 (void) FormatLocaleString(text,MagickPathExtent," %g",
cristy3ed852e2009-09-05 21:47:34 +00006032 (double) degrees);
6033 XInfoWidget(display,windows,text);
6034 XHighlightLine(display,windows->image.id,
6035 windows->image.highlight_context,&line_info);
6036 }
6037 else
cristy59864562013-04-18 11:47:41 +00006038 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00006039 (void) XWithdrawWindow(display,windows->info.id,
6040 windows->info.screen);
6041 break;
6042 }
6043 }
6044 /*
6045 Wait for next event.
6046 */
cristy6710d842011-10-20 23:23:00 +00006047 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00006048 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;
cristy49e2d862010-11-12 02:50:30 +00006108 rectangle_info.x=(ssize_t) event.xbutton.x;
6109 rectangle_info.y=(ssize_t) event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +00006110 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)
cristy051718b2011-08-28 22:49:25 +00006129 (void) ThrowMagickException(exception,GetMagickModule(),
cristyefe601c2013-01-05 17:51:12 +00006130 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
cristy3ed852e2009-09-05 21:47:34 +00006131 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;
cristy49e2d862010-11-12 02:50:30 +00006143 rectangle_info.x=(ssize_t) event.xmotion.x;
6144 rectangle_info.y=(ssize_t) event.xmotion.y;
cristy3ed852e2009-09-05 21:47:34 +00006145 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)
cristy051718b2011-08-28 22:49:25 +00006156 (void) ThrowMagickException(exception,GetMagickModule(),
cristyefe601c2013-01-05 17:51:12 +00006157 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
cristy3ed852e2009-09-05 21:47:34 +00006158 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
cristy49e2d862010-11-12 02:50:30 +00006185 if (rectangle_info.x > (ssize_t) windows->image.width)
cristybb503372010-05-27 20:51:26 +00006186 rectangle_info.x=(ssize_t) windows->image.width;
cristy3ed852e2009-09-05 21:47:34 +00006187 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);
cristy49e2d862010-11-12 02:50:30 +00006192 rectangle_info.x=(ssize_t) x;
cristy3ed852e2009-09-05 21:47:34 +00006193 }
6194 if (rectangle_info.y < 0)
6195 rectangle_info.y=0;
6196 else
cristy49e2d862010-11-12 02:50:30 +00006197 if (rectangle_info.y > (ssize_t) windows->image.height)
cristybb503372010-05-27 20:51:26 +00006198 rectangle_info.y=(ssize_t) windows->image.height;
cristy3ed852e2009-09-05 21:47:34 +00006199 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);
cristy49e2d862010-11-12 02:50:30 +00006204 rectangle_info.y=(ssize_t) y;
cristy3ed852e2009-09-05 21:47:34 +00006205 }
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 */
cristy49e2d862010-11-12 02:50:30 +00006215 rectangle_info.x=(ssize_t) coordinate_info->x;
6216 rectangle_info.y=(ssize_t) coordinate_info->y;
cristy3ed852e2009-09-05 21:47:34 +00006217 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;
cristy49e2d862010-11-12 02:50:30 +00006225 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);
cristy3ed852e2009-09-05 21:47:34 +00006229 }
cristybb503372010-05-27 20:51:26 +00006230 rectangle_info.width=(size_t) (x-rectangle_info.x);
6231 rectangle_info.height=(size_t) (y-rectangle_info.y);
cristy3ed852e2009-09-05 21:47:34 +00006232 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,
cristy051718b2011-08-28 22:49:25 +00006254 image,exception);
cristy3ed852e2009-09-05 21:47:34 +00006255 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;
cristy151b66d2015-04-15 10:50:31 +00006275 (void) FormatLocaleString(draw_info.geometry,MagickPathExtent,"%ux%u%+d%+d",
cristy3ed852e2009-09-05 21:47:34 +00006276 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;
cristy49e2d862010-11-12 02:50:30 +00006309 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2))
cristybb503372010-05-27 20:51:26 +00006310 draw_info.rectangle_info.x=(ssize_t) line_width/2;
cristy49e2d862010-11-12 02:50:30 +00006311 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2))
cristybb503372010-05-27 20:51:26 +00006312 draw_info.rectangle_info.y=(ssize_t) line_width/2;
cristy3ed852e2009-09-05 21:47:34 +00006313 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);
cristy6710d842011-10-20 23:23:00 +00006321 status=XDrawImage(display,windows->pixel_info,&draw_info,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00006322 XSetCursorState(display,windows,MagickFalse);
6323 /*
6324 Update image colormap and return to image drawing.
6325 */
cristy6710d842011-10-20 23:23:00 +00006326 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00006327 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00006328 }
6329 XSetCursorState(display,windows,MagickFalse);
6330 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info);
dirkb9dbc292015-07-26 09:50:00 +00006331 return(status != 0 ? MagickTrue : MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00006332}
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*/
6361static void XDrawPanRectangle(Display *display,XWindows *windows)
6362{
cristya19f1d72012-08-07 18:24:38 +00006363 double
cristy3ed852e2009-09-05 21:47:34 +00006364 scale_factor;
6365
6366 RectangleInfo
6367 highlight_info;
6368
6369 /*
6370 Determine dimensions of the panning rectangle.
6371 */
cristya19f1d72012-08-07 18:24:38 +00006372 scale_factor=(double) windows->pan.width/windows->image.ximage->width;
cristy49e2d862010-11-12 02:50:30 +00006373 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +00006374 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5);
cristya19f1d72012-08-07 18:24:38 +00006375 scale_factor=(double)
cristy3ed852e2009-09-05 21:47:34 +00006376 windows->pan.height/windows->image.ximage->height;
cristy49e2d862010-11-12 02:50:30 +00006377 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +00006378 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,
cristy051718b2011-08-28 22:49:25 +00006404% XWindows *windows,const CommandType command,Image **image,
6405% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00006406%
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%
cristya9a86bb2011-01-13 01:11:00 +00006418% o image: the image; XImageCache may transform the image and return a new
6419% image pointer.
cristy3ed852e2009-09-05 21:47:34 +00006420%
cristy051718b2011-08-28 22:49:25 +00006421% o exception: return any errors or warnings in this structure.
6422%
cristy3ed852e2009-09-05 21:47:34 +00006423*/
6424static void XImageCache(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +00006425 XWindows *windows,const CommandType command,Image **image,
6426 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00006427{
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 {
cristya9a86bb2011-01-13 01:11:00 +00006457 char
cristy151b66d2015-04-15 10:50:31 +00006458 image_geometry[MagickPathExtent];
cristya9a86bb2011-01-13 01:11:00 +00006459
cristy3ed852e2009-09-05 21:47:34 +00006460 /*
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;
cristy151b66d2015-04-15 10:50:31 +00006472 (void) FormatLocaleString(image_geometry,MagickPathExtent,"%dx%d!",
cristya9a86bb2011-01-13 01:11:00 +00006473 windows->image.ximage->width,windows->image.ximage->height);
cristye941a752011-10-15 01:52:48 +00006474 (void) TransformImage(image,windows->image.crop_geometry,image_geometry,
6475 exception);
cristy3ed852e2009-09-05 21:47:34 +00006476 if (windows->image.crop_geometry != (char *) NULL)
cristye941a752011-10-15 01:52:48 +00006477 windows->image.crop_geometry=(char *) RelinquishMagickMemory(
6478 windows->image.crop_geometry);
cristy3ed852e2009-09-05 21:47:34 +00006479 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);
cristy59864562013-04-18 11:47:41 +00006485 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00006486 return;
cristy6710d842011-10-20 23:23:00 +00006487 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00006488 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00006489 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
cristybb503372010-05-27 20:51:26 +00006555 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00006556 bytes;
6557
cristy101ab702011-10-13 13:06:32 +00006558 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelInfo));
cristy3ed852e2009-09-05 21:47:34 +00006559 if (undo_image != (Image *) NULL)
6560 {
6561 /*
cristya9a86bb2011-01-13 01:11:00 +00006562 Ensure the undo cache has enough memory available.
cristy3ed852e2009-09-05 21:47:34 +00006563 */
6564 previous_image=undo_image;
6565 while (previous_image != (Image *) NULL)
6566 {
6567 bytes+=previous_image->list->columns*previous_image->list->rows*
cristy101ab702011-10-13 13:06:32 +00006568 sizeof(PixelInfo);
cristybb503372010-05-27 20:51:26 +00006569 if (bytes <= (ssize_t) (resource_info->undo_cache << 20))
cristy3ed852e2009-09-05 21:47:34 +00006570 {
6571 previous_image=GetPreviousImageInList(previous_image);
6572 continue;
6573 }
6574 bytes-=previous_image->list->columns*previous_image->list->rows*
cristy101ab702011-10-13 13:06:32 +00006575 sizeof(PixelInfo);
cristy3ed852e2009-09-05 21:47:34 +00006576 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 }
cristybb503372010-05-27 20:51:26 +00006593 if (bytes > (ssize_t) (resource_info->undo_cache << 20))
cristy3ed852e2009-09-05 21:47:34 +00006594 break;
6595 /*
6596 Save image before transformations are applied.
6597 */
cristy9950d572011-10-01 18:22:35 +00006598 cache_image=AcquireImage((ImageInfo *) NULL,exception);
cristy3ed852e2009-09-05 21:47:34 +00006599 if (cache_image == (Image *) NULL)
6600 break;
6601 XSetCursorState(display,windows,MagickTrue);
6602 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00006603 cache_image->list=CloneImage(*image,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +00006604 XSetCursorState(display,windows,MagickFalse);
6605 if (cache_image->list == (Image *) NULL)
6606 {
6607 cache_image=DestroyImage(cache_image);
6608 break;
6609 }
cristybb503372010-05-27 20:51:26 +00006610 cache_image->columns=(size_t) windows->image.ximage->width;
6611 cache_image->rows=(size_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +00006612 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,
cristy151b66d2015-04-15 10:50:31 +00006617 windows->image.crop_geometry,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00006618 }
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();
cristy59864562013-04-18 11:47:41 +00006651 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00006652 return;
cristy6710d842011-10-20 23:23:00 +00006653 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00006654 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00006655 return;
6656 }
6657 if (command != InfoCommand)
6658 return;
6659 /*
6660 Display image info.
6661 */
6662 XSetCursorState(display,windows,MagickTrue);
6663 XCheckRefreshWindows(display,windows);
cristy6710d842011-10-20 23:23:00 +00006664 XDisplayImageInfo(display,resource_info,windows,undo_image,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00006665 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%
cristy051718b2011-08-28 22:49:25 +00006682% The format of the XImageWindowCommand method is:
cristy3ed852e2009-09-05 21:47:34 +00006683%
6684% CommandType XImageWindowCommand(Display *display,
6685% XResourceInfo *resource_info,XWindows *windows,
cristy051718b2011-08-28 22:49:25 +00006686% const MagickStatusType state,KeySym key_symbol,Image **image,
6687% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00006688%
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%
cristy051718b2011-08-28 22:49:25 +00006706% 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.
cristy3ed852e2009-09-05 21:47:34 +00006710%
6711*/
6712static CommandType XImageWindowCommand(Display *display,
6713 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state,
cristy051718b2011-08-28 22:49:25 +00006714 KeySym key_symbol,Image **image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00006715{
6716 static char
cristy151b66d2015-04-15 10:50:31 +00006717 delta[MagickPathExtent] = "";
cristy3ed852e2009-09-05 21:47:34 +00006718
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];
cristyf2f27272009-12-17 14:48:46 +00006735 resource_info->quantum=StringToLong(delta);
cristy3ed852e2009-09-05 21:47:34 +00006736 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;
cristybb503372010-05-27 20:51:26 +00007014 crop_info.width=(size_t) windows->image.ximage->width;
7015 crop_info.height=(size_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +00007016 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);
cristy051718b2011-08-28 22:49:25 +00007052 (void) XConfigureImage(display,resource_info,windows,*image,
7053 exception);
cristy3ed852e2009-09-05 21:47:34 +00007054 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,
cristy051718b2011-08-28 22:49:25 +00007082% XWindows *windows,const CommandType command,Image **image,
7083% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00007084%
7085% A description of each parameter follows:
7086%
cristy3ed852e2009-09-05 21:47:34 +00007087% 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%
cristy051718b2011-08-28 22:49:25 +00007096% 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.
cristy3ed852e2009-09-05 21:47:34 +00007100%
7101*/
7102static Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +00007103 XWindows *windows,const CommandType command,Image **image,
7104 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00007105{
7106 char
cristy151b66d2015-04-15 10:50:31 +00007107 filename[MagickPathExtent],
7108 geometry[MagickPathExtent],
7109 modulate_factors[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00007110
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
cristy151b66d2015-04-15 10:50:31 +00007138 color[MagickPathExtent] = "gray";
cristy3ed852e2009-09-05 21:47:34 +00007139
7140 unsigned int
7141 height,
7142 width;
7143
7144 /*
7145 Process user command.
7146 */
7147 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007148 XImageCache(display,resource_info,windows,command,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007149 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 */
cristy8a5d7f42013-01-06 15:24:33 +00007193 if (*resource_info->home_directory == '\0')
7194 (void) CopyMagickString(resource_info->home_directory,".",
cristy151b66d2015-04-15 10:50:31 +00007195 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00007196 status=chdir(resource_info->home_directory);
7197 if (status == -1)
cristy051718b2011-08-28 22:49:25 +00007198 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
7199 "UnableToOpenFile","%s",resource_info->home_directory);
cristy3ed852e2009-09-05 21:47:34 +00007200 nexus=XOpenImage(display,resource_info,windows,MagickTrue);
7201 break;
7202 }
7203 case SaveCommand:
7204 {
7205 /*
7206 Save image.
7207 */
cristy051718b2011-08-28 22:49:25 +00007208 status=XSaveImage(display,resource_info,windows,*image,exception);
cristy59864562013-04-18 11:47:41 +00007209 if (IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00007210 {
cristyc663dbd2011-09-16 19:43:14 +00007211 char
cristy151b66d2015-04-15 10:50:31 +00007212 message[MagickPathExtent];
cristyc663dbd2011-09-16 19:43:14 +00007213
cristy151b66d2015-04-15 10:50:31 +00007214 (void) FormatLocaleString(message,MagickPathExtent,"%s:%s",
cristyc663dbd2011-09-16 19:43:14 +00007215 exception->reason != (char *) NULL ? exception->reason : "",
7216 exception->description != (char *) NULL ? exception->description :
7217 "");
7218 XNoticeWidget(display,windows,"Unable to save file:",message);
cristy3ed852e2009-09-05 21:47:34 +00007219 break;
7220 }
7221 break;
7222 }
7223 case PrintCommand:
7224 {
7225 /*
7226 Print image.
7227 */
cristy051718b2011-08-28 22:49:25 +00007228 status=XPrintImage(display,resource_info,windows,*image,exception);
cristy59864562013-04-18 11:47:41 +00007229 if (IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00007230 {
cristyc663dbd2011-09-16 19:43:14 +00007231 char
cristy151b66d2015-04-15 10:50:31 +00007232 message[MagickPathExtent];
cristyc663dbd2011-09-16 19:43:14 +00007233
cristy151b66d2015-04-15 10:50:31 +00007234 (void) FormatLocaleString(message,MagickPathExtent,"%s:%s",
cristyc663dbd2011-09-16 19:43:14 +00007235 exception->reason != (char *) NULL ? exception->reason : "",
7236 exception->description != (char *) NULL ? exception->description :
7237 "");
7238 XNoticeWidget(display,windows,"Unable to print file:",message);
cristy3ed852e2009-09-05 21:47:34 +00007239 break;
7240 }
7241 break;
7242 }
7243 case DeleteCommand:
7244 {
7245 static char
cristy151b66d2015-04-15 10:50:31 +00007246 filename[MagickPathExtent] = "\0";
cristy3ed852e2009-09-05 21:47:34 +00007247
7248 /*
7249 Delete image file.
7250 */
7251 XFileBrowserWidget(display,windows,"Delete",filename);
7252 if (*filename == '\0')
7253 break;
cristy59864562013-04-18 11:47:41 +00007254 status=ShredFile(filename);
7255 if (IfMagickTrue(status) )
cristy3ed852e2009-09-05 21:47:34 +00007256 XNoticeWidget(display,windows,"Unable to delete image file:",filename);
7257 break;
7258 }
7259 case NewCommand:
7260 {
7261 int
7262 status;
7263
7264 static char
cristy151b66d2015-04-15 10:50:31 +00007265 color[MagickPathExtent] = "gray",
7266 geometry[MagickPathExtent] = "640x480";
cristy3ed852e2009-09-05 21:47:34 +00007267
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 */
cristy151b66d2015-04-15 10:50:31 +00007286 (void) FormatLocaleString(image_info->filename,MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +00007287 "%s:%s",format,color);
7288 (void) CloneString(&image_info->size,geometry);
cristy051718b2011-08-28 22:49:25 +00007289 nexus=ReadImage(image_info,exception);
7290 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00007291 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 */
cristy051718b2011-08-28 22:49:25 +00007300 nexus=XVisualDirectoryImage(display,resource_info,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +00007301 break;
7302 }
7303 case QuitCommand:
7304 {
7305 /*
7306 exit program.
7307 */
cristy59864562013-04-18 11:47:41 +00007308 if (IfMagickFalse(resource_info->confirm_exit) )
cristy3ed852e2009-09-05 21:47:34 +00007309 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 */
cristy051718b2011-08-28 22:49:25 +00007332 (void) XCropImage(display,resource_info,windows,*image,CutMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00007333 break;
7334 }
7335 case CopyCommand:
7336 {
7337 /*
7338 Copy image.
7339 */
cristy051718b2011-08-28 22:49:25 +00007340 (void) XCropImage(display,resource_info,windows,*image,CopyMode,
7341 exception);
cristy3ed852e2009-09-05 21:47:34 +00007342 break;
7343 }
7344 case PasteCommand:
7345 {
7346 /*
7347 Paste image.
7348 */
cristy051718b2011-08-28 22:49:25 +00007349 status=XPasteImage(display,resource_info,windows,*image,exception);
cristy59864562013-04-18 11:47:41 +00007350 if (IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00007351 {
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;
cristy051718b2011-08-28 22:49:25 +00007365 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007366 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;
cristy051718b2011-08-28 22:49:25 +00007375 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007376 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;
cristy051718b2011-08-28 22:49:25 +00007385 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007386 break;
7387 }
7388 case ResizeCommand:
7389 {
7390 int
7391 status;
7392
cristybb503372010-05-27 20:51:26 +00007393 size_t
cristy3ed852e2009-09-05 21:47:34 +00007394 height,
7395 width;
7396
cristy9d314ff2011-03-09 01:30:28 +00007397 ssize_t
7398 x,
7399 y;
7400
cristy3ed852e2009-09-05 21:47:34 +00007401 /*
7402 Resize image.
7403 */
cristybb503372010-05-27 20:51:26 +00007404 width=(size_t) windows->image.ximage->width;
7405 height=(size_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +00007406 x=0;
7407 y=0;
cristy151b66d2015-04-15 10:50:31 +00007408 (void) FormatLocaleString(geometry,MagickPathExtent,"%.20gx%.20g+0+0",
cristye8c25f92010-06-03 00:53:06 +00007409 (double) width,(double) height);
cristy3ed852e2009-09-05 21:47:34 +00007410 status=XDialogWidget(display,windows,"Resize",
7411 "Enter resize geometry (e.g. 640x480, 200%):",geometry);
7412 if (*geometry == '\0')
7413 break;
7414 if (status == 0)
cristy151b66d2015-04-15 10:50:31 +00007415 (void) ConcatenateMagickString(geometry,"!",MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00007416 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
7417 windows->image.window_changes.width=(int) width;
7418 windows->image.window_changes.height=(int) height;
cristy051718b2011-08-28 22:49:25 +00007419 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007420 break;
7421 }
7422 case ApplyCommand:
7423 {
7424 char
cristy151b66d2015-04-15 10:50:31 +00007425 image_geometry[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00007426
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 */
cristy151b66d2015-04-15 10:50:31 +00007439 (void) FormatLocaleString(image_geometry,MagickPathExtent,"%dx%d!",
cristy3ed852e2009-09-05 21:47:34 +00007440 windows->image.ximage->width,windows->image.ximage->height);
cristye941a752011-10-15 01:52:48 +00007441 (void) TransformImage(image,windows->image.crop_geometry,image_geometry,
7442 exception);
cristy3ed852e2009-09-05 21:47:34 +00007443 if (windows->image.crop_geometry != (char *) NULL)
cristye941a752011-10-15 01:52:48 +00007444 windows->image.crop_geometry=(char *) RelinquishMagickMemory(
7445 windows->image.crop_geometry);
cristy3ed852e2009-09-05 21:47:34 +00007446 windows->image.x=0;
7447 windows->image.y=0;
cristy6710d842011-10-20 23:23:00 +00007448 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007449 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007450 break;
7451 }
7452 case RefreshCommand:
7453 {
cristy051718b2011-08-28 22:49:25 +00007454 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007455 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 }
cristy6710d842011-10-20 23:23:00 +00007479 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007480 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007481 break;
7482 }
7483 case CropCommand:
7484 {
7485 /*
7486 Crop image.
7487 */
cristy051718b2011-08-28 22:49:25 +00007488 (void) XCropImage(display,resource_info,windows,*image,CropMode,
7489 exception);
cristy3ed852e2009-09-05 21:47:34 +00007490 break;
7491 }
7492 case ChopCommand:
7493 {
7494 /*
7495 Chop image.
7496 */
cristy051718b2011-08-28 22:49:25 +00007497 status=XChopImage(display,resource_info,windows,image,exception);
cristy59864562013-04-18 11:47:41 +00007498 if (IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00007499 {
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);
cristy051718b2011-08-28 22:49:25 +00007516 flop_image=FlopImage(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007517 if (flop_image != (Image *) NULL)
7518 {
7519 *image=DestroyImage(*image);
7520 *image=flop_image;
7521 }
cristy051718b2011-08-28 22:49:25 +00007522 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00007523 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);
cristy151b66d2015-04-15 10:50:31 +00007533 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +00007534 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y);
7535 }
cristy59864562013-04-18 11:47:41 +00007536 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007537 break;
cristy051718b2011-08-28 22:49:25 +00007538 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007539 break;
7540 }
7541 case FlipCommand:
7542 {
7543 Image
7544 *flip_image;
7545
7546 /*
7547 Flip image scanlines.
7548 */
7549 XSetCursorState(display,windows,MagickTrue);
7550 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007551 flip_image=FlipImage(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007552 if (flip_image != (Image *) NULL)
7553 {
7554 *image=DestroyImage(*image);
7555 *image=flip_image;
7556 }
cristy051718b2011-08-28 22:49:25 +00007557 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00007558 XSetCursorState(display,windows,MagickFalse);
7559 if (windows->image.crop_geometry != (char *) NULL)
7560 {
7561 /*
7562 Flip crop geometry.
7563 */
7564 width=(unsigned int) (*image)->columns;
7565 height=(unsigned int) (*image)->rows;
7566 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7567 &width,&height);
cristy151b66d2015-04-15 10:50:31 +00007568 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +00007569 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y);
7570 }
cristy59864562013-04-18 11:47:41 +00007571 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007572 break;
cristy051718b2011-08-28 22:49:25 +00007573 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007574 break;
7575 }
7576 case RotateRightCommand:
7577 {
7578 /*
7579 Rotate image 90 degrees clockwise.
7580 */
cristy051718b2011-08-28 22:49:25 +00007581 status=XRotateImage(display,resource_info,windows,90.0,image,exception);
cristy59864562013-04-18 11:47:41 +00007582 if (IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00007583 {
7584 XNoticeWidget(display,windows,"Unable to rotate X image",
7585 (*image)->filename);
7586 break;
7587 }
7588 break;
7589 }
7590 case RotateLeftCommand:
7591 {
7592 /*
7593 Rotate image 90 degrees counter-clockwise.
7594 */
cristy051718b2011-08-28 22:49:25 +00007595 status=XRotateImage(display,resource_info,windows,-90.0,image,exception);
cristy59864562013-04-18 11:47:41 +00007596 if (IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00007597 {
7598 XNoticeWidget(display,windows,"Unable to rotate X image",
7599 (*image)->filename);
7600 break;
7601 }
7602 break;
7603 }
7604 case RotateCommand:
7605 {
7606 /*
7607 Rotate image.
7608 */
cristy051718b2011-08-28 22:49:25 +00007609 status=XRotateImage(display,resource_info,windows,0.0,image,exception);
cristy59864562013-04-18 11:47:41 +00007610 if (IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00007611 {
7612 XNoticeWidget(display,windows,"Unable to rotate X image",
7613 (*image)->filename);
7614 break;
7615 }
7616 break;
7617 }
7618 case ShearCommand:
7619 {
7620 Image
7621 *shear_image;
7622
7623 static char
cristy151b66d2015-04-15 10:50:31 +00007624 geometry[MagickPathExtent] = "45.0x45.0";
cristy3ed852e2009-09-05 21:47:34 +00007625
7626 /*
7627 Query user for shear color and geometry.
7628 */
7629 XColorBrowserWidget(display,windows,"Select",color);
7630 if (*color == '\0')
7631 break;
7632 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:",
7633 geometry);
7634 if (*geometry == '\0')
7635 break;
7636 /*
7637 Shear image.
7638 */
cristy051718b2011-08-28 22:49:25 +00007639 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
7640 exception);
cristy3ed852e2009-09-05 21:47:34 +00007641 XSetCursorState(display,windows,MagickTrue);
7642 XCheckRefreshWindows(display,windows);
cristy9950d572011-10-01 18:22:35 +00007643 (void) QueryColorCompliance(color,AllCompliance,
7644 &(*image)->background_color,exception);
cristy3ed852e2009-09-05 21:47:34 +00007645 flags=ParseGeometry(geometry,&geometry_info);
7646 if ((flags & SigmaValue) == 0)
7647 geometry_info.sigma=geometry_info.rho;
7648 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma,
cristy051718b2011-08-28 22:49:25 +00007649 exception);
cristy3ed852e2009-09-05 21:47:34 +00007650 if (shear_image != (Image *) NULL)
7651 {
7652 *image=DestroyImage(*image);
7653 *image=shear_image;
7654 }
cristy051718b2011-08-28 22:49:25 +00007655 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00007656 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00007657 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007658 break;
7659 windows->image.window_changes.width=(int) (*image)->columns;
7660 windows->image.window_changes.height=(int) (*image)->rows;
cristy6710d842011-10-20 23:23:00 +00007661 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007662 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007663 break;
7664 }
7665 case RollCommand:
7666 {
7667 Image
7668 *roll_image;
7669
7670 static char
cristy151b66d2015-04-15 10:50:31 +00007671 geometry[MagickPathExtent] = "+2+2";
cristy3ed852e2009-09-05 21:47:34 +00007672
7673 /*
7674 Query user for the roll geometry.
7675 */
7676 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:",
7677 geometry);
7678 if (*geometry == '\0')
7679 break;
7680 /*
7681 Roll image.
7682 */
cristy051718b2011-08-28 22:49:25 +00007683 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
7684 exception);
cristy3ed852e2009-09-05 21:47:34 +00007685 XSetCursorState(display,windows,MagickTrue);
7686 XCheckRefreshWindows(display,windows);
7687 (void) ParsePageGeometry(*image,geometry,&page_geometry,
cristy051718b2011-08-28 22:49:25 +00007688 exception);
cristy3ed852e2009-09-05 21:47:34 +00007689 roll_image=RollImage(*image,page_geometry.x,page_geometry.y,
cristy051718b2011-08-28 22:49:25 +00007690 exception);
cristy3ed852e2009-09-05 21:47:34 +00007691 if (roll_image != (Image *) NULL)
7692 {
7693 *image=DestroyImage(*image);
7694 *image=roll_image;
7695 }
cristy051718b2011-08-28 22:49:25 +00007696 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00007697 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00007698 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007699 break;
7700 windows->image.window_changes.width=(int) (*image)->columns;
7701 windows->image.window_changes.height=(int) (*image)->rows;
cristy6710d842011-10-20 23:23:00 +00007702 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007703 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007704 break;
7705 }
7706 case TrimCommand:
7707 {
7708 static char
cristy151b66d2015-04-15 10:50:31 +00007709 fuzz[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00007710
7711 /*
7712 Query user for the fuzz factor.
7713 */
cristy151b66d2015-04-15 10:50:31 +00007714 (void) FormatLocaleString(fuzz,MagickPathExtent,"%g%%",100.0*
cristy8cd5b312010-01-07 01:10:24 +00007715 (*image)->fuzz/(QuantumRange+1.0));
cristy3ed852e2009-09-05 21:47:34 +00007716 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz);
7717 if (*fuzz == '\0')
7718 break;
cristydbdd0e32011-11-04 23:29:40 +00007719 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+1.0);
cristy3ed852e2009-09-05 21:47:34 +00007720 /*
7721 Trim image.
7722 */
cristy051718b2011-08-28 22:49:25 +00007723 status=XTrimImage(display,resource_info,windows,*image,exception);
cristy59864562013-04-18 11:47:41 +00007724 if (IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00007725 {
7726 XNoticeWidget(display,windows,"Unable to trim X image",
7727 (*image)->filename);
7728 break;
7729 }
7730 break;
7731 }
7732 case HueCommand:
7733 {
7734 static char
cristy151b66d2015-04-15 10:50:31 +00007735 hue_percent[MagickPathExtent] = "110";
cristy3ed852e2009-09-05 21:47:34 +00007736
7737 /*
7738 Query user for percent hue change.
7739 */
7740 (void) XDialogWidget(display,windows,"Apply",
7741 "Enter percent change in image hue (0-200):",hue_percent);
7742 if (*hue_percent == '\0')
7743 break;
7744 /*
7745 Vary the image hue.
7746 */
7747 XSetCursorState(display,windows,MagickTrue);
7748 XCheckRefreshWindows(display,windows);
cristy151b66d2015-04-15 10:50:31 +00007749 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00007750 (void) ConcatenateMagickString(modulate_factors,hue_percent,
cristy151b66d2015-04-15 10:50:31 +00007751 MagickPathExtent);
cristy051718b2011-08-28 22:49:25 +00007752 (void) ModulateImage(*image,modulate_factors,exception);
cristy3ed852e2009-09-05 21:47:34 +00007753 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00007754 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007755 break;
cristy6710d842011-10-20 23:23:00 +00007756 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007757 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007758 break;
7759 }
7760 case SaturationCommand:
7761 {
7762 static char
cristy151b66d2015-04-15 10:50:31 +00007763 saturation_percent[MagickPathExtent] = "110";
cristy3ed852e2009-09-05 21:47:34 +00007764
7765 /*
7766 Query user for percent saturation change.
7767 */
7768 (void) XDialogWidget(display,windows,"Apply",
7769 "Enter percent change in color saturation (0-200):",saturation_percent);
7770 if (*saturation_percent == '\0')
7771 break;
7772 /*
7773 Vary color saturation.
7774 */
7775 XSetCursorState(display,windows,MagickTrue);
7776 XCheckRefreshWindows(display,windows);
cristy151b66d2015-04-15 10:50:31 +00007777 (void) CopyMagickString(modulate_factors,"100.0/",MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00007778 (void) ConcatenateMagickString(modulate_factors,saturation_percent,
cristy151b66d2015-04-15 10:50:31 +00007779 MagickPathExtent);
cristy051718b2011-08-28 22:49:25 +00007780 (void) ModulateImage(*image,modulate_factors,exception);
cristy3ed852e2009-09-05 21:47:34 +00007781 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00007782 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007783 break;
cristy6710d842011-10-20 23:23:00 +00007784 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007785 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007786 break;
7787 }
7788 case BrightnessCommand:
7789 {
7790 static char
cristy151b66d2015-04-15 10:50:31 +00007791 brightness_percent[MagickPathExtent] = "110";
cristy3ed852e2009-09-05 21:47:34 +00007792
7793 /*
7794 Query user for percent brightness change.
7795 */
7796 (void) XDialogWidget(display,windows,"Apply",
7797 "Enter percent change in color brightness (0-200):",brightness_percent);
7798 if (*brightness_percent == '\0')
7799 break;
7800 /*
7801 Vary the color brightness.
7802 */
7803 XSetCursorState(display,windows,MagickTrue);
7804 XCheckRefreshWindows(display,windows);
7805 (void) CopyMagickString(modulate_factors,brightness_percent,
cristy151b66d2015-04-15 10:50:31 +00007806 MagickPathExtent);
cristy051718b2011-08-28 22:49:25 +00007807 (void) ModulateImage(*image,modulate_factors,exception);
cristy3ed852e2009-09-05 21:47:34 +00007808 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00007809 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007810 break;
cristy6710d842011-10-20 23:23:00 +00007811 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007812 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007813 break;
7814 }
7815 case GammaCommand:
7816 {
7817 static char
cristy151b66d2015-04-15 10:50:31 +00007818 factor[MagickPathExtent] = "1.6";
cristy3ed852e2009-09-05 21:47:34 +00007819
7820 /*
7821 Query user for gamma value.
7822 */
7823 (void) XDialogWidget(display,windows,"Gamma",
cristy50fbc382011-07-07 02:19:17 +00007824 "Enter gamma value (e.g. 1.2):",factor);
cristy3ed852e2009-09-05 21:47:34 +00007825 if (*factor == '\0')
7826 break;
7827 /*
7828 Gamma correct image.
7829 */
7830 XSetCursorState(display,windows,MagickTrue);
7831 XCheckRefreshWindows(display,windows);
cristy79d05312014-12-25 18:13:29 +00007832 (void) GammaImage(*image,strtod(factor,(char **) NULL),exception);
cristy3ed852e2009-09-05 21:47:34 +00007833 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00007834 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007835 break;
cristy6710d842011-10-20 23:23:00 +00007836 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007837 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007838 break;
7839 }
7840 case SpiffCommand:
7841 {
7842 /*
7843 Sharpen the image contrast.
7844 */
7845 XSetCursorState(display,windows,MagickTrue);
7846 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007847 (void) ContrastImage(*image,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +00007848 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00007849 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007850 break;
cristy6710d842011-10-20 23:23:00 +00007851 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007852 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007853 break;
7854 }
7855 case DullCommand:
7856 {
7857 /*
7858 Dull the image contrast.
7859 */
7860 XSetCursorState(display,windows,MagickTrue);
7861 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007862 (void) ContrastImage(*image,MagickFalse,exception);
cristy3ed852e2009-09-05 21:47:34 +00007863 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00007864 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007865 break;
cristy6710d842011-10-20 23:23:00 +00007866 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007867 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007868 break;
7869 }
7870 case ContrastStretchCommand:
7871 {
7872 double
7873 black_point,
7874 white_point;
7875
7876 static char
cristy151b66d2015-04-15 10:50:31 +00007877 levels[MagickPathExtent] = "1%";
cristy3ed852e2009-09-05 21:47:34 +00007878
7879 /*
7880 Query user for gamma value.
7881 */
7882 (void) XDialogWidget(display,windows,"Contrast Stretch",
7883 "Enter black and white points:",levels);
7884 if (*levels == '\0')
7885 break;
7886 /*
7887 Contrast stretch image.
7888 */
7889 XSetCursorState(display,windows,MagickTrue);
7890 XCheckRefreshWindows(display,windows);
7891 flags=ParseGeometry(levels,&geometry_info);
7892 black_point=geometry_info.rho;
7893 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point;
7894 if ((flags & PercentValue) != 0)
7895 {
7896 black_point*=(double) (*image)->columns*(*image)->rows/100.0;
7897 white_point*=(double) (*image)->columns*(*image)->rows/100.0;
7898 }
cristya19f1d72012-08-07 18:24:38 +00007899 white_point=(double) (*image)->columns*(*image)->rows-white_point;
cristye23ec9d2011-08-16 18:15:40 +00007900 (void) ContrastStretchImage(*image,black_point,white_point,
cristy051718b2011-08-28 22:49:25 +00007901 exception);
cristy3ed852e2009-09-05 21:47:34 +00007902 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00007903 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007904 break;
cristy6710d842011-10-20 23:23:00 +00007905 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007906 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007907 break;
7908 }
7909 case SigmoidalContrastCommand:
7910 {
cristy9ee60942011-07-06 14:54:38 +00007911 GeometryInfo
7912 geometry_info;
7913
7914 MagickStatusType
7915 flags;
7916
cristy3ed852e2009-09-05 21:47:34 +00007917 static char
cristy151b66d2015-04-15 10:50:31 +00007918 levels[MagickPathExtent] = "3x50%";
cristy3ed852e2009-09-05 21:47:34 +00007919
7920 /*
7921 Query user for gamma value.
7922 */
7923 (void) XDialogWidget(display,windows,"Sigmoidal Contrast",
7924 "Enter contrast and midpoint:",levels);
7925 if (*levels == '\0')
7926 break;
7927 /*
7928 Contrast stretch image.
7929 */
7930 XSetCursorState(display,windows,MagickTrue);
7931 XCheckRefreshWindows(display,windows);
cristy9ee60942011-07-06 14:54:38 +00007932 flags=ParseGeometry(levels,&geometry_info);
7933 if ((flags & SigmaValue) == 0)
7934 geometry_info.sigma=1.0*QuantumRange/2.0;
7935 if ((flags & PercentValue) != 0)
7936 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0;
7937 (void) SigmoidalContrastImage(*image,MagickTrue,geometry_info.rho,
cristy051718b2011-08-28 22:49:25 +00007938 geometry_info.sigma,exception);
cristy3ed852e2009-09-05 21:47:34 +00007939 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00007940 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007941 break;
cristy6710d842011-10-20 23:23:00 +00007942 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007943 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007944 break;
7945 }
7946 case NormalizeCommand:
7947 {
7948 /*
7949 Perform histogram normalization on the image.
7950 */
7951 XSetCursorState(display,windows,MagickTrue);
7952 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007953 (void) NormalizeImage(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007954 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00007955 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007956 break;
cristy6710d842011-10-20 23:23:00 +00007957 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007958 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007959 break;
7960 }
7961 case EqualizeCommand:
7962 {
7963 /*
7964 Perform histogram equalization on the image.
7965 */
7966 XSetCursorState(display,windows,MagickTrue);
7967 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007968 (void) EqualizeImage(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007969 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00007970 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007971 break;
cristy6710d842011-10-20 23:23:00 +00007972 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007973 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007974 break;
7975 }
7976 case NegateCommand:
7977 {
7978 /*
7979 Negate colors in image.
7980 */
7981 XSetCursorState(display,windows,MagickTrue);
7982 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007983 (void) NegateImage(*image,MagickFalse,exception);
cristy3ed852e2009-09-05 21:47:34 +00007984 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00007985 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007986 break;
cristy6710d842011-10-20 23:23:00 +00007987 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007988 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007989 break;
7990 }
7991 case GrayscaleCommand:
7992 {
7993 /*
7994 Convert image to grayscale.
7995 */
7996 XSetCursorState(display,windows,MagickTrue);
7997 XCheckRefreshWindows(display,windows);
cristy17f11b02014-12-20 19:37:04 +00007998 (void) SetImageType(*image,(*image)->alpha_trait == UndefinedPixelTrait ?
cristydef23e52015-01-22 11:52:01 +00007999 GrayscaleType : GrayscaleAlphaType,exception);
cristy3ed852e2009-09-05 21:47:34 +00008000 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00008001 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008002 break;
cristy6710d842011-10-20 23:23:00 +00008003 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008004 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008005 break;
8006 }
8007 case MapCommand:
8008 {
8009 Image
8010 *affinity_image;
8011
8012 static char
cristy151b66d2015-04-15 10:50:31 +00008013 filename[MagickPathExtent] = "\0";
cristy3ed852e2009-09-05 21:47:34 +00008014
8015 /*
8016 Request image file name from user.
8017 */
8018 XFileBrowserWidget(display,windows,"Map",filename);
8019 if (*filename == '\0')
8020 break;
8021 /*
8022 Map image.
8023 */
8024 XSetCursorState(display,windows,MagickTrue);
8025 XCheckRefreshWindows(display,windows);
cristy151b66d2015-04-15 10:50:31 +00008026 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
cristy051718b2011-08-28 22:49:25 +00008027 affinity_image=ReadImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00008028 if (affinity_image != (Image *) NULL)
8029 {
cristy018f07f2011-09-04 21:15:19 +00008030 (void) RemapImage(&quantize_info,*image,affinity_image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008031 affinity_image=DestroyImage(affinity_image);
8032 }
cristy051718b2011-08-28 22:49:25 +00008033 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008034 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00008035 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008036 break;
cristy6710d842011-10-20 23:23:00 +00008037 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008038 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008039 break;
8040 }
8041 case QuantizeCommand:
8042 {
8043 int
8044 status;
8045
8046 static char
cristy151b66d2015-04-15 10:50:31 +00008047 colors[MagickPathExtent] = "256";
cristy3ed852e2009-09-05 21:47:34 +00008048
8049 /*
8050 Query user for maximum number of colors.
8051 */
8052 status=XDialogWidget(display,windows,"Quantize",
8053 "Maximum number of colors:",colors);
8054 if (*colors == '\0')
8055 break;
8056 /*
8057 Color reduce the image.
8058 */
8059 XSetCursorState(display,windows,MagickTrue);
8060 XCheckRefreshWindows(display,windows);
cristye27293e2009-12-18 02:53:20 +00008061 quantize_info.number_colors=StringToUnsignedLong(colors);
cristycbda6112012-05-27 20:57:16 +00008062 quantize_info.dither_method=status != 0 ? RiemersmaDitherMethod :
8063 NoDitherMethod;
cristy018f07f2011-09-04 21:15:19 +00008064 (void) QuantizeImage(&quantize_info,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008065 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00008066 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008067 break;
cristy6710d842011-10-20 23:23:00 +00008068 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008069 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008070 break;
8071 }
8072 case DespeckleCommand:
8073 {
8074 Image
8075 *despeckle_image;
8076
8077 /*
8078 Despeckle image.
8079 */
8080 XSetCursorState(display,windows,MagickTrue);
8081 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00008082 despeckle_image=DespeckleImage(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008083 if (despeckle_image != (Image *) NULL)
8084 {
8085 *image=DestroyImage(*image);
8086 *image=despeckle_image;
8087 }
cristy051718b2011-08-28 22:49:25 +00008088 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008089 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00008090 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008091 break;
cristy6710d842011-10-20 23:23:00 +00008092 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008093 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008094 break;
8095 }
8096 case EmbossCommand:
8097 {
8098 Image
8099 *emboss_image;
8100
8101 static char
cristy151b66d2015-04-15 10:50:31 +00008102 radius[MagickPathExtent] = "0.0x1.0";
cristy3ed852e2009-09-05 21:47:34 +00008103
8104 /*
8105 Query user for emboss radius.
8106 */
8107 (void) XDialogWidget(display,windows,"Emboss",
8108 "Enter the emboss radius and standard deviation:",radius);
8109 if (*radius == '\0')
8110 break;
8111 /*
8112 Reduce noise in the image.
8113 */
8114 XSetCursorState(display,windows,MagickTrue);
8115 XCheckRefreshWindows(display,windows);
8116 flags=ParseGeometry(radius,&geometry_info);
8117 if ((flags & SigmaValue) == 0)
8118 geometry_info.sigma=1.0;
8119 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma,
cristy051718b2011-08-28 22:49:25 +00008120 exception);
cristy3ed852e2009-09-05 21:47:34 +00008121 if (emboss_image != (Image *) NULL)
8122 {
8123 *image=DestroyImage(*image);
8124 *image=emboss_image;
8125 }
cristy051718b2011-08-28 22:49:25 +00008126 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008127 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00008128 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008129 break;
cristy6710d842011-10-20 23:23:00 +00008130 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008131 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008132 break;
8133 }
8134 case ReduceNoiseCommand:
8135 {
8136 Image
8137 *noise_image;
8138
8139 static char
cristy151b66d2015-04-15 10:50:31 +00008140 radius[MagickPathExtent] = "0";
cristy3ed852e2009-09-05 21:47:34 +00008141
8142 /*
8143 Query user for noise radius.
8144 */
8145 (void) XDialogWidget(display,windows,"Reduce Noise",
8146 "Enter the noise radius:",radius);
8147 if (*radius == '\0')
8148 break;
8149 /*
8150 Reduce noise in the image.
8151 */
8152 XSetCursorState(display,windows,MagickTrue);
8153 XCheckRefreshWindows(display,windows);
8154 flags=ParseGeometry(radius,&geometry_info);
cristy95c38342011-03-18 22:39:51 +00008155 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t)
cristy051718b2011-08-28 22:49:25 +00008156 geometry_info.rho,(size_t) geometry_info.rho,exception);
cristy3ed852e2009-09-05 21:47:34 +00008157 if (noise_image != (Image *) NULL)
8158 {
8159 *image=DestroyImage(*image);
8160 *image=noise_image;
8161 }
cristy051718b2011-08-28 22:49:25 +00008162 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008163 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00008164 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008165 break;
cristy6710d842011-10-20 23:23:00 +00008166 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008167 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008168 break;
8169 }
8170 case AddNoiseCommand:
8171 {
8172 char
8173 **noises;
8174
8175 Image
8176 *noise_image;
8177
8178 static char
cristy151b66d2015-04-15 10:50:31 +00008179 noise_type[MagickPathExtent] = "Gaussian";
cristy3ed852e2009-09-05 21:47:34 +00008180
8181 /*
8182 Add noise to the image.
8183 */
cristy042ee782011-04-22 18:48:30 +00008184 noises=GetCommandOptions(MagickNoiseOptions);
cristy3ed852e2009-09-05 21:47:34 +00008185 if (noises == (char **) NULL)
8186 break;
8187 XListBrowserWidget(display,windows,&windows->widget,
8188 (const char **) noises,"Add Noise",
8189 "Select a type of noise to add to your image:",noise_type);
8190 noises=DestroyStringList(noises);
8191 if (*noise_type == '\0')
8192 break;
8193 XSetCursorState(display,windows,MagickTrue);
8194 XCheckRefreshWindows(display,windows);
cristy042ee782011-04-22 18:48:30 +00008195 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption(
cristy9ed1f812011-10-08 02:00:08 +00008196 MagickNoiseOptions,MagickFalse,noise_type),1.0,exception);
cristy3ed852e2009-09-05 21:47:34 +00008197 if (noise_image != (Image *) NULL)
8198 {
8199 *image=DestroyImage(*image);
8200 *image=noise_image;
8201 }
cristy051718b2011-08-28 22:49:25 +00008202 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008203 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00008204 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008205 break;
cristy6710d842011-10-20 23:23:00 +00008206 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008207 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008208 break;
8209 }
8210 case SharpenCommand:
8211 {
8212 Image
8213 *sharp_image;
8214
8215 static char
cristy151b66d2015-04-15 10:50:31 +00008216 radius[MagickPathExtent] = "0.0x1.0";
cristy3ed852e2009-09-05 21:47:34 +00008217
8218 /*
8219 Query user for sharpen radius.
8220 */
8221 (void) XDialogWidget(display,windows,"Sharpen",
8222 "Enter the sharpen radius and standard deviation:",radius);
8223 if (*radius == '\0')
8224 break;
8225 /*
8226 Sharpen image scanlines.
8227 */
8228 XSetCursorState(display,windows,MagickTrue);
8229 XCheckRefreshWindows(display,windows);
8230 flags=ParseGeometry(radius,&geometry_info);
8231 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma,
cristyaa2c16c2012-03-25 22:21:35 +00008232 exception);
cristy3ed852e2009-09-05 21:47:34 +00008233 if (sharp_image != (Image *) NULL)
8234 {
8235 *image=DestroyImage(*image);
8236 *image=sharp_image;
8237 }
cristy051718b2011-08-28 22:49:25 +00008238 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008239 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00008240 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008241 break;
cristy6710d842011-10-20 23:23:00 +00008242 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008243 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008244 break;
8245 }
8246 case BlurCommand:
8247 {
8248 Image
8249 *blur_image;
8250
8251 static char
cristy151b66d2015-04-15 10:50:31 +00008252 radius[MagickPathExtent] = "0.0x1.0";
cristy3ed852e2009-09-05 21:47:34 +00008253
8254 /*
8255 Query user for blur radius.
8256 */
8257 (void) XDialogWidget(display,windows,"Blur",
8258 "Enter the blur radius and standard deviation:",radius);
8259 if (*radius == '\0')
8260 break;
8261 /*
8262 Blur an image.
8263 */
8264 XSetCursorState(display,windows,MagickTrue);
8265 XCheckRefreshWindows(display,windows);
8266 flags=ParseGeometry(radius,&geometry_info);
8267 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma,
cristyaa2c16c2012-03-25 22:21:35 +00008268 exception);
cristy3ed852e2009-09-05 21:47:34 +00008269 if (blur_image != (Image *) NULL)
8270 {
8271 *image=DestroyImage(*image);
8272 *image=blur_image;
8273 }
cristy051718b2011-08-28 22:49:25 +00008274 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008275 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00008276 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008277 break;
cristy6710d842011-10-20 23:23:00 +00008278 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008279 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008280 break;
8281 }
8282 case ThresholdCommand:
8283 {
8284 double
8285 threshold;
8286
8287 static char
cristy151b66d2015-04-15 10:50:31 +00008288 factor[MagickPathExtent] = "128";
cristy3ed852e2009-09-05 21:47:34 +00008289
8290 /*
8291 Query user for threshold value.
8292 */
8293 (void) XDialogWidget(display,windows,"Threshold",
8294 "Enter threshold value:",factor);
8295 if (*factor == '\0')
8296 break;
8297 /*
8298 Gamma correct image.
8299 */
8300 XSetCursorState(display,windows,MagickTrue);
8301 XCheckRefreshWindows(display,windows);
cristy9b34e302011-11-05 02:15:45 +00008302 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
cristye941a752011-10-15 01:52:48 +00008303 (void) BilevelImage(*image,threshold,exception);
cristy3ed852e2009-09-05 21:47:34 +00008304 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00008305 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008306 break;
cristy6710d842011-10-20 23:23:00 +00008307 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008308 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008309 break;
8310 }
8311 case EdgeDetectCommand:
8312 {
8313 Image
8314 *edge_image;
8315
8316 static char
cristy151b66d2015-04-15 10:50:31 +00008317 radius[MagickPathExtent] = "0";
cristy3ed852e2009-09-05 21:47:34 +00008318
8319 /*
8320 Query user for edge factor.
8321 */
8322 (void) XDialogWidget(display,windows,"Detect Edges",
8323 "Enter the edge detect radius:",radius);
8324 if (*radius == '\0')
8325 break;
8326 /*
8327 Detect edge in image.
8328 */
8329 XSetCursorState(display,windows,MagickTrue);
8330 XCheckRefreshWindows(display,windows);
8331 flags=ParseGeometry(radius,&geometry_info);
cristy9dc4c512013-03-24 01:38:00 +00008332 edge_image=EdgeImage(*image,geometry_info.rho,exception);
cristy3ed852e2009-09-05 21:47:34 +00008333 if (edge_image != (Image *) NULL)
8334 {
8335 *image=DestroyImage(*image);
8336 *image=edge_image;
8337 }
cristy051718b2011-08-28 22:49:25 +00008338 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008339 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00008340 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008341 break;
cristy6710d842011-10-20 23:23:00 +00008342 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008343 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008344 break;
8345 }
8346 case SpreadCommand:
8347 {
8348 Image
8349 *spread_image;
8350
8351 static char
cristy151b66d2015-04-15 10:50:31 +00008352 amount[MagickPathExtent] = "2";
cristy3ed852e2009-09-05 21:47:34 +00008353
8354 /*
8355 Query user for spread amount.
8356 */
8357 (void) XDialogWidget(display,windows,"Spread",
8358 "Enter the displacement amount:",amount);
8359 if (*amount == '\0')
8360 break;
8361 /*
8362 Displace image pixels by a random amount.
8363 */
8364 XSetCursorState(display,windows,MagickTrue);
8365 XCheckRefreshWindows(display,windows);
8366 flags=ParseGeometry(amount,&geometry_info);
cristy9dc4c512013-03-24 01:38:00 +00008367 spread_image=EdgeImage(*image,geometry_info.rho,exception);
cristy3ed852e2009-09-05 21:47:34 +00008368 if (spread_image != (Image *) NULL)
8369 {
8370 *image=DestroyImage(*image);
8371 *image=spread_image;
8372 }
cristy051718b2011-08-28 22:49:25 +00008373 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008374 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00008375 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008376 break;
cristy6710d842011-10-20 23:23:00 +00008377 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008378 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008379 break;
8380 }
8381 case ShadeCommand:
8382 {
8383 Image
8384 *shade_image;
8385
8386 int
8387 status;
8388
8389 static char
cristy151b66d2015-04-15 10:50:31 +00008390 geometry[MagickPathExtent] = "30x30";
cristy3ed852e2009-09-05 21:47:34 +00008391
8392 /*
8393 Query user for the shade geometry.
8394 */
8395 status=XDialogWidget(display,windows,"Shade",
8396 "Enter the azimuth and elevation of the light source:",geometry);
8397 if (*geometry == '\0')
8398 break;
8399 /*
8400 Shade image pixels.
8401 */
8402 XSetCursorState(display,windows,MagickTrue);
8403 XCheckRefreshWindows(display,windows);
8404 flags=ParseGeometry(geometry,&geometry_info);
8405 if ((flags & SigmaValue) == 0)
8406 geometry_info.sigma=1.0;
dirkb9dbc292015-07-26 09:50:00 +00008407 shade_image=ShadeImage(*image,status != 0 ? MagickTrue : MagickFalse,
cristy051718b2011-08-28 22:49:25 +00008408 geometry_info.rho,geometry_info.sigma,exception);
cristy3ed852e2009-09-05 21:47:34 +00008409 if (shade_image != (Image *) NULL)
8410 {
8411 *image=DestroyImage(*image);
8412 *image=shade_image;
8413 }
cristy051718b2011-08-28 22:49:25 +00008414 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008415 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00008416 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008417 break;
cristy6710d842011-10-20 23:23:00 +00008418 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008419 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008420 break;
8421 }
8422 case RaiseCommand:
8423 {
8424 static char
cristy151b66d2015-04-15 10:50:31 +00008425 bevel_width[MagickPathExtent] = "10";
cristy3ed852e2009-09-05 21:47:34 +00008426
8427 /*
8428 Query user for bevel width.
8429 */
8430 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width);
8431 if (*bevel_width == '\0')
8432 break;
8433 /*
8434 Raise an image.
8435 */
cristy051718b2011-08-28 22:49:25 +00008436 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8437 exception);
cristy3ed852e2009-09-05 21:47:34 +00008438 XSetCursorState(display,windows,MagickTrue);
8439 XCheckRefreshWindows(display,windows);
8440 (void) ParsePageGeometry(*image,bevel_width,&page_geometry,
cristy051718b2011-08-28 22:49:25 +00008441 exception);
8442 (void) RaiseImage(*image,&page_geometry,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +00008443 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00008444 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008445 break;
cristy6710d842011-10-20 23:23:00 +00008446 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008447 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008448 break;
8449 }
8450 case SegmentCommand:
8451 {
8452 static char
cristy151b66d2015-04-15 10:50:31 +00008453 threshold[MagickPathExtent] = "1.0x1.5";
cristy3ed852e2009-09-05 21:47:34 +00008454
8455 /*
8456 Query user for smoothing threshold.
8457 */
8458 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:",
8459 threshold);
8460 if (*threshold == '\0')
8461 break;
8462 /*
8463 Segment an image.
8464 */
8465 XSetCursorState(display,windows,MagickTrue);
8466 XCheckRefreshWindows(display,windows);
8467 flags=ParseGeometry(threshold,&geometry_info);
8468 if ((flags & SigmaValue) == 0)
8469 geometry_info.sigma=1.0;
cristyd3d9c5d2012-02-15 22:58:57 +00008470 (void) SegmentImage(*image,sRGBColorspace,MagickFalse,geometry_info.rho,
cristy018f07f2011-09-04 21:15:19 +00008471 geometry_info.sigma,exception);
cristy3ed852e2009-09-05 21:47:34 +00008472 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00008473 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008474 break;
cristy6710d842011-10-20 23:23:00 +00008475 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008476 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008477 break;
8478 }
8479 case SepiaToneCommand:
8480 {
8481 double
8482 threshold;
8483
8484 Image
8485 *sepia_image;
8486
8487 static char
cristy151b66d2015-04-15 10:50:31 +00008488 factor[MagickPathExtent] = "80%";
cristy3ed852e2009-09-05 21:47:34 +00008489
8490 /*
8491 Query user for sepia-tone factor.
8492 */
8493 (void) XDialogWidget(display,windows,"Sepia Tone",
8494 "Enter the sepia tone factor (0 - 99.9%):",factor);
8495 if (*factor == '\0')
8496 break;
8497 /*
8498 Sepia tone image pixels.
8499 */
8500 XSetCursorState(display,windows,MagickTrue);
8501 XCheckRefreshWindows(display,windows);
cristy9b34e302011-11-05 02:15:45 +00008502 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
cristy051718b2011-08-28 22:49:25 +00008503 sepia_image=SepiaToneImage(*image,threshold,exception);
cristy3ed852e2009-09-05 21:47:34 +00008504 if (sepia_image != (Image *) NULL)
8505 {
8506 *image=DestroyImage(*image);
8507 *image=sepia_image;
8508 }
cristy051718b2011-08-28 22:49:25 +00008509 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008510 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00008511 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008512 break;
cristy6710d842011-10-20 23:23:00 +00008513 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008514 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008515 break;
8516 }
8517 case SolarizeCommand:
8518 {
8519 double
8520 threshold;
8521
8522 static char
cristy151b66d2015-04-15 10:50:31 +00008523 factor[MagickPathExtent] = "60%";
cristy3ed852e2009-09-05 21:47:34 +00008524
8525 /*
8526 Query user for solarize factor.
8527 */
8528 (void) XDialogWidget(display,windows,"Solarize",
8529 "Enter the solarize factor (0 - 99.9%):",factor);
8530 if (*factor == '\0')
8531 break;
8532 /*
8533 Solarize image pixels.
8534 */
8535 XSetCursorState(display,windows,MagickTrue);
8536 XCheckRefreshWindows(display,windows);
cristy9b34e302011-11-05 02:15:45 +00008537 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
cristy5cbc0162011-08-29 00:36:28 +00008538 (void) SolarizeImage(*image,threshold,exception);
cristy3ed852e2009-09-05 21:47:34 +00008539 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00008540 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008541 break;
cristy6710d842011-10-20 23:23:00 +00008542 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008543 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008544 break;
8545 }
8546 case SwirlCommand:
8547 {
8548 Image
8549 *swirl_image;
8550
8551 static char
cristy151b66d2015-04-15 10:50:31 +00008552 degrees[MagickPathExtent] = "60";
cristy3ed852e2009-09-05 21:47:34 +00008553
8554 /*
8555 Query user for swirl angle.
8556 */
8557 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:",
8558 degrees);
8559 if (*degrees == '\0')
8560 break;
8561 /*
8562 Swirl image pixels about the center.
8563 */
8564 XSetCursorState(display,windows,MagickTrue);
8565 XCheckRefreshWindows(display,windows);
8566 flags=ParseGeometry(degrees,&geometry_info);
cristy76f512e2011-09-12 01:26:56 +00008567 swirl_image=SwirlImage(*image,geometry_info.rho,(*image)->interpolate,
8568 exception);
cristy3ed852e2009-09-05 21:47:34 +00008569 if (swirl_image != (Image *) NULL)
8570 {
8571 *image=DestroyImage(*image);
8572 *image=swirl_image;
8573 }
cristy051718b2011-08-28 22:49:25 +00008574 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008575 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00008576 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008577 break;
cristy6710d842011-10-20 23:23:00 +00008578 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008579 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008580 break;
8581 }
8582 case ImplodeCommand:
8583 {
8584 Image
8585 *implode_image;
8586
8587 static char
cristy151b66d2015-04-15 10:50:31 +00008588 factor[MagickPathExtent] = "0.3";
cristy3ed852e2009-09-05 21:47:34 +00008589
8590 /*
8591 Query user for implode factor.
8592 */
8593 (void) XDialogWidget(display,windows,"Implode",
8594 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor);
8595 if (*factor == '\0')
8596 break;
8597 /*
8598 Implode image pixels about the center.
8599 */
8600 XSetCursorState(display,windows,MagickTrue);
8601 XCheckRefreshWindows(display,windows);
8602 flags=ParseGeometry(factor,&geometry_info);
cristy76f512e2011-09-12 01:26:56 +00008603 implode_image=ImplodeImage(*image,geometry_info.rho,(*image)->interpolate,
8604 exception);
cristy3ed852e2009-09-05 21:47:34 +00008605 if (implode_image != (Image *) NULL)
8606 {
8607 *image=DestroyImage(*image);
8608 *image=implode_image;
8609 }
cristy051718b2011-08-28 22:49:25 +00008610 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008611 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00008612 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008613 break;
cristy6710d842011-10-20 23:23:00 +00008614 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008615 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008616 break;
8617 }
8618 case VignetteCommand:
8619 {
8620 Image
8621 *vignette_image;
8622
8623 static char
cristy151b66d2015-04-15 10:50:31 +00008624 geometry[MagickPathExtent] = "0x20";
cristy3ed852e2009-09-05 21:47:34 +00008625
8626 /*
8627 Query user for the vignette geometry.
8628 */
8629 (void) XDialogWidget(display,windows,"Vignette",
8630 "Enter the radius, sigma, and x and y offsets:",geometry);
8631 if (*geometry == '\0')
8632 break;
8633 /*
8634 Soften the edges of the image in vignette style
8635 */
8636 XSetCursorState(display,windows,MagickTrue);
8637 XCheckRefreshWindows(display,windows);
8638 flags=ParseGeometry(geometry,&geometry_info);
8639 if ((flags & SigmaValue) == 0)
8640 geometry_info.sigma=1.0;
8641 if ((flags & XiValue) == 0)
8642 geometry_info.xi=0.1*(*image)->columns;
8643 if ((flags & PsiValue) == 0)
8644 geometry_info.psi=0.1*(*image)->rows;
cristyaa2c16c2012-03-25 22:21:35 +00008645 vignette_image=VignetteImage(*image,geometry_info.rho,0.0,(ssize_t)
8646 ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-0.5),
8647 exception);
cristy3ed852e2009-09-05 21:47:34 +00008648 if (vignette_image != (Image *) NULL)
8649 {
8650 *image=DestroyImage(*image);
8651 *image=vignette_image;
8652 }
cristy051718b2011-08-28 22:49:25 +00008653 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008654 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00008655 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008656 break;
cristy6710d842011-10-20 23:23:00 +00008657 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008658 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008659 break;
8660 }
8661 case WaveCommand:
8662 {
8663 Image
8664 *wave_image;
8665
8666 static char
cristy151b66d2015-04-15 10:50:31 +00008667 geometry[MagickPathExtent] = "25x150";
cristy3ed852e2009-09-05 21:47:34 +00008668
8669 /*
8670 Query user for the wave geometry.
8671 */
8672 (void) XDialogWidget(display,windows,"Wave",
8673 "Enter the amplitude and length of the wave:",geometry);
8674 if (*geometry == '\0')
8675 break;
8676 /*
cristycee97112010-05-28 00:44:52 +00008677 Alter an image along a sine wave.
cristy3ed852e2009-09-05 21:47:34 +00008678 */
8679 XSetCursorState(display,windows,MagickTrue);
8680 XCheckRefreshWindows(display,windows);
8681 flags=ParseGeometry(geometry,&geometry_info);
8682 if ((flags & SigmaValue) == 0)
8683 geometry_info.sigma=1.0;
8684 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma,
cristy5c4e2582011-09-11 19:21:03 +00008685 (*image)->interpolate,exception);
cristy3ed852e2009-09-05 21:47:34 +00008686 if (wave_image != (Image *) NULL)
8687 {
8688 *image=DestroyImage(*image);
8689 *image=wave_image;
8690 }
cristy051718b2011-08-28 22:49:25 +00008691 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008692 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00008693 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008694 break;
cristy6710d842011-10-20 23:23:00 +00008695 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008696 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008697 break;
8698 }
8699 case OilPaintCommand:
8700 {
8701 Image
8702 *paint_image;
8703
8704 static char
cristy151b66d2015-04-15 10:50:31 +00008705 radius[MagickPathExtent] = "0";
cristy3ed852e2009-09-05 21:47:34 +00008706
8707 /*
8708 Query user for circular neighborhood radius.
8709 */
8710 (void) XDialogWidget(display,windows,"Oil Paint",
8711 "Enter the mask radius:",radius);
8712 if (*radius == '\0')
8713 break;
8714 /*
8715 OilPaint image scanlines.
8716 */
8717 XSetCursorState(display,windows,MagickTrue);
8718 XCheckRefreshWindows(display,windows);
8719 flags=ParseGeometry(radius,&geometry_info);
cristy14973ba2011-08-27 23:48:07 +00008720 paint_image=OilPaintImage(*image,geometry_info.rho,geometry_info.sigma,
cristy051718b2011-08-28 22:49:25 +00008721 exception);
cristy3ed852e2009-09-05 21:47:34 +00008722 if (paint_image != (Image *) NULL)
8723 {
8724 *image=DestroyImage(*image);
8725 *image=paint_image;
8726 }
cristy051718b2011-08-28 22:49:25 +00008727 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008728 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00008729 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008730 break;
cristy6710d842011-10-20 23:23:00 +00008731 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008732 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008733 break;
8734 }
8735 case CharcoalDrawCommand:
8736 {
8737 Image
8738 *charcoal_image;
8739
8740 static char
cristy151b66d2015-04-15 10:50:31 +00008741 radius[MagickPathExtent] = "0x1";
cristy3ed852e2009-09-05 21:47:34 +00008742
8743 /*
8744 Query user for charcoal radius.
8745 */
8746 (void) XDialogWidget(display,windows,"Charcoal Draw",
8747 "Enter the charcoal radius and sigma:",radius);
8748 if (*radius == '\0')
8749 break;
8750 /*
8751 Charcoal the image.
8752 */
cristy051718b2011-08-28 22:49:25 +00008753 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8754 exception);
cristy3ed852e2009-09-05 21:47:34 +00008755 XSetCursorState(display,windows,MagickTrue);
8756 XCheckRefreshWindows(display,windows);
8757 flags=ParseGeometry(radius,&geometry_info);
8758 if ((flags & SigmaValue) == 0)
8759 geometry_info.sigma=geometry_info.rho;
8760 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma,
cristyaa2c16c2012-03-25 22:21:35 +00008761 exception);
cristy3ed852e2009-09-05 21:47:34 +00008762 if (charcoal_image != (Image *) NULL)
8763 {
8764 *image=DestroyImage(*image);
8765 *image=charcoal_image;
8766 }
cristy051718b2011-08-28 22:49:25 +00008767 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008768 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00008769 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008770 break;
cristy6710d842011-10-20 23:23:00 +00008771 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008772 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008773 break;
8774 }
8775 case AnnotateCommand:
8776 {
8777 /*
8778 Annotate the image with text.
8779 */
cristy051718b2011-08-28 22:49:25 +00008780 status=XAnnotateEditImage(display,resource_info,windows,*image,exception);
cristy59864562013-04-18 11:47:41 +00008781 if (IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00008782 {
8783 XNoticeWidget(display,windows,"Unable to annotate X image",
8784 (*image)->filename);
8785 break;
8786 }
8787 break;
8788 }
8789 case DrawCommand:
8790 {
8791 /*
8792 Draw image.
8793 */
cristy051718b2011-08-28 22:49:25 +00008794 status=XDrawEditImage(display,resource_info,windows,image,exception);
cristy59864562013-04-18 11:47:41 +00008795 if (IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00008796 {
8797 XNoticeWidget(display,windows,"Unable to draw on the X image",
8798 (*image)->filename);
8799 break;
8800 }
8801 break;
8802 }
8803 case ColorCommand:
8804 {
8805 /*
8806 Color edit.
8807 */
cristy051718b2011-08-28 22:49:25 +00008808 status=XColorEditImage(display,resource_info,windows,image,exception);
cristy59864562013-04-18 11:47:41 +00008809 if (IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00008810 {
8811 XNoticeWidget(display,windows,"Unable to pixel edit X image",
8812 (*image)->filename);
8813 break;
8814 }
8815 break;
8816 }
8817 case MatteCommand:
8818 {
8819 /*
8820 Matte edit.
8821 */
cristy051718b2011-08-28 22:49:25 +00008822 status=XMatteEditImage(display,resource_info,windows,image,exception);
cristy59864562013-04-18 11:47:41 +00008823 if (IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00008824 {
8825 XNoticeWidget(display,windows,"Unable to matte edit X image",
8826 (*image)->filename);
8827 break;
8828 }
8829 break;
8830 }
8831 case CompositeCommand:
8832 {
8833 /*
8834 Composite image.
8835 */
cristy051718b2011-08-28 22:49:25 +00008836 status=XCompositeImage(display,resource_info,windows,*image,
8837 exception);
cristy59864562013-04-18 11:47:41 +00008838 if (IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00008839 {
8840 XNoticeWidget(display,windows,"Unable to composite X image",
8841 (*image)->filename);
8842 break;
8843 }
8844 break;
8845 }
8846 case AddBorderCommand:
8847 {
8848 Image
8849 *border_image;
8850
8851 static char
cristy151b66d2015-04-15 10:50:31 +00008852 geometry[MagickPathExtent] = "6x6";
cristy3ed852e2009-09-05 21:47:34 +00008853
8854 /*
8855 Query user for border color and geometry.
8856 */
8857 XColorBrowserWidget(display,windows,"Select",color);
8858 if (*color == '\0')
8859 break;
8860 (void) XDialogWidget(display,windows,"Add Border",
8861 "Enter border geometry:",geometry);
8862 if (*geometry == '\0')
8863 break;
8864 /*
8865 Add a border to the image.
8866 */
cristy051718b2011-08-28 22:49:25 +00008867 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8868 exception);
cristy3ed852e2009-09-05 21:47:34 +00008869 XSetCursorState(display,windows,MagickTrue);
8870 XCheckRefreshWindows(display,windows);
cristy9950d572011-10-01 18:22:35 +00008871 (void) QueryColorCompliance(color,AllCompliance,&(*image)->border_color,
cristy051718b2011-08-28 22:49:25 +00008872 exception);
cristy3ed852e2009-09-05 21:47:34 +00008873 (void) ParsePageGeometry(*image,geometry,&page_geometry,
cristy051718b2011-08-28 22:49:25 +00008874 exception);
cristy633f0c62011-09-15 13:27:36 +00008875 border_image=BorderImage(*image,&page_geometry,(*image)->compose,
8876 exception);
cristy3ed852e2009-09-05 21:47:34 +00008877 if (border_image != (Image *) NULL)
8878 {
8879 *image=DestroyImage(*image);
8880 *image=border_image;
8881 }
cristy051718b2011-08-28 22:49:25 +00008882 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008883 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00008884 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008885 break;
8886 windows->image.window_changes.width=(int) (*image)->columns;
8887 windows->image.window_changes.height=(int) (*image)->rows;
cristy6710d842011-10-20 23:23:00 +00008888 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008889 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008890 break;
8891 }
8892 case AddFrameCommand:
8893 {
8894 FrameInfo
8895 frame_info;
8896
8897 Image
8898 *frame_image;
8899
8900 static char
cristy151b66d2015-04-15 10:50:31 +00008901 geometry[MagickPathExtent] = "6x6";
cristy3ed852e2009-09-05 21:47:34 +00008902
8903 /*
8904 Query user for frame color and geometry.
8905 */
8906 XColorBrowserWidget(display,windows,"Select",color);
8907 if (*color == '\0')
8908 break;
8909 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:",
8910 geometry);
8911 if (*geometry == '\0')
8912 break;
8913 /*
8914 Surround image with an ornamental border.
8915 */
cristy051718b2011-08-28 22:49:25 +00008916 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8917 exception);
cristy3ed852e2009-09-05 21:47:34 +00008918 XSetCursorState(display,windows,MagickTrue);
8919 XCheckRefreshWindows(display,windows);
cristy9950d572011-10-01 18:22:35 +00008920 (void) QueryColorCompliance(color,AllCompliance,&(*image)->matte_color,
cristy051718b2011-08-28 22:49:25 +00008921 exception);
cristy3ed852e2009-09-05 21:47:34 +00008922 (void) ParsePageGeometry(*image,geometry,&page_geometry,
cristy051718b2011-08-28 22:49:25 +00008923 exception);
cristy3ed852e2009-09-05 21:47:34 +00008924 frame_info.width=page_geometry.width;
8925 frame_info.height=page_geometry.height;
8926 frame_info.outer_bevel=page_geometry.x;
8927 frame_info.inner_bevel=page_geometry.y;
cristybb503372010-05-27 20:51:26 +00008928 frame_info.x=(ssize_t) frame_info.width;
8929 frame_info.y=(ssize_t) frame_info.height;
cristy3ed852e2009-09-05 21:47:34 +00008930 frame_info.width=(*image)->columns+2*frame_info.width;
8931 frame_info.height=(*image)->rows+2*frame_info.height;
cristy633f0c62011-09-15 13:27:36 +00008932 frame_image=FrameImage(*image,&frame_info,(*image)->compose,exception);
cristy3ed852e2009-09-05 21:47:34 +00008933 if (frame_image != (Image *) NULL)
8934 {
8935 *image=DestroyImage(*image);
8936 *image=frame_image;
8937 }
cristy051718b2011-08-28 22:49:25 +00008938 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008939 XSetCursorState(display,windows,MagickFalse);
cristy59864562013-04-18 11:47:41 +00008940 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008941 break;
8942 windows->image.window_changes.width=(int) (*image)->columns;
8943 windows->image.window_changes.height=(int) (*image)->rows;
cristy6710d842011-10-20 23:23:00 +00008944 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008945 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008946 break;
8947 }
8948 case CommentCommand:
8949 {
8950 const char
8951 *value;
8952
8953 FILE
8954 *file;
8955
8956 int
8957 unique_file;
8958
8959 /*
8960 Edit image comment.
8961 */
8962 unique_file=AcquireUniqueFileResource(image_info->filename);
8963 if (unique_file == -1)
8964 XNoticeWidget(display,windows,"Unable to edit image comment",
8965 image_info->filename);
cristyd15e6592011-10-15 00:13:06 +00008966 value=GetImageProperty(*image,"comment",exception);
cristy3ed852e2009-09-05 21:47:34 +00008967 if (value == (char *) NULL)
8968 unique_file=close(unique_file)-1;
8969 else
8970 {
8971 register const char
8972 *p;
8973
8974 file=fdopen(unique_file,"w");
8975 if (file == (FILE *) NULL)
8976 {
8977 XNoticeWidget(display,windows,"Unable to edit image comment",
8978 image_info->filename);
8979 break;
8980 }
8981 for (p=value; *p != '\0'; p++)
8982 (void) fputc((int) *p,file);
8983 (void) fputc('\n',file);
8984 (void) fclose(file);
8985 }
8986 XSetCursorState(display,windows,MagickTrue);
8987 XCheckRefreshWindows(display,windows);
8988 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL,
cristy051718b2011-08-28 22:49:25 +00008989 exception);
cristy59864562013-04-18 11:47:41 +00008990 if (IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00008991 XNoticeWidget(display,windows,"Unable to edit image comment",
8992 (char *) NULL);
8993 else
8994 {
8995 char
8996 *comment;
8997
cristy051718b2011-08-28 22:49:25 +00008998 comment=FileToString(image_info->filename,~0UL,exception);
cristy3ed852e2009-09-05 21:47:34 +00008999 if (comment != (char *) NULL)
9000 {
cristyd15e6592011-10-15 00:13:06 +00009001 (void) SetImageProperty(*image,"comment",comment,exception);
cristy3ed852e2009-09-05 21:47:34 +00009002 (*image)->taint=MagickTrue;
9003 }
9004 }
9005 (void) RelinquishUniqueFileResource(image_info->filename);
9006 XSetCursorState(display,windows,MagickFalse);
9007 break;
9008 }
9009 case LaunchCommand:
9010 {
9011 /*
9012 Launch program.
9013 */
9014 XSetCursorState(display,windows,MagickTrue);
9015 XCheckRefreshWindows(display,windows);
9016 (void) AcquireUniqueFilename(filename);
cristy151b66d2015-04-15 10:50:31 +00009017 (void) FormatLocaleString((*image)->filename,MagickPathExtent,"launch:%s",
cristy3ed852e2009-09-05 21:47:34 +00009018 filename);
cristy051718b2011-08-28 22:49:25 +00009019 status=WriteImage(image_info,*image,exception);
cristy59864562013-04-18 11:47:41 +00009020 if (IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00009021 XNoticeWidget(display,windows,"Unable to launch image editor",
9022 (char *) NULL);
9023 else
9024 {
cristy051718b2011-08-28 22:49:25 +00009025 nexus=ReadImage(resource_info->image_info,exception);
9026 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00009027 XClientMessage(display,windows->image.id,windows->im_protocols,
9028 windows->im_next_image,CurrentTime);
9029 }
9030 (void) RelinquishUniqueFileResource(filename);
9031 XSetCursorState(display,windows,MagickFalse);
9032 break;
9033 }
9034 case RegionofInterestCommand:
9035 {
9036 /*
9037 Apply an image processing technique to a region of interest.
9038 */
cristy051718b2011-08-28 22:49:25 +00009039 (void) XROIImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009040 break;
9041 }
9042 case InfoCommand:
9043 break;
9044 case ZoomCommand:
9045 {
9046 /*
9047 Zoom image.
9048 */
cristy59864562013-04-18 11:47:41 +00009049 if (IfMagickTrue(windows->magnify.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00009050 (void) XRaiseWindow(display,windows->magnify.id);
9051 else
9052 {
9053 /*
9054 Make magnify image.
9055 */
9056 XSetCursorState(display,windows,MagickTrue);
9057 (void) XMapRaised(display,windows->magnify.id);
9058 XSetCursorState(display,windows,MagickFalse);
9059 }
9060 break;
9061 }
9062 case ShowPreviewCommand:
9063 {
9064 char
9065 **previews;
9066
9067 Image
9068 *preview_image;
9069
9070 static char
cristy151b66d2015-04-15 10:50:31 +00009071 preview_type[MagickPathExtent] = "Gamma";
cristy3ed852e2009-09-05 21:47:34 +00009072
9073 /*
9074 Select preview type from menu.
9075 */
cristy042ee782011-04-22 18:48:30 +00009076 previews=GetCommandOptions(MagickPreviewOptions);
cristy3ed852e2009-09-05 21:47:34 +00009077 if (previews == (char **) NULL)
9078 break;
9079 XListBrowserWidget(display,windows,&windows->widget,
9080 (const char **) previews,"Preview",
9081 "Select an enhancement, effect, or F/X:",preview_type);
9082 previews=DestroyStringList(previews);
9083 if (*preview_type == '\0')
9084 break;
9085 /*
9086 Show image preview.
9087 */
9088 XSetCursorState(display,windows,MagickTrue);
9089 XCheckRefreshWindows(display,windows);
9090 image_info->preview_type=(PreviewType)
cristy042ee782011-04-22 18:48:30 +00009091 ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type);
cristybb503372010-05-27 20:51:26 +00009092 image_info->group=(ssize_t) windows->image.id;
cristy3ed852e2009-09-05 21:47:34 +00009093 (void) DeleteImageProperty(*image,"label");
cristyd15e6592011-10-15 00:13:06 +00009094 (void) SetImageProperty(*image,"label","Preview",exception);
cristy3ed852e2009-09-05 21:47:34 +00009095 (void) AcquireUniqueFilename(filename);
cristy151b66d2015-04-15 10:50:31 +00009096 (void) FormatLocaleString((*image)->filename,MagickPathExtent,"preview:%s",
cristy3ed852e2009-09-05 21:47:34 +00009097 filename);
cristy051718b2011-08-28 22:49:25 +00009098 status=WriteImage(image_info,*image,exception);
cristy151b66d2015-04-15 10:50:31 +00009099 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
cristy051718b2011-08-28 22:49:25 +00009100 preview_image=ReadImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00009101 (void) RelinquishUniqueFileResource(filename);
9102 if (preview_image == (Image *) NULL)
9103 break;
cristy151b66d2015-04-15 10:50:31 +00009104 (void) FormatLocaleString(preview_image->filename,MagickPathExtent,"show:%s",
cristy3ed852e2009-09-05 21:47:34 +00009105 filename);
cristy051718b2011-08-28 22:49:25 +00009106 status=WriteImage(image_info,preview_image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009107 preview_image=DestroyImage(preview_image);
cristy59864562013-04-18 11:47:41 +00009108 if (IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00009109 XNoticeWidget(display,windows,"Unable to show image preview",
9110 (*image)->filename);
9111 XDelay(display,1500);
9112 XSetCursorState(display,windows,MagickFalse);
9113 break;
9114 }
9115 case ShowHistogramCommand:
9116 {
9117 Image
9118 *histogram_image;
9119
9120 /*
9121 Show image histogram.
9122 */
9123 XSetCursorState(display,windows,MagickTrue);
9124 XCheckRefreshWindows(display,windows);
cristybb503372010-05-27 20:51:26 +00009125 image_info->group=(ssize_t) windows->image.id;
cristy3ed852e2009-09-05 21:47:34 +00009126 (void) DeleteImageProperty(*image,"label");
cristyd15e6592011-10-15 00:13:06 +00009127 (void) SetImageProperty(*image,"label","Histogram",exception);
cristy3ed852e2009-09-05 21:47:34 +00009128 (void) AcquireUniqueFilename(filename);
cristy151b66d2015-04-15 10:50:31 +00009129 (void) FormatLocaleString((*image)->filename,MagickPathExtent,"histogram:%s",
cristy3ed852e2009-09-05 21:47:34 +00009130 filename);
cristy051718b2011-08-28 22:49:25 +00009131 status=WriteImage(image_info,*image,exception);
cristy151b66d2015-04-15 10:50:31 +00009132 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
cristy051718b2011-08-28 22:49:25 +00009133 histogram_image=ReadImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00009134 (void) RelinquishUniqueFileResource(filename);
9135 if (histogram_image == (Image *) NULL)
9136 break;
cristy151b66d2015-04-15 10:50:31 +00009137 (void) FormatLocaleString(histogram_image->filename,MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +00009138 "show:%s",filename);
cristy051718b2011-08-28 22:49:25 +00009139 status=WriteImage(image_info,histogram_image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009140 histogram_image=DestroyImage(histogram_image);
cristy59864562013-04-18 11:47:41 +00009141 if (IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00009142 XNoticeWidget(display,windows,"Unable to show histogram",
9143 (*image)->filename);
9144 XDelay(display,1500);
9145 XSetCursorState(display,windows,MagickFalse);
9146 break;
9147 }
9148 case ShowMatteCommand:
9149 {
9150 Image
9151 *matte_image;
9152
cristy17f11b02014-12-20 19:37:04 +00009153 if ((*image)->alpha_trait == UndefinedPixelTrait)
cristy3ed852e2009-09-05 21:47:34 +00009154 {
9155 XNoticeWidget(display,windows,
9156 "Image does not have any matte information",(*image)->filename);
9157 break;
9158 }
9159 /*
9160 Show image matte.
9161 */
9162 XSetCursorState(display,windows,MagickTrue);
9163 XCheckRefreshWindows(display,windows);
cristybb503372010-05-27 20:51:26 +00009164 image_info->group=(ssize_t) windows->image.id;
cristy3ed852e2009-09-05 21:47:34 +00009165 (void) DeleteImageProperty(*image,"label");
cristyd15e6592011-10-15 00:13:06 +00009166 (void) SetImageProperty(*image,"label","Matte",exception);
cristy3ed852e2009-09-05 21:47:34 +00009167 (void) AcquireUniqueFilename(filename);
cristy151b66d2015-04-15 10:50:31 +00009168 (void) FormatLocaleString((*image)->filename,MagickPathExtent,"matte:%s",
cristy3ed852e2009-09-05 21:47:34 +00009169 filename);
cristy051718b2011-08-28 22:49:25 +00009170 status=WriteImage(image_info,*image,exception);
cristy151b66d2015-04-15 10:50:31 +00009171 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
cristy051718b2011-08-28 22:49:25 +00009172 matte_image=ReadImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00009173 (void) RelinquishUniqueFileResource(filename);
9174 if (matte_image == (Image *) NULL)
9175 break;
cristy151b66d2015-04-15 10:50:31 +00009176 (void) FormatLocaleString(matte_image->filename,MagickPathExtent,"show:%s",
cristy3ed852e2009-09-05 21:47:34 +00009177 filename);
cristy051718b2011-08-28 22:49:25 +00009178 status=WriteImage(image_info,matte_image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009179 matte_image=DestroyImage(matte_image);
cristy59864562013-04-18 11:47:41 +00009180 if (IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00009181 XNoticeWidget(display,windows,"Unable to show matte",
9182 (*image)->filename);
9183 XDelay(display,1500);
9184 XSetCursorState(display,windows,MagickFalse);
9185 break;
9186 }
9187 case BackgroundCommand:
9188 {
9189 /*
9190 Background image.
9191 */
cristy051718b2011-08-28 22:49:25 +00009192 status=XBackgroundImage(display,resource_info,windows,image,exception);
cristy59864562013-04-18 11:47:41 +00009193 if (IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00009194 break;
cristy051718b2011-08-28 22:49:25 +00009195 nexus=CloneImage(*image,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +00009196 if (nexus != (Image *) NULL)
9197 XClientMessage(display,windows->image.id,windows->im_protocols,
9198 windows->im_next_image,CurrentTime);
9199 break;
9200 }
9201 case SlideShowCommand:
9202 {
9203 static char
cristy151b66d2015-04-15 10:50:31 +00009204 delay[MagickPathExtent] = "5";
cristy3ed852e2009-09-05 21:47:34 +00009205
9206 /*
9207 Display next image after pausing.
9208 */
9209 (void) XDialogWidget(display,windows,"Slide Show",
9210 "Pause how many 1/100ths of a second between images:",delay);
9211 if (*delay == '\0')
9212 break;
cristye27293e2009-12-18 02:53:20 +00009213 resource_info->delay=StringToUnsignedLong(delay);
cristy3ed852e2009-09-05 21:47:34 +00009214 XClientMessage(display,windows->image.id,windows->im_protocols,
9215 windows->im_next_image,CurrentTime);
9216 break;
9217 }
9218 case PreferencesCommand:
9219 {
9220 /*
9221 Set user preferences.
9222 */
9223 status=XPreferencesWidget(display,resource_info,windows);
cristy59864562013-04-18 11:47:41 +00009224 if (IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00009225 break;
cristy051718b2011-08-28 22:49:25 +00009226 nexus=CloneImage(*image,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +00009227 if (nexus != (Image *) NULL)
9228 XClientMessage(display,windows->image.id,windows->im_protocols,
9229 windows->im_next_image,CurrentTime);
9230 break;
9231 }
9232 case HelpCommand:
9233 {
9234 /*
9235 User requested help.
9236 */
9237 XTextViewWidget(display,resource_info,windows,MagickFalse,
9238 "Help Viewer - Display",DisplayHelp);
9239 break;
9240 }
9241 case BrowseDocumentationCommand:
9242 {
9243 Atom
9244 mozilla_atom;
9245
9246 Window
9247 mozilla_window,
9248 root_window;
9249
9250 /*
9251 Browse the ImageMagick documentation.
9252 */
9253 root_window=XRootWindow(display,XDefaultScreen(display));
9254 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse);
9255 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom);
9256 if (mozilla_window != (Window) NULL)
9257 {
9258 char
cristy151b66d2015-04-15 10:50:31 +00009259 command[MagickPathExtent],
cristy3ed852e2009-09-05 21:47:34 +00009260 *url;
9261
9262 /*
9263 Display documentation using Netscape remote control.
9264 */
9265 url=GetMagickHomeURL();
cristy151b66d2015-04-15 10:50:31 +00009266 (void) FormatLocaleString(command,MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +00009267 "openurl(%s,new-tab)",url);
9268 url=DestroyString(url);
9269 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse);
9270 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING,
9271 8,PropModeReplace,(unsigned char *) command,(int) strlen(command));
9272 XSetCursorState(display,windows,MagickFalse);
9273 break;
9274 }
9275 XSetCursorState(display,windows,MagickTrue);
9276 XCheckRefreshWindows(display,windows);
9277 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL,
cristy051718b2011-08-28 22:49:25 +00009278 exception);
cristy59864562013-04-18 11:47:41 +00009279 if (IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00009280 XNoticeWidget(display,windows,"Unable to browse documentation",
9281 (char *) NULL);
9282 XDelay(display,1500);
9283 XSetCursorState(display,windows,MagickFalse);
9284 break;
9285 }
9286 case VersionCommand:
9287 {
cristybb503372010-05-27 20:51:26 +00009288 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL),
cristy3ed852e2009-09-05 21:47:34 +00009289 GetMagickCopyright());
9290 break;
9291 }
9292 case SaveToUndoBufferCommand:
9293 break;
9294 default:
9295 {
9296 (void) XBell(display,0);
9297 break;
9298 }
9299 }
9300 image_info=DestroyImageInfo(image_info);
9301 return(nexus);
9302}
9303
9304/*
9305%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9306% %
9307% %
9308% %
9309+ X M a g n i f y I m a g e %
9310% %
9311% %
9312% %
9313%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9314%
9315% XMagnifyImage() magnifies portions of the image as indicated by the pointer.
9316% The magnified portion is displayed in a separate window.
9317%
9318% The format of the XMagnifyImage method is:
9319%
cristy6710d842011-10-20 23:23:00 +00009320% void XMagnifyImage(Display *display,XWindows *windows,XEvent *event,
9321% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009322%
9323% A description of each parameter follows:
9324%
9325% o display: Specifies a connection to an X server; returned from
9326% XOpenDisplay.
9327%
9328% o windows: Specifies a pointer to a XWindows structure.
9329%
9330% o event: Specifies a pointer to a XEvent structure. If it is NULL,
9331% the entire image is refreshed.
9332%
cristy6710d842011-10-20 23:23:00 +00009333% o exception: return any errors or warnings in this structure.
9334%
cristy3ed852e2009-09-05 21:47:34 +00009335*/
cristy6710d842011-10-20 23:23:00 +00009336static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event,
9337 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009338{
9339 char
cristy151b66d2015-04-15 10:50:31 +00009340 text[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00009341
9342 register int
9343 x,
9344 y;
9345
cristybb503372010-05-27 20:51:26 +00009346 size_t
cristy3ed852e2009-09-05 21:47:34 +00009347 state;
9348
9349 /*
9350 Update magnified image until the mouse button is released.
9351 */
9352 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor);
9353 state=DefaultState;
9354 x=event->xbutton.x;
9355 y=event->xbutton.y;
cristy49e2d862010-11-12 02:50:30 +00009356 windows->magnify.x=(int) windows->image.x+x;
9357 windows->magnify.y=(int) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +00009358 do
9359 {
9360 /*
9361 Map and unmap Info widget as text cursor crosses its boundaries.
9362 */
cristy59864562013-04-18 11:47:41 +00009363 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00009364 {
9365 if ((x < (int) (windows->info.x+windows->info.width)) &&
9366 (y < (int) (windows->info.y+windows->info.height)))
9367 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
9368 }
9369 else
9370 if ((x > (int) (windows->info.x+windows->info.width)) ||
9371 (y > (int) (windows->info.y+windows->info.height)))
9372 (void) XMapWindow(display,windows->info.id);
cristy59864562013-04-18 11:47:41 +00009373 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00009374 {
9375 /*
9376 Display pointer position.
9377 */
cristy151b66d2015-04-15 10:50:31 +00009378 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +00009379 windows->magnify.x,windows->magnify.y);
9380 XInfoWidget(display,windows,text);
9381 }
9382 /*
9383 Wait for next event.
9384 */
cristy6710d842011-10-20 23:23:00 +00009385 XScreenEvent(display,windows,event,exception);
cristy3ed852e2009-09-05 21:47:34 +00009386 switch (event->type)
9387 {
9388 case ButtonPress:
9389 break;
9390 case ButtonRelease:
9391 {
9392 /*
9393 User has finished magnifying image.
9394 */
9395 x=event->xbutton.x;
9396 y=event->xbutton.y;
9397 state|=ExitState;
9398 break;
9399 }
9400 case Expose:
9401 break;
9402 case MotionNotify:
9403 {
9404 x=event->xmotion.x;
9405 y=event->xmotion.y;
9406 break;
9407 }
9408 default:
9409 break;
9410 }
9411 /*
9412 Check boundary conditions.
9413 */
9414 if (x < 0)
9415 x=0;
9416 else
9417 if (x >= (int) windows->image.width)
9418 x=(int) windows->image.width-1;
9419 if (y < 0)
9420 y=0;
9421 else
9422 if (y >= (int) windows->image.height)
9423 y=(int) windows->image.height-1;
9424 } while ((state & ExitState) == 0);
9425 /*
9426 Display magnified image.
9427 */
9428 XSetCursorState(display,windows,MagickFalse);
9429}
9430
9431/*
9432%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9433% %
9434% %
9435% %
9436+ X M a g n i f y W i n d o w C o m m a n d %
9437% %
9438% %
9439% %
9440%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9441%
9442% XMagnifyWindowCommand() moves the image within an Magnify window by one
9443% pixel as specified by the key symbol.
9444%
9445% The format of the XMagnifyWindowCommand method is:
9446%
9447% void XMagnifyWindowCommand(Display *display,XWindows *windows,
cristy6710d842011-10-20 23:23:00 +00009448% const MagickStatusType state,const KeySym key_symbol,
9449% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009450%
9451% A description of each parameter follows:
9452%
9453% o display: Specifies a connection to an X server; returned from
9454% XOpenDisplay.
9455%
9456% o windows: Specifies a pointer to a XWindows structure.
9457%
9458% o state: key mask.
9459%
9460% o key_symbol: Specifies a KeySym which indicates which side of the image
9461% to trim.
9462%
cristy6710d842011-10-20 23:23:00 +00009463% o exception: return any errors or warnings in this structure.
9464%
cristy3ed852e2009-09-05 21:47:34 +00009465*/
9466static void XMagnifyWindowCommand(Display *display,XWindows *windows,
cristy6710d842011-10-20 23:23:00 +00009467 const MagickStatusType state,const KeySym key_symbol,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009468{
9469 unsigned int
9470 quantum;
9471
9472 /*
9473 User specified a magnify factor or position.
9474 */
9475 quantum=1;
9476 if ((state & Mod1Mask) != 0)
9477 quantum=10;
9478 switch ((int) key_symbol)
9479 {
9480 case QuitCommand:
9481 {
9482 (void) XWithdrawWindow(display,windows->magnify.id,
9483 windows->magnify.screen);
9484 break;
9485 }
9486 case XK_Home:
9487 case XK_KP_Home:
9488 {
9489 windows->magnify.x=(int) windows->image.width/2;
9490 windows->magnify.y=(int) windows->image.height/2;
9491 break;
9492 }
9493 case XK_Left:
9494 case XK_KP_Left:
9495 {
9496 if (windows->magnify.x > 0)
9497 windows->magnify.x-=quantum;
9498 break;
9499 }
9500 case XK_Up:
9501 case XK_KP_Up:
9502 {
9503 if (windows->magnify.y > 0)
9504 windows->magnify.y-=quantum;
9505 break;
9506 }
9507 case XK_Right:
9508 case XK_KP_Right:
9509 {
9510 if (windows->magnify.x < (int) (windows->image.ximage->width-1))
9511 windows->magnify.x+=quantum;
9512 break;
9513 }
9514 case XK_Down:
9515 case XK_KP_Down:
9516 {
9517 if (windows->magnify.y < (int) (windows->image.ximage->height-1))
9518 windows->magnify.y+=quantum;
9519 break;
9520 }
9521 case XK_0:
9522 case XK_1:
9523 case XK_2:
9524 case XK_3:
9525 case XK_4:
9526 case XK_5:
9527 case XK_6:
9528 case XK_7:
9529 case XK_8:
9530 case XK_9:
9531 {
9532 windows->magnify.data=(key_symbol-XK_0);
9533 break;
9534 }
9535 case XK_KP_0:
9536 case XK_KP_1:
9537 case XK_KP_2:
9538 case XK_KP_3:
9539 case XK_KP_4:
9540 case XK_KP_5:
9541 case XK_KP_6:
9542 case XK_KP_7:
9543 case XK_KP_8:
9544 case XK_KP_9:
9545 {
9546 windows->magnify.data=(key_symbol-XK_KP_0);
9547 break;
9548 }
9549 default:
9550 break;
9551 }
cristy6710d842011-10-20 23:23:00 +00009552 XMakeMagnifyImage(display,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +00009553}
9554
9555/*
9556%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9557% %
9558% %
9559% %
9560+ X M a k e P a n I m a g e %
9561% %
9562% %
9563% %
9564%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9565%
9566% XMakePanImage() creates a thumbnail of the image and displays it in the Pan
9567% icon window.
9568%
9569% The format of the XMakePanImage method is:
9570%
9571% void XMakePanImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +00009572% XWindows *windows,Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009573%
9574% A description of each parameter follows:
9575%
9576% o display: Specifies a connection to an X server; returned from
9577% XOpenDisplay.
9578%
9579% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9580%
9581% o windows: Specifies a pointer to a XWindows structure.
9582%
9583% o image: the image.
9584%
cristy051718b2011-08-28 22:49:25 +00009585% o exception: return any errors or warnings in this structure.
9586%
cristy3ed852e2009-09-05 21:47:34 +00009587*/
9588static void XMakePanImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +00009589 XWindows *windows,Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009590{
9591 MagickStatusType
9592 status;
9593
9594 /*
9595 Create and display image for panning icon.
9596 */
9597 XSetCursorState(display,windows,MagickTrue);
9598 XCheckRefreshWindows(display,windows);
cristy49e2d862010-11-12 02:50:30 +00009599 windows->pan.x=(int) windows->image.x;
9600 windows->pan.y=(int) windows->image.y;
cristy3ed852e2009-09-05 21:47:34 +00009601 status=XMakeImage(display,resource_info,&windows->pan,image,
cristy051718b2011-08-28 22:49:25 +00009602 windows->pan.width,windows->pan.height,exception);
cristy59864562013-04-18 11:47:41 +00009603 if (IfMagickFalse(status) )
cristybeb1a6b2013-11-04 12:08:18 +00009604 ThrowXWindowException(ResourceLimitError,
cristy051718b2011-08-28 22:49:25 +00009605 "MemoryAllocationFailed",image->filename);
cristy3ed852e2009-09-05 21:47:34 +00009606 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
9607 windows->pan.pixmap);
9608 (void) XClearWindow(display,windows->pan.id);
9609 XDrawPanRectangle(display,windows);
9610 XSetCursorState(display,windows,MagickFalse);
9611}
9612
9613/*
9614%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9615% %
9616% %
9617% %
9618+ X M a t t a E d i t I m a g e %
9619% %
9620% %
9621% %
9622%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9623%
9624% XMatteEditImage() allows the user to interactively change the Matte channel
9625% of an image. If the image is PseudoClass it is promoted to DirectClass
9626% before the matte information is stored.
9627%
9628% The format of the XMatteEditImage method is:
9629%
9630% MagickBooleanType XMatteEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00009631% XResourceInfo *resource_info,XWindows *windows,Image **image,
9632% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009633%
9634% A description of each parameter follows:
9635%
9636% o display: Specifies a connection to an X server; returned from
9637% XOpenDisplay.
9638%
9639% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9640%
9641% o windows: Specifies a pointer to a XWindows structure.
9642%
9643% o image: the image; returned from ReadImage.
9644%
cristy051718b2011-08-28 22:49:25 +00009645% o exception: return any errors or warnings in this structure.
9646%
cristy3ed852e2009-09-05 21:47:34 +00009647*/
9648static MagickBooleanType XMatteEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00009649 XResourceInfo *resource_info,XWindows *windows,Image **image,
9650 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009651{
9652 static char
cristy151b66d2015-04-15 10:50:31 +00009653 matte[MagickPathExtent] = "0";
cristy3ed852e2009-09-05 21:47:34 +00009654
9655 static const char
9656 *MatteEditMenu[] =
9657 {
9658 "Method",
9659 "Border Color",
9660 "Fuzz",
9661 "Matte Value",
9662 "Undo",
9663 "Help",
9664 "Dismiss",
9665 (char *) NULL
9666 };
9667
9668 static const ModeType
9669 MatteEditCommands[] =
9670 {
9671 MatteEditMethod,
9672 MatteEditBorderCommand,
9673 MatteEditFuzzCommand,
9674 MatteEditValueCommand,
9675 MatteEditUndoCommand,
9676 MatteEditHelpCommand,
9677 MatteEditDismissCommand
9678 };
9679
9680 static PaintMethod
9681 method = PointMethod;
9682
9683 static XColor
9684 border_color = { 0, 0, 0, 0, 0, 0 };
9685
9686 char
cristy151b66d2015-04-15 10:50:31 +00009687 command[MagickPathExtent],
9688 text[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00009689
9690 Cursor
9691 cursor;
9692
9693 int
9694 entry,
9695 id,
9696 x,
9697 x_offset,
9698 y,
9699 y_offset;
9700
9701 register int
9702 i;
9703
cristy4c08aed2011-07-01 19:47:50 +00009704 register Quantum
cristy3ed852e2009-09-05 21:47:34 +00009705 *q;
9706
9707 unsigned int
9708 height,
9709 width;
9710
cristybb503372010-05-27 20:51:26 +00009711 size_t
cristy3ed852e2009-09-05 21:47:34 +00009712 state;
9713
9714 XEvent
9715 event;
9716
9717 /*
9718 Map Command widget.
9719 */
9720 (void) CloneString(&windows->command.name,"Matte Edit");
9721 windows->command.data=4;
9722 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL);
9723 (void) XMapRaised(display,windows->command.id);
9724 XClientMessage(display,windows->image.id,windows->im_protocols,
9725 windows->im_update_widget,CurrentTime);
9726 /*
9727 Make cursor.
9728 */
9729 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
9730 resource_info->background_color,resource_info->foreground_color);
9731 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9732 /*
9733 Track pointer until button 1 is pressed.
9734 */
9735 XQueryPosition(display,windows->image.id,&x,&y);
9736 (void) XSelectInput(display,windows->image.id,
9737 windows->image.attributes.event_mask | PointerMotionMask);
9738 state=DefaultState;
9739 do
9740 {
cristy59864562013-04-18 11:47:41 +00009741 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00009742 {
9743 /*
9744 Display pointer position.
9745 */
cristy151b66d2015-04-15 10:50:31 +00009746 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +00009747 x+windows->image.x,y+windows->image.y);
9748 XInfoWidget(display,windows,text);
9749 }
9750 /*
9751 Wait for next event.
9752 */
cristy6710d842011-10-20 23:23:00 +00009753 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00009754 if (event.xany.window == windows->command.id)
9755 {
9756 /*
9757 Select a command from the Command widget.
9758 */
9759 id=XCommandWidget(display,windows,MatteEditMenu,&event);
9760 if (id < 0)
9761 {
9762 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9763 continue;
9764 }
9765 switch (MatteEditCommands[id])
9766 {
9767 case MatteEditMethod:
9768 {
9769 char
9770 **methods;
9771
9772 /*
9773 Select a method from the pop-up menu.
9774 */
cristy042ee782011-04-22 18:48:30 +00009775 methods=GetCommandOptions(MagickMethodOptions);
cristy3ed852e2009-09-05 21:47:34 +00009776 if (methods == (char **) NULL)
9777 break;
9778 entry=XMenuWidget(display,windows,MatteEditMenu[id],
9779 (const char **) methods,command);
9780 if (entry >= 0)
cristy042ee782011-04-22 18:48:30 +00009781 method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
cristy3ed852e2009-09-05 21:47:34 +00009782 MagickFalse,methods[entry]);
9783 methods=DestroyStringList(methods);
9784 break;
9785 }
9786 case MatteEditBorderCommand:
9787 {
9788 const char
9789 *ColorMenu[MaxNumberPens];
9790
9791 int
9792 pen_number;
9793
9794 /*
9795 Initialize menu selections.
9796 */
9797 for (i=0; i < (int) (MaxNumberPens-2); i++)
9798 ColorMenu[i]=resource_info->pen_colors[i];
9799 ColorMenu[MaxNumberPens-2]="Browser...";
9800 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
9801 /*
9802 Select a pen color from the pop-up menu.
9803 */
9804 pen_number=XMenuWidget(display,windows,MatteEditMenu[id],
9805 (const char **) ColorMenu,command);
9806 if (pen_number < 0)
9807 break;
9808 if (pen_number == (MaxNumberPens-2))
9809 {
9810 static char
cristy151b66d2015-04-15 10:50:31 +00009811 color_name[MagickPathExtent] = "gray";
cristy3ed852e2009-09-05 21:47:34 +00009812
9813 /*
9814 Select a pen color from a dialog.
9815 */
9816 resource_info->pen_colors[pen_number]=color_name;
9817 XColorBrowserWidget(display,windows,"Select",color_name);
9818 if (*color_name == '\0')
9819 break;
9820 }
9821 /*
9822 Set border color.
9823 */
9824 (void) XParseColor(display,windows->map_info->colormap,
9825 resource_info->pen_colors[pen_number],&border_color);
9826 break;
9827 }
9828 case MatteEditFuzzCommand:
9829 {
9830 static char
cristy151b66d2015-04-15 10:50:31 +00009831 fuzz[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00009832
9833 static const char
9834 *FuzzMenu[] =
9835 {
9836 "0%",
9837 "2%",
9838 "5%",
9839 "10%",
9840 "15%",
9841 "Dialog...",
9842 (char *) NULL,
9843 };
9844
9845 /*
9846 Select a command from the pop-up menu.
9847 */
9848 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu,
9849 command);
9850 if (entry < 0)
9851 break;
9852 if (entry != 5)
9853 {
cristydbdd0e32011-11-04 23:29:40 +00009854 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double)
cristy4c08aed2011-07-01 19:47:50 +00009855 QuantumRange+1.0);
cristy3ed852e2009-09-05 21:47:34 +00009856 break;
9857 }
cristy151b66d2015-04-15 10:50:31 +00009858 (void) CopyMagickString(fuzz,"20%",MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00009859 (void) XDialogWidget(display,windows,"Ok",
9860 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
9861 if (*fuzz == '\0')
9862 break;
cristy151b66d2015-04-15 10:50:31 +00009863 (void) ConcatenateMagickString(fuzz,"%",MagickPathExtent);
cristy9b34e302011-11-05 02:15:45 +00009864 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+
9865 1.0);
cristy3ed852e2009-09-05 21:47:34 +00009866 break;
9867 }
9868 case MatteEditValueCommand:
9869 {
9870 static char
cristy151b66d2015-04-15 10:50:31 +00009871 message[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00009872
9873 static const char
9874 *MatteMenu[] =
9875 {
9876 "Opaque",
9877 "Transparent",
9878 "Dialog...",
9879 (char *) NULL,
9880 };
9881
9882 /*
9883 Select a command from the pop-up menu.
9884 */
9885 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu,
9886 command);
9887 if (entry < 0)
9888 break;
9889 if (entry != 2)
9890 {
cristy151b66d2015-04-15 10:50:31 +00009891 (void) FormatLocaleString(matte,MagickPathExtent,QuantumFormat,
cristy4c08aed2011-07-01 19:47:50 +00009892 OpaqueAlpha);
cristy3ed852e2009-09-05 21:47:34 +00009893 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0)
cristy151b66d2015-04-15 10:50:31 +00009894 (void) FormatLocaleString(matte,MagickPathExtent,QuantumFormat,
cristy4c08aed2011-07-01 19:47:50 +00009895 (Quantum) TransparentAlpha);
cristy3ed852e2009-09-05 21:47:34 +00009896 break;
9897 }
cristy151b66d2015-04-15 10:50:31 +00009898 (void) FormatLocaleString(message,MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +00009899 "Enter matte value (0 - " QuantumFormat "):",(Quantum)
9900 QuantumRange);
9901 (void) XDialogWidget(display,windows,"Matte",message,matte);
9902 if (*matte == '\0')
9903 break;
9904 break;
9905 }
9906 case MatteEditUndoCommand:
9907 {
9908 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
cristy051718b2011-08-28 22:49:25 +00009909 image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009910 break;
9911 }
9912 case MatteEditHelpCommand:
9913 {
9914 XTextViewWidget(display,resource_info,windows,MagickFalse,
9915 "Help Viewer - Matte Edit",ImageMatteEditHelp);
9916 break;
9917 }
9918 case MatteEditDismissCommand:
9919 {
9920 /*
9921 Prematurely exit.
9922 */
9923 state|=EscapeState;
9924 state|=ExitState;
9925 break;
9926 }
9927 default:
9928 break;
9929 }
9930 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9931 continue;
9932 }
9933 switch (event.type)
9934 {
9935 case ButtonPress:
9936 {
9937 if (event.xbutton.button != Button1)
9938 break;
9939 if ((event.xbutton.window != windows->image.id) &&
9940 (event.xbutton.window != windows->magnify.id))
9941 break;
9942 /*
9943 Update matte data.
9944 */
9945 x=event.xbutton.x;
9946 y=event.xbutton.y;
9947 (void) XMagickCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +00009948 SaveToUndoBufferCommand,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009949 state|=UpdateConfigurationState;
9950 break;
9951 }
9952 case ButtonRelease:
9953 {
9954 if (event.xbutton.button != Button1)
9955 break;
9956 if ((event.xbutton.window != windows->image.id) &&
9957 (event.xbutton.window != windows->magnify.id))
9958 break;
9959 /*
9960 Update colormap information.
9961 */
9962 x=event.xbutton.x;
9963 y=event.xbutton.y;
cristy6710d842011-10-20 23:23:00 +00009964 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00009965 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009966 XInfoWidget(display,windows,text);
9967 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9968 state&=(~UpdateConfigurationState);
9969 break;
9970 }
9971 case Expose:
9972 break;
9973 case KeyPress:
9974 {
9975 char
cristy151b66d2015-04-15 10:50:31 +00009976 command[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00009977
9978 KeySym
9979 key_symbol;
9980
9981 if (event.xkey.window == windows->magnify.id)
9982 {
9983 Window
9984 window;
9985
9986 window=windows->magnify.id;
9987 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
9988 }
9989 if (event.xkey.window != windows->image.id)
9990 break;
9991 /*
9992 Respond to a user key press.
9993 */
9994 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
9995 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
9996 switch ((int) key_symbol)
9997 {
9998 case XK_Escape:
9999 case XK_F20:
10000 {
10001 /*
10002 Prematurely exit.
10003 */
10004 state|=ExitState;
10005 break;
10006 }
10007 case XK_F1:
10008 case XK_Help:
10009 {
10010 XTextViewWidget(display,resource_info,windows,MagickFalse,
10011 "Help Viewer - Matte Edit",ImageMatteEditHelp);
10012 break;
10013 }
10014 default:
10015 {
10016 (void) XBell(display,0);
10017 break;
10018 }
10019 }
10020 break;
10021 }
10022 case MotionNotify:
10023 {
10024 /*
10025 Map and unmap Info widget as cursor crosses its boundaries.
10026 */
10027 x=event.xmotion.x;
10028 y=event.xmotion.y;
cristy59864562013-04-18 11:47:41 +000010029 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000010030 {
10031 if ((x < (int) (windows->info.x+windows->info.width)) &&
10032 (y < (int) (windows->info.y+windows->info.height)))
10033 (void) XWithdrawWindow(display,windows->info.id,
10034 windows->info.screen);
10035 }
10036 else
10037 if ((x > (int) (windows->info.x+windows->info.width)) ||
10038 (y > (int) (windows->info.y+windows->info.height)))
10039 (void) XMapWindow(display,windows->info.id);
10040 break;
10041 }
10042 default:
10043 break;
10044 }
10045 if (event.xany.window == windows->magnify.id)
10046 {
10047 x=windows->magnify.x-windows->image.x;
10048 y=windows->magnify.y-windows->image.y;
10049 }
10050 x_offset=x;
10051 y_offset=y;
10052 if ((state & UpdateConfigurationState) != 0)
10053 {
cristy49e2d862010-11-12 02:50:30 +000010054 CacheView
10055 *image_view;
10056
cristy3ed852e2009-09-05 21:47:34 +000010057 int
10058 x,
10059 y;
10060
10061 /*
10062 Matte edit is relative to image configuration.
10063 */
10064 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
10065 MagickTrue);
10066 XPutPixel(windows->image.ximage,x_offset,y_offset,
10067 windows->pixel_info->background_color.pixel);
10068 width=(unsigned int) (*image)->columns;
10069 height=(unsigned int) (*image)->rows;
10070 x=0;
10071 y=0;
10072 if (windows->image.crop_geometry != (char *) NULL)
cristy4c08aed2011-07-01 19:47:50 +000010073 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,
10074 &height);
10075 x_offset=(int) (width*(windows->image.x+x_offset)/
10076 windows->image.ximage->width+x);
10077 y_offset=(int) (height*(windows->image.y+y_offset)/
10078 windows->image.ximage->height+y);
cristy3ed852e2009-09-05 21:47:34 +000010079 if ((x_offset < 0) || (y_offset < 0))
10080 continue;
10081 if ((x_offset >= (int) (*image)->columns) ||
10082 (y_offset >= (int) (*image)->rows))
10083 continue;
cristy59864562013-04-18 11:47:41 +000010084 if (IfMagickFalse(SetImageStorageClass(*image,DirectClass,exception)) )
cristy3ed852e2009-09-05 21:47:34 +000010085 return(MagickFalse);
cristy17f11b02014-12-20 19:37:04 +000010086 if ((*image)->alpha_trait == UndefinedPixelTrait)
cristycd515282011-12-27 01:40:49 +000010087 (void) SetImageAlphaChannel(*image,OpaqueAlphaChannel,exception);
cristy6f5395d2012-12-14 18:30:30 +000010088 image_view=AcquireAuthenticCacheView(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +000010089 switch (method)
10090 {
10091 case PointMethod:
10092 default:
10093 {
10094 /*
10095 Update matte information using point algorithm.
10096 */
cristy49e2d862010-11-12 02:50:30 +000010097 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,
10098 (ssize_t) y_offset,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +000010099 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +000010100 break;
cristy4c08aed2011-07-01 19:47:50 +000010101 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
cristy49e2d862010-11-12 02:50:30 +000010102 (void) SyncCacheViewAuthenticPixels(image_view,exception);
cristy3ed852e2009-09-05 21:47:34 +000010103 break;
10104 }
10105 case ReplaceMethod:
10106 {
cristy101ab702011-10-13 13:06:32 +000010107 PixelInfo
cristy4c08aed2011-07-01 19:47:50 +000010108 pixel,
cristy3ed852e2009-09-05 21:47:34 +000010109 target;
10110
10111 /*
10112 Update matte information using replace algorithm.
10113 */
cristyf05d4942012-03-17 16:26:09 +000010114 (void) GetOneCacheViewVirtualPixelInfo(image_view,(ssize_t)
10115 x_offset,(ssize_t) y_offset,&target,exception);
cristy49e2d862010-11-12 02:50:30 +000010116 for (y=0; y < (int) (*image)->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +000010117 {
cristy49e2d862010-11-12 02:50:30 +000010118 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
cristy051718b2011-08-28 22:49:25 +000010119 (*image)->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +000010120 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +000010121 break;
10122 for (x=0; x < (int) (*image)->columns; x++)
10123 {
cristy101ab702011-10-13 13:06:32 +000010124 GetPixelInfoPixel(*image,q,&pixel);
10125 if (IsFuzzyEquivalencePixelInfo(&pixel,&target))
cristy4c08aed2011-07-01 19:47:50 +000010126 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
cristyed231572011-07-14 02:18:59 +000010127 q+=GetPixelChannels(*image);
cristy3ed852e2009-09-05 21:47:34 +000010128 }
cristy59864562013-04-18 11:47:41 +000010129 if (IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) )
cristy3ed852e2009-09-05 21:47:34 +000010130 break;
10131 }
10132 break;
10133 }
10134 case FloodfillMethod:
10135 case FillToBorderMethod:
10136 {
cristybd5a96c2011-08-21 00:04:26 +000010137 ChannelType
10138 channel_mask;
10139
cristy3ed852e2009-09-05 21:47:34 +000010140 DrawInfo
10141 *draw_info;
10142
cristy4c08aed2011-07-01 19:47:50 +000010143 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +000010144 target;
10145
10146 /*
10147 Update matte information using floodfill algorithm.
10148 */
cristy3aa93752011-12-18 15:54:24 +000010149 (void) GetOneVirtualPixelInfo(*image,
cristy52010022011-10-21 18:07:37 +000010150 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t)
10151 y_offset,&target,exception);
cristy3ed852e2009-09-05 21:47:34 +000010152 if (method == FillToBorderMethod)
10153 {
cristya19f1d72012-08-07 18:24:38 +000010154 target.red=(double) ScaleShortToQuantum(
cristy4c08aed2011-07-01 19:47:50 +000010155 border_color.red);
cristya19f1d72012-08-07 18:24:38 +000010156 target.green=(double) ScaleShortToQuantum(
cristy4c08aed2011-07-01 19:47:50 +000010157 border_color.green);
cristya19f1d72012-08-07 18:24:38 +000010158 target.blue=(double) ScaleShortToQuantum(
cristy4c08aed2011-07-01 19:47:50 +000010159 border_color.blue);
cristy3ed852e2009-09-05 21:47:34 +000010160 }
10161 draw_info=CloneDrawInfo(resource_info->image_info,
10162 (DrawInfo *) NULL);
cristya19f1d72012-08-07 18:24:38 +000010163 draw_info->fill.alpha=(double) ClampToQuantum(
cristye42f6582012-02-11 17:59:50 +000010164 StringToDouble(matte,(char **) NULL));
cristyaeded782012-09-11 23:39:36 +000010165 channel_mask=SetImageChannelMask(*image,AlphaChannel);
cristyd42d9952011-07-08 14:21:50 +000010166 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t)
anthony11d32022012-11-17 05:31:33 +000010167 x_offset,(ssize_t) y_offset,
dirkb9dbc292015-07-26 09:50:00 +000010168 method != FloodfillMethod ? MagickTrue : MagickFalse,exception);
cristycf1296e2012-08-26 23:40:49 +000010169 (void) SetPixelChannelMask(*image,channel_mask);
cristy3ed852e2009-09-05 21:47:34 +000010170 draw_info=DestroyDrawInfo(draw_info);
10171 break;
10172 }
10173 case ResetMethod:
10174 {
10175 /*
10176 Update matte information using reset algorithm.
10177 */
cristy59864562013-04-18 11:47:41 +000010178 if (IfMagickFalse(SetImageStorageClass(*image,DirectClass,exception)) )
cristy3ed852e2009-09-05 21:47:34 +000010179 return(MagickFalse);
cristy49e2d862010-11-12 02:50:30 +000010180 for (y=0; y < (int) (*image)->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +000010181 {
cristy49e2d862010-11-12 02:50:30 +000010182 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
10183 (*image)->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +000010184 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +000010185 break;
10186 for (x=0; x < (int) (*image)->columns; x++)
10187 {
cristy4c08aed2011-07-01 19:47:50 +000010188 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
cristyed231572011-07-14 02:18:59 +000010189 q+=GetPixelChannels(*image);
cristy3ed852e2009-09-05 21:47:34 +000010190 }
cristy59864562013-04-18 11:47:41 +000010191 if (IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) )
cristy3ed852e2009-09-05 21:47:34 +000010192 break;
10193 }
cristy4c08aed2011-07-01 19:47:50 +000010194 if (StringToLong(matte) == (long) OpaqueAlpha)
cristy8a46d822012-08-28 23:32:39 +000010195 (*image)->alpha_trait=UndefinedPixelTrait;
cristy3ed852e2009-09-05 21:47:34 +000010196 break;
10197 }
10198 }
cristy49e2d862010-11-12 02:50:30 +000010199 image_view=DestroyCacheView(image_view);
cristy3ed852e2009-09-05 21:47:34 +000010200 state&=(~UpdateConfigurationState);
10201 }
10202 } while ((state & ExitState) == 0);
10203 (void) XSelectInput(display,windows->image.id,
10204 windows->image.attributes.event_mask);
10205 XSetCursorState(display,windows,MagickFalse);
10206 (void) XFreeCursor(display,cursor);
10207 return(MagickTrue);
10208}
10209
10210/*
10211%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10212% %
10213% %
10214% %
10215+ X O p e n I m a g e %
10216% %
10217% %
10218% %
10219%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10220%
10221% XOpenImage() loads an image from a file.
10222%
10223% The format of the XOpenImage method is:
10224%
10225% Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10226% XWindows *windows,const unsigned int command)
10227%
10228% A description of each parameter follows:
10229%
10230% o display: Specifies a connection to an X server; returned from
10231% XOpenDisplay.
10232%
10233% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10234%
10235% o windows: Specifies a pointer to a XWindows structure.
10236%
10237% o command: A value other than zero indicates that the file is selected
10238% from the command line argument list.
10239%
10240*/
10241static Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10242 XWindows *windows,const MagickBooleanType command)
10243{
10244 const MagickInfo
10245 *magick_info;
10246
10247 ExceptionInfo
10248 *exception;
10249
10250 Image
10251 *nexus;
10252
10253 ImageInfo
10254 *image_info;
10255
10256 static char
cristy151b66d2015-04-15 10:50:31 +000010257 filename[MagickPathExtent] = "\0";
cristy3ed852e2009-09-05 21:47:34 +000010258
10259 /*
10260 Request file name from user.
10261 */
cristy59864562013-04-18 11:47:41 +000010262 if (IfMagickFalse(command) )
cristy3ed852e2009-09-05 21:47:34 +000010263 XFileBrowserWidget(display,windows,"Open",filename);
10264 else
10265 {
10266 char
10267 **filelist,
10268 **files;
10269
10270 int
10271 count,
10272 status;
10273
10274 register int
10275 i,
10276 j;
10277
10278 /*
10279 Select next image from the command line.
10280 */
10281 status=XGetCommand(display,windows->image.id,&files,&count);
10282 if (status == 0)
10283 {
cristybeb1a6b2013-11-04 12:08:18 +000010284 ThrowXWindowException(XServerError,"UnableToGetProperty","...");
cristy3ed852e2009-09-05 21:47:34 +000010285 return((Image *) NULL);
10286 }
10287 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist));
10288 if (filelist == (char **) NULL)
10289 {
cristybeb1a6b2013-11-04 12:08:18 +000010290 ThrowXWindowException(ResourceLimitError,
cristy3ed852e2009-09-05 21:47:34 +000010291 "MemoryAllocationFailed","...");
10292 (void) XFreeStringList(files);
10293 return((Image *) NULL);
10294 }
10295 j=0;
10296 for (i=1; i < count; i++)
10297 if (*files[i] != '-')
10298 filelist[j++]=files[i];
10299 filelist[j]=(char *) NULL;
10300 XListBrowserWidget(display,windows,&windows->widget,
10301 (const char **) filelist,"Load","Select Image to Load:",filename);
10302 filelist=(char **) RelinquishMagickMemory(filelist);
10303 (void) XFreeStringList(files);
10304 }
10305 if (*filename == '\0')
10306 return((Image *) NULL);
10307 image_info=CloneImageInfo(resource_info->image_info);
10308 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL,
10309 (void *) NULL);
cristy151b66d2015-04-15 10:50:31 +000010310 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +000010311 exception=AcquireExceptionInfo();
cristyd965a422010-03-03 17:47:35 +000010312 (void) SetImageInfo(image_info,0,exception);
cristy3ed852e2009-09-05 21:47:34 +000010313 if (LocaleCompare(image_info->magick,"X") == 0)
10314 {
10315 char
cristy151b66d2015-04-15 10:50:31 +000010316 seconds[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +000010317
10318 /*
10319 User may want to delay the X server screen grab.
10320 */
cristy151b66d2015-04-15 10:50:31 +000010321 (void) CopyMagickString(seconds,"0",MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +000010322 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:",
10323 seconds);
10324 if (*seconds == '\0')
10325 return((Image *) NULL);
cristybb503372010-05-27 20:51:26 +000010326 XDelay(display,(size_t) (1000*StringToLong(seconds)));
cristy3ed852e2009-09-05 21:47:34 +000010327 }
10328 magick_info=GetMagickInfo(image_info->magick,exception);
10329 if ((magick_info != (const MagickInfo *) NULL) &&
dirke8e609a2015-02-22 00:36:34 +000010330 GetMagickRawSupport(magick_info) == MagickTrue)
cristy3ed852e2009-09-05 21:47:34 +000010331 {
10332 char
cristy151b66d2015-04-15 10:50:31 +000010333 geometry[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +000010334
10335 /*
10336 Request image size from the user.
10337 */
cristy151b66d2015-04-15 10:50:31 +000010338 (void) CopyMagickString(geometry,"512x512",MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +000010339 if (image_info->size != (char *) NULL)
cristy151b66d2015-04-15 10:50:31 +000010340 (void) CopyMagickString(geometry,image_info->size,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +000010341 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:",
10342 geometry);
10343 (void) CloneString(&image_info->size,geometry);
10344 }
10345 /*
10346 Load the image.
10347 */
10348 XSetCursorState(display,windows,MagickTrue);
10349 XCheckRefreshWindows(display,windows);
cristy151b66d2015-04-15 10:50:31 +000010350 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +000010351 nexus=ReadImage(image_info,exception);
10352 CatchException(exception);
10353 XSetCursorState(display,windows,MagickFalse);
10354 if (nexus != (Image *) NULL)
10355 XClientMessage(display,windows->image.id,windows->im_protocols,
10356 windows->im_next_image,CurrentTime);
10357 else
10358 {
10359 char
10360 *text,
10361 **textlist;
10362
10363 /*
10364 Unknown image format.
10365 */
cristy3a5987c2013-11-07 14:18:46 +000010366 text=FileToString(filename,~0UL,exception);
cristy3ed852e2009-09-05 21:47:34 +000010367 if (text == (char *) NULL)
10368 return((Image *) NULL);
10369 textlist=StringToList(text);
10370 if (textlist != (char **) NULL)
10371 {
10372 char
cristy151b66d2015-04-15 10:50:31 +000010373 title[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +000010374
10375 register int
10376 i;
10377
cristy151b66d2015-04-15 10:50:31 +000010378 (void) FormatLocaleString(title,MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +000010379 "Unknown format: %s",filename);
10380 XTextViewWidget(display,resource_info,windows,MagickTrue,title,
10381 (const char **) textlist);
10382 for (i=0; textlist[i] != (char *) NULL; i++)
10383 textlist[i]=DestroyString(textlist[i]);
10384 textlist=(char **) RelinquishMagickMemory(textlist);
10385 }
10386 text=DestroyString(text);
10387 }
10388 exception=DestroyExceptionInfo(exception);
10389 image_info=DestroyImageInfo(image_info);
10390 return(nexus);
10391}
10392
10393/*
10394%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10395% %
10396% %
10397% %
10398+ X P a n I m a g e %
10399% %
10400% %
10401% %
10402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10403%
10404% XPanImage() pans the image until the mouse button is released.
10405%
10406% The format of the XPanImage method is:
10407%
cristy6710d842011-10-20 23:23:00 +000010408% void XPanImage(Display *display,XWindows *windows,XEvent *event,
10409% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000010410%
10411% A description of each parameter follows:
10412%
10413% o display: Specifies a connection to an X server; returned from
10414% XOpenDisplay.
10415%
10416% o windows: Specifies a pointer to a XWindows structure.
10417%
10418% o event: Specifies a pointer to a XEvent structure. If it is NULL,
10419% the entire image is refreshed.
10420%
cristy6710d842011-10-20 23:23:00 +000010421% o exception: return any errors or warnings in this structure.
10422%
cristy3ed852e2009-09-05 21:47:34 +000010423*/
cristy6710d842011-10-20 23:23:00 +000010424static void XPanImage(Display *display,XWindows *windows,XEvent *event,
10425 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000010426{
10427 char
cristy151b66d2015-04-15 10:50:31 +000010428 text[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +000010429
10430 Cursor
10431 cursor;
10432
cristya19f1d72012-08-07 18:24:38 +000010433 double
cristy3ed852e2009-09-05 21:47:34 +000010434 x_factor,
10435 y_factor;
10436
10437 RectangleInfo
10438 pan_info;
10439
cristybb503372010-05-27 20:51:26 +000010440 size_t
cristy3ed852e2009-09-05 21:47:34 +000010441 state;
10442
10443 /*
10444 Define cursor.
10445 */
10446 if ((windows->image.ximage->width > (int) windows->image.width) &&
10447 (windows->image.ximage->height > (int) windows->image.height))
10448 cursor=XCreateFontCursor(display,XC_fleur);
10449 else
10450 if (windows->image.ximage->width > (int) windows->image.width)
10451 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow);
10452 else
10453 if (windows->image.ximage->height > (int) windows->image.height)
10454 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow);
10455 else
10456 cursor=XCreateFontCursor(display,XC_arrow);
10457 (void) XCheckDefineCursor(display,windows->pan.id,cursor);
10458 /*
10459 Pan image as pointer moves until the mouse button is released.
10460 */
cristya19f1d72012-08-07 18:24:38 +000010461 x_factor=(double) windows->image.ximage->width/windows->pan.width;
10462 y_factor=(double) windows->image.ximage->height/windows->pan.height;
cristy3ed852e2009-09-05 21:47:34 +000010463 pan_info.width=windows->pan.width*windows->image.width/
10464 windows->image.ximage->width;
10465 pan_info.height=windows->pan.height*windows->image.height/
10466 windows->image.ximage->height;
10467 pan_info.x=0;
10468 pan_info.y=0;
10469 state=UpdateConfigurationState;
10470 do
10471 {
10472 switch (event->type)
10473 {
10474 case ButtonPress:
10475 {
10476 /*
10477 User choose an initial pan location.
10478 */
cristy49e2d862010-11-12 02:50:30 +000010479 pan_info.x=(ssize_t) event->xbutton.x;
10480 pan_info.y=(ssize_t) event->xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000010481 state|=UpdateConfigurationState;
10482 break;
10483 }
10484 case ButtonRelease:
10485 {
10486 /*
10487 User has finished panning the image.
10488 */
cristy49e2d862010-11-12 02:50:30 +000010489 pan_info.x=(ssize_t) event->xbutton.x;
10490 pan_info.y=(ssize_t) event->xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000010491 state|=UpdateConfigurationState | ExitState;
10492 break;
10493 }
10494 case MotionNotify:
10495 {
cristy49e2d862010-11-12 02:50:30 +000010496 pan_info.x=(ssize_t) event->xmotion.x;
10497 pan_info.y=(ssize_t) event->xmotion.y;
cristy3ed852e2009-09-05 21:47:34 +000010498 state|=UpdateConfigurationState;
10499 }
10500 default:
10501 break;
10502 }
10503 if ((state & UpdateConfigurationState) != 0)
10504 {
10505 /*
10506 Check boundary conditions.
10507 */
cristy49e2d862010-11-12 02:50:30 +000010508 if (pan_info.x < (ssize_t) (pan_info.width/2))
cristy3ed852e2009-09-05 21:47:34 +000010509 pan_info.x=0;
10510 else
cristy49e2d862010-11-12 02:50:30 +000010511 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2)));
cristy3ed852e2009-09-05 21:47:34 +000010512 if (pan_info.x < 0)
10513 pan_info.x=0;
10514 else
10515 if ((int) (pan_info.x+windows->image.width) >
10516 windows->image.ximage->width)
cristybb503372010-05-27 20:51:26 +000010517 pan_info.x=(ssize_t)
cristy3ed852e2009-09-05 21:47:34 +000010518 (windows->image.ximage->width-windows->image.width);
cristybb503372010-05-27 20:51:26 +000010519 if (pan_info.y < (ssize_t) (pan_info.height/2))
cristy3ed852e2009-09-05 21:47:34 +000010520 pan_info.y=0;
10521 else
cristybb503372010-05-27 20:51:26 +000010522 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2)));
cristy3ed852e2009-09-05 21:47:34 +000010523 if (pan_info.y < 0)
10524 pan_info.y=0;
10525 else
10526 if ((int) (pan_info.y+windows->image.height) >
10527 windows->image.ximage->height)
cristybb503372010-05-27 20:51:26 +000010528 pan_info.y=(ssize_t)
cristy3ed852e2009-09-05 21:47:34 +000010529 (windows->image.ximage->height-windows->image.height);
10530 if ((windows->image.x != (int) pan_info.x) ||
10531 (windows->image.y != (int) pan_info.y))
10532 {
10533 /*
10534 Display image pan offset.
10535 */
10536 windows->image.x=(int) pan_info.x;
10537 windows->image.y=(int) pan_info.y;
cristy151b66d2015-04-15 10:50:31 +000010538 (void) FormatLocaleString(text,MagickPathExtent," %ux%u%+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +000010539 windows->image.width,windows->image.height,windows->image.x,
10540 windows->image.y);
10541 XInfoWidget(display,windows,text);
10542 /*
10543 Refresh Image window.
10544 */
10545 XDrawPanRectangle(display,windows);
10546 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
10547 }
10548 state&=(~UpdateConfigurationState);
10549 }
10550 /*
10551 Wait for next event.
10552 */
10553 if ((state & ExitState) == 0)
cristy6710d842011-10-20 23:23:00 +000010554 XScreenEvent(display,windows,event,exception);
cristy3ed852e2009-09-05 21:47:34 +000010555 } while ((state & ExitState) == 0);
10556 /*
10557 Restore cursor.
10558 */
10559 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor);
10560 (void) XFreeCursor(display,cursor);
10561 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
10562}
10563
10564/*
10565%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10566% %
10567% %
10568% %
10569+ X P a s t e I m a g e %
10570% %
10571% %
10572% %
10573%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10574%
10575% XPasteImage() pastes an image previously saved with XCropImage in the X
10576% window image at a location the user chooses with the pointer.
10577%
10578% The format of the XPasteImage method is:
10579%
10580% MagickBooleanType XPasteImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000010581% XResourceInfo *resource_info,XWindows *windows,Image *image,
10582% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000010583%
10584% A description of each parameter follows:
10585%
10586% o display: Specifies a connection to an X server; returned from
10587% XOpenDisplay.
10588%
10589% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10590%
10591% o windows: Specifies a pointer to a XWindows structure.
10592%
10593% o image: the image; returned from ReadImage.
10594%
cristy051718b2011-08-28 22:49:25 +000010595% o exception: return any errors or warnings in this structure.
10596%
cristy3ed852e2009-09-05 21:47:34 +000010597*/
10598static MagickBooleanType XPasteImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000010599 XResourceInfo *resource_info,XWindows *windows,Image *image,
10600 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000010601{
10602 static const char
10603 *PasteMenu[] =
10604 {
10605 "Operator",
10606 "Help",
10607 "Dismiss",
10608 (char *) NULL
10609 };
10610
10611 static const ModeType
10612 PasteCommands[] =
10613 {
10614 PasteOperatorsCommand,
10615 PasteHelpCommand,
10616 PasteDismissCommand
10617 };
10618
10619 static CompositeOperator
10620 compose = CopyCompositeOp;
10621
10622 char
cristy151b66d2015-04-15 10:50:31 +000010623 text[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +000010624
10625 Cursor
10626 cursor;
10627
10628 Image
10629 *paste_image;
10630
10631 int
10632 entry,
10633 id,
10634 x,
10635 y;
10636
cristya19f1d72012-08-07 18:24:38 +000010637 double
cristy3ed852e2009-09-05 21:47:34 +000010638 scale_factor;
10639
10640 RectangleInfo
10641 highlight_info,
10642 paste_info;
10643
10644 unsigned int
10645 height,
10646 width;
10647
cristybb503372010-05-27 20:51:26 +000010648 size_t
cristy3ed852e2009-09-05 21:47:34 +000010649 state;
10650
10651 XEvent
10652 event;
10653
10654 /*
10655 Copy image.
10656 */
10657 if (resource_info->copy_image == (Image *) NULL)
10658 return(MagickFalse);
cristy051718b2011-08-28 22:49:25 +000010659 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +000010660 /*
10661 Map Command widget.
10662 */
10663 (void) CloneString(&windows->command.name,"Paste");
10664 windows->command.data=1;
10665 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL);
10666 (void) XMapRaised(display,windows->command.id);
10667 XClientMessage(display,windows->image.id,windows->im_protocols,
10668 windows->im_update_widget,CurrentTime);
10669 /*
10670 Track pointer until button 1 is pressed.
10671 */
10672 XSetCursorState(display,windows,MagickFalse);
10673 XQueryPosition(display,windows->image.id,&x,&y);
10674 (void) XSelectInput(display,windows->image.id,
10675 windows->image.attributes.event_mask | PointerMotionMask);
cristy49e2d862010-11-12 02:50:30 +000010676 paste_info.x=(ssize_t) windows->image.x+x;
10677 paste_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +000010678 paste_info.width=0;
10679 paste_info.height=0;
10680 cursor=XCreateFontCursor(display,XC_ul_angle);
10681 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
10682 state=DefaultState;
10683 do
10684 {
cristy59864562013-04-18 11:47:41 +000010685 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000010686 {
10687 /*
10688 Display pointer position.
10689 */
cristy151b66d2015-04-15 10:50:31 +000010690 (void) FormatLocaleString(text,MagickPathExtent," %+ld%+ld ",
cristyf2faecf2010-05-28 19:19:36 +000010691 (long) paste_info.x,(long) paste_info.y);
cristy3ed852e2009-09-05 21:47:34 +000010692 XInfoWidget(display,windows,text);
10693 }
10694 highlight_info=paste_info;
10695 highlight_info.x=paste_info.x-windows->image.x;
10696 highlight_info.y=paste_info.y-windows->image.y;
10697 XHighlightRectangle(display,windows->image.id,
10698 windows->image.highlight_context,&highlight_info);
10699 /*
10700 Wait for next event.
10701 */
cristy6710d842011-10-20 23:23:00 +000010702 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000010703 XHighlightRectangle(display,windows->image.id,
10704 windows->image.highlight_context,&highlight_info);
10705 if (event.xany.window == windows->command.id)
10706 {
10707 /*
10708 Select a command from the Command widget.
10709 */
10710 id=XCommandWidget(display,windows,PasteMenu,&event);
10711 if (id < 0)
10712 continue;
10713 switch (PasteCommands[id])
10714 {
10715 case PasteOperatorsCommand:
10716 {
10717 char
cristy151b66d2015-04-15 10:50:31 +000010718 command[MagickPathExtent],
cristy3ed852e2009-09-05 21:47:34 +000010719 **operators;
10720
10721 /*
10722 Select a command from the pop-up menu.
10723 */
cristy042ee782011-04-22 18:48:30 +000010724 operators=GetCommandOptions(MagickComposeOptions);
cristy3ed852e2009-09-05 21:47:34 +000010725 if (operators == (char **) NULL)
10726 break;
10727 entry=XMenuWidget(display,windows,PasteMenu[id],
10728 (const char **) operators,command);
10729 if (entry >= 0)
cristy042ee782011-04-22 18:48:30 +000010730 compose=(CompositeOperator) ParseCommandOption(
cristy3ed852e2009-09-05 21:47:34 +000010731 MagickComposeOptions,MagickFalse,operators[entry]);
10732 operators=DestroyStringList(operators);
10733 break;
10734 }
10735 case PasteHelpCommand:
10736 {
10737 XTextViewWidget(display,resource_info,windows,MagickFalse,
10738 "Help Viewer - Image Composite",ImagePasteHelp);
10739 break;
10740 }
10741 case PasteDismissCommand:
10742 {
10743 /*
10744 Prematurely exit.
10745 */
10746 state|=EscapeState;
10747 state|=ExitState;
10748 break;
10749 }
10750 default:
10751 break;
10752 }
10753 continue;
10754 }
10755 switch (event.type)
10756 {
10757 case ButtonPress:
10758 {
cristy59864562013-04-18 11:47:41 +000010759 if (IfMagickTrue(image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000010760 (void) LogMagickEvent(X11Event,GetMagickModule(),
10761 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
10762 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10763 if (event.xbutton.button != Button1)
10764 break;
10765 if (event.xbutton.window != windows->image.id)
10766 break;
10767 /*
10768 Paste rectangle is relative to image configuration.
10769 */
10770 width=(unsigned int) image->columns;
10771 height=(unsigned int) image->rows;
10772 x=0;
10773 y=0;
10774 if (windows->image.crop_geometry != (char *) NULL)
10775 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
10776 &width,&height);
cristya19f1d72012-08-07 18:24:38 +000010777 scale_factor=(double) windows->image.ximage->width/width;
cristy3ed852e2009-09-05 21:47:34 +000010778 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5);
cristya19f1d72012-08-07 18:24:38 +000010779 scale_factor=(double) windows->image.ximage->height/height;
cristy3ed852e2009-09-05 21:47:34 +000010780 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5);
10781 (void) XCheckDefineCursor(display,windows->image.id,cursor);
cristy49e2d862010-11-12 02:50:30 +000010782 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10783 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000010784 break;
10785 }
10786 case ButtonRelease:
10787 {
cristy59864562013-04-18 11:47:41 +000010788 if (IfMagickTrue(image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000010789 (void) LogMagickEvent(X11Event,GetMagickModule(),
10790 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
10791 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10792 if (event.xbutton.button != Button1)
10793 break;
10794 if (event.xbutton.window != windows->image.id)
10795 break;
10796 if ((paste_info.width != 0) && (paste_info.height != 0))
10797 {
10798 /*
10799 User has selected the location of the paste image.
10800 */
cristy49e2d862010-11-12 02:50:30 +000010801 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10802 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000010803 state|=ExitState;
10804 }
10805 break;
10806 }
10807 case Expose:
10808 break;
10809 case KeyPress:
10810 {
10811 char
cristy151b66d2015-04-15 10:50:31 +000010812 command[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +000010813
10814 KeySym
10815 key_symbol;
10816
10817 int
10818 length;
10819
10820 if (event.xkey.window != windows->image.id)
10821 break;
10822 /*
10823 Respond to a user key press.
10824 */
10825 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
10826 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
10827 *(command+length)='\0';
cristy59864562013-04-18 11:47:41 +000010828 if (IfMagickTrue(image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000010829 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristyf2faecf2010-05-28 19:19:36 +000010830 "Key press: 0x%lx (%s)",(long) key_symbol,command);
cristy3ed852e2009-09-05 21:47:34 +000010831 switch ((int) key_symbol)
10832 {
10833 case XK_Escape:
10834 case XK_F20:
10835 {
10836 /*
10837 Prematurely exit.
10838 */
10839 paste_image=DestroyImage(paste_image);
10840 state|=EscapeState;
10841 state|=ExitState;
10842 break;
10843 }
10844 case XK_F1:
10845 case XK_Help:
10846 {
10847 (void) XSetFunction(display,windows->image.highlight_context,
10848 GXcopy);
10849 XTextViewWidget(display,resource_info,windows,MagickFalse,
10850 "Help Viewer - Image Composite",ImagePasteHelp);
10851 (void) XSetFunction(display,windows->image.highlight_context,
10852 GXinvert);
10853 break;
10854 }
10855 default:
10856 {
10857 (void) XBell(display,0);
10858 break;
10859 }
10860 }
10861 break;
10862 }
10863 case MotionNotify:
10864 {
10865 /*
10866 Map and unmap Info widget as text cursor crosses its boundaries.
10867 */
10868 x=event.xmotion.x;
10869 y=event.xmotion.y;
cristy59864562013-04-18 11:47:41 +000010870 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000010871 {
10872 if ((x < (int) (windows->info.x+windows->info.width)) &&
10873 (y < (int) (windows->info.y+windows->info.height)))
10874 (void) XWithdrawWindow(display,windows->info.id,
10875 windows->info.screen);
10876 }
10877 else
10878 if ((x > (int) (windows->info.x+windows->info.width)) ||
10879 (y > (int) (windows->info.y+windows->info.height)))
10880 (void) XMapWindow(display,windows->info.id);
cristy49e2d862010-11-12 02:50:30 +000010881 paste_info.x=(ssize_t) windows->image.x+x;
10882 paste_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +000010883 break;
10884 }
10885 default:
10886 {
cristy59864562013-04-18 11:47:41 +000010887 if (IfMagickTrue(image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000010888 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
10889 event.type);
10890 break;
10891 }
10892 }
10893 } while ((state & ExitState) == 0);
10894 (void) XSelectInput(display,windows->image.id,
10895 windows->image.attributes.event_mask);
10896 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
10897 XSetCursorState(display,windows,MagickFalse);
10898 (void) XFreeCursor(display,cursor);
10899 if ((state & EscapeState) != 0)
10900 return(MagickTrue);
10901 /*
10902 Image pasting is relative to image configuration.
10903 */
10904 XSetCursorState(display,windows,MagickTrue);
10905 XCheckRefreshWindows(display,windows);
10906 width=(unsigned int) image->columns;
10907 height=(unsigned int) image->rows;
10908 x=0;
10909 y=0;
10910 if (windows->image.crop_geometry != (char *) NULL)
10911 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
cristya19f1d72012-08-07 18:24:38 +000010912 scale_factor=(double) width/windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +000010913 paste_info.x+=x;
cristy49e2d862010-11-12 02:50:30 +000010914 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +000010915 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5);
cristya19f1d72012-08-07 18:24:38 +000010916 scale_factor=(double) height/windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +000010917 paste_info.y+=y;
cristy49e2d862010-11-12 02:50:30 +000010918 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5);
cristy3ed852e2009-09-05 21:47:34 +000010919 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5);
10920 /*
10921 Paste image with X Image window.
10922 */
cristy39172402012-03-30 13:04:39 +000010923 (void) CompositeImage(image,paste_image,compose,MagickTrue,paste_info.x,
cristyfeb3e962012-03-29 17:25:55 +000010924 paste_info.y,exception);
cristy3ed852e2009-09-05 21:47:34 +000010925 paste_image=DestroyImage(paste_image);
10926 XSetCursorState(display,windows,MagickFalse);
10927 /*
10928 Update image colormap.
10929 */
cristy6710d842011-10-20 23:23:00 +000010930 XConfigureImageColormap(display,resource_info,windows,image,exception);
cristy051718b2011-08-28 22:49:25 +000010931 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +000010932 return(MagickTrue);
10933}
10934
10935/*
10936%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10937% %
10938% %
10939% %
10940+ X P r i n t I m a g e %
10941% %
10942% %
10943% %
10944%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10945%
10946% XPrintImage() prints an image to a Postscript printer.
10947%
10948% The format of the XPrintImage method is:
10949%
10950% MagickBooleanType XPrintImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000010951% XResourceInfo *resource_info,XWindows *windows,Image *image,
10952% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000010953%
10954% A description of each parameter follows:
10955%
10956% o display: Specifies a connection to an X server; returned from
10957% XOpenDisplay.
10958%
10959% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10960%
10961% o windows: Specifies a pointer to a XWindows structure.
10962%
10963% o image: the image.
10964%
cristy051718b2011-08-28 22:49:25 +000010965% o exception: return any errors or warnings in this structure.
10966%
cristy3ed852e2009-09-05 21:47:34 +000010967*/
10968static MagickBooleanType XPrintImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000010969 XResourceInfo *resource_info,XWindows *windows,Image *image,
10970 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000010971{
10972 char
cristy151b66d2015-04-15 10:50:31 +000010973 filename[MagickPathExtent],
10974 geometry[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +000010975
10976 Image
10977 *print_image;
10978
10979 ImageInfo
10980 *image_info;
10981
10982 MagickStatusType
10983 status;
10984
10985 /*
10986 Request Postscript page geometry from user.
10987 */
10988 image_info=CloneImageInfo(resource_info->image_info);
cristy151b66d2015-04-15 10:50:31 +000010989 (void) FormatLocaleString(geometry,MagickPathExtent,"Letter");
cristy3ed852e2009-09-05 21:47:34 +000010990 if (image_info->page != (char *) NULL)
cristy151b66d2015-04-15 10:50:31 +000010991 (void) CopyMagickString(geometry,image_info->page,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +000010992 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
10993 "Select Postscript Page Geometry:",geometry);
10994 if (*geometry == '\0')
10995 return(MagickTrue);
10996 image_info->page=GetPageGeometry(geometry);
10997 /*
10998 Apply image transforms.
10999 */
11000 XSetCursorState(display,windows,MagickTrue);
11001 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +000011002 print_image=CloneImage(image,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +000011003 if (print_image == (Image *) NULL)
11004 return(MagickFalse);
cristy151b66d2015-04-15 10:50:31 +000011005 (void) FormatLocaleString(geometry,MagickPathExtent,"%dx%d!",
cristy3ed852e2009-09-05 21:47:34 +000011006 windows->image.ximage->width,windows->image.ximage->height);
cristye941a752011-10-15 01:52:48 +000011007 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry,
11008 exception);
cristy3ed852e2009-09-05 21:47:34 +000011009 /*
11010 Print image.
11011 */
11012 (void) AcquireUniqueFilename(filename);
cristy151b66d2015-04-15 10:50:31 +000011013 (void) FormatLocaleString(print_image->filename,MagickPathExtent,"print:%s",
cristy3ed852e2009-09-05 21:47:34 +000011014 filename);
cristy051718b2011-08-28 22:49:25 +000011015 status=WriteImage(image_info,print_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000011016 (void) RelinquishUniqueFileResource(filename);
11017 print_image=DestroyImage(print_image);
11018 image_info=DestroyImageInfo(image_info);
11019 XSetCursorState(display,windows,MagickFalse);
dirkb9dbc292015-07-26 09:50:00 +000011020 return(status != 0 ? MagickTrue : MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +000011021}
11022
11023/*
11024%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11025% %
11026% %
11027% %
11028+ X R O I I m a g e %
11029% %
11030% %
11031% %
11032%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11033%
11034% XROIImage() applies an image processing technique to a region of interest.
11035%
11036% The format of the XROIImage method is:
11037%
11038% MagickBooleanType XROIImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000011039% XResourceInfo *resource_info,XWindows *windows,Image **image,
11040% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000011041%
11042% A description of each parameter follows:
11043%
11044% o display: Specifies a connection to an X server; returned from
11045% XOpenDisplay.
11046%
11047% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
11048%
11049% o windows: Specifies a pointer to a XWindows structure.
11050%
11051% o image: the image; returned from ReadImage.
11052%
cristy051718b2011-08-28 22:49:25 +000011053% o exception: return any errors or warnings in this structure.
11054%
cristy3ed852e2009-09-05 21:47:34 +000011055*/
11056static MagickBooleanType XROIImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000011057 XResourceInfo *resource_info,XWindows *windows,Image **image,
11058 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000011059{
11060#define ApplyMenus 7
11061
11062 static const char
11063 *ROIMenu[] =
11064 {
11065 "Help",
11066 "Dismiss",
11067 (char *) NULL
11068 },
11069 *ApplyMenu[] =
11070 {
11071 "File",
11072 "Edit",
11073 "Transform",
11074 "Enhance",
11075 "Effects",
11076 "F/X",
11077 "Miscellany",
11078 "Help",
11079 "Dismiss",
11080 (char *) NULL
11081 },
11082 *FileMenu[] =
11083 {
11084 "Save...",
11085 "Print...",
11086 (char *) NULL
11087 },
11088 *EditMenu[] =
11089 {
11090 "Undo",
11091 "Redo",
11092 (char *) NULL
11093 },
11094 *TransformMenu[] =
11095 {
11096 "Flop",
11097 "Flip",
11098 "Rotate Right",
11099 "Rotate Left",
11100 (char *) NULL
11101 },
11102 *EnhanceMenu[] =
11103 {
11104 "Hue...",
11105 "Saturation...",
11106 "Brightness...",
11107 "Gamma...",
11108 "Spiff",
11109 "Dull",
11110 "Contrast Stretch...",
11111 "Sigmoidal Contrast...",
11112 "Normalize",
11113 "Equalize",
11114 "Negate",
11115 "Grayscale",
11116 "Map...",
11117 "Quantize...",
11118 (char *) NULL
11119 },
11120 *EffectsMenu[] =
11121 {
11122 "Despeckle",
11123 "Emboss",
11124 "Reduce Noise",
11125 "Add Noise",
11126 "Sharpen...",
11127 "Blur...",
11128 "Threshold...",
11129 "Edge Detect...",
11130 "Spread...",
11131 "Shade...",
11132 "Raise...",
11133 "Segment...",
11134 (char *) NULL
11135 },
11136 *FXMenu[] =
11137 {
11138 "Solarize...",
11139 "Sepia Tone...",
11140 "Swirl...",
11141 "Implode...",
11142 "Vignette...",
11143 "Wave...",
11144 "Oil Paint...",
11145 "Charcoal Draw...",
11146 (char *) NULL
11147 },
11148 *MiscellanyMenu[] =
11149 {
11150 "Image Info",
11151 "Zoom Image",
11152 "Show Preview...",
11153 "Show Histogram",
11154 "Show Matte",
11155 (char *) NULL
11156 };
11157
11158 static const char
11159 **Menus[ApplyMenus] =
11160 {
11161 FileMenu,
11162 EditMenu,
11163 TransformMenu,
11164 EnhanceMenu,
11165 EffectsMenu,
11166 FXMenu,
11167 MiscellanyMenu
11168 };
11169
11170 static const CommandType
11171 ApplyCommands[] =
11172 {
11173 NullCommand,
11174 NullCommand,
11175 NullCommand,
11176 NullCommand,
11177 NullCommand,
11178 NullCommand,
11179 NullCommand,
11180 HelpCommand,
11181 QuitCommand
11182 },
11183 FileCommands[] =
11184 {
11185 SaveCommand,
11186 PrintCommand
11187 },
11188 EditCommands[] =
11189 {
11190 UndoCommand,
11191 RedoCommand
11192 },
11193 TransformCommands[] =
11194 {
11195 FlopCommand,
11196 FlipCommand,
11197 RotateRightCommand,
11198 RotateLeftCommand
11199 },
11200 EnhanceCommands[] =
11201 {
11202 HueCommand,
11203 SaturationCommand,
11204 BrightnessCommand,
11205 GammaCommand,
11206 SpiffCommand,
11207 DullCommand,
11208 ContrastStretchCommand,
11209 SigmoidalContrastCommand,
11210 NormalizeCommand,
11211 EqualizeCommand,
11212 NegateCommand,
11213 GrayscaleCommand,
11214 MapCommand,
11215 QuantizeCommand
11216 },
11217 EffectsCommands[] =
11218 {
11219 DespeckleCommand,
11220 EmbossCommand,
11221 ReduceNoiseCommand,
11222 AddNoiseCommand,
11223 SharpenCommand,
11224 BlurCommand,
11225 EdgeDetectCommand,
11226 SpreadCommand,
11227 ShadeCommand,
11228 RaiseCommand,
11229 SegmentCommand
11230 },
11231 FXCommands[] =
11232 {
11233 SolarizeCommand,
11234 SepiaToneCommand,
11235 SwirlCommand,
11236 ImplodeCommand,
11237 VignetteCommand,
11238 WaveCommand,
11239 OilPaintCommand,
11240 CharcoalDrawCommand
11241 },
11242 MiscellanyCommands[] =
11243 {
11244 InfoCommand,
11245 ZoomCommand,
11246 ShowPreviewCommand,
11247 ShowHistogramCommand,
11248 ShowMatteCommand
11249 },
11250 ROICommands[] =
11251 {
11252 ROIHelpCommand,
11253 ROIDismissCommand
11254 };
11255
11256 static const CommandType
11257 *Commands[ApplyMenus] =
11258 {
11259 FileCommands,
11260 EditCommands,
11261 TransformCommands,
11262 EnhanceCommands,
11263 EffectsCommands,
11264 FXCommands,
11265 MiscellanyCommands
11266 };
11267
11268 char
cristy151b66d2015-04-15 10:50:31 +000011269 command[MagickPathExtent],
11270 text[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +000011271
11272 CommandType
11273 command_type;
11274
11275 Cursor
11276 cursor;
11277
11278 Image
11279 *roi_image;
11280
11281 int
11282 entry,
11283 id,
11284 x,
11285 y;
11286
cristya19f1d72012-08-07 18:24:38 +000011287 double
cristy3ed852e2009-09-05 21:47:34 +000011288 scale_factor;
11289
11290 MagickProgressMonitor
11291 progress_monitor;
11292
11293 RectangleInfo
11294 crop_info,
11295 highlight_info,
11296 roi_info;
11297
11298 unsigned int
11299 height,
11300 width;
11301
cristybb503372010-05-27 20:51:26 +000011302 size_t
cristy3ed852e2009-09-05 21:47:34 +000011303 state;
11304
11305 XEvent
11306 event;
11307
11308 /*
11309 Map Command widget.
11310 */
11311 (void) CloneString(&windows->command.name,"ROI");
11312 windows->command.data=0;
11313 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL);
11314 (void) XMapRaised(display,windows->command.id);
11315 XClientMessage(display,windows->image.id,windows->im_protocols,
11316 windows->im_update_widget,CurrentTime);
11317 /*
11318 Track pointer until button 1 is pressed.
11319 */
11320 XQueryPosition(display,windows->image.id,&x,&y);
11321 (void) XSelectInput(display,windows->image.id,
11322 windows->image.attributes.event_mask | PointerMotionMask);
cristy49e2d862010-11-12 02:50:30 +000011323 roi_info.x=(ssize_t) windows->image.x+x;
11324 roi_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +000011325 roi_info.width=0;
11326 roi_info.height=0;
11327 cursor=XCreateFontCursor(display,XC_fleur);
11328 state=DefaultState;
11329 do
11330 {
cristy59864562013-04-18 11:47:41 +000011331 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000011332 {
11333 /*
11334 Display pointer position.
11335 */
cristy151b66d2015-04-15 10:50:31 +000011336 (void) FormatLocaleString(text,MagickPathExtent," %+ld%+ld ",
cristyf2faecf2010-05-28 19:19:36 +000011337 (long) roi_info.x,(long) roi_info.y);
cristy3ed852e2009-09-05 21:47:34 +000011338 XInfoWidget(display,windows,text);
11339 }
11340 /*
11341 Wait for next event.
11342 */
cristy6710d842011-10-20 23:23:00 +000011343 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000011344 if (event.xany.window == windows->command.id)
11345 {
11346 /*
11347 Select a command from the Command widget.
11348 */
11349 id=XCommandWidget(display,windows,ROIMenu,&event);
11350 if (id < 0)
11351 continue;
11352 switch (ROICommands[id])
11353 {
11354 case ROIHelpCommand:
11355 {
11356 XTextViewWidget(display,resource_info,windows,MagickFalse,
11357 "Help Viewer - Region of Interest",ImageROIHelp);
11358 break;
11359 }
11360 case ROIDismissCommand:
11361 {
11362 /*
11363 Prematurely exit.
11364 */
11365 state|=EscapeState;
11366 state|=ExitState;
11367 break;
11368 }
11369 default:
11370 break;
11371 }
11372 continue;
11373 }
11374 switch (event.type)
11375 {
11376 case ButtonPress:
11377 {
11378 if (event.xbutton.button != Button1)
11379 break;
11380 if (event.xbutton.window != windows->image.id)
11381 break;
11382 /*
11383 Note first corner of region of interest rectangle-- exit loop.
11384 */
11385 (void) XCheckDefineCursor(display,windows->image.id,cursor);
cristy49e2d862010-11-12 02:50:30 +000011386 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11387 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000011388 state|=ExitState;
11389 break;
11390 }
11391 case ButtonRelease:
11392 break;
11393 case Expose:
11394 break;
11395 case KeyPress:
11396 {
11397 KeySym
11398 key_symbol;
11399
11400 if (event.xkey.window != windows->image.id)
11401 break;
11402 /*
11403 Respond to a user key press.
11404 */
11405 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11406 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11407 switch ((int) key_symbol)
11408 {
11409 case XK_Escape:
11410 case XK_F20:
11411 {
11412 /*
11413 Prematurely exit.
11414 */
11415 state|=EscapeState;
11416 state|=ExitState;
11417 break;
11418 }
11419 case XK_F1:
11420 case XK_Help:
11421 {
11422 XTextViewWidget(display,resource_info,windows,MagickFalse,
11423 "Help Viewer - Region of Interest",ImageROIHelp);
11424 break;
11425 }
11426 default:
11427 {
11428 (void) XBell(display,0);
11429 break;
11430 }
11431 }
11432 break;
11433 }
11434 case MotionNotify:
11435 {
11436 /*
11437 Map and unmap Info widget as text cursor crosses its boundaries.
11438 */
11439 x=event.xmotion.x;
11440 y=event.xmotion.y;
cristy59864562013-04-18 11:47:41 +000011441 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000011442 {
11443 if ((x < (int) (windows->info.x+windows->info.width)) &&
11444 (y < (int) (windows->info.y+windows->info.height)))
11445 (void) XWithdrawWindow(display,windows->info.id,
11446 windows->info.screen);
11447 }
11448 else
11449 if ((x > (int) (windows->info.x+windows->info.width)) ||
11450 (y > (int) (windows->info.y+windows->info.height)))
11451 (void) XMapWindow(display,windows->info.id);
cristy49e2d862010-11-12 02:50:30 +000011452 roi_info.x=(ssize_t) windows->image.x+x;
11453 roi_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +000011454 break;
11455 }
11456 default:
11457 break;
11458 }
11459 } while ((state & ExitState) == 0);
11460 (void) XSelectInput(display,windows->image.id,
11461 windows->image.attributes.event_mask);
11462 if ((state & EscapeState) != 0)
11463 {
11464 /*
11465 User want to exit without region of interest.
11466 */
11467 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11468 (void) XFreeCursor(display,cursor);
11469 return(MagickTrue);
11470 }
11471 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
11472 do
11473 {
11474 /*
11475 Size rectangle as pointer moves until the mouse button is released.
11476 */
11477 x=(int) roi_info.x;
11478 y=(int) roi_info.y;
11479 roi_info.width=0;
11480 roi_info.height=0;
11481 state=DefaultState;
11482 do
11483 {
11484 highlight_info=roi_info;
11485 highlight_info.x=roi_info.x-windows->image.x;
11486 highlight_info.y=roi_info.y-windows->image.y;
11487 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11488 {
11489 /*
11490 Display info and draw region of interest rectangle.
11491 */
cristy59864562013-04-18 11:47:41 +000011492 if (IfMagickFalse(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000011493 (void) XMapWindow(display,windows->info.id);
cristy151b66d2015-04-15 10:50:31 +000011494 (void) FormatLocaleString(text,MagickPathExtent,
cristy6d8abba2010-06-03 01:10:47 +000011495 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +000011496 roi_info.height,(double) roi_info.x,(double) roi_info.y);
cristy3ed852e2009-09-05 21:47:34 +000011497 XInfoWidget(display,windows,text);
11498 XHighlightRectangle(display,windows->image.id,
11499 windows->image.highlight_context,&highlight_info);
11500 }
11501 else
cristy59864562013-04-18 11:47:41 +000011502 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000011503 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11504 /*
11505 Wait for next event.
11506 */
cristy6710d842011-10-20 23:23:00 +000011507 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000011508 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11509 XHighlightRectangle(display,windows->image.id,
11510 windows->image.highlight_context,&highlight_info);
11511 switch (event.type)
11512 {
11513 case ButtonPress:
11514 {
cristy49e2d862010-11-12 02:50:30 +000011515 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11516 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000011517 break;
11518 }
11519 case ButtonRelease:
11520 {
11521 /*
11522 User has committed to region of interest rectangle.
11523 */
cristy49e2d862010-11-12 02:50:30 +000011524 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11525 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000011526 XSetCursorState(display,windows,MagickFalse);
11527 state|=ExitState;
11528 if (LocaleCompare(windows->command.name,"Apply") == 0)
11529 break;
11530 (void) CloneString(&windows->command.name,"Apply");
11531 windows->command.data=ApplyMenus;
11532 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL);
11533 break;
11534 }
11535 case Expose:
11536 break;
11537 case MotionNotify:
11538 {
cristy49e2d862010-11-12 02:50:30 +000011539 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11540 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
cristy3ed852e2009-09-05 21:47:34 +000011541 }
11542 default:
11543 break;
11544 }
11545 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) ||
11546 ((state & ExitState) != 0))
11547 {
11548 /*
11549 Check boundary conditions.
11550 */
11551 if (roi_info.x < 0)
11552 roi_info.x=0;
11553 else
cristy49e2d862010-11-12 02:50:30 +000011554 if (roi_info.x > (ssize_t) windows->image.ximage->width)
11555 roi_info.x=(ssize_t) windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +000011556 if ((int) roi_info.x < x)
11557 roi_info.width=(unsigned int) (x-roi_info.x);
11558 else
11559 {
11560 roi_info.width=(unsigned int) (roi_info.x-x);
cristy49e2d862010-11-12 02:50:30 +000011561 roi_info.x=(ssize_t) x;
cristy3ed852e2009-09-05 21:47:34 +000011562 }
11563 if (roi_info.y < 0)
11564 roi_info.y=0;
11565 else
cristy49e2d862010-11-12 02:50:30 +000011566 if (roi_info.y > (ssize_t) windows->image.ximage->height)
11567 roi_info.y=(ssize_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +000011568 if ((int) roi_info.y < y)
11569 roi_info.height=(unsigned int) (y-roi_info.y);
11570 else
11571 {
11572 roi_info.height=(unsigned int) (roi_info.y-y);
cristy49e2d862010-11-12 02:50:30 +000011573 roi_info.y=(ssize_t) y;
cristy3ed852e2009-09-05 21:47:34 +000011574 }
11575 }
11576 } while ((state & ExitState) == 0);
11577 /*
11578 Wait for user to grab a corner of the rectangle or press return.
11579 */
11580 state=DefaultState;
11581 command_type=NullCommand;
cristy4d246fc2014-01-15 22:33:44 +000011582 crop_info.x=0;
11583 crop_info.y=0;
cristy3ed852e2009-09-05 21:47:34 +000011584 (void) XMapWindow(display,windows->info.id);
11585 do
11586 {
cristy59864562013-04-18 11:47:41 +000011587 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000011588 {
11589 /*
11590 Display pointer position.
11591 */
cristy151b66d2015-04-15 10:50:31 +000011592 (void) FormatLocaleString(text,MagickPathExtent,
cristy6d8abba2010-06-03 01:10:47 +000011593 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +000011594 roi_info.height,(double) roi_info.x,(double) roi_info.y);
cristy3ed852e2009-09-05 21:47:34 +000011595 XInfoWidget(display,windows,text);
11596 }
11597 highlight_info=roi_info;
11598 highlight_info.x=roi_info.x-windows->image.x;
11599 highlight_info.y=roi_info.y-windows->image.y;
11600 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
11601 {
11602 state|=EscapeState;
11603 state|=ExitState;
11604 break;
11605 }
11606 if ((state & UpdateRegionState) != 0)
11607 {
11608 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11609 switch (command_type)
11610 {
11611 case UndoCommand:
11612 case RedoCommand:
11613 {
11614 (void) XMagickCommand(display,resource_info,windows,command_type,
cristy051718b2011-08-28 22:49:25 +000011615 image,exception);
cristy3ed852e2009-09-05 21:47:34 +000011616 break;
11617 }
11618 default:
11619 {
11620 /*
11621 Region of interest is relative to image configuration.
11622 */
11623 progress_monitor=SetImageProgressMonitor(*image,
11624 (MagickProgressMonitor) NULL,(*image)->client_data);
11625 crop_info=roi_info;
11626 width=(unsigned int) (*image)->columns;
11627 height=(unsigned int) (*image)->rows;
11628 x=0;
11629 y=0;
11630 if (windows->image.crop_geometry != (char *) NULL)
11631 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
11632 &width,&height);
cristya19f1d72012-08-07 18:24:38 +000011633 scale_factor=(double) width/windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +000011634 crop_info.x+=x;
cristy49e2d862010-11-12 02:50:30 +000011635 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +000011636 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
cristya19f1d72012-08-07 18:24:38 +000011637 scale_factor=(double)
cristy3ed852e2009-09-05 21:47:34 +000011638 height/windows->image.ximage->height;
11639 crop_info.y+=y;
cristy49e2d862010-11-12 02:50:30 +000011640 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +000011641 crop_info.height=(unsigned int)
11642 (scale_factor*crop_info.height+0.5);
cristy051718b2011-08-28 22:49:25 +000011643 roi_image=CropImage(*image,&crop_info,exception);
cristy3ed852e2009-09-05 21:47:34 +000011644 (void) SetImageProgressMonitor(*image,progress_monitor,
11645 (*image)->client_data);
11646 if (roi_image == (Image *) NULL)
11647 continue;
11648 /*
11649 Apply image processing technique to the region of interest.
11650 */
11651 windows->image.orphan=MagickTrue;
11652 (void) XMagickCommand(display,resource_info,windows,command_type,
cristy051718b2011-08-28 22:49:25 +000011653 &roi_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000011654 progress_monitor=SetImageProgressMonitor(*image,
11655 (MagickProgressMonitor) NULL,(*image)->client_data);
11656 (void) XMagickCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000011657 SaveToUndoBufferCommand,image,exception);
cristy3ed852e2009-09-05 21:47:34 +000011658 windows->image.orphan=MagickFalse;
cristyfeb3e962012-03-29 17:25:55 +000011659 (void) CompositeImage(*image,roi_image,CopyCompositeOp,
cristy39172402012-03-30 13:04:39 +000011660 MagickTrue,crop_info.x,crop_info.y,exception);
cristy3ed852e2009-09-05 21:47:34 +000011661 roi_image=DestroyImage(roi_image);
11662 (void) SetImageProgressMonitor(*image,progress_monitor,
11663 (*image)->client_data);
11664 break;
11665 }
11666 }
11667 if (command_type != InfoCommand)
11668 {
cristy6710d842011-10-20 23:23:00 +000011669 XConfigureImageColormap(display,resource_info,windows,*image,
11670 exception);
11671 (void) XConfigureImage(display,resource_info,windows,*image,
11672 exception);
cristy3ed852e2009-09-05 21:47:34 +000011673 }
11674 XCheckRefreshWindows(display,windows);
11675 XInfoWidget(display,windows,text);
11676 (void) XSetFunction(display,windows->image.highlight_context,
11677 GXinvert);
11678 state&=(~UpdateRegionState);
11679 }
11680 XHighlightRectangle(display,windows->image.id,
11681 windows->image.highlight_context,&highlight_info);
cristy6710d842011-10-20 23:23:00 +000011682 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000011683 if (event.xany.window == windows->command.id)
11684 {
11685 /*
11686 Select a command from the Command widget.
11687 */
11688 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11689 command_type=NullCommand;
11690 id=XCommandWidget(display,windows,ApplyMenu,&event);
11691 if (id >= 0)
11692 {
cristy151b66d2015-04-15 10:50:31 +000011693 (void) CopyMagickString(command,ApplyMenu[id],MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +000011694 command_type=ApplyCommands[id];
11695 if (id < ApplyMenus)
11696 {
11697 /*
11698 Select a command from a pop-up menu.
11699 */
11700 entry=XMenuWidget(display,windows,ApplyMenu[id],
11701 (const char **) Menus[id],command);
11702 if (entry >= 0)
11703 {
11704 (void) CopyMagickString(command,Menus[id][entry],
cristy151b66d2015-04-15 10:50:31 +000011705 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +000011706 command_type=Commands[id][entry];
11707 }
11708 }
11709 }
11710 (void) XSetFunction(display,windows->image.highlight_context,
11711 GXinvert);
11712 XHighlightRectangle(display,windows->image.id,
11713 windows->image.highlight_context,&highlight_info);
11714 if (command_type == HelpCommand)
11715 {
11716 (void) XSetFunction(display,windows->image.highlight_context,
11717 GXcopy);
11718 XTextViewWidget(display,resource_info,windows,MagickFalse,
11719 "Help Viewer - Region of Interest",ImageROIHelp);
11720 (void) XSetFunction(display,windows->image.highlight_context,
11721 GXinvert);
11722 continue;
11723 }
11724 if (command_type == QuitCommand)
11725 {
11726 /*
11727 exit.
11728 */
11729 state|=EscapeState;
11730 state|=ExitState;
11731 continue;
11732 }
11733 if (command_type != NullCommand)
11734 state|=UpdateRegionState;
11735 continue;
11736 }
11737 XHighlightRectangle(display,windows->image.id,
11738 windows->image.highlight_context,&highlight_info);
11739 switch (event.type)
11740 {
11741 case ButtonPress:
11742 {
11743 x=windows->image.x;
11744 y=windows->image.y;
11745 if (event.xbutton.button != Button1)
11746 break;
11747 if (event.xbutton.window != windows->image.id)
11748 break;
11749 x=windows->image.x+event.xbutton.x;
11750 y=windows->image.y+event.xbutton.y;
11751 if ((x < (int) (roi_info.x+RoiDelta)) &&
11752 (x > (int) (roi_info.x-RoiDelta)) &&
11753 (y < (int) (roi_info.y+RoiDelta)) &&
11754 (y > (int) (roi_info.y-RoiDelta)))
11755 {
cristybb503372010-05-27 20:51:26 +000011756 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
11757 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
cristy3ed852e2009-09-05 21:47:34 +000011758 state|=UpdateConfigurationState;
11759 break;
11760 }
11761 if ((x < (int) (roi_info.x+RoiDelta)) &&
11762 (x > (int) (roi_info.x-RoiDelta)) &&
11763 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11764 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11765 {
cristybb503372010-05-27 20:51:26 +000011766 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
cristy3ed852e2009-09-05 21:47:34 +000011767 state|=UpdateConfigurationState;
11768 break;
11769 }
11770 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11771 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11772 (y < (int) (roi_info.y+RoiDelta)) &&
11773 (y > (int) (roi_info.y-RoiDelta)))
11774 {
cristybb503372010-05-27 20:51:26 +000011775 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
cristy3ed852e2009-09-05 21:47:34 +000011776 state|=UpdateConfigurationState;
11777 break;
11778 }
11779 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11780 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11781 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11782 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11783 {
11784 state|=UpdateConfigurationState;
11785 break;
11786 }
11787 }
11788 case ButtonRelease:
11789 {
11790 if (event.xbutton.window == windows->pan.id)
11791 if ((highlight_info.x != crop_info.x-windows->image.x) ||
11792 (highlight_info.y != crop_info.y-windows->image.y))
11793 XHighlightRectangle(display,windows->image.id,
11794 windows->image.highlight_context,&highlight_info);
11795 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11796 event.xbutton.time);
11797 break;
11798 }
11799 case Expose:
11800 {
11801 if (event.xexpose.window == windows->image.id)
11802 if (event.xexpose.count == 0)
11803 {
11804 event.xexpose.x=(int) highlight_info.x;
11805 event.xexpose.y=(int) highlight_info.y;
11806 event.xexpose.width=(int) highlight_info.width;
11807 event.xexpose.height=(int) highlight_info.height;
11808 XRefreshWindow(display,&windows->image,&event);
11809 }
11810 if (event.xexpose.window == windows->info.id)
11811 if (event.xexpose.count == 0)
11812 XInfoWidget(display,windows,text);
11813 break;
11814 }
11815 case KeyPress:
11816 {
11817 KeySym
11818 key_symbol;
11819
11820 if (event.xkey.window != windows->image.id)
11821 break;
11822 /*
11823 Respond to a user key press.
11824 */
11825 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11826 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11827 switch ((int) key_symbol)
11828 {
11829 case XK_Shift_L:
11830 case XK_Shift_R:
11831 break;
11832 case XK_Escape:
11833 case XK_F20:
11834 state|=EscapeState;
11835 case XK_Return:
11836 {
11837 state|=ExitState;
11838 break;
11839 }
11840 case XK_Home:
11841 case XK_KP_Home:
11842 {
cristybb503372010-05-27 20:51:26 +000011843 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L);
cristy49e2d862010-11-12 02:50:30 +000011844 roi_info.y=(ssize_t) (windows->image.height/2L-
11845 roi_info.height/2L);
cristy3ed852e2009-09-05 21:47:34 +000011846 break;
11847 }
11848 case XK_Left:
11849 case XK_KP_Left:
11850 {
11851 roi_info.x--;
11852 break;
11853 }
11854 case XK_Up:
11855 case XK_KP_Up:
11856 case XK_Next:
11857 {
11858 roi_info.y--;
11859 break;
11860 }
11861 case XK_Right:
11862 case XK_KP_Right:
11863 {
11864 roi_info.x++;
11865 break;
11866 }
11867 case XK_Prior:
11868 case XK_Down:
11869 case XK_KP_Down:
11870 {
11871 roi_info.y++;
11872 break;
11873 }
11874 case XK_F1:
11875 case XK_Help:
11876 {
11877 (void) XSetFunction(display,windows->image.highlight_context,
11878 GXcopy);
11879 XTextViewWidget(display,resource_info,windows,MagickFalse,
11880 "Help Viewer - Region of Interest",ImageROIHelp);
11881 (void) XSetFunction(display,windows->image.highlight_context,
11882 GXinvert);
11883 break;
11884 }
11885 default:
11886 {
11887 command_type=XImageWindowCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000011888 event.xkey.state,key_symbol,image,exception);
cristy3ed852e2009-09-05 21:47:34 +000011889 if (command_type != NullCommand)
11890 state|=UpdateRegionState;
11891 break;
11892 }
11893 }
11894 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11895 event.xkey.time);
11896 break;
11897 }
11898 case KeyRelease:
11899 break;
11900 case MotionNotify:
11901 {
11902 if (event.xbutton.window != windows->image.id)
11903 break;
11904 /*
11905 Map and unmap Info widget as text cursor crosses its boundaries.
11906 */
11907 x=event.xmotion.x;
11908 y=event.xmotion.y;
cristy59864562013-04-18 11:47:41 +000011909 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000011910 {
11911 if ((x < (int) (windows->info.x+windows->info.width)) &&
11912 (y < (int) (windows->info.y+windows->info.height)))
11913 (void) XWithdrawWindow(display,windows->info.id,
11914 windows->info.screen);
11915 }
11916 else
11917 if ((x > (int) (windows->info.x+windows->info.width)) ||
11918 (y > (int) (windows->info.y+windows->info.height)))
11919 (void) XMapWindow(display,windows->info.id);
cristy49e2d862010-11-12 02:50:30 +000011920 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11921 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
cristy3ed852e2009-09-05 21:47:34 +000011922 break;
11923 }
11924 case SelectionRequest:
11925 {
11926 XSelectionEvent
11927 notify;
11928
11929 XSelectionRequestEvent
11930 *request;
11931
11932 /*
11933 Set primary selection.
11934 */
cristy151b66d2015-04-15 10:50:31 +000011935 (void) FormatLocaleString(text,MagickPathExtent,
cristy6d8abba2010-06-03 01:10:47 +000011936 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +000011937 roi_info.height,(double) roi_info.x,(double) roi_info.y);
cristy3ed852e2009-09-05 21:47:34 +000011938 request=(&(event.xselectionrequest));
11939 (void) XChangeProperty(request->display,request->requestor,
11940 request->property,request->target,8,PropModeReplace,
11941 (unsigned char *) text,(int) strlen(text));
11942 notify.type=SelectionNotify;
11943 notify.display=request->display;
11944 notify.requestor=request->requestor;
11945 notify.selection=request->selection;
11946 notify.target=request->target;
11947 notify.time=request->time;
11948 if (request->property == None)
11949 notify.property=request->target;
11950 else
11951 notify.property=request->property;
11952 (void) XSendEvent(request->display,request->requestor,False,0,
11953 (XEvent *) &notify);
11954 }
11955 default:
11956 break;
11957 }
11958 if ((state & UpdateConfigurationState) != 0)
11959 {
11960 (void) XPutBackEvent(display,&event);
11961 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11962 break;
11963 }
11964 } while ((state & ExitState) == 0);
11965 } while ((state & ExitState) == 0);
11966 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11967 XSetCursorState(display,windows,MagickFalse);
11968 if ((state & EscapeState) != 0)
11969 return(MagickTrue);
11970 return(MagickTrue);
11971}
11972
11973/*
11974%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11975% %
11976% %
11977% %
11978+ X R o t a t e I m a g e %
11979% %
11980% %
11981% %
11982%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11983%
11984% XRotateImage() rotates the X image. If the degrees parameter if zero, the
11985% rotation angle is computed from the slope of a line drawn by the user.
11986%
11987% The format of the XRotateImage method is:
11988%
11989% MagickBooleanType XRotateImage(Display *display,
11990% XResourceInfo *resource_info,XWindows *windows,double degrees,
cristy051718b2011-08-28 22:49:25 +000011991% Image **image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000011992%
11993% A description of each parameter follows:
11994%
11995% o display: Specifies a connection to an X server; returned from
11996% XOpenDisplay.
11997%
11998% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
11999%
12000% o windows: Specifies a pointer to a XWindows structure.
12001%
12002% o degrees: Specifies the number of degrees to rotate the image.
12003%
12004% o image: the image.
12005%
cristy051718b2011-08-28 22:49:25 +000012006% o exception: return any errors or warnings in this structure.
12007%
cristy3ed852e2009-09-05 21:47:34 +000012008*/
12009static MagickBooleanType XRotateImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000012010 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image,
12011 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000012012{
12013 static const char
12014 *RotateMenu[] =
12015 {
12016 "Pixel Color",
12017 "Direction",
12018 "Help",
12019 "Dismiss",
12020 (char *) NULL
12021 };
12022
12023 static ModeType
12024 direction = HorizontalRotateCommand;
12025
12026 static const ModeType
12027 DirectionCommands[] =
12028 {
12029 HorizontalRotateCommand,
12030 VerticalRotateCommand
12031 },
12032 RotateCommands[] =
12033 {
12034 RotateColorCommand,
12035 RotateDirectionCommand,
12036 RotateHelpCommand,
12037 RotateDismissCommand
12038 };
12039
12040 static unsigned int
12041 pen_id = 0;
12042
12043 char
cristy151b66d2015-04-15 10:50:31 +000012044 command[MagickPathExtent],
12045 text[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +000012046
12047 Image
12048 *rotate_image;
12049
12050 int
12051 id,
12052 x,
12053 y;
12054
cristya19f1d72012-08-07 18:24:38 +000012055 double
cristy3ed852e2009-09-05 21:47:34 +000012056 normalized_degrees;
12057
12058 register int
12059 i;
12060
12061 unsigned int
12062 height,
12063 rotations,
12064 width;
12065
12066 if (degrees == 0.0)
12067 {
12068 unsigned int
12069 distance;
12070
cristybb503372010-05-27 20:51:26 +000012071 size_t
cristy3ed852e2009-09-05 21:47:34 +000012072 state;
12073
12074 XEvent
12075 event;
12076
12077 XSegment
12078 rotate_info;
12079
12080 /*
12081 Map Command widget.
12082 */
12083 (void) CloneString(&windows->command.name,"Rotate");
12084 windows->command.data=2;
12085 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL);
12086 (void) XMapRaised(display,windows->command.id);
12087 XClientMessage(display,windows->image.id,windows->im_protocols,
12088 windows->im_update_widget,CurrentTime);
12089 /*
12090 Wait for first button press.
12091 */
12092 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
12093 XQueryPosition(display,windows->image.id,&x,&y);
12094 rotate_info.x1=x;
12095 rotate_info.y1=y;
12096 rotate_info.x2=x;
12097 rotate_info.y2=y;
12098 state=DefaultState;
12099 do
12100 {
12101 XHighlightLine(display,windows->image.id,
12102 windows->image.highlight_context,&rotate_info);
12103 /*
12104 Wait for next event.
12105 */
cristy6710d842011-10-20 23:23:00 +000012106 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000012107 XHighlightLine(display,windows->image.id,
12108 windows->image.highlight_context,&rotate_info);
12109 if (event.xany.window == windows->command.id)
12110 {
12111 /*
12112 Select a command from the Command widget.
12113 */
12114 id=XCommandWidget(display,windows,RotateMenu,&event);
12115 if (id < 0)
12116 continue;
12117 (void) XSetFunction(display,windows->image.highlight_context,
12118 GXcopy);
12119 switch (RotateCommands[id])
12120 {
12121 case RotateColorCommand:
12122 {
12123 const char
12124 *ColorMenu[MaxNumberPens];
12125
12126 int
12127 pen_number;
12128
12129 XColor
12130 color;
12131
12132 /*
12133 Initialize menu selections.
12134 */
12135 for (i=0; i < (int) (MaxNumberPens-2); i++)
12136 ColorMenu[i]=resource_info->pen_colors[i];
12137 ColorMenu[MaxNumberPens-2]="Browser...";
12138 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
12139 /*
12140 Select a pen color from the pop-up menu.
12141 */
12142 pen_number=XMenuWidget(display,windows,RotateMenu[id],
12143 (const char **) ColorMenu,command);
12144 if (pen_number < 0)
12145 break;
12146 if (pen_number == (MaxNumberPens-2))
12147 {
12148 static char
cristy151b66d2015-04-15 10:50:31 +000012149 color_name[MagickPathExtent] = "gray";
cristy3ed852e2009-09-05 21:47:34 +000012150
12151 /*
12152 Select a pen color from a dialog.
12153 */
12154 resource_info->pen_colors[pen_number]=color_name;
12155 XColorBrowserWidget(display,windows,"Select",color_name);
12156 if (*color_name == '\0')
12157 break;
12158 }
12159 /*
12160 Set pen color.
12161 */
12162 (void) XParseColor(display,windows->map_info->colormap,
12163 resource_info->pen_colors[pen_number],&color);
12164 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
12165 (unsigned int) MaxColors,&color);
12166 windows->pixel_info->pen_colors[pen_number]=color;
12167 pen_id=(unsigned int) pen_number;
12168 break;
12169 }
12170 case RotateDirectionCommand:
12171 {
12172 static const char
12173 *Directions[] =
12174 {
12175 "horizontal",
12176 "vertical",
12177 (char *) NULL,
12178 };
12179
12180 /*
12181 Select a command from the pop-up menu.
12182 */
12183 id=XMenuWidget(display,windows,RotateMenu[id],
12184 Directions,command);
12185 if (id >= 0)
12186 direction=DirectionCommands[id];
12187 break;
12188 }
12189 case RotateHelpCommand:
12190 {
12191 XTextViewWidget(display,resource_info,windows,MagickFalse,
12192 "Help Viewer - Image Rotation",ImageRotateHelp);
12193 break;
12194 }
12195 case RotateDismissCommand:
12196 {
12197 /*
12198 Prematurely exit.
12199 */
12200 state|=EscapeState;
12201 state|=ExitState;
12202 break;
12203 }
12204 default:
12205 break;
12206 }
12207 (void) XSetFunction(display,windows->image.highlight_context,
12208 GXinvert);
12209 continue;
12210 }
12211 switch (event.type)
12212 {
12213 case ButtonPress:
12214 {
12215 if (event.xbutton.button != Button1)
12216 break;
12217 if (event.xbutton.window != windows->image.id)
12218 break;
12219 /*
12220 exit loop.
12221 */
12222 (void) XSetFunction(display,windows->image.highlight_context,
12223 GXcopy);
12224 rotate_info.x1=event.xbutton.x;
12225 rotate_info.y1=event.xbutton.y;
12226 state|=ExitState;
12227 break;
12228 }
12229 case ButtonRelease:
12230 break;
12231 case Expose:
12232 break;
12233 case KeyPress:
12234 {
12235 char
cristy151b66d2015-04-15 10:50:31 +000012236 command[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +000012237
12238 KeySym
12239 key_symbol;
12240
12241 if (event.xkey.window != windows->image.id)
12242 break;
12243 /*
12244 Respond to a user key press.
12245 */
12246 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
12247 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12248 switch ((int) key_symbol)
12249 {
12250 case XK_Escape:
12251 case XK_F20:
12252 {
12253 /*
12254 Prematurely exit.
12255 */
12256 state|=EscapeState;
12257 state|=ExitState;
12258 break;
12259 }
12260 case XK_F1:
12261 case XK_Help:
12262 {
12263 (void) XSetFunction(display,windows->image.highlight_context,
12264 GXcopy);
12265 XTextViewWidget(display,resource_info,windows,MagickFalse,
12266 "Help Viewer - Image Rotation",ImageRotateHelp);
12267 (void) XSetFunction(display,windows->image.highlight_context,
12268 GXinvert);
12269 break;
12270 }
12271 default:
12272 {
12273 (void) XBell(display,0);
12274 break;
12275 }
12276 }
12277 break;
12278 }
12279 case MotionNotify:
12280 {
12281 rotate_info.x1=event.xmotion.x;
12282 rotate_info.y1=event.xmotion.y;
12283 }
12284 }
12285 rotate_info.x2=rotate_info.x1;
12286 rotate_info.y2=rotate_info.y1;
12287 if (direction == HorizontalRotateCommand)
12288 rotate_info.x2+=32;
12289 else
12290 rotate_info.y2-=32;
12291 } while ((state & ExitState) == 0);
12292 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12293 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12294 if ((state & EscapeState) != 0)
12295 return(MagickTrue);
12296 /*
12297 Draw line as pointer moves until the mouse button is released.
12298 */
12299 distance=0;
12300 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
12301 state=DefaultState;
12302 do
12303 {
12304 if (distance > 9)
12305 {
12306 /*
12307 Display info and draw rotation line.
12308 */
cristy59864562013-04-18 11:47:41 +000012309 if (IfMagickFalse(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000012310 (void) XMapWindow(display,windows->info.id);
cristy151b66d2015-04-15 10:50:31 +000012311 (void) FormatLocaleString(text,MagickPathExtent," %g",
cristy3ed852e2009-09-05 21:47:34 +000012312 direction == VerticalRotateCommand ? degrees-90.0 : degrees);
12313 XInfoWidget(display,windows,text);
12314 XHighlightLine(display,windows->image.id,
12315 windows->image.highlight_context,&rotate_info);
12316 }
12317 else
cristy59864562013-04-18 11:47:41 +000012318 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000012319 (void) XWithdrawWindow(display,windows->info.id,
12320 windows->info.screen);
12321 /*
12322 Wait for next event.
12323 */
cristy6710d842011-10-20 23:23:00 +000012324 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000012325 if (distance > 9)
12326 XHighlightLine(display,windows->image.id,
12327 windows->image.highlight_context,&rotate_info);
12328 switch (event.type)
12329 {
12330 case ButtonPress:
12331 break;
12332 case ButtonRelease:
12333 {
12334 /*
12335 User has committed to rotation line.
12336 */
12337 rotate_info.x2=event.xbutton.x;
12338 rotate_info.y2=event.xbutton.y;
12339 state|=ExitState;
12340 break;
12341 }
12342 case Expose:
12343 break;
12344 case MotionNotify:
12345 {
12346 rotate_info.x2=event.xmotion.x;
12347 rotate_info.y2=event.xmotion.y;
12348 }
12349 default:
12350 break;
12351 }
12352 /*
12353 Check boundary conditions.
12354 */
12355 if (rotate_info.x2 < 0)
12356 rotate_info.x2=0;
12357 else
12358 if (rotate_info.x2 > (int) windows->image.width)
12359 rotate_info.x2=(short) windows->image.width;
12360 if (rotate_info.y2 < 0)
12361 rotate_info.y2=0;
12362 else
12363 if (rotate_info.y2 > (int) windows->image.height)
12364 rotate_info.y2=(short) windows->image.height;
12365 /*
12366 Compute rotation angle from the slope of the line.
12367 */
12368 degrees=0.0;
12369 distance=(unsigned int)
12370 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+
12371 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1));
12372 if (distance > 9)
12373 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2-
12374 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1)));
12375 } while ((state & ExitState) == 0);
12376 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12377 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12378 if (distance <= 9)
12379 return(MagickTrue);
12380 }
12381 if (direction == VerticalRotateCommand)
12382 degrees-=90.0;
12383 if (degrees == 0.0)
12384 return(MagickTrue);
12385 /*
12386 Rotate image.
12387 */
12388 normalized_degrees=degrees;
12389 while (normalized_degrees < -45.0)
12390 normalized_degrees+=360.0;
12391 for (rotations=0; normalized_degrees > 45.0; rotations++)
12392 normalized_degrees-=90.0;
12393 if (normalized_degrees != 0.0)
cristy051718b2011-08-28 22:49:25 +000012394 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
12395 exception);
cristy3ed852e2009-09-05 21:47:34 +000012396 XSetCursorState(display,windows,MagickTrue);
12397 XCheckRefreshWindows(display,windows);
cristye42f6582012-02-11 17:59:50 +000012398 (*image)->background_color.red=(double) ScaleShortToQuantum(
cristy3ed852e2009-09-05 21:47:34 +000012399 windows->pixel_info->pen_colors[pen_id].red);
cristye42f6582012-02-11 17:59:50 +000012400 (*image)->background_color.green=(double) ScaleShortToQuantum(
cristy3ed852e2009-09-05 21:47:34 +000012401 windows->pixel_info->pen_colors[pen_id].green);
cristye42f6582012-02-11 17:59:50 +000012402 (*image)->background_color.blue=(double) ScaleShortToQuantum(
cristy3ed852e2009-09-05 21:47:34 +000012403 windows->pixel_info->pen_colors[pen_id].blue);
cristy051718b2011-08-28 22:49:25 +000012404 rotate_image=RotateImage(*image,degrees,exception);
cristy3ed852e2009-09-05 21:47:34 +000012405 XSetCursorState(display,windows,MagickFalse);
12406 if (rotate_image == (Image *) NULL)
12407 return(MagickFalse);
12408 *image=DestroyImage(*image);
12409 *image=rotate_image;
12410 if (windows->image.crop_geometry != (char *) NULL)
12411 {
12412 /*
12413 Rotate crop geometry.
12414 */
12415 width=(unsigned int) (*image)->columns;
12416 height=(unsigned int) (*image)->rows;
12417 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12418 switch (rotations % 4)
12419 {
12420 default:
12421 case 0:
12422 break;
12423 case 1:
12424 {
12425 /*
12426 Rotate 90 degrees.
12427 */
cristy151b66d2015-04-15 10:50:31 +000012428 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +000012429 "%ux%u%+d%+d",height,width,(int) (*image)->columns-
12430 (int) height-y,x);
12431 break;
12432 }
12433 case 2:
12434 {
12435 /*
12436 Rotate 180 degrees.
12437 */
cristy151b66d2015-04-15 10:50:31 +000012438 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +000012439 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y);
12440 break;
12441 }
12442 case 3:
12443 {
12444 /*
12445 Rotate 270 degrees.
12446 */
cristy151b66d2015-04-15 10:50:31 +000012447 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +000012448 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x);
12449 break;
12450 }
12451 }
12452 }
cristy59864562013-04-18 11:47:41 +000012453 if (IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +000012454 return(MagickTrue);
12455 if (normalized_degrees != 0.0)
12456 {
12457 /*
12458 Update image colormap.
12459 */
12460 windows->image.window_changes.width=(int) (*image)->columns;
12461 windows->image.window_changes.height=(int) (*image)->rows;
12462 if (windows->image.crop_geometry != (char *) NULL)
12463 {
12464 /*
12465 Obtain dimensions of image from crop geometry.
12466 */
12467 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
12468 &width,&height);
12469 windows->image.window_changes.width=(int) width;
12470 windows->image.window_changes.height=(int) height;
12471 }
cristy6710d842011-10-20 23:23:00 +000012472 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +000012473 }
12474 else
12475 if (((rotations % 4) == 1) || ((rotations % 4) == 3))
12476 {
12477 windows->image.window_changes.width=windows->image.ximage->height;
12478 windows->image.window_changes.height=windows->image.ximage->width;
12479 }
12480 /*
12481 Update image configuration.
12482 */
cristy051718b2011-08-28 22:49:25 +000012483 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +000012484 return(MagickTrue);
12485}
12486
12487/*
12488%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12489% %
12490% %
12491% %
12492+ X S a v e I m a g e %
12493% %
12494% %
12495% %
12496%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12497%
12498% XSaveImage() saves an image to a file.
12499%
12500% The format of the XSaveImage method is:
12501%
12502% MagickBooleanType XSaveImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000012503% XResourceInfo *resource_info,XWindows *windows,Image *image,
12504% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000012505%
12506% A description of each parameter follows:
12507%
12508% o display: Specifies a connection to an X server; returned from
12509% XOpenDisplay.
12510%
12511% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12512%
12513% o windows: Specifies a pointer to a XWindows structure.
12514%
12515% o image: the image.
12516%
cristy051718b2011-08-28 22:49:25 +000012517% o exception: return any errors or warnings in this structure.
12518%
cristy3ed852e2009-09-05 21:47:34 +000012519*/
12520static MagickBooleanType XSaveImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000012521 XResourceInfo *resource_info,XWindows *windows,Image *image,
12522 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000012523{
12524 char
cristy151b66d2015-04-15 10:50:31 +000012525 filename[MagickPathExtent],
12526 geometry[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +000012527
12528 Image
12529 *save_image;
12530
12531 ImageInfo
12532 *image_info;
12533
12534 MagickStatusType
12535 status;
12536
12537 /*
12538 Request file name from user.
12539 */
12540 if (resource_info->write_filename != (char *) NULL)
12541 (void) CopyMagickString(filename,resource_info->write_filename,
cristy151b66d2015-04-15 10:50:31 +000012542 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +000012543 else
12544 {
12545 char
cristy151b66d2015-04-15 10:50:31 +000012546 path[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +000012547
12548 int
12549 status;
12550
12551 GetPathComponent(image->filename,HeadPath,path);
12552 GetPathComponent(image->filename,TailPath,filename);
cristy0da1d642011-08-29 16:53:16 +000012553 if (*path != '\0')
12554 {
12555 status=chdir(path);
12556 if (status == -1)
12557 (void) ThrowMagickException(exception,GetMagickModule(),
12558 FileOpenError,"UnableToOpenFile","%s",path);
12559 }
cristy3ed852e2009-09-05 21:47:34 +000012560 }
12561 XFileBrowserWidget(display,windows,"Save",filename);
12562 if (*filename == '\0')
12563 return(MagickTrue);
cristy59864562013-04-18 11:47:41 +000012564 if (IfMagickTrue(IsPathAccessible(filename)) )
cristy3ed852e2009-09-05 21:47:34 +000012565 {
12566 int
12567 status;
12568
12569 /*
12570 File exists-- seek user's permission before overwriting.
12571 */
12572 status=XConfirmWidget(display,windows,"Overwrite",filename);
12573 if (status <= 0)
12574 return(MagickTrue);
12575 }
12576 image_info=CloneImageInfo(resource_info->image_info);
cristy151b66d2015-04-15 10:50:31 +000012577 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
cristy051718b2011-08-28 22:49:25 +000012578 (void) SetImageInfo(image_info,1,exception);
cristy3ed852e2009-09-05 21:47:34 +000012579 if ((LocaleCompare(image_info->magick,"JPEG") == 0) ||
12580 (LocaleCompare(image_info->magick,"JPG") == 0))
12581 {
12582 char
cristy151b66d2015-04-15 10:50:31 +000012583 quality[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +000012584
12585 int
12586 status;
12587
12588 /*
12589 Request JPEG quality from user.
12590 */
cristy151b66d2015-04-15 10:50:31 +000012591 (void) FormatLocaleString(quality,MagickPathExtent,"%.20g",(double)
cristyf2faecf2010-05-28 19:19:36 +000012592 image->quality);
cristy3ed852e2009-09-05 21:47:34 +000012593 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
12594 quality);
12595 if (*quality == '\0')
12596 return(MagickTrue);
cristye27293e2009-12-18 02:53:20 +000012597 image->quality=StringToUnsignedLong(quality);
cristy3ed852e2009-09-05 21:47:34 +000012598 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace;
12599 }
12600 if ((LocaleCompare(image_info->magick,"EPS") == 0) ||
12601 (LocaleCompare(image_info->magick,"PDF") == 0) ||
12602 (LocaleCompare(image_info->magick,"PS") == 0) ||
12603 (LocaleCompare(image_info->magick,"PS2") == 0))
12604 {
12605 char
cristy151b66d2015-04-15 10:50:31 +000012606 geometry[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +000012607
12608 /*
12609 Request page geometry from user.
12610 */
cristy151b66d2015-04-15 10:50:31 +000012611 (void) CopyMagickString(geometry,PSPageGeometry,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +000012612 if (LocaleCompare(image_info->magick,"PDF") == 0)
cristy151b66d2015-04-15 10:50:31 +000012613 (void) CopyMagickString(geometry,PSPageGeometry,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +000012614 if (image_info->page != (char *) NULL)
cristy151b66d2015-04-15 10:50:31 +000012615 (void) CopyMagickString(geometry,image_info->page,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +000012616 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
12617 "Select page geometry:",geometry);
12618 if (*geometry != '\0')
12619 image_info->page=GetPageGeometry(geometry);
12620 }
12621 /*
12622 Apply image transforms.
12623 */
12624 XSetCursorState(display,windows,MagickTrue);
12625 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +000012626 save_image=CloneImage(image,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +000012627 if (save_image == (Image *) NULL)
12628 return(MagickFalse);
cristy151b66d2015-04-15 10:50:31 +000012629 (void) FormatLocaleString(geometry,MagickPathExtent,"%dx%d!",
cristy3ed852e2009-09-05 21:47:34 +000012630 windows->image.ximage->width,windows->image.ximage->height);
cristye941a752011-10-15 01:52:48 +000012631 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry,
12632 exception);
cristy3ed852e2009-09-05 21:47:34 +000012633 /*
12634 Write image.
12635 */
cristy151b66d2015-04-15 10:50:31 +000012636 (void) CopyMagickString(save_image->filename,filename,MagickPathExtent);
cristy051718b2011-08-28 22:49:25 +000012637 status=WriteImage(image_info,save_image,exception);
cristy59864562013-04-18 11:47:41 +000012638 if (IfMagickTrue(status) )
cristy3ed852e2009-09-05 21:47:34 +000012639 image->taint=MagickFalse;
12640 save_image=DestroyImage(save_image);
12641 image_info=DestroyImageInfo(image_info);
12642 XSetCursorState(display,windows,MagickFalse);
dirkb9dbc292015-07-26 09:50:00 +000012643 return(status != 0 ? MagickTrue : MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +000012644}
12645
12646/*
12647%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12648% %
12649% %
12650% %
12651+ X S c r e e n E v e n t %
12652% %
12653% %
12654% %
12655%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12656%
12657% XScreenEvent() handles global events associated with the Pan and Magnify
12658% windows.
12659%
12660% The format of the XScreenEvent function is:
12661%
cristy6710d842011-10-20 23:23:00 +000012662% void XScreenEvent(Display *display,XWindows *windows,XEvent *event,
12663% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000012664%
12665% A description of each parameter follows:
12666%
12667% o display: Specifies a pointer to the Display structure; returned from
12668% XOpenDisplay.
12669%
12670% o windows: Specifies a pointer to a XWindows structure.
12671%
12672% o event: Specifies a pointer to a X11 XEvent structure.
12673%
cristy6710d842011-10-20 23:23:00 +000012674% o exception: return any errors or warnings in this structure.
cristy3ed852e2009-09-05 21:47:34 +000012675%
12676*/
12677
12678#if defined(__cplusplus) || defined(c_plusplus)
12679extern "C" {
12680#endif
12681
12682static int XPredicate(Display *magick_unused(display),XEvent *event,char *data)
12683{
12684 register XWindows
12685 *windows;
12686
12687 windows=(XWindows *) data;
12688 if ((event->type == ClientMessage) &&
12689 (event->xclient.window == windows->image.id))
12690 return(MagickFalse);
12691 return(MagickTrue);
12692}
12693
12694#if defined(__cplusplus) || defined(c_plusplus)
12695}
12696#endif
12697
cristy6710d842011-10-20 23:23:00 +000012698static void XScreenEvent(Display *display,XWindows *windows,XEvent *event,
12699 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000012700{
12701 register int
12702 x,
12703 y;
12704
12705 (void) XIfEvent(display,event,XPredicate,(char *) windows);
12706 if (event->xany.window == windows->command.id)
12707 return;
12708 switch (event->type)
12709 {
12710 case ButtonPress:
12711 case ButtonRelease:
12712 {
12713 if ((event->xbutton.button == Button3) &&
12714 (event->xbutton.state & Mod1Mask))
12715 {
12716 /*
12717 Convert Alt-Button3 to Button2.
12718 */
12719 event->xbutton.button=Button2;
12720 event->xbutton.state&=(~Mod1Mask);
12721 }
12722 if (event->xbutton.window == windows->backdrop.id)
12723 {
12724 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent,
12725 event->xbutton.time);
12726 break;
12727 }
12728 if (event->xbutton.window == windows->pan.id)
12729 {
cristy6710d842011-10-20 23:23:00 +000012730 XPanImage(display,windows,event,exception);
cristy3ed852e2009-09-05 21:47:34 +000012731 break;
12732 }
12733 if (event->xbutton.window == windows->image.id)
12734 if (event->xbutton.button == Button2)
12735 {
12736 /*
12737 Update magnified image.
12738 */
12739 x=event->xbutton.x;
12740 y=event->xbutton.y;
12741 if (x < 0)
12742 x=0;
12743 else
12744 if (x >= (int) windows->image.width)
12745 x=(int) (windows->image.width-1);
cristy49e2d862010-11-12 02:50:30 +000012746 windows->magnify.x=(int) windows->image.x+x;
cristy3ed852e2009-09-05 21:47:34 +000012747 if (y < 0)
12748 y=0;
12749 else
12750 if (y >= (int) windows->image.height)
12751 y=(int) (windows->image.height-1);
12752 windows->magnify.y=windows->image.y+y;
cristy59864562013-04-18 11:47:41 +000012753 if (IfMagickFalse(windows->magnify.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000012754 (void) XMapRaised(display,windows->magnify.id);
cristy6710d842011-10-20 23:23:00 +000012755 XMakeMagnifyImage(display,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +000012756 if (event->type == ButtonRelease)
12757 (void) XWithdrawWindow(display,windows->info.id,
12758 windows->info.screen);
12759 break;
12760 }
12761 break;
12762 }
12763 case ClientMessage:
12764 {
12765 /*
12766 If client window delete message, exit.
12767 */
12768 if (event->xclient.message_type != windows->wm_protocols)
12769 break;
cristyecd0ab52010-05-30 14:59:20 +000012770 if (*event->xclient.data.l != (long) windows->wm_delete_window)
cristy3ed852e2009-09-05 21:47:34 +000012771 break;
12772 if (event->xclient.window == windows->magnify.id)
12773 {
12774 (void) XWithdrawWindow(display,windows->magnify.id,
12775 windows->magnify.screen);
12776 break;
12777 }
12778 break;
12779 }
12780 case ConfigureNotify:
12781 {
12782 if (event->xconfigure.window == windows->magnify.id)
12783 {
12784 unsigned int
12785 magnify;
12786
12787 /*
12788 Magnify window has a new configuration.
12789 */
12790 windows->magnify.width=(unsigned int) event->xconfigure.width;
12791 windows->magnify.height=(unsigned int) event->xconfigure.height;
cristy59864562013-04-18 11:47:41 +000012792 if (IfMagickFalse(windows->magnify.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000012793 break;
12794 magnify=1;
12795 while ((int) magnify <= event->xconfigure.width)
12796 magnify<<=1;
12797 while ((int) magnify <= event->xconfigure.height)
12798 magnify<<=1;
12799 magnify>>=1;
12800 if (((int) magnify != event->xconfigure.width) ||
12801 ((int) magnify != event->xconfigure.height))
12802 {
12803 XWindowChanges
12804 window_changes;
12805
12806 window_changes.width=(int) magnify;
12807 window_changes.height=(int) magnify;
12808 (void) XReconfigureWMWindow(display,windows->magnify.id,
12809 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
12810 &window_changes);
12811 break;
12812 }
cristy6710d842011-10-20 23:23:00 +000012813 XMakeMagnifyImage(display,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +000012814 break;
12815 }
12816 break;
12817 }
12818 case Expose:
12819 {
12820 if (event->xexpose.window == windows->image.id)
12821 {
12822 XRefreshWindow(display,&windows->image,event);
12823 break;
12824 }
12825 if (event->xexpose.window == windows->pan.id)
12826 if (event->xexpose.count == 0)
12827 {
12828 XDrawPanRectangle(display,windows);
12829 break;
12830 }
12831 if (event->xexpose.window == windows->magnify.id)
12832 if (event->xexpose.count == 0)
12833 {
cristy6710d842011-10-20 23:23:00 +000012834 XMakeMagnifyImage(display,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +000012835 break;
12836 }
12837 break;
12838 }
12839 case KeyPress:
12840 {
12841 char
cristy151b66d2015-04-15 10:50:31 +000012842 command[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +000012843
12844 KeySym
12845 key_symbol;
12846
12847 if (event->xkey.window != windows->magnify.id)
12848 break;
12849 /*
12850 Respond to a user key press.
12851 */
12852 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int)
12853 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
cristy6710d842011-10-20 23:23:00 +000012854 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol,
12855 exception);
cristy3ed852e2009-09-05 21:47:34 +000012856 break;
12857 }
12858 case MapNotify:
12859 {
12860 if (event->xmap.window == windows->magnify.id)
12861 {
12862 windows->magnify.mapped=MagickTrue;
12863 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12864 break;
12865 }
12866 if (event->xmap.window == windows->info.id)
12867 {
12868 windows->info.mapped=MagickTrue;
12869 break;
12870 }
12871 break;
12872 }
12873 case MotionNotify:
12874 {
12875 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ;
12876 if (event->xmotion.window == windows->image.id)
cristy59864562013-04-18 11:47:41 +000012877 if (IfMagickTrue(windows->magnify.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000012878 {
12879 /*
12880 Update magnified image.
12881 */
12882 x=event->xmotion.x;
12883 y=event->xmotion.y;
12884 if (x < 0)
12885 x=0;
12886 else
12887 if (x >= (int) windows->image.width)
12888 x=(int) (windows->image.width-1);
cristy49e2d862010-11-12 02:50:30 +000012889 windows->magnify.x=(int) windows->image.x+x;
cristy3ed852e2009-09-05 21:47:34 +000012890 if (y < 0)
12891 y=0;
12892 else
12893 if (y >= (int) windows->image.height)
12894 y=(int) (windows->image.height-1);
12895 windows->magnify.y=windows->image.y+y;
cristy6710d842011-10-20 23:23:00 +000012896 XMakeMagnifyImage(display,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +000012897 }
12898 break;
12899 }
12900 case UnmapNotify:
12901 {
12902 if (event->xunmap.window == windows->magnify.id)
12903 {
12904 windows->magnify.mapped=MagickFalse;
12905 break;
12906 }
12907 if (event->xunmap.window == windows->info.id)
12908 {
12909 windows->info.mapped=MagickFalse;
12910 break;
12911 }
12912 break;
12913 }
12914 default:
12915 break;
12916 }
12917}
12918
12919/*
12920%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12921% %
12922% %
12923% %
12924+ X S e t C r o p G e o m e t r y %
12925% %
12926% %
12927% %
12928%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12929%
12930% XSetCropGeometry() accepts a cropping geometry relative to the Image window
12931% and translates it to a cropping geometry relative to the image.
12932%
12933% The format of the XSetCropGeometry method is:
12934%
12935% void XSetCropGeometry(Display *display,XWindows *windows,
12936% RectangleInfo *crop_info,Image *image)
12937%
12938% A description of each parameter follows:
12939%
12940% o display: Specifies a connection to an X server; returned from
12941% XOpenDisplay.
12942%
12943% o windows: Specifies a pointer to a XWindows structure.
12944%
12945% o crop_info: A pointer to a RectangleInfo that defines a region of the
12946% Image window to crop.
12947%
12948% o image: the image.
12949%
12950*/
12951static void XSetCropGeometry(Display *display,XWindows *windows,
12952 RectangleInfo *crop_info,Image *image)
12953{
12954 char
cristy151b66d2015-04-15 10:50:31 +000012955 text[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +000012956
12957 int
12958 x,
12959 y;
12960
cristya19f1d72012-08-07 18:24:38 +000012961 double
cristy3ed852e2009-09-05 21:47:34 +000012962 scale_factor;
12963
12964 unsigned int
12965 height,
12966 width;
12967
cristy59864562013-04-18 11:47:41 +000012968 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000012969 {
12970 /*
12971 Display info on cropping rectangle.
12972 */
cristy151b66d2015-04-15 10:50:31 +000012973 (void) FormatLocaleString(text,MagickPathExtent," %.20gx%.20g%+.20g%+.20g",
cristye8c25f92010-06-03 00:53:06 +000012974 (double) crop_info->width,(double) crop_info->height,(double)
12975 crop_info->x,(double) crop_info->y);
cristy3ed852e2009-09-05 21:47:34 +000012976 XInfoWidget(display,windows,text);
12977 }
12978 /*
12979 Cropping geometry is relative to any previous crop geometry.
12980 */
12981 x=0;
12982 y=0;
12983 width=(unsigned int) image->columns;
12984 height=(unsigned int) image->rows;
12985 if (windows->image.crop_geometry != (char *) NULL)
12986 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12987 else
12988 windows->image.crop_geometry=AcquireString((char *) NULL);
12989 /*
12990 Define the crop geometry string from the cropping rectangle.
12991 */
cristya19f1d72012-08-07 18:24:38 +000012992 scale_factor=(double) width/windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +000012993 if (crop_info->x > 0)
12994 x+=(int) (scale_factor*crop_info->x+0.5);
12995 width=(unsigned int) (scale_factor*crop_info->width+0.5);
12996 if (width == 0)
12997 width=1;
cristya19f1d72012-08-07 18:24:38 +000012998 scale_factor=(double) height/windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +000012999 if (crop_info->y > 0)
13000 y+=(int) (scale_factor*crop_info->y+0.5);
13001 height=(unsigned int) (scale_factor*crop_info->height+0.5);
13002 if (height == 0)
13003 height=1;
cristy151b66d2015-04-15 10:50:31 +000013004 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +000013005 "%ux%u%+d%+d",width,height,x,y);
13006}
13007
13008/*
13009%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13010% %
13011% %
13012% %
13013+ X T i l e I m a g e %
13014% %
13015% %
13016% %
13017%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13018%
13019% XTileImage() loads or deletes a selected tile from a visual image directory.
13020% The load or delete command is chosen from a menu.
13021%
13022% The format of the XTileImage method is:
13023%
13024% Image *XTileImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +000013025% XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013026%
13027% A description of each parameter follows:
13028%
13029% o tile_image: XTileImage reads or deletes the tile image
13030% and returns it. A null image is returned if an error occurs.
13031%
13032% o display: Specifies a connection to an X server; returned from
13033% XOpenDisplay.
13034%
13035% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13036%
13037% o windows: Specifies a pointer to a XWindows structure.
13038%
13039% o image: the image; returned from ReadImage.
13040%
13041% o event: Specifies a pointer to a XEvent structure. If it is NULL,
13042% the entire image is refreshed.
13043%
cristy051718b2011-08-28 22:49:25 +000013044% o exception: return any errors or warnings in this structure.
13045%
cristy3ed852e2009-09-05 21:47:34 +000013046*/
13047static Image *XTileImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +000013048 XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013049{
13050 static const char
13051 *VerbMenu[] =
13052 {
13053 "Load",
13054 "Next",
13055 "Former",
13056 "Delete",
13057 "Update",
13058 (char *) NULL,
13059 };
13060
13061 static const ModeType
13062 TileCommands[] =
13063 {
13064 TileLoadCommand,
13065 TileNextCommand,
13066 TileFormerCommand,
13067 TileDeleteCommand,
13068 TileUpdateCommand
13069 };
13070
13071 char
cristy151b66d2015-04-15 10:50:31 +000013072 command[MagickPathExtent],
13073 filename[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +000013074
13075 Image
13076 *tile_image;
13077
13078 int
13079 id,
13080 status,
13081 tile,
13082 x,
13083 y;
13084
cristya19f1d72012-08-07 18:24:38 +000013085 double
cristy3ed852e2009-09-05 21:47:34 +000013086 scale_factor;
13087
13088 register char
13089 *p,
13090 *q;
13091
13092 register int
13093 i;
13094
13095 unsigned int
13096 height,
13097 width;
13098
13099 /*
13100 Tile image is relative to montage image configuration.
13101 */
13102 x=0;
13103 y=0;
13104 width=(unsigned int) image->columns;
13105 height=(unsigned int) image->rows;
13106 if (windows->image.crop_geometry != (char *) NULL)
13107 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
cristya19f1d72012-08-07 18:24:38 +000013108 scale_factor=(double) width/windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +000013109 event->xbutton.x+=windows->image.x;
13110 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5);
cristya19f1d72012-08-07 18:24:38 +000013111 scale_factor=(double) height/windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +000013112 event->xbutton.y+=windows->image.y;
13113 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5);
13114 /*
13115 Determine size and location of each tile in the visual image directory.
13116 */
13117 width=(unsigned int) image->columns;
13118 height=(unsigned int) image->rows;
13119 x=0;
13120 y=0;
13121 (void) XParseGeometry(image->montage,&x,&y,&width,&height);
13122 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+
13123 (event->xbutton.x-x)/width;
13124 if (tile < 0)
13125 {
13126 /*
13127 Button press is outside any tile.
13128 */
13129 (void) XBell(display,0);
13130 return((Image *) NULL);
13131 }
13132 /*
13133 Determine file name from the tile directory.
13134 */
13135 p=image->directory;
13136 for (i=tile; (i != 0) && (*p != '\0'); )
13137 {
13138 if (*p == '\n')
13139 i--;
13140 p++;
13141 }
13142 if (*p == '\0')
13143 {
13144 /*
13145 Button press is outside any tile.
13146 */
13147 (void) XBell(display,0);
13148 return((Image *) NULL);
13149 }
13150 /*
13151 Select a command from the pop-up menu.
13152 */
13153 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command);
13154 if (id < 0)
13155 return((Image *) NULL);
13156 q=p;
13157 while ((*q != '\n') && (*q != '\0'))
13158 q++;
13159 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13160 /*
13161 Perform command for the selected tile.
13162 */
13163 XSetCursorState(display,windows,MagickTrue);
13164 XCheckRefreshWindows(display,windows);
13165 tile_image=NewImageList();
13166 switch (TileCommands[id])
13167 {
13168 case TileLoadCommand:
13169 {
13170 /*
13171 Load tile image.
13172 */
13173 XCheckRefreshWindows(display,windows);
13174 (void) CopyMagickString(resource_info->image_info->magick,"MIFF",
cristy151b66d2015-04-15 10:50:31 +000013175 MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +000013176 (void) CopyMagickString(resource_info->image_info->filename,filename,
cristy151b66d2015-04-15 10:50:31 +000013177 MagickPathExtent);
cristy051718b2011-08-28 22:49:25 +000013178 tile_image=ReadImage(resource_info->image_info,exception);
13179 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +000013180 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13181 break;
13182 }
13183 case TileNextCommand:
13184 {
13185 /*
13186 Display next image.
13187 */
13188 XClientMessage(display,windows->image.id,windows->im_protocols,
13189 windows->im_next_image,CurrentTime);
13190 break;
13191 }
13192 case TileFormerCommand:
13193 {
13194 /*
13195 Display former image.
13196 */
13197 XClientMessage(display,windows->image.id,windows->im_protocols,
13198 windows->im_former_image,CurrentTime);
13199 break;
13200 }
13201 case TileDeleteCommand:
13202 {
13203 /*
13204 Delete tile image.
13205 */
cristy59864562013-04-18 11:47:41 +000013206 if (IfMagickFalse(IsPathAccessible(filename)) )
cristy3ed852e2009-09-05 21:47:34 +000013207 {
13208 XNoticeWidget(display,windows,"Image file does not exist:",filename);
13209 break;
13210 }
13211 status=XConfirmWidget(display,windows,"Really delete tile",filename);
13212 if (status <= 0)
13213 break;
cristy59864562013-04-18 11:47:41 +000013214 status=ShredFile(filename);
13215 if (IfMagickTrue(status) )
cristy3ed852e2009-09-05 21:47:34 +000013216 {
13217 XNoticeWidget(display,windows,"Unable to delete image file:",
13218 filename);
13219 break;
13220 }
13221 }
13222 case TileUpdateCommand:
13223 {
cristy3ed852e2009-09-05 21:47:34 +000013224 int
13225 x_offset,
13226 y_offset;
13227
cristy101ab702011-10-13 13:06:32 +000013228 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +000013229 pixel;
13230
13231 register int
13232 j;
13233
cristy4c08aed2011-07-01 19:47:50 +000013234 register Quantum
cristy3ed852e2009-09-05 21:47:34 +000013235 *s;
13236
13237 /*
13238 Ensure all the images exist.
13239 */
13240 tile=0;
cristy101ab702011-10-13 13:06:32 +000013241 GetPixelInfo(image,&pixel);
cristy3ed852e2009-09-05 21:47:34 +000013242 for (p=image->directory; *p != '\0'; p++)
13243 {
cristyf7c25522010-11-15 01:25:14 +000013244 CacheView
13245 *image_view;
13246
cristy3ed852e2009-09-05 21:47:34 +000013247 q=p;
13248 while ((*q != '\n') && (*q != '\0'))
13249 q++;
13250 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13251 p=q;
cristy59864562013-04-18 11:47:41 +000013252 if (IfMagickTrue(IsPathAccessible(filename)) )
cristy3ed852e2009-09-05 21:47:34 +000013253 {
13254 tile++;
13255 continue;
13256 }
13257 /*
13258 Overwrite tile with background color.
13259 */
13260 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x);
13261 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y);
cristy46ff2672012-12-14 15:32:26 +000013262 image_view=AcquireAuthenticCacheView(image,exception);
cristyf05d4942012-03-17 16:26:09 +000013263 (void) GetOneCacheViewVirtualPixelInfo(image_view,0,0,&pixel,exception);
cristy3ed852e2009-09-05 21:47:34 +000013264 for (i=0; i < (int) height; i++)
13265 {
cristy49e2d862010-11-12 02:50:30 +000013266 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t)
13267 y_offset+i,width,1,exception);
cristy4c08aed2011-07-01 19:47:50 +000013268 if (s == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +000013269 break;
13270 for (j=0; j < (int) width; j++)
cristy4c08aed2011-07-01 19:47:50 +000013271 {
cristy11a06d32015-01-04 12:03:27 +000013272 SetPixelViaPixelInfo(image,&pixel,s);
cristyed231572011-07-14 02:18:59 +000013273 s+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +000013274 }
cristy59864562013-04-18 11:47:41 +000013275 if (IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) )
cristy3ed852e2009-09-05 21:47:34 +000013276 break;
13277 }
cristyca1628f2010-11-15 01:17:49 +000013278 image_view=DestroyCacheView(image_view);
cristy3ed852e2009-09-05 21:47:34 +000013279 tile++;
13280 }
13281 windows->image.window_changes.width=(int) image->columns;
13282 windows->image.window_changes.height=(int) image->rows;
cristy6710d842011-10-20 23:23:00 +000013283 XConfigureImageColormap(display,resource_info,windows,image,exception);
cristy051718b2011-08-28 22:49:25 +000013284 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +000013285 break;
13286 }
13287 default:
13288 break;
13289 }
13290 XSetCursorState(display,windows,MagickFalse);
13291 return(tile_image);
13292}
13293
13294/*
13295%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13296% %
13297% %
13298% %
13299+ X T r a n s l a t e I m a g e %
13300% %
13301% %
13302% %
13303%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13304%
13305% XTranslateImage() translates the image within an Image window by one pixel
anthonye5b39652012-04-21 05:37:29 +000013306% as specified by the key symbol. If the image has a montage string the
cristy3ed852e2009-09-05 21:47:34 +000013307% translation is respect to the width and height contained within the string.
13308%
13309% The format of the XTranslateImage method is:
13310%
13311% void XTranslateImage(Display *display,XWindows *windows,
13312% Image *image,const KeySym key_symbol)
13313%
13314% A description of each parameter follows:
13315%
13316% o display: Specifies a connection to an X server; returned from
13317% XOpenDisplay.
13318%
13319% o windows: Specifies a pointer to a XWindows structure.
13320%
13321% o image: the image.
13322%
13323% o key_symbol: Specifies a KeySym which indicates which side of the image
13324% to trim.
13325%
13326*/
13327static void XTranslateImage(Display *display,XWindows *windows,
13328 Image *image,const KeySym key_symbol)
13329{
13330 char
cristy151b66d2015-04-15 10:50:31 +000013331 text[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +000013332
13333 int
13334 x,
13335 y;
13336
13337 unsigned int
13338 x_offset,
13339 y_offset;
13340
13341 /*
13342 User specified a pan position offset.
13343 */
13344 x_offset=windows->image.width;
13345 y_offset=windows->image.height;
13346 if (image->montage != (char *) NULL)
13347 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset);
13348 switch ((int) key_symbol)
13349 {
13350 case XK_Home:
13351 case XK_KP_Home:
13352 {
13353 windows->image.x=(int) windows->image.width/2;
13354 windows->image.y=(int) windows->image.height/2;
13355 break;
13356 }
13357 case XK_Left:
13358 case XK_KP_Left:
13359 {
13360 windows->image.x-=x_offset;
13361 break;
13362 }
13363 case XK_Next:
13364 case XK_Up:
13365 case XK_KP_Up:
13366 {
13367 windows->image.y-=y_offset;
13368 break;
13369 }
13370 case XK_Right:
13371 case XK_KP_Right:
13372 {
13373 windows->image.x+=x_offset;
13374 break;
13375 }
13376 case XK_Prior:
13377 case XK_Down:
13378 case XK_KP_Down:
13379 {
13380 windows->image.y+=y_offset;
13381 break;
13382 }
13383 default:
13384 return;
13385 }
13386 /*
13387 Check boundary conditions.
13388 */
13389 if (windows->image.x < 0)
13390 windows->image.x=0;
13391 else
13392 if ((int) (windows->image.x+windows->image.width) >
13393 windows->image.ximage->width)
cristy49e2d862010-11-12 02:50:30 +000013394 windows->image.x=(int) windows->image.ximage->width-windows->image.width;
cristy3ed852e2009-09-05 21:47:34 +000013395 if (windows->image.y < 0)
13396 windows->image.y=0;
13397 else
13398 if ((int) (windows->image.y+windows->image.height) >
13399 windows->image.ximage->height)
cristy49e2d862010-11-12 02:50:30 +000013400 windows->image.y=(int) windows->image.ximage->height-windows->image.height;
cristy3ed852e2009-09-05 21:47:34 +000013401 /*
13402 Refresh Image window.
13403 */
cristy151b66d2015-04-15 10:50:31 +000013404 (void) FormatLocaleString(text,MagickPathExtent," %ux%u%+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +000013405 windows->image.width,windows->image.height,windows->image.x,
13406 windows->image.y);
13407 XInfoWidget(display,windows,text);
13408 XCheckRefreshWindows(display,windows);
13409 XDrawPanRectangle(display,windows);
13410 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
13411 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13412}
13413
13414/*
13415%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13416% %
13417% %
13418% %
13419+ X T r i m I m a g e %
13420% %
13421% %
13422% %
13423%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13424%
13425% XTrimImage() trims the edges from the Image window.
13426%
13427% The format of the XTrimImage method is:
13428%
13429% MagickBooleanType XTrimImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000013430% XResourceInfo *resource_info,XWindows *windows,Image *image,
13431% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013432%
13433% A description of each parameter follows:
13434%
13435% o display: Specifies a connection to an X server; returned from
13436% XOpenDisplay.
13437%
13438% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13439%
13440% o windows: Specifies a pointer to a XWindows structure.
13441%
13442% o image: the image.
13443%
cristy051718b2011-08-28 22:49:25 +000013444% o exception: return any errors or warnings in this structure.
13445%
cristy3ed852e2009-09-05 21:47:34 +000013446*/
13447static MagickBooleanType XTrimImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000013448 XResourceInfo *resource_info,XWindows *windows,Image *image,
13449 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013450{
13451 RectangleInfo
13452 trim_info;
13453
13454 register int
13455 x,
13456 y;
13457
cristybb503372010-05-27 20:51:26 +000013458 size_t
cristy3ed852e2009-09-05 21:47:34 +000013459 background,
13460 pixel;
13461
13462 /*
13463 Trim edges from image.
13464 */
13465 XSetCursorState(display,windows,MagickTrue);
13466 XCheckRefreshWindows(display,windows);
13467 /*
13468 Crop the left edge.
13469 */
13470 background=XGetPixel(windows->image.ximage,0,0);
cristybb503372010-05-27 20:51:26 +000013471 trim_info.width=(size_t) windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +000013472 for (x=0; x < windows->image.ximage->width; x++)
13473 {
13474 for (y=0; y < windows->image.ximage->height; y++)
13475 {
13476 pixel=XGetPixel(windows->image.ximage,x,y);
13477 if (pixel != background)
13478 break;
13479 }
13480 if (y < windows->image.ximage->height)
13481 break;
13482 }
cristy49e2d862010-11-12 02:50:30 +000013483 trim_info.x=(ssize_t) x;
13484 if (trim_info.x == (ssize_t) windows->image.ximage->width)
cristy3ed852e2009-09-05 21:47:34 +000013485 {
13486 XSetCursorState(display,windows,MagickFalse);
13487 return(MagickFalse);
13488 }
13489 /*
13490 Crop the right edge.
13491 */
13492 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0);
13493 for (x=windows->image.ximage->width-1; x != 0; x--)
13494 {
13495 for (y=0; y < windows->image.ximage->height; y++)
13496 {
13497 pixel=XGetPixel(windows->image.ximage,x,y);
13498 if (pixel != background)
13499 break;
13500 }
13501 if (y < windows->image.ximage->height)
13502 break;
13503 }
cristybb503372010-05-27 20:51:26 +000013504 trim_info.width=(size_t) (x-trim_info.x+1);
cristy3ed852e2009-09-05 21:47:34 +000013505 /*
13506 Crop the top edge.
13507 */
13508 background=XGetPixel(windows->image.ximage,0,0);
cristybb503372010-05-27 20:51:26 +000013509 trim_info.height=(size_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +000013510 for (y=0; y < windows->image.ximage->height; y++)
13511 {
13512 for (x=0; x < windows->image.ximage->width; x++)
13513 {
13514 pixel=XGetPixel(windows->image.ximage,x,y);
13515 if (pixel != background)
13516 break;
13517 }
13518 if (x < windows->image.ximage->width)
13519 break;
13520 }
cristy49e2d862010-11-12 02:50:30 +000013521 trim_info.y=(ssize_t) y;
cristy3ed852e2009-09-05 21:47:34 +000013522 /*
13523 Crop the bottom edge.
13524 */
13525 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1);
13526 for (y=windows->image.ximage->height-1; y != 0; y--)
13527 {
13528 for (x=0; x < windows->image.ximage->width; x++)
13529 {
13530 pixel=XGetPixel(windows->image.ximage,x,y);
13531 if (pixel != background)
13532 break;
13533 }
13534 if (x < windows->image.ximage->width)
13535 break;
13536 }
cristybb503372010-05-27 20:51:26 +000013537 trim_info.height=(size_t) y-trim_info.y+1;
cristy3ed852e2009-09-05 21:47:34 +000013538 if (((unsigned int) trim_info.width != windows->image.width) ||
13539 ((unsigned int) trim_info.height != windows->image.height))
13540 {
13541 /*
13542 Reconfigure Image window as defined by the trimming rectangle.
13543 */
13544 XSetCropGeometry(display,windows,&trim_info,image);
13545 windows->image.window_changes.width=(int) trim_info.width;
13546 windows->image.window_changes.height=(int) trim_info.height;
cristy051718b2011-08-28 22:49:25 +000013547 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +000013548 }
13549 XSetCursorState(display,windows,MagickFalse);
13550 return(MagickTrue);
13551}
13552
13553/*
13554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13555% %
13556% %
13557% %
13558+ X V i s u a l D i r e c t o r y I m a g e %
13559% %
13560% %
13561% %
13562%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13563%
13564% XVisualDirectoryImage() creates a Visual Image Directory.
13565%
13566% The format of the XVisualDirectoryImage method is:
13567%
13568% Image *XVisualDirectoryImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000013569% XResourceInfo *resource_info,XWindows *windows,
13570% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013571%
13572% A description of each parameter follows:
13573%
cristy3ed852e2009-09-05 21:47:34 +000013574% o display: Specifies a connection to an X server; returned from
13575% XOpenDisplay.
13576%
13577% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13578%
13579% o windows: Specifies a pointer to a XWindows structure.
13580%
cristy051718b2011-08-28 22:49:25 +000013581% o exception: return any errors or warnings in this structure.
13582%
cristy3ed852e2009-09-05 21:47:34 +000013583*/
13584static Image *XVisualDirectoryImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000013585 XResourceInfo *resource_info,XWindows *windows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013586{
13587#define TileImageTag "Scale/Image"
13588#define XClientName "montage"
13589
13590 char
13591 **filelist;
13592
cristy3ed852e2009-09-05 21:47:34 +000013593 Image
13594 *images,
13595 *montage_image,
13596 *next_image,
13597 *thumbnail_image;
13598
13599 ImageInfo
13600 *read_info;
13601
13602 int
13603 number_files;
13604
13605 MagickBooleanType
13606 backdrop;
13607
13608 MagickStatusType
13609 status;
13610
13611 MontageInfo
13612 *montage_info;
13613
13614 RectangleInfo
13615 geometry;
13616
13617 register int
13618 i;
13619
13620 static char
cristy151b66d2015-04-15 10:50:31 +000013621 filename[MagickPathExtent] = "\0",
13622 filenames[MagickPathExtent] = "*";
cristy3ed852e2009-09-05 21:47:34 +000013623
13624 XResourceInfo
13625 background_resources;
13626
13627 /*
13628 Request file name from user.
13629 */
13630 XFileBrowserWidget(display,windows,"Directory",filenames);
13631 if (*filenames == '\0')
13632 return((Image *) NULL);
13633 /*
13634 Expand the filenames.
13635 */
cristy73bd4a52010-10-05 11:24:23 +000013636 filelist=(char **) AcquireMagickMemory(sizeof(*filelist));
cristy3ed852e2009-09-05 21:47:34 +000013637 if (filelist == (char **) NULL)
13638 {
cristybeb1a6b2013-11-04 12:08:18 +000013639 ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
cristy3ed852e2009-09-05 21:47:34 +000013640 filenames);
13641 return((Image *) NULL);
13642 }
13643 number_files=1;
13644 filelist[0]=filenames;
13645 status=ExpandFilenames(&number_files,&filelist);
cristy59864562013-04-18 11:47:41 +000013646 if (IfMagickFalse(status) || (number_files == 0))
cristy3ed852e2009-09-05 21:47:34 +000013647 {
13648 if (number_files == 0)
cristybeb1a6b2013-11-04 12:08:18 +000013649 ThrowXWindowException(ImageError,"NoImagesWereFound",filenames)
cristy3ed852e2009-09-05 21:47:34 +000013650 else
cristybeb1a6b2013-11-04 12:08:18 +000013651 ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
cristy3ed852e2009-09-05 21:47:34 +000013652 filenames);
13653 return((Image *) NULL);
13654 }
13655 /*
13656 Set image background resources.
13657 */
13658 background_resources=(*resource_info);
13659 background_resources.window_id=AcquireString("");
cristy151b66d2015-04-15 10:50:31 +000013660 (void) FormatLocaleString(background_resources.window_id,MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +000013661 "0x%lx",windows->image.id);
13662 background_resources.backdrop=MagickTrue;
13663 /*
13664 Read each image and convert them to a tile.
13665 */
dirkb9dbc292015-07-26 09:50:00 +000013666 backdrop=((windows->visual_info->klass == TrueColor) ||
13667 (windows->visual_info->klass == DirectColor)) ? MagickTrue : MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +000013668 read_info=CloneImageInfo(resource_info->image_info);
cristy9ce61202010-11-24 00:38:37 +000013669 (void) SetImageOption(read_info,"jpeg:size","120x120");
13670 (void) CloneString(&read_info->size,DefaultTileGeometry);
cristy3ed852e2009-09-05 21:47:34 +000013671 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL,
13672 (void *) NULL);
13673 images=NewImageList();
cristy3ed852e2009-09-05 21:47:34 +000013674 XSetCursorState(display,windows,MagickTrue);
13675 XCheckRefreshWindows(display,windows);
cristy49e2d862010-11-12 02:50:30 +000013676 for (i=0; i < (int) number_files; i++)
cristy3ed852e2009-09-05 21:47:34 +000013677 {
cristy151b66d2015-04-15 10:50:31 +000013678 (void) CopyMagickString(read_info->filename,filelist[i],MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +000013679 filelist[i]=DestroyString(filelist[i]);
13680 *read_info->magick='\0';
cristy3ed852e2009-09-05 21:47:34 +000013681 next_image=ReadImage(read_info,exception);
13682 CatchException(exception);
13683 if (next_image != (Image *) NULL)
13684 {
13685 (void) DeleteImageProperty(next_image,"label");
cristy77619442010-11-24 00:27:23 +000013686 (void) SetImageProperty(next_image,"label",InterpretImageProperties(
cristyd15e6592011-10-15 00:13:06 +000013687 read_info,next_image,DefaultTileLabel,exception),exception);
cristy3ed852e2009-09-05 21:47:34 +000013688 (void) ParseRegionGeometry(next_image,read_info->size,&geometry,
13689 exception);
13690 thumbnail_image=ThumbnailImage(next_image,geometry.width,
13691 geometry.height,exception);
13692 if (thumbnail_image != (Image *) NULL)
13693 {
13694 next_image=DestroyImage(next_image);
13695 next_image=thumbnail_image;
13696 }
13697 if (backdrop)
13698 {
13699 (void) XDisplayBackgroundImage(display,&background_resources,
cristy051718b2011-08-28 22:49:25 +000013700 next_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000013701 XSetCursorState(display,windows,MagickTrue);
13702 }
13703 AppendImageToList(&images,next_image);
13704 if (images->progress_monitor != (MagickProgressMonitor) NULL)
13705 {
13706 MagickBooleanType
13707 proceed;
13708
13709 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i,
13710 (MagickSizeType) number_files);
cristy59864562013-04-18 11:47:41 +000013711 if (IfMagickFalse(proceed) )
cristy3ed852e2009-09-05 21:47:34 +000013712 break;
13713 }
13714 }
13715 }
cristy3ed852e2009-09-05 21:47:34 +000013716 filelist=(char **) RelinquishMagickMemory(filelist);
cristy3ed852e2009-09-05 21:47:34 +000013717 if (images == (Image *) NULL)
13718 {
cristy8d52fca2010-11-24 00:45:05 +000013719 read_info=DestroyImageInfo(read_info);
cristy3ed852e2009-09-05 21:47:34 +000013720 XSetCursorState(display,windows,MagickFalse);
cristybeb1a6b2013-11-04 12:08:18 +000013721 ThrowXWindowException(ImageError,"NoImagesWereLoaded",filenames);
cristy3ed852e2009-09-05 21:47:34 +000013722 return((Image *) NULL);
13723 }
13724 /*
13725 Create the Visual Image Directory.
13726 */
cristy8d52fca2010-11-24 00:45:05 +000013727 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL);
13728 montage_info->pointsize=10;
cristy3ed852e2009-09-05 21:47:34 +000013729 if (resource_info->font != (char *) NULL)
13730 (void) CloneString(&montage_info->font,resource_info->font);
cristy151b66d2015-04-15 10:50:31 +000013731 (void) CopyMagickString(montage_info->filename,filename,MagickPathExtent);
cristy8d52fca2010-11-24 00:45:05 +000013732 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList(
cristy051718b2011-08-28 22:49:25 +000013733 images),exception);
cristy3ed852e2009-09-05 21:47:34 +000013734 images=DestroyImageList(images);
cristy8d52fca2010-11-24 00:45:05 +000013735 montage_info=DestroyMontageInfo(montage_info);
13736 read_info=DestroyImageInfo(read_info);
cristy3ed852e2009-09-05 21:47:34 +000013737 XSetCursorState(display,windows,MagickFalse);
13738 if (montage_image == (Image *) NULL)
13739 return(montage_image);
13740 XClientMessage(display,windows->image.id,windows->im_protocols,
13741 windows->im_next_image,CurrentTime);
13742 return(montage_image);
13743}
13744
13745/*
13746%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13747% %
13748% %
13749% %
13750% X D i s p l a y B a c k g r o u n d I m a g e %
13751% %
13752% %
13753% %
13754%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13755%
13756% XDisplayBackgroundImage() displays an image in the background of a window.
13757%
13758% The format of the XDisplayBackgroundImage method is:
13759%
13760% MagickBooleanType XDisplayBackgroundImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000013761% XResourceInfo *resource_info,Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013762%
13763% A description of each parameter follows:
13764%
13765% o display: Specifies a connection to an X server; returned from
13766% XOpenDisplay.
13767%
13768% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13769%
13770% o image: the image.
13771%
cristy051718b2011-08-28 22:49:25 +000013772% o exception: return any errors or warnings in this structure.
13773%
cristy3ed852e2009-09-05 21:47:34 +000013774*/
13775MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000013776 XResourceInfo *resource_info,Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013777{
13778 char
cristy151b66d2015-04-15 10:50:31 +000013779 geometry[MagickPathExtent],
13780 visual_type[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +000013781
13782 int
13783 height,
13784 status,
13785 width;
13786
13787 RectangleInfo
13788 geometry_info;
13789
13790 static XPixelInfo
13791 pixel;
13792
13793 static XStandardColormap
13794 *map_info;
13795
13796 static XVisualInfo
13797 *visual_info = (XVisualInfo *) NULL;
13798
13799 static XWindowInfo
13800 window_info;
13801
cristybb503372010-05-27 20:51:26 +000013802 size_t
cristy3ed852e2009-09-05 21:47:34 +000013803 delay;
13804
13805 Window
13806 root_window;
13807
13808 XGCValues
13809 context_values;
13810
13811 XResourceInfo
13812 resources;
13813
13814 XWindowAttributes
13815 window_attributes;
13816
13817 /*
13818 Determine target window.
13819 */
13820 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +000013821 assert(image->signature == MagickCoreSignature);
cristy59864562013-04-18 11:47:41 +000013822 if (IfMagickTrue(image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000013823 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
13824 resources=(*resource_info);
13825 window_info.id=(Window) NULL;
13826 root_window=XRootWindow(display,XDefaultScreen(display));
13827 if (LocaleCompare(resources.window_id,"root") == 0)
13828 window_info.id=root_window;
13829 else
13830 {
cristy02e64f82013-11-14 16:20:04 +000013831 if (isdigit((int) ((unsigned char) *resources.window_id)) != 0)
cristy3ed852e2009-09-05 21:47:34 +000013832 window_info.id=XWindowByID(display,root_window,
13833 (Window) strtol((char *) resources.window_id,(char **) NULL,0));
13834 if (window_info.id == (Window) NULL)
13835 window_info.id=XWindowByName(display,root_window,resources.window_id);
13836 }
13837 if (window_info.id == (Window) NULL)
13838 {
cristybeb1a6b2013-11-04 12:08:18 +000013839 ThrowXWindowException(XServerError,"NoWindowWithSpecifiedIDExists",
cristy3ed852e2009-09-05 21:47:34 +000013840 resources.window_id);
13841 return(MagickFalse);
13842 }
13843 /*
13844 Determine window visual id.
13845 */
13846 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display));
13847 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display));
cristy151b66d2015-04-15 10:50:31 +000013848 (void) CopyMagickString(visual_type,"default",MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +000013849 status=XGetWindowAttributes(display,window_info.id,&window_attributes);
13850 if (status != 0)
cristy151b66d2015-04-15 10:50:31 +000013851 (void) FormatLocaleString(visual_type,MagickPathExtent,"0x%lx",
cristy3ed852e2009-09-05 21:47:34 +000013852 XVisualIDFromVisual(window_attributes.visual));
13853 if (visual_info == (XVisualInfo *) NULL)
13854 {
13855 /*
13856 Allocate standard colormap.
13857 */
13858 map_info=XAllocStandardColormap();
13859 if (map_info == (XStandardColormap *) NULL)
13860 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
13861 image->filename);
13862 map_info->colormap=(Colormap) NULL;
cristyf2faecf2010-05-28 19:19:36 +000013863 pixel.pixels=(unsigned long *) NULL;
cristy3ed852e2009-09-05 21:47:34 +000013864 /*
13865 Initialize visual info.
13866 */
13867 resources.map_type=(char *) NULL;
13868 resources.visual_type=visual_type;
13869 visual_info=XBestVisualInfo(display,map_info,&resources);
13870 if (visual_info == (XVisualInfo *) NULL)
13871 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual",
13872 resources.visual_type);
13873 /*
13874 Initialize window info.
13875 */
13876 window_info.ximage=(XImage *) NULL;
13877 window_info.matte_image=(XImage *) NULL;
13878 window_info.pixmap=(Pixmap) NULL;
13879 window_info.matte_pixmap=(Pixmap) NULL;
13880 }
13881 /*
13882 Free previous root colors.
13883 */
13884 if (window_info.id == root_window)
13885 (void) XDestroyWindowColors(display,root_window);
13886 /*
13887 Initialize Standard Colormap.
13888 */
13889 resources.colormap=SharedColormap;
cristy6710d842011-10-20 23:23:00 +000013890 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel,
13891 exception);
cristy3ed852e2009-09-05 21:47:34 +000013892 /*
13893 Graphic context superclass.
13894 */
13895 context_values.background=pixel.background_color.pixel;
13896 context_values.foreground=pixel.foreground_color.pixel;
13897 pixel.annotate_context=XCreateGC(display,window_info.id,
cristybb503372010-05-27 20:51:26 +000013898 (size_t) (GCBackground | GCForeground),&context_values);
cristy3ed852e2009-09-05 21:47:34 +000013899 if (pixel.annotate_context == (GC) NULL)
13900 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
13901 image->filename);
13902 /*
13903 Initialize Image window attributes.
13904 */
13905 window_info.name=AcquireString("\0");
13906 window_info.icon_name=AcquireString("\0");
13907 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL,
13908 &resources,&window_info);
13909 /*
13910 Create the X image.
13911 */
13912 window_info.width=(unsigned int) image->columns;
13913 window_info.height=(unsigned int) image->rows;
13914 if ((image->columns != window_info.width) ||
13915 (image->rows != window_info.height))
13916 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13917 image->filename);
cristy151b66d2015-04-15 10:50:31 +000013918 (void) FormatLocaleString(geometry,MagickPathExtent,"%ux%u+0+0>",
cristy3ed852e2009-09-05 21:47:34 +000013919 window_attributes.width,window_attributes.height);
13920 geometry_info.width=window_info.width;
13921 geometry_info.height=window_info.height;
cristyecd0ab52010-05-30 14:59:20 +000013922 geometry_info.x=(ssize_t) window_info.x;
13923 geometry_info.y=(ssize_t) window_info.y;
cristy3ed852e2009-09-05 21:47:34 +000013924 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
13925 &geometry_info.width,&geometry_info.height);
13926 window_info.width=(unsigned int) geometry_info.width;
13927 window_info.height=(unsigned int) geometry_info.height;
13928 window_info.x=(int) geometry_info.x;
13929 window_info.y=(int) geometry_info.y;
13930 status=XMakeImage(display,&resources,&window_info,image,window_info.width,
cristy051718b2011-08-28 22:49:25 +000013931 window_info.height,exception);
cristy59864562013-04-18 11:47:41 +000013932 if (IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +000013933 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13934 image->filename);
13935 window_info.x=0;
13936 window_info.y=0;
cristy59864562013-04-18 11:47:41 +000013937 if (IfMagickTrue(image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000013938 {
13939 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +000013940 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene,
13941 (double) image->columns,(double) image->rows);
cristy3ed852e2009-09-05 21:47:34 +000013942 if (image->colors != 0)
cristye8c25f92010-06-03 00:53:06 +000013943 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
13944 image->colors);
cristy3ed852e2009-09-05 21:47:34 +000013945 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick);
13946 }
13947 /*
13948 Adjust image dimensions as specified by backdrop or geometry options.
13949 */
13950 width=(int) window_info.width;
13951 height=(int) window_info.height;
cristy59864562013-04-18 11:47:41 +000013952 if (IfMagickTrue(resources.backdrop) )
cristy3ed852e2009-09-05 21:47:34 +000013953 {
13954 /*
13955 Center image on window.
13956 */
13957 window_info.x=(window_attributes.width/2)-
13958 (window_info.ximage->width/2);
13959 window_info.y=(window_attributes.height/2)-
13960 (window_info.ximage->height/2);
13961 width=window_attributes.width;
13962 height=window_attributes.height;
13963 }
13964 if ((resources.image_geometry != (char *) NULL) &&
13965 (*resources.image_geometry != '\0'))
13966 {
13967 char
cristy151b66d2015-04-15 10:50:31 +000013968 default_geometry[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +000013969
13970 int
13971 flags,
13972 gravity;
13973
13974 XSizeHints
13975 *size_hints;
13976
13977 /*
13978 User specified geometry.
13979 */
13980 size_hints=XAllocSizeHints();
13981 if (size_hints == (XSizeHints *) NULL)
13982 ThrowXWindowFatalException(ResourceLimitFatalError,
13983 "MemoryAllocationFailed",image->filename);
13984 size_hints->flags=0L;
cristy151b66d2015-04-15 10:50:31 +000013985 (void) FormatLocaleString(default_geometry,MagickPathExtent,"%dx%d",
cristy3ed852e2009-09-05 21:47:34 +000013986 width,height);
13987 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry,
13988 default_geometry,window_info.border_width,size_hints,&window_info.x,
13989 &window_info.y,&width,&height,&gravity);
13990 if (flags & (XValue | YValue))
13991 {
13992 width=window_attributes.width;
13993 height=window_attributes.height;
13994 }
13995 (void) XFree((void *) size_hints);
13996 }
13997 /*
13998 Create the X pixmap.
13999 */
14000 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width,
14001 (unsigned int) height,window_info.depth);
14002 if (window_info.pixmap == (Pixmap) NULL)
14003 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
14004 image->filename);
14005 /*
14006 Display pixmap on the window.
14007 */
14008 if (((unsigned int) width > window_info.width) ||
14009 ((unsigned int) height > window_info.height))
14010 (void) XFillRectangle(display,window_info.pixmap,
14011 window_info.annotate_context,0,0,(unsigned int) width,
14012 (unsigned int) height);
14013 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
14014 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int)
14015 window_info.width,(unsigned int) window_info.height);
14016 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
14017 (void) XClearWindow(display,window_info.id);
14018 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L);
14019 XDelay(display,delay == 0UL ? 10UL : delay);
14020 (void) XSync(display,MagickFalse);
dirkb9dbc292015-07-26 09:50:00 +000014021 return(window_info.id == root_window ? MagickTrue : MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +000014022}
14023
14024/*
14025%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14026% %
14027% %
14028% %
14029+ X D i s p l a y I m a g e %
14030% %
14031% %
14032% %
14033%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14034%
14035% XDisplayImage() displays an image via X11. A new image is created and
14036% returned if the user interactively transforms the displayed image.
14037%
14038% The format of the XDisplayImage method is:
14039%
14040% Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +000014041% char **argv,int argc,Image **image,size_t *state,
14042% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000014043%
14044% A description of each parameter follows:
14045%
14046% o nexus: Method XDisplayImage returns an image when the
14047% user chooses 'Open Image' from the command menu or picks a tile
14048% from the image directory. Otherwise a null image is returned.
14049%
14050% o display: Specifies a connection to an X server; returned from
14051% XOpenDisplay.
14052%
14053% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
14054%
14055% o argv: Specifies the application's argument list.
14056%
14057% o argc: Specifies the number of arguments.
14058%
14059% o image: Specifies an address to an address of an Image structure;
14060%
cristy051718b2011-08-28 22:49:25 +000014061% o exception: return any errors or warnings in this structure.
14062%
cristy3ed852e2009-09-05 21:47:34 +000014063*/
14064MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +000014065 char **argv,int argc,Image **image,size_t *state,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000014066{
14067#define MagnifySize 256 /* must be a power of 2 */
14068#define MagickMenus 10
14069#define MagickTitle "Commands"
14070
14071 static const char
14072 *CommandMenu[] =
14073 {
14074 "File",
14075 "Edit",
14076 "View",
14077 "Transform",
14078 "Enhance",
14079 "Effects",
14080 "F/X",
14081 "Image Edit",
14082 "Miscellany",
14083 "Help",
14084 (char *) NULL
14085 },
14086 *FileMenu[] =
14087 {
14088 "Open...",
14089 "Next",
14090 "Former",
14091 "Select...",
14092 "Save...",
14093 "Print...",
14094 "Delete...",
14095 "New...",
14096 "Visual Directory...",
14097 "Quit",
14098 (char *) NULL
14099 },
14100 *EditMenu[] =
14101 {
14102 "Undo",
14103 "Redo",
14104 "Cut",
14105 "Copy",
14106 "Paste",
14107 (char *) NULL
14108 },
14109 *ViewMenu[] =
14110 {
14111 "Half Size",
14112 "Original Size",
14113 "Double Size",
14114 "Resize...",
14115 "Apply",
14116 "Refresh",
14117 "Restore",
14118 (char *) NULL
14119 },
14120 *TransformMenu[] =
14121 {
14122 "Crop",
14123 "Chop",
14124 "Flop",
14125 "Flip",
14126 "Rotate Right",
14127 "Rotate Left",
14128 "Rotate...",
14129 "Shear...",
14130 "Roll...",
14131 "Trim Edges",
14132 (char *) NULL
14133 },
14134 *EnhanceMenu[] =
14135 {
14136 "Hue...",
14137 "Saturation...",
14138 "Brightness...",
14139 "Gamma...",
14140 "Spiff",
14141 "Dull",
14142 "Contrast Stretch...",
14143 "Sigmoidal Contrast...",
14144 "Normalize",
14145 "Equalize",
14146 "Negate",
14147 "Grayscale",
14148 "Map...",
14149 "Quantize...",
14150 (char *) NULL
14151 },
14152 *EffectsMenu[] =
14153 {
14154 "Despeckle",
14155 "Emboss",
14156 "Reduce Noise",
14157 "Add Noise...",
14158 "Sharpen...",
14159 "Blur...",
14160 "Threshold...",
14161 "Edge Detect...",
14162 "Spread...",
14163 "Shade...",
14164 "Raise...",
14165 "Segment...",
14166 (char *) NULL
14167 },
14168 *FXMenu[] =
14169 {
14170 "Solarize...",
14171 "Sepia Tone...",
14172 "Swirl...",
14173 "Implode...",
14174 "Vignette...",
14175 "Wave...",
14176 "Oil Paint...",
14177 "Charcoal Draw...",
14178 (char *) NULL
14179 },
14180 *ImageEditMenu[] =
14181 {
14182 "Annotate...",
14183 "Draw...",
14184 "Color...",
14185 "Matte...",
14186 "Composite...",
14187 "Add Border...",
14188 "Add Frame...",
14189 "Comment...",
14190 "Launch...",
14191 "Region of Interest...",
14192 (char *) NULL
14193 },
14194 *MiscellanyMenu[] =
14195 {
14196 "Image Info",
14197 "Zoom Image",
14198 "Show Preview...",
14199 "Show Histogram",
14200 "Show Matte",
14201 "Background...",
14202 "Slide Show...",
14203 "Preferences...",
14204 (char *) NULL
14205 },
14206 *HelpMenu[] =
14207 {
14208 "Overview",
14209 "Browse Documentation",
14210 "About Display",
14211 (char *) NULL
14212 },
14213 *ShortCutsMenu[] =
14214 {
14215 "Next",
14216 "Former",
14217 "Open...",
14218 "Save...",
14219 "Print...",
14220 "Undo",
14221 "Restore",
14222 "Image Info",
14223 "Quit",
14224 (char *) NULL
14225 },
14226 *VirtualMenu[] =
14227 {
14228 "Image Info",
14229 "Print",
14230 "Next",
14231 "Quit",
14232 (char *) NULL
14233 };
14234
14235 static const char
14236 **Menus[MagickMenus] =
14237 {
14238 FileMenu,
14239 EditMenu,
14240 ViewMenu,
14241 TransformMenu,
14242 EnhanceMenu,
14243 EffectsMenu,
14244 FXMenu,
14245 ImageEditMenu,
14246 MiscellanyMenu,
14247 HelpMenu
14248 };
14249
14250 static CommandType
14251 CommandMenus[] =
14252 {
14253 NullCommand,
14254 NullCommand,
14255 NullCommand,
14256 NullCommand,
14257 NullCommand,
14258 NullCommand,
14259 NullCommand,
14260 NullCommand,
14261 NullCommand,
14262 NullCommand,
14263 },
14264 FileCommands[] =
14265 {
14266 OpenCommand,
14267 NextCommand,
14268 FormerCommand,
14269 SelectCommand,
14270 SaveCommand,
14271 PrintCommand,
14272 DeleteCommand,
14273 NewCommand,
14274 VisualDirectoryCommand,
14275 QuitCommand
14276 },
14277 EditCommands[] =
14278 {
14279 UndoCommand,
14280 RedoCommand,
14281 CutCommand,
14282 CopyCommand,
14283 PasteCommand
14284 },
14285 ViewCommands[] =
14286 {
14287 HalfSizeCommand,
14288 OriginalSizeCommand,
14289 DoubleSizeCommand,
14290 ResizeCommand,
14291 ApplyCommand,
14292 RefreshCommand,
14293 RestoreCommand
14294 },
14295 TransformCommands[] =
14296 {
14297 CropCommand,
14298 ChopCommand,
14299 FlopCommand,
14300 FlipCommand,
14301 RotateRightCommand,
14302 RotateLeftCommand,
14303 RotateCommand,
14304 ShearCommand,
14305 RollCommand,
14306 TrimCommand
14307 },
14308 EnhanceCommands[] =
14309 {
14310 HueCommand,
14311 SaturationCommand,
14312 BrightnessCommand,
14313 GammaCommand,
14314 SpiffCommand,
14315 DullCommand,
14316 ContrastStretchCommand,
14317 SigmoidalContrastCommand,
14318 NormalizeCommand,
14319 EqualizeCommand,
14320 NegateCommand,
14321 GrayscaleCommand,
14322 MapCommand,
14323 QuantizeCommand
14324 },
14325 EffectsCommands[] =
14326 {
14327 DespeckleCommand,
14328 EmbossCommand,
14329 ReduceNoiseCommand,
14330 AddNoiseCommand,
14331 SharpenCommand,
14332 BlurCommand,
14333 ThresholdCommand,
14334 EdgeDetectCommand,
14335 SpreadCommand,
14336 ShadeCommand,
14337 RaiseCommand,
14338 SegmentCommand
14339 },
14340 FXCommands[] =
14341 {
14342 SolarizeCommand,
14343 SepiaToneCommand,
14344 SwirlCommand,
14345 ImplodeCommand,
14346 VignetteCommand,
14347 WaveCommand,
14348 OilPaintCommand,
14349 CharcoalDrawCommand
14350 },
14351 ImageEditCommands[] =
14352 {
14353 AnnotateCommand,
14354 DrawCommand,
14355 ColorCommand,
14356 MatteCommand,
14357 CompositeCommand,
14358 AddBorderCommand,
14359 AddFrameCommand,
14360 CommentCommand,
14361 LaunchCommand,
14362 RegionofInterestCommand
14363 },
14364 MiscellanyCommands[] =
14365 {
14366 InfoCommand,
14367 ZoomCommand,
14368 ShowPreviewCommand,
14369 ShowHistogramCommand,
14370 ShowMatteCommand,
14371 BackgroundCommand,
14372 SlideShowCommand,
14373 PreferencesCommand
14374 },
14375 HelpCommands[] =
14376 {
14377 HelpCommand,
14378 BrowseDocumentationCommand,
14379 VersionCommand
14380 },
14381 ShortCutsCommands[] =
14382 {
14383 NextCommand,
14384 FormerCommand,
14385 OpenCommand,
14386 SaveCommand,
14387 PrintCommand,
14388 UndoCommand,
14389 RestoreCommand,
14390 InfoCommand,
14391 QuitCommand
14392 },
14393 VirtualCommands[] =
14394 {
14395 InfoCommand,
14396 PrintCommand,
14397 NextCommand,
14398 QuitCommand
14399 };
14400
14401 static CommandType
14402 *Commands[MagickMenus] =
14403 {
14404 FileCommands,
14405 EditCommands,
14406 ViewCommands,
14407 TransformCommands,
14408 EnhanceCommands,
14409 EffectsCommands,
14410 FXCommands,
14411 ImageEditCommands,
14412 MiscellanyCommands,
14413 HelpCommands
14414 };
14415
14416 char
cristy151b66d2015-04-15 10:50:31 +000014417 command[MagickPathExtent],
cristy00976d82011-02-20 20:31:28 +000014418 *directory,
cristy151b66d2015-04-15 10:50:31 +000014419 geometry[MagickPathExtent],
14420 resource_name[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +000014421
14422 CommandType
14423 command_type;
14424
14425 Image
14426 *display_image,
14427 *nexus;
14428
14429 int
14430 entry,
14431 id;
14432
14433 KeySym
14434 key_symbol;
14435
14436 MagickStatusType
14437 context_mask,
14438 status;
14439
14440 RectangleInfo
14441 geometry_info;
14442
14443 register int
14444 i;
14445
14446 static char
cristy151b66d2015-04-15 10:50:31 +000014447 working_directory[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +000014448
14449 static XPoint
14450 vid_info;
14451
14452 static XWindowInfo
14453 *magick_windows[MaxXWindows];
14454
14455 static unsigned int
14456 number_windows;
14457
14458 struct stat
14459 attributes;
14460
14461 time_t
14462 timer,
14463 timestamp,
14464 update_time;
14465
14466 unsigned int
14467 height,
14468 width;
14469
cristybb503372010-05-27 20:51:26 +000014470 size_t
cristy3ed852e2009-09-05 21:47:34 +000014471 delay;
14472
14473 WarningHandler
14474 warning_handler;
14475
14476 Window
14477 root_window;
14478
14479 XClassHint
14480 *class_hints;
14481
14482 XEvent
14483 event;
14484
14485 XFontStruct
14486 *font_info;
14487
14488 XGCValues
14489 context_values;
14490
14491 XPixelInfo
14492 *icon_pixel,
14493 *pixel;
14494
14495 XResourceInfo
14496 *icon_resources;
14497
14498 XStandardColormap
14499 *icon_map,
14500 *map_info;
14501
14502 XVisualInfo
14503 *icon_visual,
14504 *visual_info;
14505
14506 XWindowChanges
14507 window_changes;
14508
14509 XWindows
14510 *windows;
14511
14512 XWMHints
14513 *manager_hints;
14514
14515 assert(image != (Image **) NULL);
cristye1c94d92015-06-28 12:16:33 +000014516 assert((*image)->signature == MagickCoreSignature);
cristy59864562013-04-18 11:47:41 +000014517 if (IfMagickTrue((*image)->debug) )
cristy3ed852e2009-09-05 21:47:34 +000014518 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
14519 display_image=(*image);
14520 warning_handler=(WarningHandler) NULL;
14521 windows=XSetWindows((XWindows *) ~0);
14522 if (windows != (XWindows *) NULL)
14523 {
14524 int
14525 status;
14526
cristy8a5d7f42013-01-06 15:24:33 +000014527 if (*working_directory == '\0')
cristy151b66d2015-04-15 10:50:31 +000014528 (void) CopyMagickString(working_directory,".",MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +000014529 status=chdir(working_directory);
14530 if (status == -1)
cristy051718b2011-08-28 22:49:25 +000014531 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
14532 "UnableToOpenFile","%s",working_directory);
cristy3ed852e2009-09-05 21:47:34 +000014533 warning_handler=resource_info->display_warnings ?
14534 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
14535 warning_handler=resource_info->display_warnings ?
14536 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
14537 }
14538 else
14539 {
14540 /*
14541 Allocate windows structure.
14542 */
14543 resource_info->colors=display_image->colors;
14544 windows=XSetWindows(XInitializeWindows(display,resource_info));
14545 if (windows == (XWindows *) NULL)
14546 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow",
14547 (*image)->filename);
14548 /*
14549 Initialize window id's.
14550 */
14551 number_windows=0;
14552 magick_windows[number_windows++]=(&windows->icon);
14553 magick_windows[number_windows++]=(&windows->backdrop);
14554 magick_windows[number_windows++]=(&windows->image);
14555 magick_windows[number_windows++]=(&windows->info);
14556 magick_windows[number_windows++]=(&windows->command);
14557 magick_windows[number_windows++]=(&windows->widget);
14558 magick_windows[number_windows++]=(&windows->popup);
14559 magick_windows[number_windows++]=(&windows->magnify);
14560 magick_windows[number_windows++]=(&windows->pan);
14561 for (i=0; i < (int) number_windows; i++)
14562 magick_windows[i]->id=(Window) NULL;
14563 vid_info.x=0;
14564 vid_info.y=0;
14565 }
14566 /*
14567 Initialize font info.
14568 */
14569 if (windows->font_info != (XFontStruct *) NULL)
14570 (void) XFreeFont(display,windows->font_info);
14571 windows->font_info=XBestFont(display,resource_info,MagickFalse);
14572 if (windows->font_info == (XFontStruct *) NULL)
14573 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont",
14574 resource_info->font);
14575 /*
14576 Initialize Standard Colormap.
14577 */
14578 map_info=windows->map_info;
14579 icon_map=windows->icon_map;
14580 visual_info=windows->visual_info;
14581 icon_visual=windows->icon_visual;
14582 pixel=windows->pixel_info;
14583 icon_pixel=windows->icon_pixel;
14584 font_info=windows->font_info;
14585 icon_resources=windows->icon_resources;
14586 class_hints=windows->class_hints;
14587 manager_hints=windows->manager_hints;
14588 root_window=XRootWindow(display,visual_info->screen);
14589 nexus=NewImageList();
cristy59864562013-04-18 11:47:41 +000014590 if (IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000014591 {
14592 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +000014593 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename,
14594 (double) display_image->scene,(double) display_image->columns,
14595 (double) display_image->rows);
cristy3ed852e2009-09-05 21:47:34 +000014596 if (display_image->colors != 0)
cristye8c25f92010-06-03 00:53:06 +000014597 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
14598 display_image->colors);
cristy3ed852e2009-09-05 21:47:34 +000014599 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
14600 display_image->magick);
14601 }
14602 XMakeStandardColormap(display,visual_info,resource_info,display_image,
cristy6710d842011-10-20 23:23:00 +000014603 map_info,pixel,exception);
cristy3ed852e2009-09-05 21:47:34 +000014604 display_image->taint=MagickFalse;
14605 /*
14606 Initialize graphic context.
14607 */
14608 windows->context.id=(Window) NULL;
14609 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14610 resource_info,&windows->context);
14611 (void) CloneString(&class_hints->res_name,resource_info->client_name);
14612 (void) CloneString(&class_hints->res_class,resource_info->client_name);
14613 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]);
14614 manager_hints->flags=InputHint | StateHint;
14615 manager_hints->input=MagickFalse;
14616 manager_hints->initial_state=WithdrawnState;
14617 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14618 &windows->context);
cristy59864562013-04-18 11:47:41 +000014619 if (IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000014620 (void) LogMagickEvent(X11Event,GetMagickModule(),
14621 "Window id: 0x%lx (context)",windows->context.id);
14622 context_values.background=pixel->background_color.pixel;
14623 context_values.font=font_info->fid;
14624 context_values.foreground=pixel->foreground_color.pixel;
14625 context_values.graphics_exposures=MagickFalse;
14626 context_mask=(MagickStatusType)
14627 (GCBackground | GCFont | GCForeground | GCGraphicsExposures);
14628 if (pixel->annotate_context != (GC) NULL)
14629 (void) XFreeGC(display,pixel->annotate_context);
14630 pixel->annotate_context=XCreateGC(display,windows->context.id,
14631 context_mask,&context_values);
14632 if (pixel->annotate_context == (GC) NULL)
14633 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14634 display_image->filename);
14635 context_values.background=pixel->depth_color.pixel;
14636 if (pixel->widget_context != (GC) NULL)
14637 (void) XFreeGC(display,pixel->widget_context);
14638 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask,
14639 &context_values);
14640 if (pixel->widget_context == (GC) NULL)
14641 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14642 display_image->filename);
14643 context_values.background=pixel->foreground_color.pixel;
14644 context_values.foreground=pixel->background_color.pixel;
14645 context_values.plane_mask=context_values.background ^
14646 context_values.foreground;
14647 if (pixel->highlight_context != (GC) NULL)
14648 (void) XFreeGC(display,pixel->highlight_context);
14649 pixel->highlight_context=XCreateGC(display,windows->context.id,
cristybb503372010-05-27 20:51:26 +000014650 (size_t) (context_mask | GCPlaneMask),&context_values);
cristy3ed852e2009-09-05 21:47:34 +000014651 if (pixel->highlight_context == (GC) NULL)
14652 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14653 display_image->filename);
14654 (void) XDestroyWindow(display,windows->context.id);
14655 /*
14656 Initialize icon window.
14657 */
14658 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL,
14659 icon_resources,&windows->icon);
14660 windows->icon.geometry=resource_info->icon_geometry;
14661 XBestIconSize(display,&windows->icon,display_image);
14662 windows->icon.attributes.colormap=XDefaultColormap(display,
14663 icon_visual->screen);
14664 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask;
14665 manager_hints->flags=InputHint | StateHint;
14666 manager_hints->input=MagickFalse;
14667 manager_hints->initial_state=IconicState;
14668 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14669 &windows->icon);
cristy59864562013-04-18 11:47:41 +000014670 if (IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000014671 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)",
14672 windows->icon.id);
14673 /*
14674 Initialize graphic context for icon window.
14675 */
14676 if (icon_pixel->annotate_context != (GC) NULL)
14677 (void) XFreeGC(display,icon_pixel->annotate_context);
14678 context_values.background=icon_pixel->background_color.pixel;
14679 context_values.foreground=icon_pixel->foreground_color.pixel;
14680 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id,
cristybb503372010-05-27 20:51:26 +000014681 (size_t) (GCBackground | GCForeground),&context_values);
cristy3ed852e2009-09-05 21:47:34 +000014682 if (icon_pixel->annotate_context == (GC) NULL)
14683 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14684 display_image->filename);
14685 windows->icon.annotate_context=icon_pixel->annotate_context;
14686 /*
14687 Initialize Image window.
14688 */
14689 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14690 &windows->image);
14691 windows->image.shape=MagickTrue; /* non-rectangular shape hint */
cristy59864562013-04-18 11:47:41 +000014692 if (IfMagickFalse(resource_info->use_shared_memory) )
cristy3ed852e2009-09-05 21:47:34 +000014693 windows->image.shared_memory=MagickFalse;
14694 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState))
14695 {
14696 char
14697 *title;
14698
14699 title=InterpretImageProperties(resource_info->image_info,display_image,
cristy018f07f2011-09-04 21:15:19 +000014700 resource_info->title,exception);
cristy151b66d2015-04-15 10:50:31 +000014701 (void) CopyMagickString(windows->image.name,title,MagickPathExtent);
14702 (void) CopyMagickString(windows->image.icon_name,title,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +000014703 title=DestroyString(title);
14704 }
14705 else
14706 {
14707 char
cristy151b66d2015-04-15 10:50:31 +000014708 filename[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +000014709
14710 /*
14711 Window name is the base of the filename.
14712 */
14713 GetPathComponent(display_image->magick_filename,TailPath,filename);
cristy9a48b172011-09-20 17:41:05 +000014714 if (display_image->scene == 0)
cristy151b66d2015-04-15 10:50:31 +000014715 (void) FormatLocaleString(windows->image.name,MagickPathExtent,
cristy40a08ad2010-02-09 02:27:44 +000014716 "%s: %s",MagickPackageName,filename);
cristy3ed852e2009-09-05 21:47:34 +000014717 else
cristy151b66d2015-04-15 10:50:31 +000014718 (void) FormatLocaleString(windows->image.name,MagickPathExtent,
cristy04d55062011-03-15 18:58:50 +000014719 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename,
14720 (double) display_image->scene,(double) GetImageListLength(
14721 display_image));
cristy151b66d2015-04-15 10:50:31 +000014722 (void) CopyMagickString(windows->image.icon_name,filename,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +000014723 }
14724 if (resource_info->immutable)
14725 windows->image.immutable=MagickTrue;
14726 windows->image.use_pixmap=resource_info->use_pixmap;
14727 windows->image.geometry=resource_info->image_geometry;
cristy151b66d2015-04-15 10:50:31 +000014728 (void) FormatLocaleString(geometry,MagickPathExtent,"%ux%u+0+0>!",
cristy3ed852e2009-09-05 21:47:34 +000014729 XDisplayWidth(display,visual_info->screen),
14730 XDisplayHeight(display,visual_info->screen));
14731 geometry_info.width=display_image->columns;
14732 geometry_info.height=display_image->rows;
14733 geometry_info.x=0;
14734 geometry_info.y=0;
14735 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
14736 &geometry_info.width,&geometry_info.height);
14737 windows->image.width=(unsigned int) geometry_info.width;
14738 windows->image.height=(unsigned int) geometry_info.height;
14739 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14740 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14741 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14742 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask;
14743 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14744 resource_info,&windows->backdrop);
14745 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL))
14746 {
14747 /*
14748 Initialize backdrop window.
14749 */
14750 windows->backdrop.x=0;
14751 windows->backdrop.y=0;
cristy40a08ad2010-02-09 02:27:44 +000014752 (void) CloneString(&windows->backdrop.name,"Backdrop");
cristybb503372010-05-27 20:51:26 +000014753 windows->backdrop.flags=(size_t) (USSize | USPosition);
cristy3ed852e2009-09-05 21:47:34 +000014754 windows->backdrop.width=(unsigned int)
14755 XDisplayWidth(display,visual_info->screen);
14756 windows->backdrop.height=(unsigned int)
14757 XDisplayHeight(display,visual_info->screen);
14758 windows->backdrop.border_width=0;
14759 windows->backdrop.immutable=MagickTrue;
14760 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask |
14761 ButtonReleaseMask;
14762 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask |
14763 StructureNotifyMask;
14764 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14765 manager_hints->icon_window=windows->icon.id;
14766 manager_hints->input=MagickTrue;
14767 manager_hints->initial_state=resource_info->iconic ? IconicState :
14768 NormalState;
14769 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14770 &windows->backdrop);
cristy59864562013-04-18 11:47:41 +000014771 if (IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000014772 (void) LogMagickEvent(X11Event,GetMagickModule(),
14773 "Window id: 0x%lx (backdrop)",windows->backdrop.id);
14774 (void) XMapWindow(display,windows->backdrop.id);
14775 (void) XClearWindow(display,windows->backdrop.id);
14776 if (windows->image.id != (Window) NULL)
14777 {
14778 (void) XDestroyWindow(display,windows->image.id);
14779 windows->image.id=(Window) NULL;
14780 }
14781 /*
14782 Position image in the center the backdrop.
14783 */
14784 windows->image.flags|=USPosition;
14785 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)-
14786 (windows->image.width/2);
14787 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)-
14788 (windows->image.height/2);
14789 }
14790 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14791 manager_hints->icon_window=windows->icon.id;
14792 manager_hints->input=MagickTrue;
14793 manager_hints->initial_state=resource_info->iconic ? IconicState :
14794 NormalState;
14795 if (windows->group_leader.id != (Window) NULL)
14796 {
14797 /*
14798 Follow the leader.
14799 */
14800 manager_hints->flags|=WindowGroupHint;
14801 manager_hints->window_group=windows->group_leader.id;
14802 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask);
cristy59864562013-04-18 11:47:41 +000014803 if (IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000014804 (void) LogMagickEvent(X11Event,GetMagickModule(),
14805 "Window id: 0x%lx (group leader)",windows->group_leader.id);
14806 }
14807 XMakeWindow(display,
14808 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window),
14809 argv,argc,class_hints,manager_hints,&windows->image);
14810 (void) XChangeProperty(display,windows->image.id,windows->im_protocols,
14811 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0);
14812 if (windows->group_leader.id != (Window) NULL)
14813 (void) XSetTransientForHint(display,windows->image.id,
14814 windows->group_leader.id);
cristy59864562013-04-18 11:47:41 +000014815 if (IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000014816 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)",
14817 windows->image.id);
14818 /*
14819 Initialize Info widget.
14820 */
14821 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14822 &windows->info);
14823 (void) CloneString(&windows->info.name,"Info");
14824 (void) CloneString(&windows->info.icon_name,"Info");
14825 windows->info.border_width=1;
14826 windows->info.x=2;
14827 windows->info.y=2;
14828 windows->info.flags|=PPosition;
14829 windows->info.attributes.win_gravity=UnmapGravity;
14830 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask |
14831 StructureNotifyMask;
14832 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14833 manager_hints->input=MagickFalse;
14834 manager_hints->initial_state=NormalState;
14835 manager_hints->window_group=windows->image.id;
14836 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints,
14837 &windows->info);
14838 windows->info.highlight_stipple=XCreateBitmapFromData(display,
14839 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14840 windows->info.shadow_stipple=XCreateBitmapFromData(display,
14841 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14842 (void) XSetTransientForHint(display,windows->info.id,windows->image.id);
cristy59864562013-04-18 11:47:41 +000014843 if (IfMagickTrue(windows->image.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000014844 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
cristy59864562013-04-18 11:47:41 +000014845 if (IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000014846 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)",
14847 windows->info.id);
14848 /*
14849 Initialize Command widget.
14850 */
14851 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14852 resource_info,&windows->command);
14853 windows->command.data=MagickMenus;
14854 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL);
cristy151b66d2015-04-15 10:50:31 +000014855 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.command",
cristy3ed852e2009-09-05 21:47:34 +000014856 resource_info->client_name);
14857 windows->command.geometry=XGetResourceClass(resource_info->resource_database,
14858 resource_name,"geometry",(char *) NULL);
14859 (void) CloneString(&windows->command.name,MagickTitle);
14860 windows->command.border_width=0;
14861 windows->command.flags|=PPosition;
14862 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14863 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask |
14864 OwnerGrabButtonMask | StructureNotifyMask;
14865 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14866 manager_hints->input=MagickTrue;
14867 manager_hints->initial_state=NormalState;
14868 manager_hints->window_group=windows->image.id;
14869 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14870 &windows->command);
14871 windows->command.highlight_stipple=XCreateBitmapFromData(display,
14872 windows->command.id,(char *) HighlightBitmap,HighlightWidth,
14873 HighlightHeight);
14874 windows->command.shadow_stipple=XCreateBitmapFromData(display,
14875 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14876 (void) XSetTransientForHint(display,windows->command.id,windows->image.id);
cristy59864562013-04-18 11:47:41 +000014877 if (IfMagickTrue(windows->command.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000014878 (void) XMapRaised(display,windows->command.id);
cristy59864562013-04-18 11:47:41 +000014879 if (IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000014880 (void) LogMagickEvent(X11Event,GetMagickModule(),
14881 "Window id: 0x%lx (command)",windows->command.id);
14882 /*
14883 Initialize Widget window.
14884 */
14885 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14886 resource_info,&windows->widget);
cristy151b66d2015-04-15 10:50:31 +000014887 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.widget",
cristy3ed852e2009-09-05 21:47:34 +000014888 resource_info->client_name);
14889 windows->widget.geometry=XGetResourceClass(resource_info->resource_database,
14890 resource_name,"geometry",(char *) NULL);
14891 windows->widget.border_width=0;
14892 windows->widget.flags|=PPosition;
14893 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14894 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14895 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14896 StructureNotifyMask;
14897 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14898 manager_hints->input=MagickTrue;
14899 manager_hints->initial_state=NormalState;
14900 manager_hints->window_group=windows->image.id;
14901 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14902 &windows->widget);
14903 windows->widget.highlight_stipple=XCreateBitmapFromData(display,
14904 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14905 windows->widget.shadow_stipple=XCreateBitmapFromData(display,
14906 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14907 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id);
cristy59864562013-04-18 11:47:41 +000014908 if (IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000014909 (void) LogMagickEvent(X11Event,GetMagickModule(),
14910 "Window id: 0x%lx (widget)",windows->widget.id);
14911 /*
14912 Initialize popup window.
14913 */
14914 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14915 resource_info,&windows->popup);
14916 windows->popup.border_width=0;
14917 windows->popup.flags|=PPosition;
14918 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14919 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14920 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask;
14921 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14922 manager_hints->input=MagickTrue;
14923 manager_hints->initial_state=NormalState;
14924 manager_hints->window_group=windows->image.id;
14925 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14926 &windows->popup);
14927 windows->popup.highlight_stipple=XCreateBitmapFromData(display,
14928 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14929 windows->popup.shadow_stipple=XCreateBitmapFromData(display,
14930 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14931 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id);
cristy59864562013-04-18 11:47:41 +000014932 if (IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000014933 (void) LogMagickEvent(X11Event,GetMagickModule(),
14934 "Window id: 0x%lx (pop up)",windows->popup.id);
14935 /*
14936 Initialize Magnify window and cursor.
14937 */
14938 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14939 resource_info,&windows->magnify);
cristy59864562013-04-18 11:47:41 +000014940 if (IfMagickFalse(resource_info->use_shared_memory) )
cristy3ed852e2009-09-05 21:47:34 +000014941 windows->magnify.shared_memory=MagickFalse;
cristy151b66d2015-04-15 10:50:31 +000014942 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.magnify",
cristy3ed852e2009-09-05 21:47:34 +000014943 resource_info->client_name);
14944 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database,
14945 resource_name,"geometry",(char *) NULL);
cristy151b66d2015-04-15 10:50:31 +000014946 (void) FormatLocaleString(windows->magnify.name,MagickPathExtent,"Magnify %uX",
cristy3ed852e2009-09-05 21:47:34 +000014947 resource_info->magnify);
14948 if (windows->magnify.cursor != (Cursor) NULL)
14949 (void) XFreeCursor(display,windows->magnify.cursor);
14950 windows->magnify.cursor=XMakeCursor(display,windows->image.id,
14951 map_info->colormap,resource_info->background_color,
14952 resource_info->foreground_color);
14953 if (windows->magnify.cursor == (Cursor) NULL)
14954 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor",
14955 display_image->filename);
14956 windows->magnify.width=MagnifySize;
14957 windows->magnify.height=MagnifySize;
14958 windows->magnify.flags|=PPosition;
14959 windows->magnify.min_width=MagnifySize;
14960 windows->magnify.min_height=MagnifySize;
14961 windows->magnify.width_inc=MagnifySize;
14962 windows->magnify.height_inc=MagnifySize;
14963 windows->magnify.data=resource_info->magnify;
14964 windows->magnify.attributes.cursor=windows->magnify.cursor;
14965 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask |
14966 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask |
14967 StructureNotifyMask;
14968 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14969 manager_hints->input=MagickTrue;
14970 manager_hints->initial_state=NormalState;
14971 manager_hints->window_group=windows->image.id;
14972 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14973 &windows->magnify);
cristy59864562013-04-18 11:47:41 +000014974 if (IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000014975 (void) LogMagickEvent(X11Event,GetMagickModule(),
14976 "Window id: 0x%lx (magnify)",windows->magnify.id);
14977 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id);
14978 /*
14979 Initialize panning window.
14980 */
14981 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14982 resource_info,&windows->pan);
14983 (void) CloneString(&windows->pan.name,"Pan Icon");
14984 windows->pan.width=windows->icon.width;
14985 windows->pan.height=windows->icon.height;
cristy151b66d2015-04-15 10:50:31 +000014986 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.pan",
cristy3ed852e2009-09-05 21:47:34 +000014987 resource_info->client_name);
14988 windows->pan.geometry=XGetResourceClass(resource_info->resource_database,
14989 resource_name,"geometry",(char *) NULL);
14990 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
14991 &windows->pan.width,&windows->pan.height);
14992 windows->pan.flags|=PPosition;
14993 windows->pan.immutable=MagickTrue;
14994 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14995 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask |
14996 StructureNotifyMask;
14997 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14998 manager_hints->input=MagickFalse;
14999 manager_hints->initial_state=NormalState;
15000 manager_hints->window_group=windows->image.id;
15001 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
15002 &windows->pan);
cristy59864562013-04-18 11:47:41 +000015003 if (IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000015004 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)",
15005 windows->pan.id);
15006 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id);
cristy59864562013-04-18 11:47:41 +000015007 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000015008 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
cristy59864562013-04-18 11:47:41 +000015009 if (IfMagickFalse(windows->image.mapped) ||
cristy3ed852e2009-09-05 21:47:34 +000015010 (windows->backdrop.id != (Window) NULL))
15011 (void) XMapWindow(display,windows->image.id);
15012 /*
15013 Set our progress monitor and warning handlers.
15014 */
15015 if (warning_handler == (WarningHandler) NULL)
15016 {
15017 warning_handler=resource_info->display_warnings ?
15018 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
15019 warning_handler=resource_info->display_warnings ?
15020 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
15021 }
15022 /*
15023 Initialize Image and Magnify X images.
15024 */
15025 windows->image.x=0;
15026 windows->image.y=0;
15027 windows->magnify.shape=MagickFalse;
15028 width=(unsigned int) display_image->columns;
15029 height=(unsigned int) display_image->rows;
15030 if ((display_image->columns != width) || (display_image->rows != height))
15031 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
15032 display_image->filename);
15033 status=XMakeImage(display,resource_info,&windows->image,display_image,
cristy051718b2011-08-28 22:49:25 +000015034 width,height,exception);
cristy59864562013-04-18 11:47:41 +000015035 if (IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +000015036 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
15037 display_image->filename);
15038 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL,
cristy051718b2011-08-28 22:49:25 +000015039 windows->magnify.width,windows->magnify.height,exception);
cristybeb1a6b2013-11-04 12:08:18 +000015040 if (IfMagickFalse(status))
cristy3ed852e2009-09-05 21:47:34 +000015041 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
15042 display_image->filename);
cristy59864562013-04-18 11:47:41 +000015043 if (IfMagickTrue(windows->magnify.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000015044 (void) XMapRaised(display,windows->magnify.id);
cristy59864562013-04-18 11:47:41 +000015045 if (IfMagickTrue(windows->pan.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000015046 (void) XMapRaised(display,windows->pan.id);
15047 windows->image.window_changes.width=(int) display_image->columns;
15048 windows->image.window_changes.height=(int) display_image->rows;
cristy051718b2011-08-28 22:49:25 +000015049 (void) XConfigureImage(display,resource_info,windows,display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015050 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
15051 (void) XSync(display,MagickFalse);
15052 /*
15053 Respond to events.
15054 */
15055 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L);
15056 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15057 update_time=0;
cristy59864562013-04-18 11:47:41 +000015058 if (IfMagickTrue(resource_info->update) )
cristy3ed852e2009-09-05 21:47:34 +000015059 {
15060 MagickBooleanType
15061 status;
15062
15063 /*
15064 Determine when file data was last modified.
15065 */
15066 status=GetPathAttributes(display_image->filename,&attributes);
cristy59864562013-04-18 11:47:41 +000015067 if (IfMagickTrue(status) )
cristy3ed852e2009-09-05 21:47:34 +000015068 update_time=attributes.st_mtime;
15069 }
15070 *state&=(~FormerImageState);
15071 *state&=(~MontageImageState);
15072 *state&=(~NextImageState);
15073 do
15074 {
15075 /*
15076 Handle a window event.
15077 */
cristy59864562013-04-18 11:47:41 +000015078 if (IfMagickTrue(windows->image.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000015079 if ((display_image->delay != 0) || (resource_info->update != 0))
15080 {
15081 if (timer < time((time_t *) NULL))
15082 {
cristy59864562013-04-18 11:47:41 +000015083 if (IfMagickFalse(resource_info->update) )
cristy3ed852e2009-09-05 21:47:34 +000015084 *state|=NextImageState | ExitState;
15085 else
15086 {
15087 MagickBooleanType
15088 status;
15089
15090 /*
15091 Determine if image file was modified.
15092 */
15093 status=GetPathAttributes(display_image->filename,&attributes);
cristy59864562013-04-18 11:47:41 +000015094 if (IfMagickTrue(status) )
cristy3ed852e2009-09-05 21:47:34 +000015095 if (update_time != attributes.st_mtime)
15096 {
15097 /*
15098 Redisplay image.
15099 */
cristyb51dff52011-05-19 16:55:47 +000015100 (void) FormatLocaleString(
cristy151b66d2015-04-15 10:50:31 +000015101 resource_info->image_info->filename,MagickPathExtent,
cristy3ed852e2009-09-05 21:47:34 +000015102 "%s:%s",display_image->magick,
15103 display_image->filename);
cristy947cb4c2011-10-20 18:41:46 +000015104 nexus=ReadImage(resource_info->image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +000015105 if (nexus != (Image *) NULL)
cristye799ee22015-06-30 14:26:05 +000015106 *state|=NextImageState | ExitState;
cristy3ed852e2009-09-05 21:47:34 +000015107 }
15108 delay=display_image->delay/MagickMax(
15109 display_image->ticks_per_second,1L);
15110 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15111 }
15112 }
15113 if (XEventsQueued(display,QueuedAfterFlush) == 0)
15114 {
15115 /*
15116 Do not block if delay > 0.
15117 */
15118 XDelay(display,SuspendTime << 2);
15119 continue;
15120 }
15121 }
15122 timestamp=time((time_t *) NULL);
15123 (void) XNextEvent(display,&event);
dirkb9dbc292015-07-26 09:50:00 +000015124 if ((windows->image.stasis == MagickFalse) ||
15125 (windows->magnify.stasis == MagickFalse))
15126 {
15127 if ((time((time_t *) NULL)-timestamp) > 0)
15128 {
15129 windows->image.stasis=MagickTrue;
15130 windows->magnify.stasis=MagickTrue;
15131 }
15132 }
cristy3ed852e2009-09-05 21:47:34 +000015133 if (event.xany.window == windows->command.id)
15134 {
15135 /*
15136 Select a command from the Command widget.
15137 */
15138 id=XCommandWidget(display,windows,CommandMenu,&event);
15139 if (id < 0)
15140 continue;
cristy151b66d2015-04-15 10:50:31 +000015141 (void) CopyMagickString(command,CommandMenu[id],MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +000015142 command_type=CommandMenus[id];
15143 if (id < MagickMenus)
15144 {
15145 /*
15146 Select a command from a pop-up menu.
15147 */
15148 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id],
15149 command);
15150 if (entry < 0)
15151 continue;
cristy151b66d2015-04-15 10:50:31 +000015152 (void) CopyMagickString(command,Menus[id][entry],MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +000015153 command_type=Commands[id][entry];
15154 }
15155 if (command_type != NullCommand)
15156 nexus=XMagickCommand(display,resource_info,windows,command_type,
cristy051718b2011-08-28 22:49:25 +000015157 &display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015158 continue;
15159 }
15160 switch (event.type)
15161 {
15162 case ButtonPress:
15163 {
cristy59864562013-04-18 11:47:41 +000015164 if (IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000015165 (void) LogMagickEvent(X11Event,GetMagickModule(),
15166 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
15167 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15168 if ((event.xbutton.button == Button3) &&
15169 (event.xbutton.state & Mod1Mask))
15170 {
15171 /*
15172 Convert Alt-Button3 to Button2.
15173 */
15174 event.xbutton.button=Button2;
15175 event.xbutton.state&=(~Mod1Mask);
15176 }
15177 if (event.xbutton.window == windows->backdrop.id)
15178 {
15179 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent,
15180 event.xbutton.time);
15181 break;
15182 }
15183 if (event.xbutton.window == windows->image.id)
15184 {
15185 switch (event.xbutton.button)
15186 {
15187 case Button1:
15188 {
15189 if (resource_info->immutable)
15190 {
15191 /*
15192 Select a command from the Virtual menu.
15193 */
15194 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15195 command);
15196 if (entry >= 0)
15197 nexus=XMagickCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015198 VirtualCommands[entry],&display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015199 break;
15200 }
15201 /*
15202 Map/unmap Command widget.
15203 */
cristy59864562013-04-18 11:47:41 +000015204 if (IfMagickTrue(windows->command.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000015205 (void) XWithdrawWindow(display,windows->command.id,
15206 windows->command.screen);
15207 else
15208 {
15209 (void) XCommandWidget(display,windows,CommandMenu,
15210 (XEvent *) NULL);
15211 (void) XMapRaised(display,windows->command.id);
15212 }
15213 break;
15214 }
15215 case Button2:
15216 {
15217 /*
15218 User pressed the image magnify button.
15219 */
15220 (void) XMagickCommand(display,resource_info,windows,ZoomCommand,
cristy051718b2011-08-28 22:49:25 +000015221 &display_image,exception);
cristy6710d842011-10-20 23:23:00 +000015222 XMagnifyImage(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000015223 break;
15224 }
15225 case Button3:
15226 {
15227 if (resource_info->immutable)
15228 {
15229 /*
15230 Select a command from the Virtual menu.
15231 */
15232 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15233 command);
15234 if (entry >= 0)
15235 nexus=XMagickCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015236 VirtualCommands[entry],&display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015237 break;
15238 }
15239 if (display_image->montage != (char *) NULL)
15240 {
15241 /*
15242 Open or delete a tile from a visual image directory.
15243 */
15244 nexus=XTileImage(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015245 display_image,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000015246 if (nexus != (Image *) NULL)
15247 *state|=MontageImageState | NextImageState | ExitState;
cristy49e2d862010-11-12 02:50:30 +000015248 vid_info.x=(short int) windows->image.x;
15249 vid_info.y=(short int) windows->image.y;
cristy3ed852e2009-09-05 21:47:34 +000015250 break;
15251 }
15252 /*
15253 Select a command from the Short Cuts menu.
15254 */
15255 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu,
15256 command);
15257 if (entry >= 0)
15258 nexus=XMagickCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015259 ShortCutsCommands[entry],&display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015260 break;
15261 }
15262 case Button4:
15263 {
15264 /*
15265 Wheel up.
15266 */
15267 XTranslateImage(display,windows,*image,XK_Up);
15268 break;
15269 }
15270 case Button5:
15271 {
15272 /*
15273 Wheel down.
15274 */
15275 XTranslateImage(display,windows,*image,XK_Down);
15276 break;
15277 }
15278 default:
15279 break;
15280 }
15281 break;
15282 }
15283 if (event.xbutton.window == windows->magnify.id)
15284 {
15285 int
15286 factor;
15287
15288 static const char
15289 *MagnifyMenu[] =
15290 {
15291 "2",
15292 "4",
15293 "5",
15294 "6",
15295 "7",
15296 "8",
15297 "9",
15298 "3",
15299 (char *) NULL,
15300 };
15301
15302 static KeySym
15303 MagnifyCommands[] =
15304 {
15305 XK_2,
15306 XK_4,
15307 XK_5,
15308 XK_6,
15309 XK_7,
15310 XK_8,
15311 XK_9,
15312 XK_3
15313 };
15314
15315 /*
15316 Select a magnify factor from the pop-up menu.
15317 */
15318 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command);
15319 if (factor >= 0)
cristy6710d842011-10-20 23:23:00 +000015320 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor],
15321 exception);
cristy3ed852e2009-09-05 21:47:34 +000015322 break;
15323 }
15324 if (event.xbutton.window == windows->pan.id)
15325 {
15326 switch (event.xbutton.button)
15327 {
15328 case Button4:
15329 {
15330 /*
15331 Wheel up.
15332 */
15333 XTranslateImage(display,windows,*image,XK_Up);
15334 break;
15335 }
15336 case Button5:
15337 {
15338 /*
15339 Wheel down.
15340 */
15341 XTranslateImage(display,windows,*image,XK_Down);
15342 break;
15343 }
15344 default:
15345 {
cristy6710d842011-10-20 23:23:00 +000015346 XPanImage(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000015347 break;
15348 }
15349 }
15350 break;
15351 }
15352 delay=display_image->delay/MagickMax(display_image->ticks_per_second,
15353 1L);
15354 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15355 break;
15356 }
15357 case ButtonRelease:
15358 {
cristy59864562013-04-18 11:47:41 +000015359 if (IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000015360 (void) LogMagickEvent(X11Event,GetMagickModule(),
15361 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
15362 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15363 break;
15364 }
15365 case ClientMessage:
15366 {
cristy59864562013-04-18 11:47:41 +000015367 if (IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000015368 (void) LogMagickEvent(X11Event,GetMagickModule(),
15369 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window,
cristyf2faecf2010-05-28 19:19:36 +000015370 event.xclient.message_type,event.xclient.format,(unsigned long)
cristy3ed852e2009-09-05 21:47:34 +000015371 event.xclient.data.l[0]);
15372 if (event.xclient.message_type == windows->im_protocols)
15373 {
cristyecd0ab52010-05-30 14:59:20 +000015374 if (*event.xclient.data.l == (long) windows->im_update_widget)
cristy3ed852e2009-09-05 21:47:34 +000015375 {
15376 (void) CloneString(&windows->command.name,MagickTitle);
15377 windows->command.data=MagickMenus;
15378 (void) XCommandWidget(display,windows,CommandMenu,
15379 (XEvent *) NULL);
15380 break;
15381 }
cristyecd0ab52010-05-30 14:59:20 +000015382 if (*event.xclient.data.l == (long) windows->im_update_colormap)
cristy3ed852e2009-09-05 21:47:34 +000015383 {
15384 /*
15385 Update graphic context and window colormap.
15386 */
15387 for (i=0; i < (int) number_windows; i++)
15388 {
15389 if (magick_windows[i]->id == windows->icon.id)
15390 continue;
15391 context_values.background=pixel->background_color.pixel;
15392 context_values.foreground=pixel->foreground_color.pixel;
15393 (void) XChangeGC(display,magick_windows[i]->annotate_context,
15394 context_mask,&context_values);
15395 (void) XChangeGC(display,magick_windows[i]->widget_context,
15396 context_mask,&context_values);
15397 context_values.background=pixel->foreground_color.pixel;
15398 context_values.foreground=pixel->background_color.pixel;
15399 context_values.plane_mask=context_values.background ^
15400 context_values.foreground;
15401 (void) XChangeGC(display,magick_windows[i]->highlight_context,
cristybb503372010-05-27 20:51:26 +000015402 (size_t) (context_mask | GCPlaneMask),
cristy3ed852e2009-09-05 21:47:34 +000015403 &context_values);
15404 magick_windows[i]->attributes.background_pixel=
15405 pixel->background_color.pixel;
15406 magick_windows[i]->attributes.border_pixel=
15407 pixel->border_color.pixel;
15408 magick_windows[i]->attributes.colormap=map_info->colormap;
15409 (void) XChangeWindowAttributes(display,magick_windows[i]->id,
cristy49e2d862010-11-12 02:50:30 +000015410 (unsigned long) magick_windows[i]->mask,
15411 &magick_windows[i]->attributes);
cristy3ed852e2009-09-05 21:47:34 +000015412 }
cristy59864562013-04-18 11:47:41 +000015413 if (IfMagickTrue(windows->pan.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000015414 {
15415 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
15416 windows->pan.pixmap);
15417 (void) XClearWindow(display,windows->pan.id);
15418 XDrawPanRectangle(display,windows);
15419 }
15420 if (windows->backdrop.id != (Window) NULL)
15421 (void) XInstallColormap(display,map_info->colormap);
15422 break;
15423 }
cristyecd0ab52010-05-30 14:59:20 +000015424 if (*event.xclient.data.l == (long) windows->im_former_image)
cristy3ed852e2009-09-05 21:47:34 +000015425 {
15426 *state|=FormerImageState | ExitState;
15427 break;
15428 }
cristyecd0ab52010-05-30 14:59:20 +000015429 if (*event.xclient.data.l == (long) windows->im_next_image)
cristy3ed852e2009-09-05 21:47:34 +000015430 {
15431 *state|=NextImageState | ExitState;
15432 break;
15433 }
cristyecd0ab52010-05-30 14:59:20 +000015434 if (*event.xclient.data.l == (long) windows->im_retain_colors)
cristy3ed852e2009-09-05 21:47:34 +000015435 {
15436 *state|=RetainColorsState;
15437 break;
15438 }
cristyecd0ab52010-05-30 14:59:20 +000015439 if (*event.xclient.data.l == (long) windows->im_exit)
cristy3ed852e2009-09-05 21:47:34 +000015440 {
15441 *state|=ExitState;
15442 break;
15443 }
15444 break;
15445 }
15446 if (event.xclient.message_type == windows->dnd_protocols)
15447 {
15448 Atom
15449 selection,
15450 type;
15451
15452 int
15453 format,
15454 status;
15455
15456 unsigned char
15457 *data;
15458
cristyf2faecf2010-05-28 19:19:36 +000015459 unsigned long
cristy3ed852e2009-09-05 21:47:34 +000015460 after,
15461 length;
15462
15463 /*
15464 Display image named by the Drag-and-Drop selection.
15465 */
15466 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128))
15467 break;
15468 selection=XInternAtom(display,"DndSelection",MagickFalse);
cristyecd0ab52010-05-30 14:59:20 +000015469 status=XGetWindowProperty(display,root_window,selection,0L,(long)
cristy151b66d2015-04-15 10:50:31 +000015470 MagickPathExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format,
cristy3ed852e2009-09-05 21:47:34 +000015471 &length,&after,&data);
15472 if ((status != Success) || (length == 0))
15473 break;
15474 if (*event.xclient.data.l == 2)
15475 {
15476 /*
15477 Offix DND.
15478 */
15479 (void) CopyMagickString(resource_info->image_info->filename,
cristy151b66d2015-04-15 10:50:31 +000015480 (char *) data,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +000015481 }
15482 else
15483 {
15484 /*
15485 XDND.
15486 */
15487 if (strncmp((char *) data, "file:", 5) != 0)
15488 {
15489 (void) XFree((void *) data);
15490 break;
15491 }
15492 (void) CopyMagickString(resource_info->image_info->filename,
cristy151b66d2015-04-15 10:50:31 +000015493 ((char *) data)+5,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +000015494 }
cristy947cb4c2011-10-20 18:41:46 +000015495 nexus=ReadImage(resource_info->image_info,exception);
15496 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +000015497 if (nexus != (Image *) NULL)
15498 *state|=NextImageState | ExitState;
15499 (void) XFree((void *) data);
15500 break;
15501 }
15502 /*
15503 If client window delete message, exit.
15504 */
15505 if (event.xclient.message_type != windows->wm_protocols)
15506 break;
cristyecd0ab52010-05-30 14:59:20 +000015507 if (*event.xclient.data.l != (long) windows->wm_delete_window)
cristy3ed852e2009-09-05 21:47:34 +000015508 break;
15509 (void) XWithdrawWindow(display,event.xclient.window,
15510 visual_info->screen);
15511 if (event.xclient.window == windows->image.id)
15512 {
15513 *state|=ExitState;
15514 break;
15515 }
15516 if (event.xclient.window == windows->pan.id)
15517 {
15518 /*
15519 Restore original image size when pan window is deleted.
15520 */
15521 windows->image.window_changes.width=windows->image.ximage->width;
15522 windows->image.window_changes.height=windows->image.ximage->height;
15523 (void) XConfigureImage(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015524 display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015525 }
15526 break;
15527 }
15528 case ConfigureNotify:
15529 {
cristy59864562013-04-18 11:47:41 +000015530 if (IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000015531 (void) LogMagickEvent(X11Event,GetMagickModule(),
15532 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window,
15533 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x,
15534 event.xconfigure.y,event.xconfigure.send_event);
15535 if (event.xconfigure.window == windows->image.id)
15536 {
15537 /*
15538 Image window has a new configuration.
15539 */
15540 if (event.xconfigure.send_event != 0)
15541 {
15542 XWindowChanges
15543 window_changes;
15544
15545 /*
15546 Position the transient windows relative of the Image window.
15547 */
15548 if (windows->command.geometry == (char *) NULL)
cristy59864562013-04-18 11:47:41 +000015549 if (IfMagickFalse(windows->command.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000015550 {
15551 windows->command.x=event.xconfigure.x-
15552 windows->command.width-25;
15553 windows->command.y=event.xconfigure.y;
15554 XConstrainWindowPosition(display,&windows->command);
15555 window_changes.x=windows->command.x;
15556 window_changes.y=windows->command.y;
15557 (void) XReconfigureWMWindow(display,windows->command.id,
15558 windows->command.screen,(unsigned int) (CWX | CWY),
15559 &window_changes);
15560 }
15561 if (windows->widget.geometry == (char *) NULL)
cristy59864562013-04-18 11:47:41 +000015562 if (IfMagickFalse(windows->widget.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000015563 {
15564 windows->widget.x=event.xconfigure.x+
15565 event.xconfigure.width/10;
15566 windows->widget.y=event.xconfigure.y+
15567 event.xconfigure.height/10;
15568 XConstrainWindowPosition(display,&windows->widget);
15569 window_changes.x=windows->widget.x;
15570 window_changes.y=windows->widget.y;
15571 (void) XReconfigureWMWindow(display,windows->widget.id,
15572 windows->widget.screen,(unsigned int) (CWX | CWY),
15573 &window_changes);
15574 }
15575 if (windows->magnify.geometry == (char *) NULL)
cristy59864562013-04-18 11:47:41 +000015576 if (IfMagickFalse(windows->magnify.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000015577 {
15578 windows->magnify.x=event.xconfigure.x+
15579 event.xconfigure.width+25;
15580 windows->magnify.y=event.xconfigure.y;
15581 XConstrainWindowPosition(display,&windows->magnify);
15582 window_changes.x=windows->magnify.x;
15583 window_changes.y=windows->magnify.y;
15584 (void) XReconfigureWMWindow(display,windows->magnify.id,
15585 windows->magnify.screen,(unsigned int) (CWX | CWY),
15586 &window_changes);
15587 }
15588 if (windows->pan.geometry == (char *) NULL)
cristy59864562013-04-18 11:47:41 +000015589 if (IfMagickFalse(windows->pan.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000015590 {
15591 windows->pan.x=event.xconfigure.x+
15592 event.xconfigure.width+25;
15593 windows->pan.y=event.xconfigure.y+
15594 windows->magnify.height+50;
15595 XConstrainWindowPosition(display,&windows->pan);
15596 window_changes.x=windows->pan.x;
15597 window_changes.y=windows->pan.y;
15598 (void) XReconfigureWMWindow(display,windows->pan.id,
15599 windows->pan.screen,(unsigned int) (CWX | CWY),
15600 &window_changes);
15601 }
15602 }
cristyecd0ab52010-05-30 14:59:20 +000015603 if ((event.xconfigure.width == (int) windows->image.width) &&
15604 (event.xconfigure.height == (int) windows->image.height))
cristy3ed852e2009-09-05 21:47:34 +000015605 break;
15606 windows->image.width=(unsigned int) event.xconfigure.width;
15607 windows->image.height=(unsigned int) event.xconfigure.height;
15608 windows->image.x=0;
15609 windows->image.y=0;
15610 if (display_image->montage != (char *) NULL)
15611 {
15612 windows->image.x=vid_info.x;
15613 windows->image.y=vid_info.y;
15614 }
cristy59864562013-04-18 11:47:41 +000015615 if (IfMagickTrue(windows->image.mapped) &&
anthony11d32022012-11-17 05:31:33 +000015616 IfMagickTrue(windows->image.stasis) )
cristy34b9f452010-01-06 20:04:29 +000015617 {
15618 /*
15619 Update image window configuration.
15620 */
15621 windows->image.window_changes.width=event.xconfigure.width;
15622 windows->image.window_changes.height=event.xconfigure.height;
15623 (void) XConfigureImage(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015624 display_image,exception);
cristy34b9f452010-01-06 20:04:29 +000015625 }
cristy3ed852e2009-09-05 21:47:34 +000015626 /*
15627 Update pan window configuration.
15628 */
15629 if ((event.xconfigure.width < windows->image.ximage->width) ||
15630 (event.xconfigure.height < windows->image.ximage->height))
15631 {
15632 (void) XMapRaised(display,windows->pan.id);
15633 XDrawPanRectangle(display,windows);
15634 }
15635 else
cristy59864562013-04-18 11:47:41 +000015636 if (IfMagickTrue(windows->pan.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000015637 (void) XWithdrawWindow(display,windows->pan.id,
15638 windows->pan.screen);
15639 break;
15640 }
15641 if (event.xconfigure.window == windows->magnify.id)
15642 {
15643 unsigned int
15644 magnify;
15645
15646 /*
15647 Magnify window has a new configuration.
15648 */
15649 windows->magnify.width=(unsigned int) event.xconfigure.width;
15650 windows->magnify.height=(unsigned int) event.xconfigure.height;
cristy59864562013-04-18 11:47:41 +000015651 if (IfMagickFalse(windows->magnify.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000015652 break;
15653 magnify=1;
15654 while ((int) magnify <= event.xconfigure.width)
15655 magnify<<=1;
15656 while ((int) magnify <= event.xconfigure.height)
15657 magnify<<=1;
15658 magnify>>=1;
15659 if (((int) magnify != event.xconfigure.width) ||
15660 ((int) magnify != event.xconfigure.height))
15661 {
15662 window_changes.width=(int) magnify;
15663 window_changes.height=(int) magnify;
15664 (void) XReconfigureWMWindow(display,windows->magnify.id,
15665 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
15666 &window_changes);
15667 break;
15668 }
cristy59864562013-04-18 11:47:41 +000015669 if (IfMagickTrue(windows->magnify.mapped) &&
anthony11d32022012-11-17 05:31:33 +000015670 IfMagickTrue(windows->magnify.stasis) )
cristy3ed852e2009-09-05 21:47:34 +000015671 {
15672 status=XMakeImage(display,resource_info,&windows->magnify,
cristy051718b2011-08-28 22:49:25 +000015673 display_image,windows->magnify.width,windows->magnify.height,
15674 exception);
cristy6710d842011-10-20 23:23:00 +000015675 XMakeMagnifyImage(display,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +000015676 }
15677 break;
15678 }
cristy59864562013-04-18 11:47:41 +000015679 if (IfMagickTrue(windows->magnify.mapped) &&
cristy3ed852e2009-09-05 21:47:34 +000015680 (event.xconfigure.window == windows->pan.id))
15681 {
15682 /*
15683 Pan icon window has a new configuration.
15684 */
15685 if (event.xconfigure.send_event != 0)
15686 {
15687 windows->pan.x=event.xconfigure.x;
15688 windows->pan.y=event.xconfigure.y;
15689 }
15690 windows->pan.width=(unsigned int) event.xconfigure.width;
15691 windows->pan.height=(unsigned int) event.xconfigure.height;
15692 break;
15693 }
15694 if (event.xconfigure.window == windows->icon.id)
15695 {
15696 /*
15697 Icon window has a new configuration.
15698 */
15699 windows->icon.width=(unsigned int) event.xconfigure.width;
15700 windows->icon.height=(unsigned int) event.xconfigure.height;
15701 break;
15702 }
15703 break;
15704 }
15705 case DestroyNotify:
15706 {
15707 /*
15708 Group leader has exited.
15709 */
cristy59864562013-04-18 11:47:41 +000015710 if (IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000015711 (void) LogMagickEvent(X11Event,GetMagickModule(),
15712 "Destroy Notify: 0x%lx",event.xdestroywindow.window);
15713 if (event.xdestroywindow.window == windows->group_leader.id)
15714 {
15715 *state|=ExitState;
15716 break;
15717 }
15718 break;
15719 }
15720 case EnterNotify:
15721 {
15722 /*
15723 Selectively install colormap.
15724 */
15725 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15726 if (event.xcrossing.mode != NotifyUngrab)
15727 XInstallColormap(display,map_info->colormap);
15728 break;
15729 }
15730 case Expose:
15731 {
cristy59864562013-04-18 11:47:41 +000015732 if (IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000015733 (void) LogMagickEvent(X11Event,GetMagickModule(),
15734 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window,
15735 event.xexpose.width,event.xexpose.height,event.xexpose.x,
15736 event.xexpose.y);
15737 /*
15738 Refresh windows that are now exposed.
15739 */
cristy6bee4042010-01-30 15:27:14 +000015740 if ((event.xexpose.window == windows->image.id) &&
anthony11d32022012-11-17 05:31:33 +000015741 IfMagickTrue(windows->image.mapped) )
cristy6bee4042010-01-30 15:27:14 +000015742 {
15743 XRefreshWindow(display,&windows->image,&event);
15744 delay=display_image->delay/MagickMax(
15745 display_image->ticks_per_second,1L);
15746 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15747 break;
15748 }
15749 if ((event.xexpose.window == windows->magnify.id) &&
anthony11d32022012-11-17 05:31:33 +000015750 IfMagickTrue(windows->magnify.mapped))
cristy6bee4042010-01-30 15:27:14 +000015751 {
cristy6710d842011-10-20 23:23:00 +000015752 XMakeMagnifyImage(display,windows,exception);
cristy6bee4042010-01-30 15:27:14 +000015753 break;
15754 }
cristy3ed852e2009-09-05 21:47:34 +000015755 if (event.xexpose.window == windows->pan.id)
cristy6bee4042010-01-30 15:27:14 +000015756 {
15757 XDrawPanRectangle(display,windows);
15758 break;
15759 }
cristy3ed852e2009-09-05 21:47:34 +000015760 if (event.xexpose.window == windows->icon.id)
cristy6bee4042010-01-30 15:27:14 +000015761 {
15762 XRefreshWindow(display,&windows->icon,&event);
15763 break;
15764 }
cristy3ed852e2009-09-05 21:47:34 +000015765 break;
15766 }
15767 case KeyPress:
15768 {
15769 int
15770 length;
15771
15772 /*
15773 Respond to a user key press.
15774 */
15775 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
15776 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15777 *(command+length)='\0';
cristy59864562013-04-18 11:47:41 +000015778 if (IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000015779 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristyf2faecf2010-05-28 19:19:36 +000015780 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long)
cristy3ed852e2009-09-05 21:47:34 +000015781 key_symbol,command);
15782 if (event.xkey.window == windows->image.id)
15783 {
15784 command_type=XImageWindowCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015785 event.xkey.state,key_symbol,&display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015786 if (command_type != NullCommand)
15787 nexus=XMagickCommand(display,resource_info,windows,command_type,
cristy051718b2011-08-28 22:49:25 +000015788 &display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015789 }
15790 if (event.xkey.window == windows->magnify.id)
cristy6710d842011-10-20 23:23:00 +000015791 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol,
15792 exception);
cristy3ed852e2009-09-05 21:47:34 +000015793 if (event.xkey.window == windows->pan.id)
15794 {
15795 if ((key_symbol == XK_q) || (key_symbol == XK_Escape))
15796 (void) XWithdrawWindow(display,windows->pan.id,
15797 windows->pan.screen);
15798 else
15799 if ((key_symbol == XK_F1) || (key_symbol == XK_Help))
15800 XTextViewWidget(display,resource_info,windows,MagickFalse,
15801 "Help Viewer - Image Pan",ImagePanHelp);
15802 else
15803 XTranslateImage(display,windows,*image,key_symbol);
15804 }
15805 delay=display_image->delay/MagickMax(
15806 display_image->ticks_per_second,1L);
15807 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15808 break;
15809 }
15810 case KeyRelease:
15811 {
15812 /*
15813 Respond to a user key release.
15814 */
15815 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
15816 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
cristy59864562013-04-18 11:47:41 +000015817 if (IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000015818 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristyf2faecf2010-05-28 19:19:36 +000015819 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command);
cristy3ed852e2009-09-05 21:47:34 +000015820 break;
15821 }
15822 case LeaveNotify:
15823 {
15824 /*
15825 Selectively uninstall colormap.
15826 */
15827 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15828 if (event.xcrossing.mode != NotifyUngrab)
15829 XUninstallColormap(display,map_info->colormap);
15830 break;
15831 }
15832 case MapNotify:
15833 {
cristy59864562013-04-18 11:47:41 +000015834 if (IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000015835 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx",
15836 event.xmap.window);
15837 if (event.xmap.window == windows->backdrop.id)
15838 {
15839 (void) XSetInputFocus(display,event.xmap.window,RevertToParent,
15840 CurrentTime);
15841 windows->backdrop.mapped=MagickTrue;
15842 break;
15843 }
15844 if (event.xmap.window == windows->image.id)
15845 {
15846 if (windows->backdrop.id != (Window) NULL)
15847 (void) XInstallColormap(display,map_info->colormap);
15848 if (LocaleCompare(display_image->magick,"LOGO") == 0)
15849 {
15850 if (LocaleCompare(display_image->filename,"LOGO") == 0)
15851 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
15852 }
15853 if (((int) windows->image.width < windows->image.ximage->width) ||
15854 ((int) windows->image.height < windows->image.ximage->height))
15855 (void) XMapRaised(display,windows->pan.id);
15856 windows->image.mapped=MagickTrue;
15857 break;
15858 }
15859 if (event.xmap.window == windows->magnify.id)
15860 {
cristy6710d842011-10-20 23:23:00 +000015861 XMakeMagnifyImage(display,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +000015862 windows->magnify.mapped=MagickTrue;
15863 (void) XWithdrawWindow(display,windows->info.id,
15864 windows->info.screen);
15865 break;
15866 }
15867 if (event.xmap.window == windows->pan.id)
15868 {
cristy051718b2011-08-28 22:49:25 +000015869 XMakePanImage(display,resource_info,windows,display_image,
15870 exception);
cristy3ed852e2009-09-05 21:47:34 +000015871 windows->pan.mapped=MagickTrue;
15872 break;
15873 }
15874 if (event.xmap.window == windows->info.id)
15875 {
15876 windows->info.mapped=MagickTrue;
15877 break;
15878 }
15879 if (event.xmap.window == windows->icon.id)
15880 {
15881 MagickBooleanType
15882 taint;
15883
15884 /*
15885 Create an icon image.
15886 */
15887 taint=display_image->taint;
15888 XMakeStandardColormap(display,icon_visual,icon_resources,
cristy6710d842011-10-20 23:23:00 +000015889 display_image,icon_map,icon_pixel,exception);
cristy3ed852e2009-09-05 21:47:34 +000015890 (void) XMakeImage(display,icon_resources,&windows->icon,
cristy051718b2011-08-28 22:49:25 +000015891 display_image,windows->icon.width,windows->icon.height,
15892 exception);
cristy3ed852e2009-09-05 21:47:34 +000015893 display_image->taint=taint;
15894 (void) XSetWindowBackgroundPixmap(display,windows->icon.id,
15895 windows->icon.pixmap);
15896 (void) XClearWindow(display,windows->icon.id);
15897 (void) XWithdrawWindow(display,windows->info.id,
15898 windows->info.screen);
15899 windows->icon.mapped=MagickTrue;
15900 break;
15901 }
15902 if (event.xmap.window == windows->command.id)
15903 {
15904 windows->command.mapped=MagickTrue;
15905 break;
15906 }
15907 if (event.xmap.window == windows->popup.id)
15908 {
15909 windows->popup.mapped=MagickTrue;
15910 break;
15911 }
15912 if (event.xmap.window == windows->widget.id)
15913 {
15914 windows->widget.mapped=MagickTrue;
15915 break;
15916 }
15917 break;
15918 }
15919 case MappingNotify:
15920 {
15921 (void) XRefreshKeyboardMapping(&event.xmapping);
15922 break;
15923 }
15924 case NoExpose:
15925 break;
15926 case PropertyNotify:
15927 {
15928 Atom
15929 type;
15930
15931 int
15932 format,
15933 status;
15934
15935 unsigned char
15936 *data;
15937
cristyf2faecf2010-05-28 19:19:36 +000015938 unsigned long
cristy3ed852e2009-09-05 21:47:34 +000015939 after,
15940 length;
15941
cristy59864562013-04-18 11:47:41 +000015942 if (IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000015943 (void) LogMagickEvent(X11Event,GetMagickModule(),
15944 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window,
15945 event.xproperty.atom,event.xproperty.state);
15946 if (event.xproperty.atom != windows->im_remote_command)
15947 break;
15948 /*
15949 Display image named by the remote command protocol.
15950 */
15951 status=XGetWindowProperty(display,event.xproperty.window,
cristy151b66d2015-04-15 10:50:31 +000015952 event.xproperty.atom,0L,(long) MagickPathExtent,MagickFalse,(Atom)
cristy3ed852e2009-09-05 21:47:34 +000015953 AnyPropertyType,&type,&format,&length,&after,&data);
15954 if ((status != Success) || (length == 0))
15955 break;
15956 if (LocaleCompare((char *) data,"-quit") == 0)
15957 {
15958 XClientMessage(display,windows->image.id,windows->im_protocols,
15959 windows->im_exit,CurrentTime);
15960 (void) XFree((void *) data);
15961 break;
15962 }
15963 (void) CopyMagickString(resource_info->image_info->filename,
cristy151b66d2015-04-15 10:50:31 +000015964 (char *) data,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +000015965 (void) XFree((void *) data);
cristy947cb4c2011-10-20 18:41:46 +000015966 nexus=ReadImage(resource_info->image_info,exception);
15967 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +000015968 if (nexus != (Image *) NULL)
15969 *state|=NextImageState | ExitState;
15970 break;
15971 }
15972 case ReparentNotify:
15973 {
cristy59864562013-04-18 11:47:41 +000015974 if (IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000015975 (void) LogMagickEvent(X11Event,GetMagickModule(),
15976 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent,
15977 event.xreparent.window);
15978 break;
15979 }
15980 case UnmapNotify:
15981 {
cristy59864562013-04-18 11:47:41 +000015982 if (IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000015983 (void) LogMagickEvent(X11Event,GetMagickModule(),
15984 "Unmap Notify: 0x%lx",event.xunmap.window);
15985 if (event.xunmap.window == windows->backdrop.id)
15986 {
15987 windows->backdrop.mapped=MagickFalse;
15988 break;
15989 }
15990 if (event.xunmap.window == windows->image.id)
15991 {
15992 windows->image.mapped=MagickFalse;
15993 break;
15994 }
15995 if (event.xunmap.window == windows->magnify.id)
15996 {
15997 windows->magnify.mapped=MagickFalse;
15998 break;
15999 }
16000 if (event.xunmap.window == windows->pan.id)
16001 {
16002 windows->pan.mapped=MagickFalse;
16003 break;
16004 }
16005 if (event.xunmap.window == windows->info.id)
16006 {
16007 windows->info.mapped=MagickFalse;
16008 break;
16009 }
16010 if (event.xunmap.window == windows->icon.id)
16011 {
16012 if (map_info->colormap == icon_map->colormap)
16013 XConfigureImageColormap(display,resource_info,windows,
cristy6710d842011-10-20 23:23:00 +000016014 display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000016015 (void) XFreeStandardColormap(display,icon_visual,icon_map,
16016 icon_pixel);
16017 windows->icon.mapped=MagickFalse;
16018 break;
16019 }
16020 if (event.xunmap.window == windows->command.id)
16021 {
16022 windows->command.mapped=MagickFalse;
16023 break;
16024 }
16025 if (event.xunmap.window == windows->popup.id)
16026 {
16027 if (windows->backdrop.id != (Window) NULL)
16028 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
16029 CurrentTime);
16030 windows->popup.mapped=MagickFalse;
16031 break;
16032 }
16033 if (event.xunmap.window == windows->widget.id)
16034 {
16035 if (windows->backdrop.id != (Window) NULL)
16036 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
16037 CurrentTime);
16038 windows->widget.mapped=MagickFalse;
16039 break;
16040 }
16041 break;
16042 }
16043 default:
16044 {
cristy59864562013-04-18 11:47:41 +000016045 if (IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000016046 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
16047 event.type);
16048 break;
16049 }
16050 }
16051 } while (!(*state & ExitState));
16052 if ((*state & ExitState) == 0)
16053 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand,
cristy051718b2011-08-28 22:49:25 +000016054 &display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000016055 else
cristy59864562013-04-18 11:47:41 +000016056 if (IfMagickTrue(resource_info->confirm_edit) )
cristy3ed852e2009-09-05 21:47:34 +000016057 {
16058 /*
16059 Query user if image has changed.
16060 */
cristy59864562013-04-18 11:47:41 +000016061 if (IfMagickFalse(resource_info->immutable) &&
anthony11d32022012-11-17 05:31:33 +000016062 IfMagickTrue(display_image->taint))
cristy3ed852e2009-09-05 21:47:34 +000016063 {
16064 int
16065 status;
16066
16067 status=XConfirmWidget(display,windows,"Your image changed.",
16068 "Do you want to save it");
16069 if (status == 0)
16070 *state&=(~ExitState);
16071 else
16072 if (status > 0)
16073 (void) XMagickCommand(display,resource_info,windows,SaveCommand,
cristy051718b2011-08-28 22:49:25 +000016074 &display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000016075 }
16076 }
16077 if ((windows->visual_info->klass == GrayScale) ||
16078 (windows->visual_info->klass == PseudoColor) ||
16079 (windows->visual_info->klass == DirectColor))
16080 {
16081 /*
16082 Withdraw pan and Magnify window.
16083 */
cristy59864562013-04-18 11:47:41 +000016084 if (IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000016085 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
cristy59864562013-04-18 11:47:41 +000016086 if (IfMagickTrue(windows->magnify.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000016087 (void) XWithdrawWindow(display,windows->magnify.id,
16088 windows->magnify.screen);
cristy59864562013-04-18 11:47:41 +000016089 if (IfMagickTrue(windows->command.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000016090 (void) XWithdrawWindow(display,windows->command.id,
16091 windows->command.screen);
16092 }
cristy59864562013-04-18 11:47:41 +000016093 if (IfMagickTrue(windows->pan.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000016094 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen);
cristy59864562013-04-18 11:47:41 +000016095 if (IfMagickFalse(resource_info->backdrop) )
cristy3ed852e2009-09-05 21:47:34 +000016096 if (windows->backdrop.mapped)
16097 {
16098 (void) XWithdrawWindow(display,windows->backdrop.id,
16099 windows->backdrop.screen);
16100 (void) XDestroyWindow(display,windows->backdrop.id);
16101 windows->backdrop.id=(Window) NULL;
16102 (void) XWithdrawWindow(display,windows->image.id,
16103 windows->image.screen);
16104 (void) XDestroyWindow(display,windows->image.id);
16105 windows->image.id=(Window) NULL;
16106 }
16107 XSetCursorState(display,windows,MagickTrue);
16108 XCheckRefreshWindows(display,windows);
16109 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0))
16110 *state&=(~ExitState);
16111 if (*state & ExitState)
16112 {
16113 /*
16114 Free Standard Colormap.
16115 */
16116 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel);
16117 if (resource_info->map_type == (char *) NULL)
16118 (void) XFreeStandardColormap(display,visual_info,map_info,pixel);
16119 /*
16120 Free X resources.
16121 */
16122 if (resource_info->copy_image != (Image *) NULL)
16123 {
16124 resource_info->copy_image=DestroyImage(resource_info->copy_image);
16125 resource_info->copy_image=NewImageList();
16126 }
16127 DestroyXResources();
16128 }
16129 (void) XSync(display,MagickFalse);
16130 /*
16131 Restore our progress monitor and warning handlers.
16132 */
16133 (void) SetErrorHandler(warning_handler);
16134 (void) SetWarningHandler(warning_handler);
16135 /*
16136 Change to home directory.
16137 */
cristy151b66d2015-04-15 10:50:31 +000016138 directory=getcwd(working_directory,MagickPathExtent);
cristy00976d82011-02-20 20:31:28 +000016139 (void) directory;
cristy3ed852e2009-09-05 21:47:34 +000016140 {
16141 int
16142 status;
16143
cristy8a5d7f42013-01-06 15:24:33 +000016144 if (*resource_info->home_directory == '\0')
cristy151b66d2015-04-15 10:50:31 +000016145 (void) CopyMagickString(resource_info->home_directory,".",MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +000016146 status=chdir(resource_info->home_directory);
16147 if (status == -1)
cristy947cb4c2011-10-20 18:41:46 +000016148 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
16149 "UnableToOpenFile","%s",resource_info->home_directory);
cristy3ed852e2009-09-05 21:47:34 +000016150 }
16151 *image=display_image;
16152 return(nexus);
16153}
16154#else
16155
16156/*
16157%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16158% %
16159% %
16160% %
16161+ D i s p l a y I m a g e s %
16162% %
16163% %
16164% %
16165%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16166%
16167% DisplayImages() displays an image sequence to any X window screen. It
16168% returns a value other than 0 if successful. Check the exception member
16169% of image to determine the reason for any failure.
16170%
16171% The format of the DisplayImages method is:
16172%
16173% MagickBooleanType DisplayImages(const ImageInfo *image_info,
cristy051718b2011-08-28 22:49:25 +000016174% Image *images,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000016175%
16176% A description of each parameter follows:
16177%
16178% o image_info: the image info.
16179%
16180% o image: the image.
16181%
cristy051718b2011-08-28 22:49:25 +000016182% o exception: return any errors or warnings in this structure.
16183%
cristy3ed852e2009-09-05 21:47:34 +000016184*/
16185MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
cristy051718b2011-08-28 22:49:25 +000016186 Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000016187{
16188 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +000016189 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +000016190 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +000016191 assert(image->signature == MagickCoreSignature);
cristy5f0da772013-12-01 17:43:03 +000016192 (void) image_info;
cristy59864562013-04-18 11:47:41 +000016193 if (IfMagickTrue(image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000016194 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy051718b2011-08-28 22:49:25 +000016195 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
anthonye5b39652012-04-21 05:37:29 +000016196 "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image->filename);
cristy3ed852e2009-09-05 21:47:34 +000016197 return(MagickFalse);
16198}
16199
16200/*
16201%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16202% %
16203% %
16204% %
16205+ R e m o t e D i s p l a y C o m m a n d %
16206% %
16207% %
16208% %
16209%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16210%
16211% RemoteDisplayCommand() encourages a remote display program to display the
16212% specified image filename.
16213%
16214% The format of the RemoteDisplayCommand method is:
16215%
16216% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image,
16217% const char *window,const char *filename,ExceptionInfo *exception)
16218%
16219% A description of each parameter follows:
16220%
16221% o image_info: the image info.
16222%
16223% o window: Specifies the name or id of an X window.
16224%
16225% o filename: the name of the image filename to display.
16226%
16227% o exception: return any errors or warnings in this structure.
16228%
16229*/
16230MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
16231 const char *window,const char *filename,ExceptionInfo *exception)
16232{
16233 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +000016234 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +000016235 assert(filename != (char *) NULL);
16236 (void) window;
16237 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
16238 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
anthonye5b39652012-04-21 05:37:29 +000016239 "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image_info->filename);
cristy3ed852e2009-09-05 21:47:34 +000016240 return(MagickFalse);
16241}
16242#endif