blob: a1a0ec6ac7e5bd464433c73a37a957fcbc97797a [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 %
16% John Cristy %
17% July 1992 %
18% %
19% %
cristy45ef08f2012-12-07 13:13:34 +000020% Copyright 1999-2013 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"
cristy4c08aed2011-07-01 19:47:50 +000048#include "MagickCore/client.h"
49#include "MagickCore/color.h"
50#include "MagickCore/colorspace.h"
51#include "MagickCore/composite.h"
52#include "MagickCore/constitute.h"
53#include "MagickCore/decorate.h"
54#include "MagickCore/delegate.h"
55#include "MagickCore/display.h"
56#include "MagickCore/display-private.h"
cristyc53413d2011-11-17 13:04:26 +000057#include "MagickCore/distort.h"
cristy4c08aed2011-07-01 19:47:50 +000058#include "MagickCore/draw.h"
59#include "MagickCore/effect.h"
60#include "MagickCore/enhance.h"
61#include "MagickCore/exception.h"
62#include "MagickCore/exception-private.h"
63#include "MagickCore/fx.h"
64#include "MagickCore/geometry.h"
65#include "MagickCore/image.h"
66#include "MagickCore/image-private.h"
67#include "MagickCore/list.h"
68#include "MagickCore/log.h"
69#include "MagickCore/magick.h"
70#include "MagickCore/memory_.h"
71#include "MagickCore/monitor.h"
72#include "MagickCore/monitor-private.h"
73#include "MagickCore/montage.h"
74#include "MagickCore/option.h"
75#include "MagickCore/paint.h"
76#include "MagickCore/pixel.h"
77#include "MagickCore/pixel-accessor.h"
78#include "MagickCore/PreRvIcccm.h"
79#include "MagickCore/property.h"
80#include "MagickCore/quantum.h"
81#include "MagickCore/quantum-private.h"
82#include "MagickCore/resize.h"
83#include "MagickCore/resource_.h"
84#include "MagickCore/shear.h"
85#include "MagickCore/segment.h"
cristy7497f482011-12-08 01:57:31 +000086#include "MagickCore/statistic.h"
cristy4c08aed2011-07-01 19:47:50 +000087#include "MagickCore/string_.h"
88#include "MagickCore/string-private.h"
89#include "MagickCore/transform.h"
90#include "MagickCore/threshold.h"
91#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000092#include "MagickCore/utility-private.h"
cristy4c08aed2011-07-01 19:47:50 +000093#include "MagickCore/version.h"
94#include "MagickCore/widget.h"
cristybcbda3f2011-09-03 13:01:22 +000095#include "MagickCore/widget-private.h"
96#include "MagickCore/xwindow.h"
cristy4c08aed2011-07-01 19:47:50 +000097#include "MagickCore/xwindow-private.h"
cristy3ed852e2009-09-05 21:47:34 +000098
99#if defined(MAGICKCORE_X11_DELEGATE)
100/*
101 Define declarations.
102*/
cristy49e2d862010-11-12 02:50:30 +0000103#define MaxColors MagickMin((ssize_t) windows->visual_info->colormap_size,256L)
cristy3ed852e2009-09-05 21:47:34 +0000104
105/*
106 Constant declarations.
107*/
108static const unsigned char
109 HighlightBitmap[8] =
110 {
111 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55
112 },
cristydd05beb2010-11-21 21:23:39 +0000113 OpaqueBitmap[8] =
114 {
115 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
116 },
cristy3ed852e2009-09-05 21:47:34 +0000117 ShadowBitmap[8] =
118 {
119 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
120 };
121
122static const char
123 *PageSizes[] =
124 {
125 "Letter",
126 "Tabloid",
127 "Ledger",
128 "Legal",
129 "Statement",
130 "Executive",
131 "A3",
132 "A4",
133 "A5",
134 "B4",
135 "B5",
136 "Folio",
137 "Quarto",
138 "10x14",
139 (char *) NULL
140 };
141
142/*
143 Help widget declarations.
144*/
145static const char
146 *ImageAnnotateHelp[] =
147 {
148 "In annotate mode, the Command widget has these options:",
149 "",
150 " Font Name",
151 " fixed",
152 " variable",
153 " 5x8",
154 " 6x10",
155 " 7x13bold",
156 " 8x13bold",
157 " 9x15bold",
158 " 10x20",
159 " 12x24",
160 " Browser...",
161 " Font Color",
162 " black",
163 " blue",
164 " cyan",
165 " green",
166 " gray",
167 " red",
168 " magenta",
169 " yellow",
170 " white",
171 " transparent",
172 " Browser...",
173 " Font Color",
174 " black",
175 " blue",
176 " cyan",
177 " green",
178 " gray",
179 " red",
180 " magenta",
181 " yellow",
182 " white",
183 " transparent",
184 " Browser...",
185 " Rotate Text",
186 " -90",
187 " -45",
188 " -30",
189 " 0",
190 " 30",
191 " 45",
192 " 90",
193 " 180",
194 " Dialog...",
195 " Help",
196 " Dismiss",
197 "",
198 "Choose a font name from the Font Name sub-menu. Additional",
199 "font names can be specified with the font browser. You can",
200 "change the menu names by setting the X resources font1",
201 "through font9.",
202 "",
203 "Choose a font color from the Font Color sub-menu.",
204 "Additional font colors can be specified with the color",
205 "browser. You can change the menu colors by setting the X",
206 "resources pen1 through pen9.",
207 "",
208 "If you select the color browser and press Grab, you can",
209 "choose the font color by moving the pointer to the desired",
210 "color on the screen and press any button.",
211 "",
212 "If you choose to rotate the text, choose Rotate Text from the",
213 "menu and select an angle. Typically you will only want to",
214 "rotate one line of text at a time. Depending on the angle you",
215 "choose, subsequent lines may end up overwriting each other.",
216 "",
217 "Choosing a font and its color is optional. The default font",
218 "is fixed and the default color is black. However, you must",
219 "choose a location to begin entering text and press button 1.",
220 "An underscore character will appear at the location of the",
221 "pointer. The cursor changes to a pencil to indicate you are",
222 "in text mode. To exit immediately, press Dismiss.",
223 "",
224 "In text mode, any key presses will display the character at",
225 "the location of the underscore and advance the underscore",
226 "cursor. Enter your text and once completed press Apply to",
227 "finish your image annotation. To correct errors press BACK",
228 "SPACE. To delete an entire line of text, press DELETE. Any",
229 "text that exceeds the boundaries of the image window is",
230 "automagically continued onto the next line.",
231 "",
232 "The actual color you request for the font is saved in the",
233 "image. However, the color that appears in your image window",
234 "may be different. For example, on a monochrome screen the",
235 "text will appear black or white even if you choose the color",
236 "red as the font color. However, the image saved to a file",
237 "with -write is written with red lettering. To assure the",
238 "correct color text in the final image, any PseudoClass image",
239 "is promoted to DirectClass (see miff(5)). To force a",
240 "PseudoClass image to remain PseudoClass, use -colors.",
241 (char *) NULL,
242 },
243 *ImageChopHelp[] =
244 {
245 "In chop mode, the Command widget has these options:",
246 "",
247 " Direction",
248 " horizontal",
249 " vertical",
250 " Help",
251 " Dismiss",
252 "",
253 "If the you choose the horizontal direction (this the",
254 "default), the area of the image between the two horizontal",
255 "endpoints of the chop line is removed. Otherwise, the area",
256 "of the image between the two vertical endpoints of the chop",
257 "line is removed.",
258 "",
259 "Select a location within the image window to begin your chop,",
260 "press and hold any button. Next, move the pointer to",
261 "another location in the image. As you move a line will",
262 "connect the initial location and the pointer. When you",
263 "release the button, the area within the image to chop is",
264 "determined by which direction you choose from the Command",
265 "widget.",
266 "",
267 "To cancel the image chopping, move the pointer back to the",
268 "starting point of the line and release the button.",
269 (char *) NULL,
270 },
271 *ImageColorEditHelp[] =
272 {
273 "In color edit mode, the Command widget has these options:",
274 "",
275 " Method",
276 " point",
277 " replace",
278 " floodfill",
279 " filltoborder",
280 " reset",
281 " Pixel Color",
282 " black",
283 " blue",
284 " cyan",
285 " green",
286 " gray",
287 " red",
288 " magenta",
289 " yellow",
290 " white",
291 " Browser...",
292 " Border Color",
293 " black",
294 " blue",
295 " cyan",
296 " green",
297 " gray",
298 " red",
299 " magenta",
300 " yellow",
301 " white",
302 " Browser...",
303 " Fuzz",
304 " 0%",
305 " 2%",
306 " 5%",
307 " 10%",
308 " 15%",
309 " Dialog...",
310 " Undo",
311 " Help",
312 " Dismiss",
313 "",
314 "Choose a color editing method from the Method sub-menu",
315 "of the Command widget. The point method recolors any pixel",
316 "selected with the pointer until the button is released. The",
317 "replace method recolors any pixel that matches the color of",
318 "the pixel you select with a button press. Floodfill recolors",
319 "any pixel that matches the color of the pixel you select with",
320 "a button press and is a neighbor. Whereas filltoborder recolors",
321 "any neighbor pixel that is not the border color. Finally reset",
322 "changes the entire image to the designated color.",
323 "",
324 "Next, choose a pixel color from the Pixel Color sub-menu.",
325 "Additional pixel colors can be specified with the color",
326 "browser. You can change the menu colors by setting the X",
327 "resources pen1 through pen9.",
328 "",
329 "Now press button 1 to select a pixel within the image window",
330 "to change its color. Additional pixels may be recolored as",
331 "prescribed by the method you choose.",
332 "",
333 "If the Magnify widget is mapped, it can be helpful in positioning",
334 "your pointer within the image (refer to button 2).",
335 "",
336 "The actual color you request for the pixels is saved in the",
337 "image. However, the color that appears in your image window",
338 "may be different. For example, on a monochrome screen the",
339 "pixel will appear black or white even if you choose the",
340 "color red as the pixel color. However, the image saved to a",
341 "file with -write is written with red pixels. To assure the",
342 "correct color text in the final image, any PseudoClass image",
343 "is promoted to DirectClass (see miff(5)). To force a",
344 "PseudoClass image to remain PseudoClass, use -colors.",
345 (char *) NULL,
346 },
347 *ImageCompositeHelp[] =
348 {
349 "First a widget window is displayed requesting you to enter an",
350 "image name. Press Composite, Grab or type a file name.",
351 "Press Cancel if you choose not to create a composite image.",
352 "When you choose Grab, move the pointer to the desired window",
353 "and press any button.",
354 "",
355 "If the Composite image does not have any matte information,",
356 "you are informed and the file browser is displayed again.",
357 "Enter the name of a mask image. The image is typically",
358 "grayscale and the same size as the composite image. If the",
359 "image is not grayscale, it is converted to grayscale and the",
360 "resulting intensities are used as matte information.",
361 "",
362 "A small window appears showing the location of the cursor in",
363 "the image window. You are now in composite mode. To exit",
364 "immediately, press Dismiss. In composite mode, the Command",
365 "widget has these options:",
366 "",
367 " Operators",
368 " Over",
369 " In",
370 " Out",
371 " Atop",
372 " Xor",
373 " Plus",
374 " Minus",
375 " Add",
376 " Subtract",
377 " Difference",
378 " Multiply",
379 " Bumpmap",
380 " Copy",
381 " CopyRed",
382 " CopyGreen",
383 " CopyBlue",
384 " CopyOpacity",
385 " Clear",
386 " Dissolve",
387 " Displace",
388 " Help",
389 " Dismiss",
390 "",
391 "Choose a composite operation from the Operators sub-menu of",
392 "the Command widget. How each operator behaves is described",
393 "below. Image window is the image currently displayed on",
394 "your X server and image is the image obtained with the File",
395 "Browser widget.",
396 "",
397 "Over The result is the union of the two image shapes,",
398 " with image obscuring image window in the region of",
399 " overlap.",
400 "",
401 "In The result is simply image cut by the shape of",
402 " image window. None of the image data of image",
403 " window is in the result.",
404 "",
405 "Out The resulting image is image with the shape of",
406 " image window cut out.",
407 "",
408 "Atop The result is the same shape as image image window,",
409 " with image obscuring image window where the image",
410 " shapes overlap. Note this differs from over",
411 " because the portion of image outside image window's",
412 " shape does not appear in the result.",
413 "",
414 "Xor The result is the image data from both image and",
415 " image window that is outside the overlap region.",
416 " The overlap region is blank.",
417 "",
418 "Plus The result is just the sum of the image data.",
419 " Output values are cropped to QuantumRange (no overflow).",
420 "",
421 "Minus The result of image - image window, with underflow",
422 " cropped to zero.",
423 "",
424 "Add The result of image + image window, with overflow",
425 " wrapping around (mod 256).",
426 "",
427 "Subtract The result of image - image window, with underflow",
428 " wrapping around (mod 256). The add and subtract",
429 " operators can be used to perform reversible",
430 " transformations.",
431 "",
432 "Difference",
433 " The result of abs(image - image window). This",
434 " useful for comparing two very similar images.",
435 "",
436 "Multiply",
437 " The result of image * image window. This",
438 " useful for the creation of drop-shadows.",
439 "",
440 "Bumpmap The result of surface normals from image * image",
441 " window.",
442 "",
443 "Copy The resulting image is image window replaced with",
444 " image. Here the matte information is ignored.",
445 "",
446 "CopyRed The red layer of the image window is replace with",
447 " the red layer of the image. The other layers are",
448 " untouched.",
449 "",
450 "CopyGreen",
451 " The green layer of the image window is replace with",
452 " the green layer of the image. The other layers are",
453 " untouched.",
454 "",
455 "CopyBlue The blue layer of the image window is replace with",
456 " the blue layer of the image. The other layers are",
457 " untouched.",
458 "",
459 "CopyOpacity",
460 " The matte layer of the image window is replace with",
461 " the matte layer of the image. The other layers are",
462 " untouched.",
463 "",
464 "The image compositor requires a matte, or alpha channel in",
465 "the image for some operations. This extra channel usually",
466 "defines a mask which represents a sort of a cookie-cutter",
467 "for the image. This the case when matte is opaque (full",
468 "coverage) for pixels inside the shape, zero outside, and",
469 "between 0 and QuantumRange on the boundary. If image does not",
470 "have a matte channel, it is initialized with 0 for any pixel",
471 "matching in color to pixel location (0,0), otherwise QuantumRange.",
472 "",
473 "If you choose Dissolve, the composite operator becomes Over. The",
474 "image matte channel percent transparency is initialized to factor.",
475 "The image window is initialized to (100-factor). Where factor is the",
476 "value you specify in the Dialog widget.",
477 "",
478 "Displace shifts the image pixels as defined by a displacement",
479 "map. With this option, image is used as a displacement map.",
480 "Black, within the displacement map, is a maximum positive",
481 "displacement. White is a maximum negative displacement and",
482 "middle gray is neutral. The displacement is scaled to determine",
483 "the pixel shift. By default, the displacement applies in both the",
484 "horizontal and vertical directions. However, if you specify a mask,",
485 "image is the horizontal X displacement and mask the vertical Y",
486 "displacement.",
487 "",
488 "Note that matte information for image window is not retained",
489 "for colormapped X server visuals (e.g. StaticColor,",
490 "StaticColor, GrayScale, PseudoColor). Correct compositing",
491 "behavior may require a TrueColor or DirectColor visual or a",
492 "Standard Colormap.",
493 "",
494 "Choosing a composite operator is optional. The default",
495 "operator is replace. However, you must choose a location to",
496 "composite your image and press button 1. Press and hold the",
497 "button before releasing and an outline of the image will",
498 "appear to help you identify your location.",
499 "",
500 "The actual colors of the composite image is saved. However,",
501 "the color that appears in image window may be different.",
502 "For example, on a monochrome screen image window will appear",
503 "black or white even though your composited image may have",
504 "many colors. If the image is saved to a file it is written",
505 "with the correct colors. To assure the correct colors are",
506 "saved in the final image, any PseudoClass image is promoted",
507 "to DirectClass (see miff(5)). To force a PseudoClass image",
508 "to remain PseudoClass, use -colors.",
509 (char *) NULL,
510 },
511 *ImageCutHelp[] =
512 {
513 "In cut mode, the Command widget has these options:",
514 "",
515 " Help",
516 " Dismiss",
517 "",
518 "To define a cut region, press button 1 and drag. The",
519 "cut region is defined by a highlighted rectangle that",
520 "expands or contracts as it follows the pointer. Once you",
521 "are satisfied with the cut region, release the button.",
522 "You are now in rectify mode. In rectify mode, the Command",
523 "widget has these options:",
524 "",
525 " Cut",
526 " Help",
527 " Dismiss",
528 "",
529 "You can make adjustments by moving the pointer to one of the",
530 "cut rectangle corners, pressing a button, and dragging.",
531 "Finally, press Cut to commit your copy region. To",
532 "exit without cutting the image, press Dismiss.",
533 (char *) NULL,
534 },
535 *ImageCopyHelp[] =
536 {
537 "In copy mode, the Command widget has these options:",
538 "",
539 " Help",
540 " Dismiss",
541 "",
542 "To define a copy region, press button 1 and drag. The",
543 "copy region is defined by a highlighted rectangle that",
544 "expands or contracts as it follows the pointer. Once you",
545 "are satisfied with the copy region, release the button.",
546 "You are now in rectify mode. In rectify mode, the Command",
547 "widget has these options:",
548 "",
549 " Copy",
550 " Help",
551 " Dismiss",
552 "",
553 "You can make adjustments by moving the pointer to one of the",
554 "copy rectangle corners, pressing a button, and dragging.",
555 "Finally, press Copy to commit your copy region. To",
556 "exit without copying the image, press Dismiss.",
557 (char *) NULL,
558 },
559 *ImageCropHelp[] =
560 {
561 "In crop mode, the Command widget has these options:",
562 "",
563 " Help",
564 " Dismiss",
565 "",
566 "To define a cropping region, press button 1 and drag. The",
567 "cropping region is defined by a highlighted rectangle that",
568 "expands or contracts as it follows the pointer. Once you",
569 "are satisfied with the cropping region, release the button.",
570 "You are now in rectify mode. In rectify mode, the Command",
571 "widget has these options:",
572 "",
573 " Crop",
574 " Help",
575 " Dismiss",
576 "",
577 "You can make adjustments by moving the pointer to one of the",
578 "cropping rectangle corners, pressing a button, and dragging.",
579 "Finally, press Crop to commit your cropping region. To",
580 "exit without cropping the image, press Dismiss.",
581 (char *) NULL,
582 },
583 *ImageDrawHelp[] =
584 {
585 "The cursor changes to a crosshair to indicate you are in",
586 "draw mode. To exit immediately, press Dismiss. In draw mode,",
587 "the Command widget has these options:",
588 "",
589 " Element",
590 " point",
591 " line",
592 " rectangle",
593 " fill rectangle",
594 " circle",
595 " fill circle",
596 " ellipse",
597 " fill ellipse",
598 " polygon",
599 " fill polygon",
600 " Color",
601 " black",
602 " blue",
603 " cyan",
604 " green",
605 " gray",
606 " red",
607 " magenta",
608 " yellow",
609 " white",
610 " transparent",
611 " Browser...",
612 " Stipple",
613 " Brick",
614 " Diagonal",
615 " Scales",
616 " Vertical",
617 " Wavy",
618 " Translucent",
619 " Opaque",
620 " Open...",
621 " Width",
622 " 1",
623 " 2",
624 " 4",
625 " 8",
626 " 16",
627 " Dialog...",
628 " Undo",
629 " Help",
630 " Dismiss",
631 "",
632 "Choose a drawing primitive from the Element sub-menu.",
633 "",
634 "Choose a color from the Color sub-menu. Additional",
635 "colors can be specified with the color browser.",
636 "",
637 "If you choose the color browser and press Grab, you can",
638 "select the color by moving the pointer to the desired",
639 "color on the screen and press any button. The transparent",
640 "color updates the image matte channel and is useful for",
641 "image compositing.",
642 "",
643 "Choose a stipple, if appropriate, from the Stipple sub-menu.",
644 "Additional stipples can be specified with the file browser.",
645 "Stipples obtained from the file browser must be on disk in the",
646 "X11 bitmap format.",
647 "",
648 "Choose a width, if appropriate, from the Width sub-menu. To",
649 "choose a specific width select the Dialog widget.",
650 "",
651 "Choose a point in the Image window and press button 1 and",
652 "hold. Next, move the pointer to another location in the",
653 "image. As you move, a line connects the initial location and",
654 "the pointer. When you release the button, the image is",
655 "updated with the primitive you just drew. For polygons, the",
656 "image is updated when you press and release the button without",
657 "moving the pointer.",
658 "",
659 "To cancel image drawing, move the pointer back to the",
660 "starting point of the line and release the button.",
661 (char *) NULL,
662 },
663 *DisplayHelp[] =
664 {
665 "BUTTONS",
666 " The effects of each button press is described below. Three",
667 " buttons are required. If you have a two button mouse,",
668 " button 1 and 3 are returned. Press ALT and button 3 to",
669 " simulate button 2.",
670 "",
671 " 1 Press this button to map or unmap the Command widget.",
672 "",
673 " 2 Press and drag to define a region of the image to",
674 " magnify.",
675 "",
676 " 3 Press and drag to choose from a select set of commands.",
677 " This button behaves differently if the image being",
678 " displayed is a visual image directory. Here, choose a",
679 " particular tile of the directory and press this button and",
680 " drag to select a command from a pop-up menu. Choose from",
681 " these menu items:",
682 "",
683 " Open",
684 " Next",
685 " Former",
686 " Delete",
687 " Update",
688 "",
689 " If you choose Open, the image represented by the tile is",
690 " displayed. To return to the visual image directory, choose",
691 " Next from the Command widget. Next and Former moves to the",
692 " next or former image respectively. Choose Delete to delete",
693 " a particular image tile. Finally, choose Update to",
694 " synchronize all the image tiles with their respective",
695 " images.",
696 "",
697 "COMMAND WIDGET",
698 " The Command widget lists a number of sub-menus and commands.",
699 " They are",
700 "",
701 " File",
702 " Open...",
703 " Next",
704 " Former",
705 " Select...",
706 " Save...",
707 " Print...",
708 " Delete...",
709 " New...",
710 " Visual Directory...",
711 " Quit",
712 " Edit",
713 " Undo",
714 " Redo",
715 " Cut",
716 " Copy",
717 " Paste",
718 " View",
719 " Half Size",
720 " Original Size",
721 " Double Size",
722 " Resize...",
723 " Apply",
724 " Refresh",
725 " Restore",
726 " Transform",
727 " Crop",
728 " Chop",
729 " Flop",
730 " Flip",
731 " Rotate Right",
732 " Rotate Left",
733 " Rotate...",
734 " Shear...",
735 " Roll...",
736 " Trim Edges",
737 " Enhance",
738 " Brightness...",
739 " Saturation...",
740 " Hue...",
741 " Gamma...",
742 " Sharpen...",
743 " Dull",
744 " Contrast Stretch...",
745 " Sigmoidal Contrast...",
746 " Normalize",
747 " Equalize",
748 " Negate",
749 " Grayscale",
750 " Map...",
751 " Quantize...",
752 " Effects",
753 " Despeckle",
754 " Emboss",
755 " Reduce Noise",
756 " Add Noise",
757 " Sharpen...",
758 " Blur...",
759 " Threshold...",
760 " Edge Detect...",
761 " Spread...",
762 " Shade...",
763 " Painting...",
764 " Segment...",
765 " F/X",
766 " Solarize...",
767 " Sepia Tone...",
768 " Swirl...",
769 " Implode...",
770 " Vignette...",
771 " Wave...",
772 " Oil Painting...",
773 " Charcoal Drawing...",
774 " Image Edit",
775 " Annotate...",
776 " Draw...",
777 " Color...",
778 " Matte...",
779 " Composite...",
780 " Add Border...",
781 " Add Frame...",
782 " Comment...",
783 " Launch...",
784 " Region of Interest...",
785 " Miscellany",
786 " Image Info",
787 " Zoom Image",
788 " Show Preview...",
789 " Show Histogram",
790 " Show Matte",
791 " Background...",
792 " Slide Show",
793 " Preferences...",
794 " Help",
795 " Overview",
796 " Browse Documentation",
797 " About Display",
798 "",
799 " Menu items with a indented triangle have a sub-menu. They",
800 " are represented above as the indented items. To access a",
801 " sub-menu item, move the pointer to the appropriate menu and",
802 " press a button and drag. When you find the desired sub-menu",
803 " item, release the button and the command is executed. Move",
804 " the pointer away from the sub-menu if you decide not to",
805 " execute a particular command.",
806 "",
807 "KEYBOARD ACCELERATORS",
808 " Accelerators are one or two key presses that effect a",
809 " particular command. The keyboard accelerators that",
810 " display(1) understands is:",
811 "",
812 " Ctl+O Press to open an image from a file.",
813 "",
814 " space Press to display the next image.",
815 "",
816 " If the image is a multi-paged document such as a Postscript",
817 " document, you can skip ahead several pages by preceding",
818 " this command with a number. For example to display the",
819 " third page beyond the current page, press 3<space>.",
820 "",
821 " backspace Press to display the former image.",
822 "",
823 " If the image is a multi-paged document such as a Postscript",
824 " document, you can skip behind several pages by preceding",
825 " this command with a number. For example to display the",
826 " third page preceding the current page, press 3<backspace>.",
827 "",
828 " Ctl+S Press to write the image to a file.",
829 "",
830 " Ctl+P Press to print the image to a Postscript printer.",
831 "",
832 " Ctl+D Press to delete an image file.",
833 "",
834 " Ctl+N Press to create a blank canvas.",
835 "",
836 " Ctl+Q Press to discard all images and exit program.",
837 "",
838 " Ctl+Z Press to undo last image transformation.",
839 "",
840 " Ctl+R Press to redo last image transformation.",
841 "",
842 " Ctl+X Press to cut a region of the image.",
843 "",
844 " Ctl+C Press to copy a region of the image.",
845 "",
846 " Ctl+V Press to paste a region to the image.",
847 "",
848 " < Press to half the image size.",
849 "",
850 " - Press to return to the original image size.",
851 "",
852 " > Press to double the image size.",
853 "",
854 " % Press to resize the image to a width and height you",
855 " specify.",
856 "",
857 "Cmd-A Press to make any image transformations permanent."
858 "",
859 " By default, any image size transformations are applied",
860 " to the original image to create the image displayed on",
861 " the X server. However, the transformations are not",
862 " permanent (i.e. the original image does not change",
863 " size only the X image does). For example, if you",
864 " press > the X image will appear to double in size,",
865 " but the original image will in fact remain the same size.",
866 " To force the original image to double in size, press >",
867 " followed by Cmd-A.",
868 "",
869 " @ Press to refresh the image window.",
870 "",
871 " C Press to cut out a rectangular region of the image.",
872 "",
873 " [ Press to chop the image.",
874 "",
875 " H Press to flop image in the horizontal direction.",
876 "",
877 " V Press to flip image in the vertical direction.",
878 "",
879 " / Press to rotate the image 90 degrees clockwise.",
880 "",
881 " \\ Press to rotate the image 90 degrees counter-clockwise.",
882 "",
883 " * Press to rotate the image the number of degrees you",
884 " specify.",
885 "",
886 " S Press to shear the image the number of degrees you",
887 " specify.",
888 "",
889 " R Press to roll the image.",
890 "",
891 " T Press to trim the image edges.",
892 "",
893 " Shft-H Press to vary the image hue.",
894 "",
895 " Shft-S Press to vary the color saturation.",
896 "",
897 " Shft-L Press to vary the color brightness.",
898 "",
899 " Shft-G Press to gamma correct the image.",
900 "",
901 " Shft-C Press to sharpen the image contrast.",
902 "",
903 " Shft-Z Press to dull the image contrast.",
904 "",
905 " = Press to perform histogram equalization on the image.",
906 "",
907 " Shft-N Press to perform histogram normalization on the image.",
908 "",
909 " Shft-~ Press to negate the colors of the image.",
910 "",
911 " . Press to convert the image colors to gray.",
912 "",
913 " Shft-# Press to set the maximum number of unique colors in the",
914 " image.",
915 "",
916 " F2 Press to reduce the speckles in an image.",
917 "",
918 " F3 Press to eliminate peak noise from an image.",
919 "",
920 " F4 Press to add noise to an image.",
921 "",
922 " F5 Press to sharpen an image.",
923 "",
924 " F6 Press to delete an image file.",
925 "",
926 " F7 Press to threshold the image.",
927 "",
928 " F8 Press to detect edges within an image.",
929 "",
930 " F9 Press to emboss an image.",
931 "",
932 " F10 Press to displace pixels by a random amount.",
933 "",
934 " F11 Press to negate all pixels above the threshold level.",
935 "",
936 " F12 Press to shade the image using a distant light source.",
937 "",
938 " F13 Press to lighten or darken image edges to create a 3-D effect.",
939 "",
940 " F14 Press to segment the image by color.",
941 "",
942 " Meta-S Press to swirl image pixels about the center.",
943 "",
944 " Meta-I Press to implode image pixels about the center.",
945 "",
cristycee97112010-05-28 00:44:52 +0000946 " Meta-W Press to alter an image along a sine wave.",
cristy3ed852e2009-09-05 21:47:34 +0000947 "",
948 " Meta-P Press to simulate an oil painting.",
949 "",
950 " Meta-C Press to simulate a charcoal drawing.",
951 "",
952 " Alt-A Press to annotate the image with text.",
953 "",
954 " Alt-D Press to draw on an image.",
955 "",
956 " Alt-P Press to edit an image pixel color.",
957 "",
958 " Alt-M Press to edit the image matte information.",
959 "",
960 " Alt-V Press to composite the image with another.",
961 "",
962 " Alt-B Press to add a border to the image.",
963 "",
964 " Alt-F Press to add an ornamental border to the image.",
965 "",
966 " Alt-Shft-!",
967 " Press to add an image comment.",
968 "",
969 " Ctl-A Press to apply image processing techniques to a region",
970 " of interest.",
971 "",
972 " Shft-? Press to display information about the image.",
973 "",
974 " Shft-+ Press to map the zoom image window.",
975 "",
976 " Shft-P Press to preview an image enhancement, effect, or f/x.",
977 "",
978 " F1 Press to display helpful information about display(1).",
979 "",
980 " Find Press to browse documentation about ImageMagick.",
981 "",
982 " 1-9 Press to change the level of magnification.",
983 "",
984 " Use the arrow keys to move the image one pixel up, down,",
985 " left, or right within the magnify window. Be sure to first",
986 " map the magnify window by pressing button 2.",
987 "",
988 " Press ALT and one of the arrow keys to trim off one pixel",
989 " from any side of the image.",
990 (char *) NULL,
991 },
992 *ImageMatteEditHelp[] =
993 {
994 "Matte information within an image is useful for some",
995 "operations such as image compositing (See IMAGE",
996 "COMPOSITING). This extra channel usually defines a mask",
997 "which represents a sort of a cookie-cutter for the image.",
998 "This the case when matte is opaque (full coverage) for",
999 "pixels inside the shape, zero outside, and between 0 and",
1000 "QuantumRange on the boundary.",
1001 "",
1002 "A small window appears showing the location of the cursor in",
1003 "the image window. You are now in matte edit mode. To exit",
1004 "immediately, press Dismiss. In matte edit mode, the Command",
1005 "widget has these options:",
1006 "",
1007 " Method",
1008 " point",
1009 " replace",
1010 " floodfill",
1011 " filltoborder",
1012 " reset",
1013 " Border Color",
1014 " black",
1015 " blue",
1016 " cyan",
1017 " green",
1018 " gray",
1019 " red",
1020 " magenta",
1021 " yellow",
1022 " white",
1023 " Browser...",
1024 " Fuzz",
1025 " 0%",
1026 " 2%",
1027 " 5%",
1028 " 10%",
1029 " 15%",
1030 " Dialog...",
1031 " Matte",
1032 " Opaque",
1033 " Transparent",
1034 " Dialog...",
1035 " Undo",
1036 " Help",
1037 " Dismiss",
1038 "",
1039 "Choose a matte editing method from the Method sub-menu of",
1040 "the Command widget. The point method changes the matte value",
1041 "of any pixel selected with the pointer until the button is",
1042 "is released. The replace method changes the matte value of",
1043 "any pixel that matches the color of the pixel you select with",
1044 "a button press. Floodfill changes the matte value of any pixel",
1045 "that matches the color of the pixel you select with a button",
1046 "press and is a neighbor. Whereas filltoborder changes the matte",
1047 "value any neighbor pixel that is not the border color. Finally",
1048 "reset changes the entire image to the designated matte value.",
1049 "",
1050 "Choose Matte Value and pick Opaque or Transarent. For other values",
1051 "select the Dialog entry. Here a dialog appears requesting a matte",
1052 "value. The value you select is assigned as the opacity value of the",
1053 "selected pixel or pixels.",
1054 "",
1055 "Now, press any button to select a pixel within the image",
1056 "window to change its matte value.",
1057 "",
1058 "If the Magnify widget is mapped, it can be helpful in positioning",
1059 "your pointer within the image (refer to button 2).",
1060 "",
1061 "Matte information is only valid in a DirectClass image.",
1062 "Therefore, any PseudoClass image is promoted to DirectClass",
1063 "(see miff(5)). Note that matte information for PseudoClass",
1064 "is not retained for colormapped X server visuals (e.g.",
1065 "StaticColor, StaticColor, GrayScale, PseudoColor) unless you",
1066 "immediately save your image to a file (refer to Write).",
1067 "Correct matte editing behavior may require a TrueColor or",
1068 "DirectColor visual or a Standard Colormap.",
1069 (char *) NULL,
1070 },
1071 *ImagePanHelp[] =
1072 {
1073 "When an image exceeds the width or height of the X server",
1074 "screen, display maps a small panning icon. The rectangle",
1075 "within the panning icon shows the area that is currently",
1076 "displayed in the image window. To pan about the image,",
1077 "press any button and drag the pointer within the panning",
1078 "icon. The pan rectangle moves with the pointer and the",
1079 "image window is updated to reflect the location of the",
1080 "rectangle within the panning icon. When you have selected",
1081 "the area of the image you wish to view, release the button.",
1082 "",
1083 "Use the arrow keys to pan the image one pixel up, down,",
1084 "left, or right within the image window.",
1085 "",
1086 "The panning icon is withdrawn if the image becomes smaller",
1087 "than the dimensions of the X server screen.",
1088 (char *) NULL,
1089 },
1090 *ImagePasteHelp[] =
1091 {
1092 "A small window appears showing the location of the cursor in",
1093 "the image window. You are now in paste mode. To exit",
1094 "immediately, press Dismiss. In paste mode, the Command",
1095 "widget has these options:",
1096 "",
1097 " Operators",
1098 " over",
1099 " in",
1100 " out",
1101 " atop",
1102 " xor",
1103 " plus",
1104 " minus",
1105 " add",
1106 " subtract",
1107 " difference",
1108 " replace",
1109 " Help",
1110 " Dismiss",
1111 "",
1112 "Choose a composite operation from the Operators sub-menu of",
1113 "the Command widget. How each operator behaves is described",
1114 "below. Image window is the image currently displayed on",
1115 "your X server and image is the image obtained with the File",
1116 "Browser widget.",
1117 "",
1118 "Over The result is the union of the two image shapes,",
1119 " with image obscuring image window in the region of",
1120 " overlap.",
1121 "",
1122 "In The result is simply image cut by the shape of",
1123 " image window. None of the image data of image",
1124 " window is in the result.",
1125 "",
1126 "Out The resulting image is image with the shape of",
1127 " image window cut out.",
1128 "",
1129 "Atop The result is the same shape as image image window,",
1130 " with image obscuring image window where the image",
1131 " shapes overlap. Note this differs from over",
1132 " because the portion of image outside image window's",
1133 " shape does not appear in the result.",
1134 "",
1135 "Xor The result is the image data from both image and",
1136 " image window that is outside the overlap region.",
1137 " The overlap region is blank.",
1138 "",
1139 "Plus The result is just the sum of the image data.",
1140 " Output values are cropped to QuantumRange (no overflow).",
1141 " This operation is independent of the matte",
1142 " channels.",
1143 "",
1144 "Minus The result of image - image window, with underflow",
1145 " cropped to zero.",
1146 "",
1147 "Add The result of image + image window, with overflow",
1148 " wrapping around (mod 256).",
1149 "",
1150 "Subtract The result of image - image window, with underflow",
1151 " wrapping around (mod 256). The add and subtract",
1152 " operators can be used to perform reversible",
1153 " transformations.",
1154 "",
1155 "Difference",
1156 " The result of abs(image - image window). This",
1157 " useful for comparing two very similar images.",
1158 "",
1159 "Copy The resulting image is image window replaced with",
1160 " image. Here the matte information is ignored.",
1161 "",
1162 "CopyRed The red layer of the image window is replace with",
1163 " the red layer of the image. The other layers are",
1164 " untouched.",
1165 "",
1166 "CopyGreen",
1167 " The green layer of the image window is replace with",
1168 " the green layer of the image. The other layers are",
1169 " untouched.",
1170 "",
1171 "CopyBlue The blue layer of the image window is replace with",
1172 " the blue layer of the image. The other layers are",
1173 " untouched.",
1174 "",
1175 "CopyOpacity",
1176 " The matte layer of the image window is replace with",
1177 " the matte layer of the image. The other layers are",
1178 " untouched.",
1179 "",
1180 "The image compositor requires a matte, or alpha channel in",
1181 "the image for some operations. This extra channel usually",
1182 "defines a mask which represents a sort of a cookie-cutter",
1183 "for the image. This the case when matte is opaque (full",
1184 "coverage) for pixels inside the shape, zero outside, and",
1185 "between 0 and QuantumRange on the boundary. If image does not",
1186 "have a matte channel, it is initialized with 0 for any pixel",
1187 "matching in color to pixel location (0,0), otherwise QuantumRange.",
1188 "",
1189 "Note that matte information for image window is not retained",
1190 "for colormapped X server visuals (e.g. StaticColor,",
1191 "StaticColor, GrayScale, PseudoColor). Correct compositing",
1192 "behavior may require a TrueColor or DirectColor visual or a",
1193 "Standard Colormap.",
1194 "",
1195 "Choosing a composite operator is optional. The default",
1196 "operator is replace. However, you must choose a location to",
1197 "paste your image and press button 1. Press and hold the",
1198 "button before releasing and an outline of the image will",
1199 "appear to help you identify your location.",
1200 "",
1201 "The actual colors of the pasted image is saved. However,",
1202 "the color that appears in image window may be different.",
1203 "For example, on a monochrome screen image window will appear",
1204 "black or white even though your pasted image may have",
1205 "many colors. If the image is saved to a file it is written",
1206 "with the correct colors. To assure the correct colors are",
1207 "saved in the final image, any PseudoClass image is promoted",
1208 "to DirectClass (see miff(5)). To force a PseudoClass image",
1209 "to remain PseudoClass, use -colors.",
1210 (char *) NULL,
1211 },
1212 *ImageROIHelp[] =
1213 {
1214 "In region of interest mode, the Command widget has these",
1215 "options:",
1216 "",
1217 " Help",
1218 " Dismiss",
1219 "",
1220 "To define a region of interest, press button 1 and drag.",
1221 "The region of interest is defined by a highlighted rectangle",
1222 "that expands or contracts as it follows the pointer. Once",
1223 "you are satisfied with the region of interest, release the",
1224 "button. You are now in apply mode. In apply mode the",
1225 "Command widget has these options:",
1226 "",
1227 " File",
1228 " Save...",
1229 " Print...",
1230 " Edit",
1231 " Undo",
1232 " Redo",
1233 " Transform",
1234 " Flop",
1235 " Flip",
1236 " Rotate Right",
1237 " Rotate Left",
1238 " Enhance",
1239 " Hue...",
1240 " Saturation...",
1241 " Brightness...",
1242 " Gamma...",
1243 " Spiff",
1244 " Dull",
1245 " Contrast Stretch",
1246 " Sigmoidal Contrast...",
1247 " Normalize",
1248 " Equalize",
1249 " Negate",
1250 " Grayscale",
1251 " Map...",
1252 " Quantize...",
1253 " Effects",
1254 " Despeckle",
1255 " Emboss",
1256 " Reduce Noise",
1257 " Sharpen...",
1258 " Blur...",
1259 " Threshold...",
1260 " Edge Detect...",
1261 " Spread...",
1262 " Shade...",
1263 " Raise...",
1264 " Segment...",
1265 " F/X",
1266 " Solarize...",
1267 " Sepia Tone...",
1268 " Swirl...",
1269 " Implode...",
1270 " Vignette...",
1271 " Wave...",
1272 " Oil Painting...",
1273 " Charcoal Drawing...",
1274 " Miscellany",
1275 " Image Info",
1276 " Zoom Image",
1277 " Show Preview...",
1278 " Show Histogram",
1279 " Show Matte",
1280 " Help",
1281 " Dismiss",
1282 "",
1283 "You can make adjustments to the region of interest by moving",
1284 "the pointer to one of the rectangle corners, pressing a",
1285 "button, and dragging. Finally, choose an image processing",
1286 "technique from the Command widget. You can choose more than",
1287 "one image processing technique to apply to an area.",
1288 "Alternatively, you can move the region of interest before",
1289 "applying another image processing technique. To exit, press",
1290 "Dismiss.",
1291 (char *) NULL,
1292 },
1293 *ImageRotateHelp[] =
1294 {
1295 "In rotate mode, the Command widget has these options:",
1296 "",
1297 " Pixel Color",
1298 " black",
1299 " blue",
1300 " cyan",
1301 " green",
1302 " gray",
1303 " red",
1304 " magenta",
1305 " yellow",
1306 " white",
1307 " Browser...",
1308 " Direction",
1309 " horizontal",
1310 " vertical",
1311 " Help",
1312 " Dismiss",
1313 "",
1314 "Choose a background color from the Pixel Color sub-menu.",
1315 "Additional background colors can be specified with the color",
1316 "browser. You can change the menu colors by setting the X",
1317 "resources pen1 through pen9.",
1318 "",
1319 "If you choose the color browser and press Grab, you can",
1320 "select the background color by moving the pointer to the",
1321 "desired color on the screen and press any button.",
1322 "",
1323 "Choose a point in the image window and press this button and",
1324 "hold. Next, move the pointer to another location in the",
1325 "image. As you move a line connects the initial location and",
1326 "the pointer. When you release the button, the degree of",
1327 "image rotation is determined by the slope of the line you",
1328 "just drew. The slope is relative to the direction you",
1329 "choose from the Direction sub-menu of the Command widget.",
1330 "",
1331 "To cancel the image rotation, move the pointer back to the",
1332 "starting point of the line and release the button.",
1333 (char *) NULL,
1334 };
1335
1336/*
1337 Enumeration declarations.
1338*/
1339typedef enum
1340{
1341 CopyMode,
1342 CropMode,
1343 CutMode
1344} ClipboardMode;
1345
1346typedef enum
1347{
1348 OpenCommand,
1349 NextCommand,
1350 FormerCommand,
1351 SelectCommand,
1352 SaveCommand,
1353 PrintCommand,
1354 DeleteCommand,
1355 NewCommand,
1356 VisualDirectoryCommand,
1357 QuitCommand,
1358 UndoCommand,
1359 RedoCommand,
1360 CutCommand,
1361 CopyCommand,
1362 PasteCommand,
1363 HalfSizeCommand,
1364 OriginalSizeCommand,
1365 DoubleSizeCommand,
1366 ResizeCommand,
1367 ApplyCommand,
1368 RefreshCommand,
1369 RestoreCommand,
1370 CropCommand,
1371 ChopCommand,
1372 FlopCommand,
1373 FlipCommand,
1374 RotateRightCommand,
1375 RotateLeftCommand,
1376 RotateCommand,
1377 ShearCommand,
1378 RollCommand,
1379 TrimCommand,
1380 HueCommand,
1381 SaturationCommand,
1382 BrightnessCommand,
1383 GammaCommand,
1384 SpiffCommand,
1385 DullCommand,
1386 ContrastStretchCommand,
1387 SigmoidalContrastCommand,
1388 NormalizeCommand,
1389 EqualizeCommand,
1390 NegateCommand,
1391 GrayscaleCommand,
1392 MapCommand,
1393 QuantizeCommand,
1394 DespeckleCommand,
1395 EmbossCommand,
1396 ReduceNoiseCommand,
1397 AddNoiseCommand,
1398 SharpenCommand,
1399 BlurCommand,
1400 ThresholdCommand,
1401 EdgeDetectCommand,
1402 SpreadCommand,
1403 ShadeCommand,
1404 RaiseCommand,
1405 SegmentCommand,
1406 SolarizeCommand,
1407 SepiaToneCommand,
1408 SwirlCommand,
1409 ImplodeCommand,
1410 VignetteCommand,
1411 WaveCommand,
1412 OilPaintCommand,
1413 CharcoalDrawCommand,
1414 AnnotateCommand,
1415 DrawCommand,
1416 ColorCommand,
1417 MatteCommand,
1418 CompositeCommand,
1419 AddBorderCommand,
1420 AddFrameCommand,
1421 CommentCommand,
1422 LaunchCommand,
1423 RegionofInterestCommand,
1424 ROIHelpCommand,
1425 ROIDismissCommand,
1426 InfoCommand,
1427 ZoomCommand,
1428 ShowPreviewCommand,
1429 ShowHistogramCommand,
1430 ShowMatteCommand,
1431 BackgroundCommand,
1432 SlideShowCommand,
1433 PreferencesCommand,
1434 HelpCommand,
1435 BrowseDocumentationCommand,
1436 VersionCommand,
1437 SaveToUndoBufferCommand,
1438 FreeBuffersCommand,
1439 NullCommand
1440} CommandType;
1441
1442typedef enum
1443{
1444 AnnotateNameCommand,
1445 AnnotateFontColorCommand,
1446 AnnotateBackgroundColorCommand,
1447 AnnotateRotateCommand,
1448 AnnotateHelpCommand,
1449 AnnotateDismissCommand,
1450 TextHelpCommand,
1451 TextApplyCommand,
1452 ChopDirectionCommand,
1453 ChopHelpCommand,
1454 ChopDismissCommand,
1455 HorizontalChopCommand,
1456 VerticalChopCommand,
1457 ColorEditMethodCommand,
1458 ColorEditColorCommand,
1459 ColorEditBorderCommand,
1460 ColorEditFuzzCommand,
1461 ColorEditUndoCommand,
1462 ColorEditHelpCommand,
1463 ColorEditDismissCommand,
1464 CompositeOperatorsCommand,
1465 CompositeDissolveCommand,
1466 CompositeDisplaceCommand,
1467 CompositeHelpCommand,
1468 CompositeDismissCommand,
1469 CropHelpCommand,
1470 CropDismissCommand,
1471 RectifyCopyCommand,
1472 RectifyHelpCommand,
1473 RectifyDismissCommand,
1474 DrawElementCommand,
1475 DrawColorCommand,
1476 DrawStippleCommand,
1477 DrawWidthCommand,
1478 DrawUndoCommand,
1479 DrawHelpCommand,
1480 DrawDismissCommand,
1481 MatteEditMethod,
1482 MatteEditBorderCommand,
1483 MatteEditFuzzCommand,
1484 MatteEditValueCommand,
1485 MatteEditUndoCommand,
1486 MatteEditHelpCommand,
1487 MatteEditDismissCommand,
1488 PasteOperatorsCommand,
1489 PasteHelpCommand,
1490 PasteDismissCommand,
1491 RotateColorCommand,
1492 RotateDirectionCommand,
1493 RotateCropCommand,
1494 RotateSharpenCommand,
1495 RotateHelpCommand,
1496 RotateDismissCommand,
1497 HorizontalRotateCommand,
1498 VerticalRotateCommand,
1499 TileLoadCommand,
1500 TileNextCommand,
1501 TileFormerCommand,
1502 TileDeleteCommand,
1503 TileUpdateCommand
1504} ModeType;
1505
1506/*
1507 Stipples.
1508*/
1509#define BricksWidth 20
1510#define BricksHeight 20
1511#define DiagonalWidth 16
1512#define DiagonalHeight 16
1513#define HighlightWidth 8
1514#define HighlightHeight 8
cristydd05beb2010-11-21 21:23:39 +00001515#define OpaqueWidth 8
1516#define OpaqueHeight 8
cristy3ed852e2009-09-05 21:47:34 +00001517#define ScalesWidth 16
1518#define ScalesHeight 16
1519#define ShadowWidth 8
1520#define ShadowHeight 8
1521#define VerticalWidth 16
1522#define VerticalHeight 16
1523#define WavyWidth 16
1524#define WavyHeight 16
1525
1526/*
1527 Constant declaration.
1528*/
1529static const int
1530 RoiDelta = 8;
1531
1532static const unsigned char
1533 BricksBitmap[] =
1534 {
1535 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00,
1536 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01,
1537 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00,
1538 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f,
1539 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01
1540 },
1541 DiagonalBitmap[] =
1542 {
1543 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88,
1544 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22,
1545 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22
1546 },
1547 ScalesBitmap[] =
1548 {
1549 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80,
1550 0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3,
1551 0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e
1552 },
1553 VerticalBitmap[] =
1554 {
1555 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
1556 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
1557 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11
1558 },
1559 WavyBitmap[] =
1560 {
1561 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff,
1562 0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf,
1563 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f
1564 };
1565
1566/*
1567 Function prototypes.
1568*/
1569static CommandType
1570 XImageWindowCommand(Display *,XResourceInfo *,XWindows *,
cristy051718b2011-08-28 22:49:25 +00001571 const MagickStatusType,KeySym,Image **,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +00001572
1573static Image
1574 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType,
cristy051718b2011-08-28 22:49:25 +00001575 Image **,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +00001576 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType),
cristy051718b2011-08-28 22:49:25 +00001577 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *,
1578 ExceptionInfo *),
1579 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *,
1580 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +00001581
1582static MagickBooleanType
cristy051718b2011-08-28 22:49:25 +00001583 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *,
1584 ExceptionInfo *),
1585 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **,
1586 ExceptionInfo *),
1587 XChopImage(Display *,XResourceInfo *,XWindows *,Image **,
1588 ExceptionInfo *),
1589 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode,
1590 ExceptionInfo *),
1591 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **,
1592 ExceptionInfo *),
1593 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *,
1594 ExceptionInfo *),
1595 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1596 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **,
1597 ExceptionInfo *),
1598 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **,
1599 ExceptionInfo *),
1600 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1601 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1602 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **,
1603 ExceptionInfo *),
1604 XROIImage(Display *,XResourceInfo *,XWindows *,Image **,ExceptionInfo *),
1605 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
1606 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +00001607
1608static void
1609 XDrawPanRectangle(Display *,XWindows *),
cristy051718b2011-08-28 22:49:25 +00001610 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **,
1611 ExceptionInfo *),
cristy6710d842011-10-20 23:23:00 +00001612 XMagnifyImage(Display *,XWindows *,XEvent *,ExceptionInfo *),
cristy051718b2011-08-28 22:49:25 +00001613 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *),
cristy6710d842011-10-20 23:23:00 +00001614 XPanImage(Display *,XWindows *,XEvent *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +00001615 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType,
cristy6710d842011-10-20 23:23:00 +00001616 const KeySym,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +00001617 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *),
cristy6710d842011-10-20 23:23:00 +00001618 XScreenEvent(Display *,XWindows *,XEvent *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +00001619 XTranslateImage(Display *,XWindows *,Image *,const KeySym);
1620
1621/*
1622%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1623% %
1624% %
1625% %
1626% D i s p l a y I m a g e s %
1627% %
1628% %
1629% %
1630%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1631%
1632% DisplayImages() displays an image sequence to any X window screen. It
1633% returns a value other than 0 if successful. Check the exception member
1634% of image to determine the reason for any failure.
1635%
1636% The format of the DisplayImages method is:
1637%
1638% MagickBooleanType DisplayImages(const ImageInfo *image_info,
cristy051718b2011-08-28 22:49:25 +00001639% Image *images,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001640%
1641% A description of each parameter follows:
1642%
1643% o image_info: the image info.
1644%
1645% o image: the image.
1646%
cristy051718b2011-08-28 22:49:25 +00001647% o exception: return any errors or warnings in this structure.
1648%
cristy3ed852e2009-09-05 21:47:34 +00001649*/
1650MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
cristy051718b2011-08-28 22:49:25 +00001651 Image *images,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001652{
1653 char
1654 *argv[1];
1655
1656 Display
1657 *display;
1658
1659 Image
1660 *image;
1661
cristybb503372010-05-27 20:51:26 +00001662 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001663 i;
1664
cristybb503372010-05-27 20:51:26 +00001665 size_t
cristy3ed852e2009-09-05 21:47:34 +00001666 state;
1667
1668 XrmDatabase
1669 resource_database;
1670
1671 XResourceInfo
1672 resource_info;
1673
1674 assert(image_info != (const ImageInfo *) NULL);
1675 assert(image_info->signature == MagickSignature);
1676 assert(images != (Image *) NULL);
1677 assert(images->signature == MagickSignature);
anthony11d32022012-11-17 05:31:33 +00001678 if( IfMagickTrue(images->debug) )
cristy3ed852e2009-09-05 21:47:34 +00001679 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
1680 display=XOpenDisplay(image_info->server_name);
1681 if (display == (Display *) NULL)
1682 {
cristy051718b2011-08-28 22:49:25 +00001683 (void) ThrowMagickException(exception,GetMagickModule(),XServerError,
cristyefe601c2013-01-05 17:51:12 +00001684 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name));
cristy3ed852e2009-09-05 21:47:34 +00001685 return(MagickFalse);
1686 }
cristy051718b2011-08-28 22:49:25 +00001687 if (exception->severity != UndefinedException)
1688 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00001689 (void) XSetErrorHandler(XError);
1690 resource_database=XGetResourceDatabase(display,GetClientName());
1691 (void) ResetMagickMemory(&resource_info,0,sizeof(resource_info));
1692 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info);
1693 if (image_info->page != (char *) NULL)
1694 resource_info.image_geometry=AcquireString(image_info->page);
1695 resource_info.immutable=MagickTrue;
1696 argv[0]=AcquireString(GetClientName());
1697 state=DefaultState;
1698 for (i=0; (state & ExitState) == 0; i++)
1699 {
cristybb503372010-05-27 20:51:26 +00001700 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations))
cristy3ed852e2009-09-05 21:47:34 +00001701 break;
1702 image=GetImageFromList(images,i % GetImageListLength(images));
cristy051718b2011-08-28 22:49:25 +00001703 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state,exception);
cristy3ed852e2009-09-05 21:47:34 +00001704 }
cristye42f6582012-02-11 17:59:50 +00001705 (void) SetErrorHandler((ErrorHandler) NULL);
1706 (void) SetWarningHandler((WarningHandler) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001707 argv[0]=DestroyString(argv[0]);
1708 (void) XCloseDisplay(display);
1709 XDestroyResourceInfo(&resource_info);
cristy051718b2011-08-28 22:49:25 +00001710 if (exception->severity != UndefinedException)
cristy3ed852e2009-09-05 21:47:34 +00001711 return(MagickFalse);
1712 return(MagickTrue);
1713}
1714
1715/*
1716%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1717% %
1718% %
1719% %
1720% R e m o t e D i s p l a y C o m m a n d %
1721% %
1722% %
1723% %
1724%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1725%
1726% RemoteDisplayCommand() encourages a remote display program to display the
1727% specified image filename.
1728%
1729% The format of the RemoteDisplayCommand method is:
1730%
1731% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
1732% const char *window,const char *filename,ExceptionInfo *exception)
1733%
1734% A description of each parameter follows:
1735%
1736% o image_info: the image info.
1737%
1738% o window: Specifies the name or id of an X window.
1739%
1740% o filename: the name of the image filename to display.
1741%
1742% o exception: return any errors or warnings in this structure.
1743%
1744*/
1745MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
1746 const char *window,const char *filename,ExceptionInfo *exception)
1747{
1748 Display
1749 *display;
1750
1751 MagickStatusType
1752 status;
1753
1754 assert(image_info != (const ImageInfo *) NULL);
1755 assert(image_info->signature == MagickSignature);
1756 assert(filename != (char *) NULL);
1757 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
1758 display=XOpenDisplay(image_info->server_name);
1759 if (display == (Display *) NULL)
1760 {
1761 (void) ThrowMagickException(exception,GetMagickModule(),XServerError,
cristyefe601c2013-01-05 17:51:12 +00001762 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name));
cristy3ed852e2009-09-05 21:47:34 +00001763 return(MagickFalse);
1764 }
1765 (void) XSetErrorHandler(XError);
1766 status=XRemoteCommand(display,window,filename);
1767 (void) XCloseDisplay(display);
anthony11d32022012-11-17 05:31:33 +00001768 return(IsMagickTrue(status));
cristy3ed852e2009-09-05 21:47:34 +00001769}
1770
1771/*
1772%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1773% %
1774% %
1775% %
1776+ X A n n o t a t e E d i t I m a g e %
1777% %
1778% %
1779% %
1780%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1781%
1782% XAnnotateEditImage() annotates the image with text.
1783%
1784% The format of the XAnnotateEditImage method is:
1785%
1786% MagickBooleanType XAnnotateEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00001787% XResourceInfo *resource_info,XWindows *windows,Image *image,
1788% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001789%
1790% A description of each parameter follows:
1791%
1792% o display: Specifies a connection to an X server; returned from
1793% XOpenDisplay.
1794%
1795% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
1796%
1797% o windows: Specifies a pointer to a XWindows structure.
1798%
1799% o image: the image; returned from ReadImage.
1800%
1801*/
1802
cristybb503372010-05-27 20:51:26 +00001803static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
cristy3ed852e2009-09-05 21:47:34 +00001804{
1805 if (x > y)
1806 return(x);
1807 return(y);
1808}
1809
cristybb503372010-05-27 20:51:26 +00001810static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
cristy3ed852e2009-09-05 21:47:34 +00001811{
1812 if (x < y)
1813 return(x);
1814 return(y);
1815}
1816
1817static MagickBooleanType XAnnotateEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00001818 XResourceInfo *resource_info,XWindows *windows,Image *image,
1819 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001820{
1821 static const char
1822 *AnnotateMenu[] =
1823 {
1824 "Font Name",
1825 "Font Color",
1826 "Box Color",
1827 "Rotate Text",
1828 "Help",
1829 "Dismiss",
1830 (char *) NULL
1831 },
1832 *TextMenu[] =
1833 {
1834 "Help",
1835 "Apply",
1836 (char *) NULL
1837 };
1838
1839 static const ModeType
1840 AnnotateCommands[] =
1841 {
1842 AnnotateNameCommand,
1843 AnnotateFontColorCommand,
1844 AnnotateBackgroundColorCommand,
1845 AnnotateRotateCommand,
1846 AnnotateHelpCommand,
1847 AnnotateDismissCommand
1848 },
1849 TextCommands[] =
1850 {
1851 TextHelpCommand,
1852 TextApplyCommand
1853 };
1854
1855 static MagickBooleanType
1856 transparent_box = MagickTrue,
1857 transparent_pen = MagickFalse;
1858
cristya19f1d72012-08-07 18:24:38 +00001859 static double
cristy3ed852e2009-09-05 21:47:34 +00001860 degrees = 0.0;
1861
1862 static unsigned int
1863 box_id = MaxNumberPens-2,
1864 font_id = 0,
1865 pen_id = 0;
1866
1867 char
1868 command[MaxTextExtent],
1869 text[MaxTextExtent];
1870
1871 const char
1872 *ColorMenu[MaxNumberPens+1];
1873
1874 Cursor
1875 cursor;
1876
1877 GC
1878 annotate_context;
1879
1880 int
1881 id,
1882 pen_number,
1883 status,
1884 x,
1885 y;
1886
1887 KeySym
1888 key_symbol;
1889
1890 register char
1891 *p;
1892
cristybb503372010-05-27 20:51:26 +00001893 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001894 i;
1895
1896 unsigned int
1897 height,
1898 width;
1899
cristybb503372010-05-27 20:51:26 +00001900 size_t
cristy3ed852e2009-09-05 21:47:34 +00001901 state;
1902
1903 XAnnotateInfo
1904 *annotate_info,
1905 *previous_info;
1906
1907 XColor
1908 color;
1909
1910 XFontStruct
1911 *font_info;
1912
1913 XEvent
1914 event,
1915 text_event;
1916
1917 /*
1918 Map Command widget.
1919 */
1920 (void) CloneString(&windows->command.name,"Annotate");
1921 windows->command.data=4;
1922 (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL);
1923 (void) XMapRaised(display,windows->command.id);
1924 XClientMessage(display,windows->image.id,windows->im_protocols,
1925 windows->im_update_widget,CurrentTime);
1926 /*
1927 Track pointer until button 1 is pressed.
1928 */
1929 XQueryPosition(display,windows->image.id,&x,&y);
1930 (void) XSelectInput(display,windows->image.id,
1931 windows->image.attributes.event_mask | PointerMotionMask);
1932 cursor=XCreateFontCursor(display,XC_left_side);
1933 (void) XCheckDefineCursor(display,windows->image.id,cursor);
1934 state=DefaultState;
1935 do
1936 {
anthony11d32022012-11-17 05:31:33 +00001937 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00001938 {
1939 /*
1940 Display pointer position.
1941 */
cristyb51dff52011-05-19 16:55:47 +00001942 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +00001943 x+windows->image.x,y+windows->image.y);
1944 XInfoWidget(display,windows,text);
1945 }
1946 /*
1947 Wait for next event.
1948 */
cristy6710d842011-10-20 23:23:00 +00001949 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00001950 if (event.xany.window == windows->command.id)
1951 {
1952 /*
1953 Select a command from the Command widget.
1954 */
1955 id=XCommandWidget(display,windows,AnnotateMenu,&event);
1956 (void) XCheckDefineCursor(display,windows->image.id,cursor);
1957 if (id < 0)
1958 continue;
1959 switch (AnnotateCommands[id])
1960 {
1961 case AnnotateNameCommand:
1962 {
1963 const char
1964 *FontMenu[MaxNumberFonts];
1965
1966 int
1967 font_number;
1968
1969 /*
1970 Initialize menu selections.
1971 */
1972 for (i=0; i < MaxNumberFonts; i++)
1973 FontMenu[i]=resource_info->font_name[i];
1974 FontMenu[MaxNumberFonts-2]="Browser...";
1975 FontMenu[MaxNumberFonts-1]=(const char *) NULL;
1976 /*
1977 Select a font name from the pop-up menu.
1978 */
1979 font_number=XMenuWidget(display,windows,AnnotateMenu[id],
1980 (const char **) FontMenu,command);
1981 if (font_number < 0)
1982 break;
1983 if (font_number == (MaxNumberFonts-2))
1984 {
1985 static char
1986 font_name[MaxTextExtent] = "fixed";
1987
1988 /*
1989 Select a font name from a browser.
1990 */
1991 resource_info->font_name[font_number]=font_name;
1992 XFontBrowserWidget(display,windows,"Select",font_name);
1993 if (*font_name == '\0')
1994 break;
1995 }
1996 /*
1997 Initialize font info.
1998 */
1999 font_info=XLoadQueryFont(display,resource_info->font_name[
2000 font_number]);
2001 if (font_info == (XFontStruct *) NULL)
2002 {
2003 XNoticeWidget(display,windows,"Unable to load font:",
2004 resource_info->font_name[font_number]);
2005 break;
2006 }
2007 font_id=(unsigned int) font_number;
2008 (void) XFreeFont(display,font_info);
2009 break;
2010 }
2011 case AnnotateFontColorCommand:
2012 {
2013 /*
2014 Initialize menu selections.
2015 */
2016 for (i=0; i < (int) (MaxNumberPens-2); i++)
2017 ColorMenu[i]=resource_info->pen_colors[i];
2018 ColorMenu[MaxNumberPens-2]="transparent";
2019 ColorMenu[MaxNumberPens-1]="Browser...";
2020 ColorMenu[MaxNumberPens]=(const char *) NULL;
2021 /*
2022 Select a pen color from the pop-up menu.
2023 */
2024 pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
2025 (const char **) ColorMenu,command);
2026 if (pen_number < 0)
2027 break;
2028 transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue :
2029 MagickFalse;
anthony11d32022012-11-17 05:31:33 +00002030 if( IfMagickTrue(transparent_pen) )
cristy3ed852e2009-09-05 21:47:34 +00002031 break;
2032 if (pen_number == (MaxNumberPens-1))
2033 {
2034 static char
2035 color_name[MaxTextExtent] = "gray";
2036
2037 /*
2038 Select a pen color from a dialog.
2039 */
2040 resource_info->pen_colors[pen_number]=color_name;
2041 XColorBrowserWidget(display,windows,"Select",color_name);
2042 if (*color_name == '\0')
2043 break;
2044 }
2045 /*
2046 Set pen color.
2047 */
2048 (void) XParseColor(display,windows->map_info->colormap,
2049 resource_info->pen_colors[pen_number],&color);
2050 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
2051 (unsigned int) MaxColors,&color);
2052 windows->pixel_info->pen_colors[pen_number]=color;
2053 pen_id=(unsigned int) pen_number;
2054 break;
2055 }
2056 case AnnotateBackgroundColorCommand:
2057 {
2058 /*
2059 Initialize menu selections.
2060 */
2061 for (i=0; i < (int) (MaxNumberPens-2); i++)
2062 ColorMenu[i]=resource_info->pen_colors[i];
2063 ColorMenu[MaxNumberPens-2]="transparent";
2064 ColorMenu[MaxNumberPens-1]="Browser...";
2065 ColorMenu[MaxNumberPens]=(const char *) NULL;
2066 /*
2067 Select a pen color from the pop-up menu.
2068 */
2069 pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
2070 (const char **) ColorMenu,command);
2071 if (pen_number < 0)
2072 break;
2073 transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue :
2074 MagickFalse;
anthony11d32022012-11-17 05:31:33 +00002075 if( IfMagickTrue(transparent_box) )
cristy3ed852e2009-09-05 21:47:34 +00002076 break;
2077 if (pen_number == (MaxNumberPens-1))
2078 {
2079 static char
2080 color_name[MaxTextExtent] = "gray";
2081
2082 /*
2083 Select a pen color from a dialog.
2084 */
2085 resource_info->pen_colors[pen_number]=color_name;
2086 XColorBrowserWidget(display,windows,"Select",color_name);
2087 if (*color_name == '\0')
2088 break;
2089 }
2090 /*
2091 Set pen color.
2092 */
2093 (void) XParseColor(display,windows->map_info->colormap,
2094 resource_info->pen_colors[pen_number],&color);
2095 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
2096 (unsigned int) MaxColors,&color);
2097 windows->pixel_info->pen_colors[pen_number]=color;
2098 box_id=(unsigned int) pen_number;
2099 break;
2100 }
2101 case AnnotateRotateCommand:
2102 {
2103 int
2104 entry;
2105
2106 static char
2107 angle[MaxTextExtent] = "30.0";
2108
2109 static const char
2110 *RotateMenu[] =
2111 {
2112 "-90",
2113 "-45",
2114 "-30",
2115 "0",
2116 "30",
2117 "45",
2118 "90",
2119 "180",
2120 "Dialog...",
2121 (char *) NULL,
2122 };
2123
2124 /*
2125 Select a command from the pop-up menu.
2126 */
2127 entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu,
2128 command);
2129 if (entry < 0)
2130 break;
2131 if (entry != 8)
2132 {
cristydbdd0e32011-11-04 23:29:40 +00002133 degrees=StringToDouble(RotateMenu[entry],(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002134 break;
2135 }
2136 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:",
2137 angle);
2138 if (*angle == '\0')
2139 break;
cristydbdd0e32011-11-04 23:29:40 +00002140 degrees=StringToDouble(angle,(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +00002141 break;
2142 }
2143 case AnnotateHelpCommand:
2144 {
2145 XTextViewWidget(display,resource_info,windows,MagickFalse,
2146 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2147 break;
2148 }
2149 case AnnotateDismissCommand:
2150 {
2151 /*
2152 Prematurely exit.
2153 */
2154 state|=EscapeState;
2155 state|=ExitState;
2156 break;
2157 }
2158 default:
2159 break;
2160 }
2161 continue;
2162 }
2163 switch (event.type)
2164 {
2165 case ButtonPress:
2166 {
2167 if (event.xbutton.button != Button1)
2168 break;
2169 if (event.xbutton.window != windows->image.id)
2170 break;
2171 /*
2172 Change to text entering mode.
2173 */
2174 x=event.xbutton.x;
2175 y=event.xbutton.y;
2176 state|=ExitState;
2177 break;
2178 }
2179 case ButtonRelease:
2180 break;
2181 case Expose:
2182 break;
2183 case KeyPress:
2184 {
2185 if (event.xkey.window != windows->image.id)
2186 break;
2187 /*
2188 Respond to a user key press.
2189 */
2190 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2191 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2192 switch ((int) key_symbol)
2193 {
2194 case XK_Escape:
2195 case XK_F20:
2196 {
2197 /*
2198 Prematurely exit.
2199 */
2200 state|=EscapeState;
2201 state|=ExitState;
2202 break;
2203 }
2204 case XK_F1:
2205 case XK_Help:
2206 {
2207 XTextViewWidget(display,resource_info,windows,MagickFalse,
2208 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2209 break;
2210 }
2211 default:
2212 {
2213 (void) XBell(display,0);
2214 break;
2215 }
2216 }
2217 break;
2218 }
2219 case MotionNotify:
2220 {
2221 /*
2222 Map and unmap Info widget as cursor crosses its boundaries.
2223 */
2224 x=event.xmotion.x;
2225 y=event.xmotion.y;
anthony11d32022012-11-17 05:31:33 +00002226 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00002227 {
2228 if ((x < (int) (windows->info.x+windows->info.width)) &&
2229 (y < (int) (windows->info.y+windows->info.height)))
2230 (void) XWithdrawWindow(display,windows->info.id,
2231 windows->info.screen);
2232 }
2233 else
2234 if ((x > (int) (windows->info.x+windows->info.width)) ||
2235 (y > (int) (windows->info.y+windows->info.height)))
2236 (void) XMapWindow(display,windows->info.id);
2237 break;
2238 }
2239 default:
2240 break;
2241 }
2242 } while ((state & ExitState) == 0);
2243 (void) XSelectInput(display,windows->image.id,
2244 windows->image.attributes.event_mask);
2245 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
2246 if ((state & EscapeState) != 0)
2247 return(MagickTrue);
2248 /*
2249 Set font info and check boundary conditions.
2250 */
2251 font_info=XLoadQueryFont(display,resource_info->font_name[font_id]);
2252 if (font_info == (XFontStruct *) NULL)
2253 {
2254 XNoticeWidget(display,windows,"Unable to load font:",
2255 resource_info->font_name[font_id]);
2256 font_info=windows->font_info;
2257 }
2258 if ((x+font_info->max_bounds.width) >= (int) windows->image.width)
2259 x=(int) windows->image.width-font_info->max_bounds.width;
2260 if (y < (int) (font_info->ascent+font_info->descent))
2261 y=(int) font_info->ascent+font_info->descent;
2262 if (((int) font_info->max_bounds.width > (int) windows->image.width) ||
2263 ((font_info->ascent+font_info->descent) >= (int) windows->image.height))
2264 return(MagickFalse);
2265 /*
2266 Initialize annotate structure.
2267 */
cristy73bd4a52010-10-05 11:24:23 +00002268 annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info));
cristy3ed852e2009-09-05 21:47:34 +00002269 if (annotate_info == (XAnnotateInfo *) NULL)
2270 return(MagickFalse);
2271 XGetAnnotateInfo(annotate_info);
2272 annotate_info->x=x;
2273 annotate_info->y=y;
anthony11d32022012-11-17 05:31:33 +00002274 if( IfMagickFalse(transparent_box) && IfMagickFalse(transparent_pen))
cristy3ed852e2009-09-05 21:47:34 +00002275 annotate_info->stencil=OpaqueStencil;
2276 else
anthony11d32022012-11-17 05:31:33 +00002277 if( IfMagickFalse(transparent_box) )
cristy3ed852e2009-09-05 21:47:34 +00002278 annotate_info->stencil=BackgroundStencil;
2279 else
2280 annotate_info->stencil=ForegroundStencil;
2281 annotate_info->height=(unsigned int) font_info->ascent+font_info->descent;
2282 annotate_info->degrees=degrees;
2283 annotate_info->font_info=font_info;
2284 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
cristy49e2d862010-11-12 02:50:30 +00002285 windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL,
cristy3ed852e2009-09-05 21:47:34 +00002286 sizeof(*annotate_info->text));
2287 if (annotate_info->text == (char *) NULL)
2288 return(MagickFalse);
2289 /*
2290 Create cursor and set graphic context.
2291 */
2292 cursor=XCreateFontCursor(display,XC_pencil);
2293 (void) XCheckDefineCursor(display,windows->image.id,cursor);
2294 annotate_context=windows->image.annotate_context;
2295 (void) XSetFont(display,annotate_context,font_info->fid);
2296 (void) XSetBackground(display,annotate_context,
2297 windows->pixel_info->pen_colors[box_id].pixel);
2298 (void) XSetForeground(display,annotate_context,
2299 windows->pixel_info->pen_colors[pen_id].pixel);
2300 /*
2301 Begin annotating the image with text.
2302 */
2303 (void) CloneString(&windows->command.name,"Text");
2304 windows->command.data=0;
2305 (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL);
2306 state=DefaultState;
2307 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
2308 text_event.xexpose.width=(int) font_info->max_bounds.width;
2309 text_event.xexpose.height=font_info->max_bounds.ascent+
2310 font_info->max_bounds.descent;
2311 p=annotate_info->text;
2312 do
2313 {
2314 /*
2315 Display text cursor.
2316 */
2317 *p='\0';
2318 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
2319 /*
2320 Wait for next event.
2321 */
cristy6710d842011-10-20 23:23:00 +00002322 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00002323 if (event.xany.window == windows->command.id)
2324 {
2325 /*
2326 Select a command from the Command widget.
2327 */
2328 (void) XSetBackground(display,annotate_context,
2329 windows->pixel_info->background_color.pixel);
2330 (void) XSetForeground(display,annotate_context,
2331 windows->pixel_info->foreground_color.pixel);
2332 id=XCommandWidget(display,windows,AnnotateMenu,&event);
2333 (void) XSetBackground(display,annotate_context,
2334 windows->pixel_info->pen_colors[box_id].pixel);
2335 (void) XSetForeground(display,annotate_context,
2336 windows->pixel_info->pen_colors[pen_id].pixel);
2337 if (id < 0)
2338 continue;
2339 switch (TextCommands[id])
2340 {
2341 case TextHelpCommand:
2342 {
2343 XTextViewWidget(display,resource_info,windows,MagickFalse,
2344 "Help Viewer - Image Annotation",ImageAnnotateHelp);
2345 (void) XCheckDefineCursor(display,windows->image.id,cursor);
2346 break;
2347 }
2348 case TextApplyCommand:
2349 {
2350 /*
2351 Finished annotating.
2352 */
2353 annotate_info->width=(unsigned int) XTextWidth(font_info,
2354 annotate_info->text,(int) strlen(annotate_info->text));
2355 XRefreshWindow(display,&windows->image,&text_event);
2356 state|=ExitState;
2357 break;
2358 }
2359 default:
2360 break;
2361 }
2362 continue;
2363 }
2364 /*
2365 Erase text cursor.
2366 */
2367 text_event.xexpose.x=x;
2368 text_event.xexpose.y=y-font_info->max_bounds.ascent;
2369 (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y,
2370 (unsigned int) text_event.xexpose.width,(unsigned int)
2371 text_event.xexpose.height,MagickFalse);
2372 XRefreshWindow(display,&windows->image,&text_event);
2373 switch (event.type)
2374 {
2375 case ButtonPress:
2376 {
2377 if (event.xbutton.window != windows->image.id)
2378 break;
2379 if (event.xbutton.button == Button2)
2380 {
2381 /*
2382 Request primary selection.
2383 */
2384 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
2385 windows->image.id,CurrentTime);
2386 break;
2387 }
2388 break;
2389 }
2390 case Expose:
2391 {
2392 if (event.xexpose.count == 0)
2393 {
2394 XAnnotateInfo
2395 *text_info;
2396
2397 /*
2398 Refresh Image window.
2399 */
2400 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
2401 text_info=annotate_info;
2402 while (text_info != (XAnnotateInfo *) NULL)
2403 {
2404 if (annotate_info->stencil == ForegroundStencil)
2405 (void) XDrawString(display,windows->image.id,annotate_context,
2406 text_info->x,text_info->y,text_info->text,
2407 (int) strlen(text_info->text));
2408 else
2409 (void) XDrawImageString(display,windows->image.id,
2410 annotate_context,text_info->x,text_info->y,text_info->text,
2411 (int) strlen(text_info->text));
2412 text_info=text_info->previous;
2413 }
2414 (void) XDrawString(display,windows->image.id,annotate_context,
2415 x,y,"_",1);
2416 }
2417 break;
2418 }
2419 case KeyPress:
2420 {
2421 int
2422 length;
2423
2424 if (event.xkey.window != windows->image.id)
2425 break;
2426 /*
2427 Respond to a user key press.
2428 */
2429 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
2430 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2431 *(command+length)='\0';
2432 if (((event.xkey.state & ControlMask) != 0) ||
2433 ((event.xkey.state & Mod1Mask) != 0))
2434 state|=ModifierState;
2435 if ((state & ModifierState) != 0)
2436 switch ((int) key_symbol)
2437 {
2438 case XK_u:
2439 case XK_U:
2440 {
2441 key_symbol=DeleteCommand;
2442 break;
2443 }
2444 default:
2445 break;
2446 }
2447 switch ((int) key_symbol)
2448 {
2449 case XK_BackSpace:
2450 {
2451 /*
2452 Erase one character.
2453 */
2454 if (p == annotate_info->text)
2455 {
2456 if (annotate_info->previous == (XAnnotateInfo *) NULL)
2457 break;
2458 else
2459 {
2460 /*
2461 Go to end of the previous line of text.
2462 */
2463 annotate_info=annotate_info->previous;
2464 p=annotate_info->text;
2465 x=annotate_info->x+annotate_info->width;
2466 y=annotate_info->y;
2467 if (annotate_info->width != 0)
2468 p+=strlen(annotate_info->text);
2469 break;
2470 }
2471 }
2472 p--;
2473 x-=XTextWidth(font_info,p,1);
2474 text_event.xexpose.x=x;
2475 text_event.xexpose.y=y-font_info->max_bounds.ascent;
2476 XRefreshWindow(display,&windows->image,&text_event);
2477 break;
2478 }
2479 case XK_bracketleft:
2480 {
2481 key_symbol=XK_Escape;
2482 break;
2483 }
2484 case DeleteCommand:
2485 {
2486 /*
2487 Erase the entire line of text.
2488 */
2489 while (p != annotate_info->text)
2490 {
2491 p--;
2492 x-=XTextWidth(font_info,p,1);
2493 text_event.xexpose.x=x;
2494 XRefreshWindow(display,&windows->image,&text_event);
2495 }
2496 break;
2497 }
2498 case XK_Escape:
2499 case XK_F20:
2500 {
2501 /*
2502 Finished annotating.
2503 */
2504 annotate_info->width=(unsigned int) XTextWidth(font_info,
2505 annotate_info->text,(int) strlen(annotate_info->text));
2506 XRefreshWindow(display,&windows->image,&text_event);
2507 state|=ExitState;
2508 break;
2509 }
2510 default:
2511 {
2512 /*
2513 Draw a single character on the Image window.
2514 */
2515 if ((state & ModifierState) != 0)
2516 break;
2517 if (*command == '\0')
2518 break;
2519 *p=(*command);
2520 if (annotate_info->stencil == ForegroundStencil)
2521 (void) XDrawString(display,windows->image.id,annotate_context,
2522 x,y,p,1);
2523 else
2524 (void) XDrawImageString(display,windows->image.id,
2525 annotate_context,x,y,p,1);
2526 x+=XTextWidth(font_info,p,1);
2527 p++;
2528 if ((x+font_info->max_bounds.width) < (int) windows->image.width)
2529 break;
2530 }
2531 case XK_Return:
2532 case XK_KP_Enter:
2533 {
2534 /*
2535 Advance to the next line of text.
2536 */
2537 *p='\0';
2538 annotate_info->width=(unsigned int) XTextWidth(font_info,
2539 annotate_info->text,(int) strlen(annotate_info->text));
2540 if (annotate_info->next != (XAnnotateInfo *) NULL)
2541 {
2542 /*
2543 Line of text already exists.
2544 */
2545 annotate_info=annotate_info->next;
2546 x=annotate_info->x;
2547 y=annotate_info->y;
2548 p=annotate_info->text;
2549 break;
2550 }
2551 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory(
2552 sizeof(*annotate_info->next));
2553 if (annotate_info->next == (XAnnotateInfo *) NULL)
2554 return(MagickFalse);
2555 *annotate_info->next=(*annotate_info);
2556 annotate_info->next->previous=annotate_info;
2557 annotate_info=annotate_info->next;
2558 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
cristy49e2d862010-11-12 02:50:30 +00002559 windows->image.width/MagickMax((ssize_t)
2560 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text));
cristy3ed852e2009-09-05 21:47:34 +00002561 if (annotate_info->text == (char *) NULL)
2562 return(MagickFalse);
2563 annotate_info->y+=annotate_info->height;
2564 if (annotate_info->y > (int) windows->image.height)
2565 annotate_info->y=(int) annotate_info->height;
2566 annotate_info->next=(XAnnotateInfo *) NULL;
2567 x=annotate_info->x;
2568 y=annotate_info->y;
2569 p=annotate_info->text;
2570 break;
2571 }
2572 }
2573 break;
2574 }
2575 case KeyRelease:
2576 {
2577 /*
2578 Respond to a user key release.
2579 */
2580 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
2581 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
2582 state&=(~ModifierState);
2583 break;
2584 }
2585 case SelectionNotify:
2586 {
2587 Atom
2588 type;
2589
2590 int
2591 format;
2592
2593 unsigned char
2594 *data;
2595
cristyf2faecf2010-05-28 19:19:36 +00002596 unsigned long
cristy3ed852e2009-09-05 21:47:34 +00002597 after,
2598 length;
2599
2600 /*
2601 Obtain response from primary selection.
2602 */
2603 if (event.xselection.property == (Atom) None)
2604 break;
2605 status=XGetWindowProperty(display,event.xselection.requestor,
cristyecd0ab52010-05-30 14:59:20 +00002606 event.xselection.property,0L,(long) MaxTextExtent,True,XA_STRING,
cristy3ed852e2009-09-05 21:47:34 +00002607 &type,&format,&length,&after,&data);
2608 if ((status != Success) || (type != XA_STRING) || (format == 32) ||
2609 (length == 0))
2610 break;
2611 /*
2612 Annotate Image window with primary selection.
2613 */
cristybb503372010-05-27 20:51:26 +00002614 for (i=0; i < (ssize_t) length; i++)
cristy3ed852e2009-09-05 21:47:34 +00002615 {
2616 if ((char) data[i] != '\n')
2617 {
2618 /*
2619 Draw a single character on the Image window.
2620 */
2621 *p=(char) data[i];
2622 (void) XDrawString(display,windows->image.id,annotate_context,
2623 x,y,p,1);
2624 x+=XTextWidth(font_info,p,1);
2625 p++;
2626 if ((x+font_info->max_bounds.width) < (int) windows->image.width)
2627 continue;
2628 }
2629 /*
2630 Advance to the next line of text.
2631 */
2632 *p='\0';
2633 annotate_info->width=(unsigned int) XTextWidth(font_info,
2634 annotate_info->text,(int) strlen(annotate_info->text));
2635 if (annotate_info->next != (XAnnotateInfo *) NULL)
2636 {
2637 /*
2638 Line of text already exists.
2639 */
2640 annotate_info=annotate_info->next;
2641 x=annotate_info->x;
2642 y=annotate_info->y;
2643 p=annotate_info->text;
2644 continue;
2645 }
2646 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory(
2647 sizeof(*annotate_info->next));
2648 if (annotate_info->next == (XAnnotateInfo *) NULL)
2649 return(MagickFalse);
2650 *annotate_info->next=(*annotate_info);
2651 annotate_info->next->previous=annotate_info;
2652 annotate_info=annotate_info->next;
2653 annotate_info->text=(char *) AcquireQuantumMemory((size_t)
cristy49e2d862010-11-12 02:50:30 +00002654 windows->image.width/MagickMax((ssize_t)
2655 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text));
cristy3ed852e2009-09-05 21:47:34 +00002656 if (annotate_info->text == (char *) NULL)
2657 return(MagickFalse);
2658 annotate_info->y+=annotate_info->height;
2659 if (annotate_info->y > (int) windows->image.height)
2660 annotate_info->y=(int) annotate_info->height;
2661 annotate_info->next=(XAnnotateInfo *) NULL;
2662 x=annotate_info->x;
2663 y=annotate_info->y;
2664 p=annotate_info->text;
2665 }
2666 (void) XFree((void *) data);
2667 break;
2668 }
2669 default:
2670 break;
2671 }
2672 } while ((state & ExitState) == 0);
2673 (void) XFreeCursor(display,cursor);
2674 /*
2675 Annotation is relative to image configuration.
2676 */
2677 width=(unsigned int) image->columns;
2678 height=(unsigned int) image->rows;
2679 x=0;
2680 y=0;
2681 if (windows->image.crop_geometry != (char *) NULL)
2682 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
2683 /*
2684 Initialize annotated image.
2685 */
2686 XSetCursorState(display,windows,MagickTrue);
2687 XCheckRefreshWindows(display,windows);
2688 while (annotate_info != (XAnnotateInfo *) NULL)
2689 {
2690 if (annotate_info->width == 0)
2691 {
2692 /*
2693 No text on this line-- go to the next line of text.
2694 */
2695 previous_info=annotate_info->previous;
2696 annotate_info->text=(char *)
2697 RelinquishMagickMemory(annotate_info->text);
2698 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
2699 annotate_info=previous_info;
2700 continue;
2701 }
2702 /*
2703 Determine pixel index for box and pen color.
2704 */
2705 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id];
2706 if (windows->pixel_info->colors != 0)
cristybb503372010-05-27 20:51:26 +00002707 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00002708 if (windows->pixel_info->pixels[i] ==
2709 windows->pixel_info->pen_colors[box_id].pixel)
2710 {
2711 windows->pixel_info->box_index=(unsigned short) i;
2712 break;
2713 }
2714 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
2715 if (windows->pixel_info->colors != 0)
cristybb503372010-05-27 20:51:26 +00002716 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00002717 if (windows->pixel_info->pixels[i] ==
2718 windows->pixel_info->pen_colors[pen_id].pixel)
2719 {
2720 windows->pixel_info->pen_index=(unsigned short) i;
2721 break;
2722 }
2723 /*
2724 Define the annotate geometry string.
2725 */
2726 annotate_info->x=(int)
2727 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width;
2728 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+
2729 windows->image.y)/windows->image.ximage->height;
cristyb51dff52011-05-19 16:55:47 +00002730 (void) FormatLocaleString(annotate_info->geometry,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00002731 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width,
2732 height*annotate_info->height/windows->image.ximage->height,
2733 annotate_info->x+x,annotate_info->y+y);
2734 /*
2735 Annotate image with text.
2736 */
cristy7c3af952011-10-20 16:04:16 +00002737 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image,
2738 exception);
cristy3ed852e2009-09-05 21:47:34 +00002739 if (status == 0)
2740 return(MagickFalse);
2741 /*
2742 Free up memory.
2743 */
2744 previous_info=annotate_info->previous;
2745 annotate_info->text=DestroyString(annotate_info->text);
2746 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
2747 annotate_info=previous_info;
2748 }
2749 (void) XSetForeground(display,annotate_context,
2750 windows->pixel_info->foreground_color.pixel);
2751 (void) XSetBackground(display,annotate_context,
2752 windows->pixel_info->background_color.pixel);
2753 (void) XSetFont(display,annotate_context,windows->font_info->fid);
2754 XSetCursorState(display,windows,MagickFalse);
2755 (void) XFreeFont(display,font_info);
2756 /*
2757 Update image configuration.
2758 */
cristy6710d842011-10-20 23:23:00 +00002759 XConfigureImageColormap(display,resource_info,windows,image,exception);
cristy051718b2011-08-28 22:49:25 +00002760 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00002761 return(MagickTrue);
2762}
2763
2764/*
2765%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2766% %
2767% %
2768% %
2769+ X B a c k g r o u n d I m a g e %
2770% %
2771% %
2772% %
2773%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2774%
2775% XBackgroundImage() displays the image in the background of a window.
2776%
2777% The format of the XBackgroundImage method is:
2778%
2779% MagickBooleanType XBackgroundImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00002780% XResourceInfo *resource_info,XWindows *windows,Image **image,
2781% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002782%
2783% A description of each parameter follows:
2784%
2785% o display: Specifies a connection to an X server; returned from
2786% XOpenDisplay.
2787%
2788% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2789%
2790% o windows: Specifies a pointer to a XWindows structure.
2791%
2792% o image: the image.
2793%
cristy051718b2011-08-28 22:49:25 +00002794% o exception: return any errors or warnings in this structure.
2795%
cristy3ed852e2009-09-05 21:47:34 +00002796*/
2797static MagickBooleanType XBackgroundImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00002798 XResourceInfo *resource_info,XWindows *windows,Image **image,
2799 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002800{
2801#define BackgroundImageTag "Background/Image"
2802
2803 int
2804 status;
2805
2806 static char
2807 window_id[MaxTextExtent] = "root";
2808
2809 XResourceInfo
2810 background_resources;
2811
2812 /*
2813 Put image in background.
2814 */
2815 status=XDialogWidget(display,windows,"Background",
2816 "Enter window id (id 0x00 selects window with pointer):",window_id);
2817 if (*window_id == '\0')
2818 return(MagickFalse);
cristy051718b2011-08-28 22:49:25 +00002819 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
2820 exception);
cristy3ed852e2009-09-05 21:47:34 +00002821 XInfoWidget(display,windows,BackgroundImageTag);
2822 XSetCursorState(display,windows,MagickTrue);
2823 XCheckRefreshWindows(display,windows);
2824 background_resources=(*resource_info);
2825 background_resources.window_id=window_id;
anthony11d32022012-11-17 05:31:33 +00002826 background_resources.backdrop=IsMagickTrue(status);
cristy051718b2011-08-28 22:49:25 +00002827 status=XDisplayBackgroundImage(display,&background_resources,*image,
2828 exception);
anthony11d32022012-11-17 05:31:33 +00002829 if (IfMagickTrue(status))
cristy3ed852e2009-09-05 21:47:34 +00002830 XClientMessage(display,windows->image.id,windows->im_protocols,
2831 windows->im_retain_colors,CurrentTime);
2832 XSetCursorState(display,windows,MagickFalse);
cristy051718b2011-08-28 22:49:25 +00002833 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image,
2834 exception);
cristy3ed852e2009-09-05 21:47:34 +00002835 return(MagickTrue);
2836}
2837
2838/*
2839%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2840% %
2841% %
2842% %
2843+ X C h o p I m a g e %
2844% %
2845% %
2846% %
2847%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2848%
2849% XChopImage() chops the X image.
2850%
2851% The format of the XChopImage method is:
2852%
2853% MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +00002854% XWindows *windows,Image **image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002855%
2856% A description of each parameter follows:
2857%
2858% o display: Specifies a connection to an X server; returned from
2859% XOpenDisplay.
2860%
2861% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
2862%
2863% o windows: Specifies a pointer to a XWindows structure.
2864%
2865% o image: the image.
2866%
cristy051718b2011-08-28 22:49:25 +00002867% o exception: return any errors or warnings in this structure.
2868%
cristy3ed852e2009-09-05 21:47:34 +00002869*/
2870static MagickBooleanType XChopImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00002871 XResourceInfo *resource_info,XWindows *windows,Image **image,
2872 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002873{
2874 static const char
2875 *ChopMenu[] =
2876 {
2877 "Direction",
2878 "Help",
2879 "Dismiss",
2880 (char *) NULL
2881 };
2882
2883 static ModeType
2884 direction = HorizontalChopCommand;
2885
2886 static const ModeType
2887 ChopCommands[] =
2888 {
2889 ChopDirectionCommand,
2890 ChopHelpCommand,
2891 ChopDismissCommand
2892 },
2893 DirectionCommands[] =
2894 {
2895 HorizontalChopCommand,
2896 VerticalChopCommand
2897 };
2898
2899 char
2900 text[MaxTextExtent];
2901
2902 Image
2903 *chop_image;
2904
2905 int
2906 id,
2907 x,
2908 y;
2909
cristya19f1d72012-08-07 18:24:38 +00002910 double
cristy3ed852e2009-09-05 21:47:34 +00002911 scale_factor;
2912
2913 RectangleInfo
2914 chop_info;
2915
2916 unsigned int
2917 distance,
2918 height,
2919 width;
2920
cristybb503372010-05-27 20:51:26 +00002921 size_t
cristy3ed852e2009-09-05 21:47:34 +00002922 state;
2923
2924 XEvent
2925 event;
2926
2927 XSegment
2928 segment_info;
2929
2930 /*
2931 Map Command widget.
2932 */
2933 (void) CloneString(&windows->command.name,"Chop");
2934 windows->command.data=1;
2935 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL);
2936 (void) XMapRaised(display,windows->command.id);
2937 XClientMessage(display,windows->image.id,windows->im_protocols,
2938 windows->im_update_widget,CurrentTime);
2939 /*
2940 Track pointer until button 1 is pressed.
2941 */
2942 XQueryPosition(display,windows->image.id,&x,&y);
2943 (void) XSelectInput(display,windows->image.id,
2944 windows->image.attributes.event_mask | PointerMotionMask);
2945 state=DefaultState;
2946 do
2947 {
anthony11d32022012-11-17 05:31:33 +00002948 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00002949 {
2950 /*
2951 Display pointer position.
2952 */
cristyb51dff52011-05-19 16:55:47 +00002953 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +00002954 x+windows->image.x,y+windows->image.y);
2955 XInfoWidget(display,windows,text);
2956 }
2957 /*
2958 Wait for next event.
2959 */
cristy6710d842011-10-20 23:23:00 +00002960 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00002961 if (event.xany.window == windows->command.id)
2962 {
2963 /*
2964 Select a command from the Command widget.
2965 */
2966 id=XCommandWidget(display,windows,ChopMenu,&event);
2967 if (id < 0)
2968 continue;
2969 switch (ChopCommands[id])
2970 {
2971 case ChopDirectionCommand:
2972 {
2973 char
2974 command[MaxTextExtent];
2975
2976 static const char
2977 *Directions[] =
2978 {
2979 "horizontal",
2980 "vertical",
2981 (char *) NULL,
2982 };
2983
2984 /*
2985 Select a command from the pop-up menu.
2986 */
2987 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command);
2988 if (id >= 0)
2989 direction=DirectionCommands[id];
2990 break;
2991 }
2992 case ChopHelpCommand:
2993 {
2994 XTextViewWidget(display,resource_info,windows,MagickFalse,
2995 "Help Viewer - Image Chop",ImageChopHelp);
2996 break;
2997 }
2998 case ChopDismissCommand:
2999 {
3000 /*
3001 Prematurely exit.
3002 */
3003 state|=EscapeState;
3004 state|=ExitState;
3005 break;
3006 }
3007 default:
3008 break;
3009 }
3010 continue;
3011 }
3012 switch (event.type)
3013 {
3014 case ButtonPress:
3015 {
3016 if (event.xbutton.button != Button1)
3017 break;
3018 if (event.xbutton.window != windows->image.id)
3019 break;
3020 /*
3021 User has committed to start point of chopping line.
3022 */
3023 segment_info.x1=(short int) event.xbutton.x;
3024 segment_info.x2=(short int) event.xbutton.x;
3025 segment_info.y1=(short int) event.xbutton.y;
3026 segment_info.y2=(short int) event.xbutton.y;
3027 state|=ExitState;
3028 break;
3029 }
3030 case ButtonRelease:
3031 break;
3032 case Expose:
3033 break;
3034 case KeyPress:
3035 {
3036 char
3037 command[MaxTextExtent];
3038
3039 KeySym
3040 key_symbol;
3041
3042 if (event.xkey.window != windows->image.id)
3043 break;
3044 /*
3045 Respond to a user key press.
3046 */
3047 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
3048 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
3049 switch ((int) key_symbol)
3050 {
3051 case XK_Escape:
3052 case XK_F20:
3053 {
3054 /*
3055 Prematurely exit.
3056 */
3057 state|=EscapeState;
3058 state|=ExitState;
3059 break;
3060 }
3061 case XK_F1:
3062 case XK_Help:
3063 {
3064 (void) XSetFunction(display,windows->image.highlight_context,
3065 GXcopy);
3066 XTextViewWidget(display,resource_info,windows,MagickFalse,
3067 "Help Viewer - Image Chop",ImageChopHelp);
3068 (void) XSetFunction(display,windows->image.highlight_context,
3069 GXinvert);
3070 break;
3071 }
3072 default:
3073 {
3074 (void) XBell(display,0);
3075 break;
3076 }
3077 }
3078 break;
3079 }
3080 case MotionNotify:
3081 {
3082 /*
3083 Map and unmap Info widget as text cursor crosses its boundaries.
3084 */
3085 x=event.xmotion.x;
3086 y=event.xmotion.y;
anthony11d32022012-11-17 05:31:33 +00003087 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00003088 {
3089 if ((x < (int) (windows->info.x+windows->info.width)) &&
3090 (y < (int) (windows->info.y+windows->info.height)))
3091 (void) XWithdrawWindow(display,windows->info.id,
3092 windows->info.screen);
3093 }
3094 else
3095 if ((x > (int) (windows->info.x+windows->info.width)) ||
3096 (y > (int) (windows->info.y+windows->info.height)))
3097 (void) XMapWindow(display,windows->info.id);
3098 }
3099 }
3100 } while ((state & ExitState) == 0);
3101 (void) XSelectInput(display,windows->image.id,
3102 windows->image.attributes.event_mask);
3103 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3104 if ((state & EscapeState) != 0)
3105 return(MagickTrue);
3106 /*
3107 Draw line as pointer moves until the mouse button is released.
3108 */
3109 chop_info.width=0;
3110 chop_info.height=0;
3111 chop_info.x=0;
3112 chop_info.y=0;
3113 distance=0;
3114 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
3115 state=DefaultState;
3116 do
3117 {
3118 if (distance > 9)
3119 {
3120 /*
3121 Display info and draw chopping line.
3122 */
anthony11d32022012-11-17 05:31:33 +00003123 if( IfMagickFalse(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00003124 (void) XMapWindow(display,windows->info.id);
cristyb51dff52011-05-19 16:55:47 +00003125 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +00003126 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +00003127 chop_info.height,(double) chop_info.x,(double) chop_info.y);
cristy3ed852e2009-09-05 21:47:34 +00003128 XInfoWidget(display,windows,text);
3129 XHighlightLine(display,windows->image.id,
3130 windows->image.highlight_context,&segment_info);
3131 }
3132 else
anthony11d32022012-11-17 05:31:33 +00003133 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00003134 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3135 /*
3136 Wait for next event.
3137 */
cristy6710d842011-10-20 23:23:00 +00003138 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00003139 if (distance > 9)
3140 XHighlightLine(display,windows->image.id,
3141 windows->image.highlight_context,&segment_info);
3142 switch (event.type)
3143 {
3144 case ButtonPress:
3145 {
3146 segment_info.x2=(short int) event.xmotion.x;
3147 segment_info.y2=(short int) event.xmotion.y;
3148 break;
3149 }
3150 case ButtonRelease:
3151 {
3152 /*
3153 User has committed to chopping line.
3154 */
3155 segment_info.x2=(short int) event.xbutton.x;
3156 segment_info.y2=(short int) event.xbutton.y;
3157 state|=ExitState;
3158 break;
3159 }
3160 case Expose:
3161 break;
3162 case MotionNotify:
3163 {
3164 segment_info.x2=(short int) event.xmotion.x;
3165 segment_info.y2=(short int) event.xmotion.y;
3166 }
3167 default:
3168 break;
3169 }
3170 /*
3171 Check boundary conditions.
3172 */
3173 if (segment_info.x2 < 0)
3174 segment_info.x2=0;
3175 else
3176 if (segment_info.x2 > windows->image.ximage->width)
3177 segment_info.x2=windows->image.ximage->width;
3178 if (segment_info.y2 < 0)
3179 segment_info.y2=0;
3180 else
3181 if (segment_info.y2 > windows->image.ximage->height)
3182 segment_info.y2=windows->image.ximage->height;
3183 distance=(unsigned int)
3184 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+
3185 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1)));
3186 /*
3187 Compute chopping geometry.
3188 */
3189 if (direction == HorizontalChopCommand)
3190 {
cristybb503372010-05-27 20:51:26 +00003191 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1);
cristy49e2d862010-11-12 02:50:30 +00003192 chop_info.x=(ssize_t) windows->image.x+segment_info.x1;
cristy3ed852e2009-09-05 21:47:34 +00003193 chop_info.height=0;
3194 chop_info.y=0;
3195 if (segment_info.x1 > (int) segment_info.x2)
3196 {
cristybb503372010-05-27 20:51:26 +00003197 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1);
cristy49e2d862010-11-12 02:50:30 +00003198 chop_info.x=(ssize_t) windows->image.x+segment_info.x2;
cristy3ed852e2009-09-05 21:47:34 +00003199 }
3200 }
3201 else
3202 {
3203 chop_info.width=0;
cristybb503372010-05-27 20:51:26 +00003204 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1);
cristy3ed852e2009-09-05 21:47:34 +00003205 chop_info.x=0;
cristy49e2d862010-11-12 02:50:30 +00003206 chop_info.y=(ssize_t) windows->image.y+segment_info.y1;
cristy3ed852e2009-09-05 21:47:34 +00003207 if (segment_info.y1 > segment_info.y2)
3208 {
cristy49e2d862010-11-12 02:50:30 +00003209 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1);
3210 chop_info.y=(ssize_t) windows->image.y+segment_info.y2;
cristy3ed852e2009-09-05 21:47:34 +00003211 }
3212 }
3213 } while ((state & ExitState) == 0);
3214 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
3215 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
3216 if (distance <= 9)
3217 return(MagickTrue);
3218 /*
3219 Image chopping is relative to image configuration.
3220 */
cristy051718b2011-08-28 22:49:25 +00003221 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
3222 exception);
cristy3ed852e2009-09-05 21:47:34 +00003223 XSetCursorState(display,windows,MagickTrue);
3224 XCheckRefreshWindows(display,windows);
3225 windows->image.window_changes.width=windows->image.ximage->width-
3226 (unsigned int) chop_info.width;
3227 windows->image.window_changes.height=windows->image.ximage->height-
3228 (unsigned int) chop_info.height;
3229 width=(unsigned int) (*image)->columns;
3230 height=(unsigned int) (*image)->rows;
3231 x=0;
3232 y=0;
3233 if (windows->image.crop_geometry != (char *) NULL)
3234 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
cristya19f1d72012-08-07 18:24:38 +00003235 scale_factor=(double) width/windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +00003236 chop_info.x+=x;
cristy49e2d862010-11-12 02:50:30 +00003237 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +00003238 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5);
cristya19f1d72012-08-07 18:24:38 +00003239 scale_factor=(double) height/windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +00003240 chop_info.y+=y;
cristy49e2d862010-11-12 02:50:30 +00003241 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +00003242 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5);
3243 /*
3244 Chop image.
3245 */
cristy051718b2011-08-28 22:49:25 +00003246 chop_image=ChopImage(*image,&chop_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00003247 XSetCursorState(display,windows,MagickFalse);
3248 if (chop_image == (Image *) NULL)
3249 return(MagickFalse);
3250 *image=DestroyImage(*image);
3251 *image=chop_image;
3252 /*
3253 Update image configuration.
3254 */
cristy6710d842011-10-20 23:23:00 +00003255 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00003256 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00003257 return(MagickTrue);
3258}
3259
3260/*
3261%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3262% %
3263% %
3264% %
3265+ X C o l o r E d i t I m a g e %
3266% %
3267% %
3268% %
3269%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3270%
3271% XColorEditImage() allows the user to interactively change the color of one
3272% pixel for a DirectColor image or one colormap entry for a PseudoClass image.
3273%
3274% The format of the XColorEditImage method is:
3275%
3276% MagickBooleanType XColorEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00003277% XResourceInfo *resource_info,XWindows *windows,Image **image,
3278% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003279%
3280% A description of each parameter follows:
3281%
3282% o display: Specifies a connection to an X server; returned from
3283% XOpenDisplay.
3284%
3285% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
3286%
3287% o windows: Specifies a pointer to a XWindows structure.
3288%
3289% o image: the image; returned from ReadImage.
3290%
cristy051718b2011-08-28 22:49:25 +00003291% o exception: return any errors or warnings in this structure.
3292%
cristy3ed852e2009-09-05 21:47:34 +00003293*/
cristy3ed852e2009-09-05 21:47:34 +00003294static MagickBooleanType XColorEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00003295 XResourceInfo *resource_info,XWindows *windows,Image **image,
3296 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003297{
3298 static const char
3299 *ColorEditMenu[] =
3300 {
3301 "Method",
3302 "Pixel Color",
3303 "Border Color",
3304 "Fuzz",
3305 "Undo",
3306 "Help",
3307 "Dismiss",
3308 (char *) NULL
3309 };
3310
3311 static const ModeType
3312 ColorEditCommands[] =
3313 {
3314 ColorEditMethodCommand,
3315 ColorEditColorCommand,
3316 ColorEditBorderCommand,
3317 ColorEditFuzzCommand,
3318 ColorEditUndoCommand,
3319 ColorEditHelpCommand,
3320 ColorEditDismissCommand
3321 };
3322
3323 static PaintMethod
3324 method = PointMethod;
3325
3326 static unsigned int
3327 pen_id = 0;
3328
3329 static XColor
3330 border_color = { 0, 0, 0, 0, 0, 0 };
3331
3332 char
3333 command[MaxTextExtent],
3334 text[MaxTextExtent];
3335
3336 Cursor
3337 cursor;
3338
cristy3ed852e2009-09-05 21:47:34 +00003339 int
3340 entry,
3341 id,
3342 x,
3343 x_offset,
3344 y,
3345 y_offset;
3346
cristy4c08aed2011-07-01 19:47:50 +00003347 register Quantum
cristy3ed852e2009-09-05 21:47:34 +00003348 *q;
3349
cristybb503372010-05-27 20:51:26 +00003350 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003351 i;
3352
3353 unsigned int
3354 height,
3355 width;
3356
cristybb503372010-05-27 20:51:26 +00003357 size_t
cristy3ed852e2009-09-05 21:47:34 +00003358 state;
3359
3360 XColor
3361 color;
3362
3363 XEvent
3364 event;
3365
3366 /*
3367 Map Command widget.
3368 */
3369 (void) CloneString(&windows->command.name,"Color Edit");
3370 windows->command.data=4;
3371 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL);
3372 (void) XMapRaised(display,windows->command.id);
3373 XClientMessage(display,windows->image.id,windows->im_protocols,
3374 windows->im_update_widget,CurrentTime);
3375 /*
3376 Make cursor.
3377 */
3378 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
3379 resource_info->background_color,resource_info->foreground_color);
3380 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3381 /*
3382 Track pointer until button 1 is pressed.
3383 */
3384 XQueryPosition(display,windows->image.id,&x,&y);
3385 (void) XSelectInput(display,windows->image.id,
3386 windows->image.attributes.event_mask | PointerMotionMask);
3387 state=DefaultState;
3388 do
3389 {
anthony11d32022012-11-17 05:31:33 +00003390 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00003391 {
3392 /*
3393 Display pointer position.
3394 */
cristyb51dff52011-05-19 16:55:47 +00003395 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +00003396 x+windows->image.x,y+windows->image.y);
3397 XInfoWidget(display,windows,text);
3398 }
3399 /*
3400 Wait for next event.
3401 */
cristy6710d842011-10-20 23:23:00 +00003402 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00003403 if (event.xany.window == windows->command.id)
3404 {
3405 /*
3406 Select a command from the Command widget.
3407 */
3408 id=XCommandWidget(display,windows,ColorEditMenu,&event);
3409 if (id < 0)
3410 {
3411 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3412 continue;
3413 }
3414 switch (ColorEditCommands[id])
3415 {
3416 case ColorEditMethodCommand:
3417 {
3418 char
3419 **methods;
3420
3421 /*
3422 Select a method from the pop-up menu.
3423 */
cristy042ee782011-04-22 18:48:30 +00003424 methods=(char **) GetCommandOptions(MagickMethodOptions);
cristy3ed852e2009-09-05 21:47:34 +00003425 if (methods == (char **) NULL)
3426 break;
3427 entry=XMenuWidget(display,windows,ColorEditMenu[id],
3428 (const char **) methods,command);
3429 if (entry >= 0)
cristy042ee782011-04-22 18:48:30 +00003430 method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
cristy3ed852e2009-09-05 21:47:34 +00003431 MagickFalse,methods[entry]);
3432 methods=DestroyStringList(methods);
3433 break;
3434 }
3435 case ColorEditColorCommand:
3436 {
3437 const char
3438 *ColorMenu[MaxNumberPens];
3439
3440 int
3441 pen_number;
3442
3443 /*
3444 Initialize menu selections.
3445 */
3446 for (i=0; i < (int) (MaxNumberPens-2); i++)
3447 ColorMenu[i]=resource_info->pen_colors[i];
3448 ColorMenu[MaxNumberPens-2]="Browser...";
3449 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
3450 /*
3451 Select a pen color from the pop-up menu.
3452 */
3453 pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
3454 (const char **) ColorMenu,command);
3455 if (pen_number < 0)
3456 break;
3457 if (pen_number == (MaxNumberPens-2))
3458 {
3459 static char
3460 color_name[MaxTextExtent] = "gray";
3461
3462 /*
3463 Select a pen color from a dialog.
3464 */
3465 resource_info->pen_colors[pen_number]=color_name;
3466 XColorBrowserWidget(display,windows,"Select",color_name);
3467 if (*color_name == '\0')
3468 break;
3469 }
3470 /*
3471 Set pen color.
3472 */
3473 (void) XParseColor(display,windows->map_info->colormap,
3474 resource_info->pen_colors[pen_number],&color);
3475 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
3476 (unsigned int) MaxColors,&color);
3477 windows->pixel_info->pen_colors[pen_number]=color;
3478 pen_id=(unsigned int) pen_number;
3479 break;
3480 }
3481 case ColorEditBorderCommand:
3482 {
3483 const char
3484 *ColorMenu[MaxNumberPens];
3485
3486 int
3487 pen_number;
3488
3489 /*
3490 Initialize menu selections.
3491 */
3492 for (i=0; i < (int) (MaxNumberPens-2); i++)
3493 ColorMenu[i]=resource_info->pen_colors[i];
3494 ColorMenu[MaxNumberPens-2]="Browser...";
3495 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
3496 /*
3497 Select a pen color from the pop-up menu.
3498 */
3499 pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
3500 (const char **) ColorMenu,command);
3501 if (pen_number < 0)
3502 break;
3503 if (pen_number == (MaxNumberPens-2))
3504 {
3505 static char
3506 color_name[MaxTextExtent] = "gray";
3507
3508 /*
3509 Select a pen color from a dialog.
3510 */
3511 resource_info->pen_colors[pen_number]=color_name;
3512 XColorBrowserWidget(display,windows,"Select",color_name);
3513 if (*color_name == '\0')
3514 break;
3515 }
3516 /*
3517 Set border color.
3518 */
3519 (void) XParseColor(display,windows->map_info->colormap,
3520 resource_info->pen_colors[pen_number],&border_color);
3521 break;
3522 }
3523 case ColorEditFuzzCommand:
3524 {
3525 static char
3526 fuzz[MaxTextExtent];
3527
3528 static const char
3529 *FuzzMenu[] =
3530 {
3531 "0%",
3532 "2%",
3533 "5%",
3534 "10%",
3535 "15%",
3536 "Dialog...",
3537 (char *) NULL,
3538 };
3539
3540 /*
3541 Select a command from the pop-up menu.
3542 */
3543 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu,
3544 command);
3545 if (entry < 0)
3546 break;
3547 if (entry != 5)
3548 {
cristydbdd0e32011-11-04 23:29:40 +00003549 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double)
cristy40a08ad2010-02-09 02:27:44 +00003550 QuantumRange+1.0);
cristy3ed852e2009-09-05 21:47:34 +00003551 break;
3552 }
3553 (void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent);
3554 (void) XDialogWidget(display,windows,"Ok",
3555 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
3556 if (*fuzz == '\0')
3557 break;
3558 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent);
cristy9b34e302011-11-05 02:15:45 +00003559 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+
3560 1.0);
cristy3ed852e2009-09-05 21:47:34 +00003561 break;
3562 }
3563 case ColorEditUndoCommand:
3564 {
3565 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
cristy051718b2011-08-28 22:49:25 +00003566 image,exception);
cristy3ed852e2009-09-05 21:47:34 +00003567 break;
3568 }
3569 case ColorEditHelpCommand:
3570 default:
3571 {
3572 XTextViewWidget(display,resource_info,windows,MagickFalse,
3573 "Help Viewer - Image Annotation",ImageColorEditHelp);
3574 break;
3575 }
3576 case ColorEditDismissCommand:
3577 {
3578 /*
3579 Prematurely exit.
3580 */
3581 state|=EscapeState;
3582 state|=ExitState;
3583 break;
3584 }
3585 }
3586 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3587 continue;
3588 }
3589 switch (event.type)
3590 {
3591 case ButtonPress:
3592 {
3593 if (event.xbutton.button != Button1)
3594 break;
3595 if ((event.xbutton.window != windows->image.id) &&
3596 (event.xbutton.window != windows->magnify.id))
3597 break;
3598 /*
3599 exit loop.
3600 */
3601 x=event.xbutton.x;
3602 y=event.xbutton.y;
3603 (void) XMagickCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +00003604 SaveToUndoBufferCommand,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00003605 state|=UpdateConfigurationState;
3606 break;
3607 }
3608 case ButtonRelease:
3609 {
3610 if (event.xbutton.button != Button1)
3611 break;
3612 if ((event.xbutton.window != windows->image.id) &&
3613 (event.xbutton.window != windows->magnify.id))
3614 break;
3615 /*
3616 Update colormap information.
3617 */
3618 x=event.xbutton.x;
3619 y=event.xbutton.y;
cristy6710d842011-10-20 23:23:00 +00003620 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00003621 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00003622 XInfoWidget(display,windows,text);
3623 (void) XCheckDefineCursor(display,windows->image.id,cursor);
3624 state&=(~UpdateConfigurationState);
3625 break;
3626 }
3627 case Expose:
3628 break;
3629 case KeyPress:
3630 {
3631 KeySym
3632 key_symbol;
3633
3634 if (event.xkey.window == windows->magnify.id)
3635 {
3636 Window
3637 window;
3638
3639 window=windows->magnify.id;
3640 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
3641 }
3642 if (event.xkey.window != windows->image.id)
3643 break;
3644 /*
3645 Respond to a user key press.
3646 */
3647 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
3648 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
3649 switch ((int) key_symbol)
3650 {
3651 case XK_Escape:
3652 case XK_F20:
3653 {
3654 /*
3655 Prematurely exit.
3656 */
3657 state|=ExitState;
3658 break;
3659 }
3660 case XK_F1:
3661 case XK_Help:
3662 {
3663 XTextViewWidget(display,resource_info,windows,MagickFalse,
3664 "Help Viewer - Image Annotation",ImageColorEditHelp);
3665 break;
3666 }
3667 default:
3668 {
3669 (void) XBell(display,0);
3670 break;
3671 }
3672 }
3673 break;
3674 }
3675 case MotionNotify:
3676 {
3677 /*
3678 Map and unmap Info widget as cursor crosses its boundaries.
3679 */
3680 x=event.xmotion.x;
3681 y=event.xmotion.y;
anthony11d32022012-11-17 05:31:33 +00003682 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00003683 {
3684 if ((x < (int) (windows->info.x+windows->info.width)) &&
3685 (y < (int) (windows->info.y+windows->info.height)))
3686 (void) XWithdrawWindow(display,windows->info.id,
3687 windows->info.screen);
3688 }
3689 else
3690 if ((x > (int) (windows->info.x+windows->info.width)) ||
3691 (y > (int) (windows->info.y+windows->info.height)))
3692 (void) XMapWindow(display,windows->info.id);
3693 break;
3694 }
3695 default:
3696 break;
3697 }
3698 if (event.xany.window == windows->magnify.id)
3699 {
3700 x=windows->magnify.x-windows->image.x;
3701 y=windows->magnify.y-windows->image.y;
3702 }
3703 x_offset=x;
3704 y_offset=y;
3705 if ((state & UpdateConfigurationState) != 0)
3706 {
cristy49e2d862010-11-12 02:50:30 +00003707 CacheView
3708 *image_view;
3709
cristy3ed852e2009-09-05 21:47:34 +00003710 int
3711 x,
3712 y;
3713
3714 /*
3715 Pixel edit is relative to image configuration.
3716 */
3717 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
3718 MagickTrue);
3719 color=windows->pixel_info->pen_colors[pen_id];
3720 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel);
3721 width=(unsigned int) (*image)->columns;
3722 height=(unsigned int) (*image)->rows;
3723 x=0;
3724 y=0;
3725 if (windows->image.crop_geometry != (char *) NULL)
3726 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
3727 &width,&height);
3728 x_offset=(int)
3729 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x);
3730 y_offset=(int)
3731 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y);
3732 if ((x_offset < 0) || (y_offset < 0))
3733 continue;
cristy49e2d862010-11-12 02:50:30 +00003734 if ((x_offset >= (int) (*image)->columns) ||
3735 (y_offset >= (int) (*image)->rows))
cristy3ed852e2009-09-05 21:47:34 +00003736 continue;
cristy6f5395d2012-12-14 18:30:30 +00003737 image_view=AcquireAuthenticCacheView(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00003738 switch (method)
3739 {
3740 case PointMethod:
3741 default:
3742 {
3743 /*
3744 Update color information using point algorithm.
3745 */
anthony11d32022012-11-17 05:31:33 +00003746 if( IfMagickFalse(SetImageStorageClass(*image,DirectClass,exception)) )
cristy3ed852e2009-09-05 21:47:34 +00003747 return(MagickFalse);
cristy49e2d862010-11-12 02:50:30 +00003748 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset,
cristy574cc262011-08-05 01:23:58 +00003749 (ssize_t) y_offset,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003750 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003751 break;
cristy4c08aed2011-07-01 19:47:50 +00003752 SetPixelRed(*image,ScaleShortToQuantum(color.red),q);
3753 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q);
3754 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q);
cristy051718b2011-08-28 22:49:25 +00003755 (void) SyncCacheViewAuthenticPixels(image_view,exception);
cristy3ed852e2009-09-05 21:47:34 +00003756 break;
3757 }
3758 case ReplaceMethod:
3759 {
cristy101ab702011-10-13 13:06:32 +00003760 PixelInfo
cristy4c08aed2011-07-01 19:47:50 +00003761 pixel,
cristy3ed852e2009-09-05 21:47:34 +00003762 target;
3763
3764 /*
3765 Update color information using replace algorithm.
3766 */
cristyf05d4942012-03-17 16:26:09 +00003767 (void) GetOneCacheViewVirtualPixelInfo(image_view,(ssize_t)
3768 x_offset,(ssize_t) y_offset,&target,exception);
cristy3ed852e2009-09-05 21:47:34 +00003769 if ((*image)->storage_class == DirectClass)
3770 {
cristy49e2d862010-11-12 02:50:30 +00003771 for (y=0; y < (int) (*image)->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003772 {
cristy49e2d862010-11-12 02:50:30 +00003773 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
3774 (*image)->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003775 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003776 break;
3777 for (x=0; x < (int) (*image)->columns; x++)
3778 {
cristy101ab702011-10-13 13:06:32 +00003779 GetPixelInfoPixel(*image,q,&pixel);
3780 if (IsFuzzyEquivalencePixelInfo(&pixel,&target))
cristy3ed852e2009-09-05 21:47:34 +00003781 {
cristy4c08aed2011-07-01 19:47:50 +00003782 SetPixelRed(*image,ScaleShortToQuantum(
3783 color.red),q);
3784 SetPixelGreen(*image,ScaleShortToQuantum(
3785 color.green),q);
3786 SetPixelBlue(*image,ScaleShortToQuantum(
3787 color.blue),q);
cristy3ed852e2009-09-05 21:47:34 +00003788 }
cristyed231572011-07-14 02:18:59 +00003789 q+=GetPixelChannels(*image);
cristy3ed852e2009-09-05 21:47:34 +00003790 }
anthony11d32022012-11-17 05:31:33 +00003791 if( IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) )
cristy3ed852e2009-09-05 21:47:34 +00003792 break;
3793 }
3794 }
3795 else
3796 {
cristy49e2d862010-11-12 02:50:30 +00003797 for (i=0; i < (ssize_t) (*image)->colors; i++)
cristy101ab702011-10-13 13:06:32 +00003798 if (IsFuzzyEquivalencePixelInfo((*image)->colormap+i,&target))
cristy3ed852e2009-09-05 21:47:34 +00003799 {
cristye42f6582012-02-11 17:59:50 +00003800 (*image)->colormap[i].red=(double) ScaleShortToQuantum(
cristy4c08aed2011-07-01 19:47:50 +00003801 color.red);
cristye42f6582012-02-11 17:59:50 +00003802 (*image)->colormap[i].green=(double) ScaleShortToQuantum(
cristy3ed852e2009-09-05 21:47:34 +00003803 color.green);
cristye42f6582012-02-11 17:59:50 +00003804 (*image)->colormap[i].blue=(double) ScaleShortToQuantum(
cristy3ed852e2009-09-05 21:47:34 +00003805 color.blue);
3806 }
cristyea1a8aa2011-10-20 13:24:06 +00003807 (void) SyncImage(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00003808 }
3809 break;
3810 }
3811 case FloodfillMethod:
3812 case FillToBorderMethod:
3813 {
3814 DrawInfo
3815 *draw_info;
3816
cristy4c08aed2011-07-01 19:47:50 +00003817 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +00003818 target;
3819
3820 /*
3821 Update color information using floodfill algorithm.
3822 */
cristy3aa93752011-12-18 15:54:24 +00003823 (void) GetOneVirtualPixelInfo(*image,
cristy52010022011-10-21 18:07:37 +00003824 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t)
3825 y_offset,&target,exception);
cristy3ed852e2009-09-05 21:47:34 +00003826 if (method == FillToBorderMethod)
3827 {
cristya19f1d72012-08-07 18:24:38 +00003828 target.red=(double)
cristy3ed852e2009-09-05 21:47:34 +00003829 ScaleShortToQuantum(border_color.red);
cristya19f1d72012-08-07 18:24:38 +00003830 target.green=(double)
cristy3ed852e2009-09-05 21:47:34 +00003831 ScaleShortToQuantum(border_color.green);
cristya19f1d72012-08-07 18:24:38 +00003832 target.blue=(double)
cristy3ed852e2009-09-05 21:47:34 +00003833 ScaleShortToQuantum(border_color.blue);
3834 }
3835 draw_info=CloneDrawInfo(resource_info->image_info,
3836 (DrawInfo *) NULL);
cristy9950d572011-10-01 18:22:35 +00003837 (void) QueryColorCompliance(resource_info->pen_colors[pen_id],
3838 AllCompliance,&draw_info->fill,exception);
anthony11d32022012-11-17 05:31:33 +00003839 (void) FloodfillPaintImage(*image,draw_info,&target,
3840 (ssize_t)x_offset,(ssize_t)y_offset,
3841 IsMagickFalse(method == FloodfillMethod),exception);
cristy3ed852e2009-09-05 21:47:34 +00003842 draw_info=DestroyDrawInfo(draw_info);
3843 break;
3844 }
3845 case ResetMethod:
3846 {
3847 /*
3848 Update color information using reset algorithm.
3849 */
anthony11d32022012-11-17 05:31:33 +00003850 if( IfMagickFalse(SetImageStorageClass(*image,DirectClass,exception)) )
cristy3ed852e2009-09-05 21:47:34 +00003851 return(MagickFalse);
cristy49e2d862010-11-12 02:50:30 +00003852 for (y=0; y < (int) (*image)->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003853 {
cristy49e2d862010-11-12 02:50:30 +00003854 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
3855 (*image)->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003856 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003857 break;
3858 for (x=0; x < (int) (*image)->columns; x++)
3859 {
cristy4c08aed2011-07-01 19:47:50 +00003860 SetPixelRed(*image,ScaleShortToQuantum(color.red),q);
3861 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q);
3862 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q);
cristyed231572011-07-14 02:18:59 +00003863 q+=GetPixelChannels(*image);
cristy3ed852e2009-09-05 21:47:34 +00003864 }
anthony11d32022012-11-17 05:31:33 +00003865 if( IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) )
cristy3ed852e2009-09-05 21:47:34 +00003866 break;
3867 }
3868 break;
3869 }
3870 }
cristy49e2d862010-11-12 02:50:30 +00003871 image_view=DestroyCacheView(image_view);
cristy3ed852e2009-09-05 21:47:34 +00003872 state&=(~UpdateConfigurationState);
3873 }
3874 } while ((state & ExitState) == 0);
3875 (void) XSelectInput(display,windows->image.id,
3876 windows->image.attributes.event_mask);
3877 XSetCursorState(display,windows,MagickFalse);
3878 (void) XFreeCursor(display,cursor);
3879 return(MagickTrue);
3880}
3881
3882/*
3883%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3884% %
3885% %
3886% %
3887+ X C o m p o s i t e I m a g e %
3888% %
3889% %
3890% %
3891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3892%
3893% XCompositeImage() requests an image name from the user, reads the image and
3894% composites it with the X window image at a location the user chooses with
3895% the pointer.
3896%
3897% The format of the XCompositeImage method is:
3898%
3899% MagickBooleanType XCompositeImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00003900% XResourceInfo *resource_info,XWindows *windows,Image *image,
3901% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003902%
3903% A description of each parameter follows:
3904%
3905% o display: Specifies a connection to an X server; returned from
3906% XOpenDisplay.
3907%
3908% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
3909%
3910% o windows: Specifies a pointer to a XWindows structure.
3911%
3912% o image: the image; returned from ReadImage.
3913%
cristy051718b2011-08-28 22:49:25 +00003914% o exception: return any errors or warnings in this structure.
3915%
cristy3ed852e2009-09-05 21:47:34 +00003916*/
3917static MagickBooleanType XCompositeImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00003918 XResourceInfo *resource_info,XWindows *windows,Image *image,
3919 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003920{
3921 static char
3922 displacement_geometry[MaxTextExtent] = "30x30",
3923 filename[MaxTextExtent] = "\0";
3924
3925 static const char
3926 *CompositeMenu[] =
3927 {
3928 "Operators",
3929 "Dissolve",
3930 "Displace",
3931 "Help",
3932 "Dismiss",
3933 (char *) NULL
3934 };
3935
3936 static CompositeOperator
3937 compose = CopyCompositeOp;
3938
3939 static const ModeType
3940 CompositeCommands[] =
3941 {
3942 CompositeOperatorsCommand,
3943 CompositeDissolveCommand,
3944 CompositeDisplaceCommand,
3945 CompositeHelpCommand,
3946 CompositeDismissCommand
3947 };
3948
3949 char
3950 text[MaxTextExtent];
3951
3952 Cursor
3953 cursor;
3954
3955 Image
3956 *composite_image;
3957
3958 int
3959 entry,
3960 id,
3961 x,
3962 y;
3963
cristya19f1d72012-08-07 18:24:38 +00003964 double
cristy3ed852e2009-09-05 21:47:34 +00003965 blend,
3966 scale_factor;
3967
3968 RectangleInfo
3969 highlight_info,
3970 composite_info;
3971
3972 unsigned int
3973 height,
3974 width;
3975
cristybb503372010-05-27 20:51:26 +00003976 size_t
cristy3ed852e2009-09-05 21:47:34 +00003977 state;
3978
3979 XEvent
3980 event;
3981
3982 /*
3983 Request image file name from user.
3984 */
3985 XFileBrowserWidget(display,windows,"Composite",filename);
3986 if (*filename == '\0')
3987 return(MagickTrue);
3988 /*
3989 Read image.
3990 */
3991 XSetCursorState(display,windows,MagickTrue);
3992 XCheckRefreshWindows(display,windows);
3993 (void) CopyMagickString(resource_info->image_info->filename,filename,
3994 MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00003995 composite_image=ReadImage(resource_info->image_info,exception);
3996 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00003997 XSetCursorState(display,windows,MagickFalse);
3998 if (composite_image == (Image *) NULL)
3999 return(MagickFalse);
4000 /*
4001 Map Command widget.
4002 */
4003 (void) CloneString(&windows->command.name,"Composite");
4004 windows->command.data=1;
4005 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL);
4006 (void) XMapRaised(display,windows->command.id);
4007 XClientMessage(display,windows->image.id,windows->im_protocols,
4008 windows->im_update_widget,CurrentTime);
4009 /*
4010 Track pointer until button 1 is pressed.
4011 */
4012 XQueryPosition(display,windows->image.id,&x,&y);
4013 (void) XSelectInput(display,windows->image.id,
4014 windows->image.attributes.event_mask | PointerMotionMask);
cristy49e2d862010-11-12 02:50:30 +00004015 composite_info.x=(ssize_t) windows->image.x+x;
4016 composite_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +00004017 composite_info.width=0;
4018 composite_info.height=0;
4019 cursor=XCreateFontCursor(display,XC_ul_angle);
4020 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
4021 blend=0.0;
4022 state=DefaultState;
4023 do
4024 {
anthony11d32022012-11-17 05:31:33 +00004025 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00004026 {
4027 /*
4028 Display pointer position.
4029 */
cristyb51dff52011-05-19 16:55:47 +00004030 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
cristyf2faecf2010-05-28 19:19:36 +00004031 (long) composite_info.x,(long) composite_info.y);
cristy3ed852e2009-09-05 21:47:34 +00004032 XInfoWidget(display,windows,text);
4033 }
4034 highlight_info=composite_info;
4035 highlight_info.x=composite_info.x-windows->image.x;
4036 highlight_info.y=composite_info.y-windows->image.y;
4037 XHighlightRectangle(display,windows->image.id,
4038 windows->image.highlight_context,&highlight_info);
4039 /*
4040 Wait for next event.
4041 */
cristy6710d842011-10-20 23:23:00 +00004042 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00004043 XHighlightRectangle(display,windows->image.id,
4044 windows->image.highlight_context,&highlight_info);
4045 if (event.xany.window == windows->command.id)
4046 {
4047 /*
4048 Select a command from the Command widget.
4049 */
4050 id=XCommandWidget(display,windows,CompositeMenu,&event);
4051 if (id < 0)
4052 continue;
4053 switch (CompositeCommands[id])
4054 {
4055 case CompositeOperatorsCommand:
4056 {
4057 char
4058 command[MaxTextExtent],
4059 **operators;
4060
4061 /*
4062 Select a command from the pop-up menu.
4063 */
cristy042ee782011-04-22 18:48:30 +00004064 operators=GetCommandOptions(MagickComposeOptions);
cristy3ed852e2009-09-05 21:47:34 +00004065 if (operators == (char **) NULL)
4066 break;
4067 entry=XMenuWidget(display,windows,CompositeMenu[id],
4068 (const char **) operators,command);
4069 if (entry >= 0)
cristy042ee782011-04-22 18:48:30 +00004070 compose=(CompositeOperator) ParseCommandOption(
cristy3ed852e2009-09-05 21:47:34 +00004071 MagickComposeOptions,MagickFalse,operators[entry]);
4072 operators=DestroyStringList(operators);
4073 break;
4074 }
4075 case CompositeDissolveCommand:
4076 {
4077 static char
4078 factor[MaxTextExtent] = "20.0";
4079
4080 /*
4081 Dissolve the two images a given percent.
4082 */
4083 (void) XSetFunction(display,windows->image.highlight_context,
4084 GXcopy);
4085 (void) XDialogWidget(display,windows,"Dissolve",
4086 "Enter the blend factor (0.0 - 99.9%):",factor);
4087 (void) XSetFunction(display,windows->image.highlight_context,
4088 GXinvert);
4089 if (*factor == '\0')
4090 break;
cristydbdd0e32011-11-04 23:29:40 +00004091 blend=StringToDouble(factor,(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004092 compose=DissolveCompositeOp;
4093 break;
4094 }
4095 case CompositeDisplaceCommand:
4096 {
4097 /*
4098 Get horizontal and vertical scale displacement geometry.
4099 */
4100 (void) XSetFunction(display,windows->image.highlight_context,
4101 GXcopy);
4102 (void) XDialogWidget(display,windows,"Displace",
4103 "Enter the horizontal and vertical scale:",displacement_geometry);
4104 (void) XSetFunction(display,windows->image.highlight_context,
4105 GXinvert);
4106 if (*displacement_geometry == '\0')
4107 break;
4108 compose=DisplaceCompositeOp;
4109 break;
4110 }
4111 case CompositeHelpCommand:
4112 {
4113 (void) XSetFunction(display,windows->image.highlight_context,
4114 GXcopy);
4115 XTextViewWidget(display,resource_info,windows,MagickFalse,
4116 "Help Viewer - Image Composite",ImageCompositeHelp);
4117 (void) XSetFunction(display,windows->image.highlight_context,
4118 GXinvert);
4119 break;
4120 }
4121 case CompositeDismissCommand:
4122 {
4123 /*
4124 Prematurely exit.
4125 */
4126 state|=EscapeState;
4127 state|=ExitState;
4128 break;
4129 }
4130 default:
4131 break;
4132 }
4133 continue;
4134 }
4135 switch (event.type)
4136 {
4137 case ButtonPress:
4138 {
anthony11d32022012-11-17 05:31:33 +00004139 if( IfMagickTrue(image->debug) )
cristy3ed852e2009-09-05 21:47:34 +00004140 (void) LogMagickEvent(X11Event,GetMagickModule(),
4141 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
4142 event.xbutton.button,event.xbutton.x,event.xbutton.y);
4143 if (event.xbutton.button != Button1)
4144 break;
4145 if (event.xbutton.window != windows->image.id)
4146 break;
4147 /*
4148 Change cursor.
4149 */
4150 composite_info.width=composite_image->columns;
4151 composite_info.height=composite_image->rows;
4152 (void) XCheckDefineCursor(display,windows->image.id,cursor);
cristy49e2d862010-11-12 02:50:30 +00004153 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4154 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +00004155 break;
4156 }
4157 case ButtonRelease:
4158 {
anthony11d32022012-11-17 05:31:33 +00004159 if( IfMagickTrue(image->debug) )
cristy3ed852e2009-09-05 21:47:34 +00004160 (void) LogMagickEvent(X11Event,GetMagickModule(),
4161 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
4162 event.xbutton.button,event.xbutton.x,event.xbutton.y);
4163 if (event.xbutton.button != Button1)
4164 break;
4165 if (event.xbutton.window != windows->image.id)
4166 break;
4167 if ((composite_info.width != 0) && (composite_info.height != 0))
4168 {
4169 /*
4170 User has selected the location of the composite image.
4171 */
cristy49e2d862010-11-12 02:50:30 +00004172 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4173 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +00004174 state|=ExitState;
4175 }
4176 break;
4177 }
4178 case Expose:
4179 break;
4180 case KeyPress:
4181 {
4182 char
4183 command[MaxTextExtent];
4184
4185 KeySym
4186 key_symbol;
4187
4188 int
4189 length;
4190
4191 if (event.xkey.window != windows->image.id)
4192 break;
4193 /*
4194 Respond to a user key press.
4195 */
4196 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
4197 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4198 *(command+length)='\0';
anthony11d32022012-11-17 05:31:33 +00004199 if( IfMagickTrue(image->debug) )
cristy3ed852e2009-09-05 21:47:34 +00004200 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristyf2faecf2010-05-28 19:19:36 +00004201 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command);
cristy3ed852e2009-09-05 21:47:34 +00004202 switch ((int) key_symbol)
4203 {
4204 case XK_Escape:
4205 case XK_F20:
4206 {
4207 /*
4208 Prematurely exit.
4209 */
4210 composite_image=DestroyImage(composite_image);
4211 state|=EscapeState;
4212 state|=ExitState;
4213 break;
4214 }
4215 case XK_F1:
4216 case XK_Help:
4217 {
4218 (void) XSetFunction(display,windows->image.highlight_context,
4219 GXcopy);
4220 XTextViewWidget(display,resource_info,windows,MagickFalse,
4221 "Help Viewer - Image Composite",ImageCompositeHelp);
4222 (void) XSetFunction(display,windows->image.highlight_context,
4223 GXinvert);
4224 break;
4225 }
4226 default:
4227 {
4228 (void) XBell(display,0);
4229 break;
4230 }
4231 }
4232 break;
4233 }
4234 case MotionNotify:
4235 {
4236 /*
4237 Map and unmap Info widget as text cursor crosses its boundaries.
4238 */
4239 x=event.xmotion.x;
4240 y=event.xmotion.y;
anthony11d32022012-11-17 05:31:33 +00004241 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00004242 {
4243 if ((x < (int) (windows->info.x+windows->info.width)) &&
4244 (y < (int) (windows->info.y+windows->info.height)))
4245 (void) XWithdrawWindow(display,windows->info.id,
4246 windows->info.screen);
4247 }
4248 else
4249 if ((x > (int) (windows->info.x+windows->info.width)) ||
4250 (y > (int) (windows->info.y+windows->info.height)))
4251 (void) XMapWindow(display,windows->info.id);
cristy49e2d862010-11-12 02:50:30 +00004252 composite_info.x=(ssize_t) windows->image.x+x;
4253 composite_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +00004254 break;
4255 }
4256 default:
4257 {
anthony11d32022012-11-17 05:31:33 +00004258 if( IfMagickTrue(image->debug) )
cristy3ed852e2009-09-05 21:47:34 +00004259 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
4260 event.type);
4261 break;
4262 }
4263 }
4264 } while ((state & ExitState) == 0);
4265 (void) XSelectInput(display,windows->image.id,
4266 windows->image.attributes.event_mask);
4267 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
4268 XSetCursorState(display,windows,MagickFalse);
4269 (void) XFreeCursor(display,cursor);
4270 if ((state & EscapeState) != 0)
4271 return(MagickTrue);
4272 /*
4273 Image compositing is relative to image configuration.
4274 */
4275 XSetCursorState(display,windows,MagickTrue);
4276 XCheckRefreshWindows(display,windows);
4277 width=(unsigned int) image->columns;
4278 height=(unsigned int) image->rows;
4279 x=0;
4280 y=0;
4281 if (windows->image.crop_geometry != (char *) NULL)
4282 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
cristya19f1d72012-08-07 18:24:38 +00004283 scale_factor=(double) width/windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +00004284 composite_info.x+=x;
cristy49e2d862010-11-12 02:50:30 +00004285 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +00004286 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5);
cristya19f1d72012-08-07 18:24:38 +00004287 scale_factor=(double) height/windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +00004288 composite_info.y+=y;
cristy49e2d862010-11-12 02:50:30 +00004289 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +00004290 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5);
4291 if ((composite_info.width != composite_image->columns) ||
4292 (composite_info.height != composite_image->rows))
4293 {
4294 Image
4295 *resize_image;
4296
4297 /*
4298 Scale composite image.
4299 */
cristy15b98cd2010-09-12 19:42:50 +00004300 resize_image=ResizeImage(composite_image,composite_info.width,
cristyaa2c16c2012-03-25 22:21:35 +00004301 composite_info.height,composite_image->filter,exception);
cristy3ed852e2009-09-05 21:47:34 +00004302 composite_image=DestroyImage(composite_image);
4303 if (resize_image == (Image *) NULL)
4304 {
4305 XSetCursorState(display,windows,MagickFalse);
4306 return(MagickFalse);
4307 }
4308 composite_image=resize_image;
4309 }
4310 if (compose == DisplaceCompositeOp)
4311 (void) SetImageArtifact(composite_image,"compose:args",
4312 displacement_geometry);
4313 if (blend != 0.0)
4314 {
cristy49e2d862010-11-12 02:50:30 +00004315 CacheView
4316 *image_view;
4317
cristy3ed852e2009-09-05 21:47:34 +00004318 int
4319 y;
4320
4321 Quantum
4322 opacity;
4323
4324 register int
4325 x;
4326
cristy4c08aed2011-07-01 19:47:50 +00004327 register Quantum
cristy3ed852e2009-09-05 21:47:34 +00004328 *q;
4329
4330 /*
4331 Create mattes for blending.
4332 */
cristy63240882011-08-05 19:05:27 +00004333 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel,exception);
cristy6e963d82012-06-19 15:23:24 +00004334 opacity=(Quantum) (ScaleQuantumToChar(QuantumRange)-
4335 ((ssize_t) ScaleQuantumToChar(QuantumRange)*blend)/100);
anthony11d32022012-11-17 05:31:33 +00004336 if( IfMagickFalse(SetImageStorageClass(image,DirectClass,exception)) )
cristy3ed852e2009-09-05 21:47:34 +00004337 return(MagickFalse);
cristy8a46d822012-08-28 23:32:39 +00004338 image->alpha_trait=BlendPixelTrait;
cristy46ff2672012-12-14 15:32:26 +00004339 image_view=AcquireAuthenticCacheView(image,exception);
cristy49e2d862010-11-12 02:50:30 +00004340 for (y=0; y < (int) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004341 {
cristy49e2d862010-11-12 02:50:30 +00004342 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1,
4343 exception);
cristy4c08aed2011-07-01 19:47:50 +00004344 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00004345 break;
4346 for (x=0; x < (int) image->columns; x++)
4347 {
cristy4c08aed2011-07-01 19:47:50 +00004348 SetPixelAlpha(image,opacity,q);
cristyed231572011-07-14 02:18:59 +00004349 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00004350 }
anthony11d32022012-11-17 05:31:33 +00004351 if( IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) )
cristy3ed852e2009-09-05 21:47:34 +00004352 break;
4353 }
cristy49e2d862010-11-12 02:50:30 +00004354 image_view=DestroyCacheView(image_view);
cristy3ed852e2009-09-05 21:47:34 +00004355 }
4356 /*
4357 Composite image with X Image window.
4358 */
cristy39172402012-03-30 13:04:39 +00004359 (void) CompositeImage(image,composite_image,compose,MagickTrue,
cristyfeb3e962012-03-29 17:25:55 +00004360 composite_info.x,composite_info.y,exception);
cristy3ed852e2009-09-05 21:47:34 +00004361 composite_image=DestroyImage(composite_image);
4362 XSetCursorState(display,windows,MagickFalse);
4363 /*
4364 Update image configuration.
4365 */
cristy6710d842011-10-20 23:23:00 +00004366 XConfigureImageColormap(display,resource_info,windows,image,exception);
cristy051718b2011-08-28 22:49:25 +00004367 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00004368 return(MagickTrue);
4369}
4370
4371/*
4372%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4373% %
4374% %
4375% %
4376+ X C o n f i g u r e I m a g e %
4377% %
4378% %
4379% %
4380%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4381%
4382% XConfigureImage() creates a new X image. It also notifies the window
4383% manager of the new image size and configures the transient widows.
4384%
4385% The format of the XConfigureImage method is:
4386%
4387% MagickBooleanType XConfigureImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00004388% XResourceInfo *resource_info,XWindows *windows,Image *image,
4389% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004390%
4391% A description of each parameter follows:
4392%
4393% o display: Specifies a connection to an X server; returned from
4394% XOpenDisplay.
4395%
4396% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
4397%
4398% o windows: Specifies a pointer to a XWindows structure.
4399%
4400% o image: the image.
4401%
cristy051718b2011-08-28 22:49:25 +00004402% o exception: return any errors or warnings in this structure.
4403%
4404% o exception: return any errors or warnings in this structure.
cristy3ed852e2009-09-05 21:47:34 +00004405%
4406*/
4407static MagickBooleanType XConfigureImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00004408 XResourceInfo *resource_info,XWindows *windows,Image *image,
4409 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004410{
4411 char
4412 geometry[MaxTextExtent];
4413
cristy3ed852e2009-09-05 21:47:34 +00004414 MagickStatusType
4415 status;
4416
cristybb503372010-05-27 20:51:26 +00004417 size_t
cristy3ed852e2009-09-05 21:47:34 +00004418 mask,
4419 height,
4420 width;
4421
cristy9d314ff2011-03-09 01:30:28 +00004422 ssize_t
4423 x,
4424 y;
4425
cristy3ed852e2009-09-05 21:47:34 +00004426 XSizeHints
4427 *size_hints;
4428
4429 XWindowChanges
4430 window_changes;
4431
4432 /*
4433 Dismiss if window dimensions are zero.
4434 */
4435 width=(unsigned int) windows->image.window_changes.width;
4436 height=(unsigned int) windows->image.window_changes.height;
anthony11d32022012-11-17 05:31:33 +00004437 if( IfMagickTrue(image->debug) )
cristy3ed852e2009-09-05 21:47:34 +00004438 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +00004439 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width,
4440 windows->image.ximage->height,(double) width,(double) height);
cristy3ed852e2009-09-05 21:47:34 +00004441 if ((width*height) == 0)
4442 return(MagickTrue);
4443 x=0;
4444 y=0;
4445 /*
4446 Resize image to fit Image window dimensions.
4447 */
4448 XSetCursorState(display,windows,MagickTrue);
4449 (void) XFlush(display);
4450 if (((int) width != windows->image.ximage->width) ||
4451 ((int) height != windows->image.ximage->height))
4452 image->taint=MagickTrue;
4453 windows->magnify.x=(int)
4454 width*windows->magnify.x/windows->image.ximage->width;
4455 windows->magnify.y=(int)
4456 height*windows->magnify.y/windows->image.ximage->height;
4457 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width);
4458 windows->image.y=(int)
4459 (height*windows->image.y/windows->image.ximage->height);
4460 status=XMakeImage(display,resource_info,&windows->image,image,
cristy051718b2011-08-28 22:49:25 +00004461 (unsigned int) width,(unsigned int) height,exception);
anthony11d32022012-11-17 05:31:33 +00004462 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00004463 XNoticeWidget(display,windows,"Unable to configure X image:",
4464 windows->image.name);
4465 /*
4466 Notify window manager of the new configuration.
4467 */
4468 if (resource_info->image_geometry != (char *) NULL)
cristyb51dff52011-05-19 16:55:47 +00004469 (void) FormatLocaleString(geometry,MaxTextExtent,"%s>!",
cristy3ed852e2009-09-05 21:47:34 +00004470 resource_info->image_geometry);
4471 else
cristyb51dff52011-05-19 16:55:47 +00004472 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!",
cristy3ed852e2009-09-05 21:47:34 +00004473 XDisplayWidth(display,windows->image.screen),
4474 XDisplayHeight(display,windows->image.screen));
4475 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
4476 window_changes.width=(int) width;
4477 if (window_changes.width > XDisplayWidth(display,windows->image.screen))
4478 window_changes.width=XDisplayWidth(display,windows->image.screen);
4479 window_changes.height=(int) height;
4480 if (window_changes.height > XDisplayHeight(display,windows->image.screen))
4481 window_changes.height=XDisplayHeight(display,windows->image.screen);
cristybb503372010-05-27 20:51:26 +00004482 mask=(size_t) (CWWidth | CWHeight);
cristy3ed852e2009-09-05 21:47:34 +00004483 if (resource_info->backdrop)
4484 {
4485 mask|=CWX | CWY;
4486 window_changes.x=(int)
4487 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2));
4488 window_changes.y=(int)
4489 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2));
4490 }
4491 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen,
4492 (unsigned int) mask,&window_changes);
4493 (void) XClearWindow(display,windows->image.id);
4494 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
4495 /*
4496 Update Magnify window configuration.
4497 */
anthony11d32022012-11-17 05:31:33 +00004498 if( IfMagickTrue(windows->magnify.mapped) )
cristy6710d842011-10-20 23:23:00 +00004499 XMakeMagnifyImage(display,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +00004500 windows->pan.crop_geometry=windows->image.crop_geometry;
4501 XBestIconSize(display,&windows->pan,image);
4502 while (((windows->pan.width << 1) < MaxIconSize) &&
4503 ((windows->pan.height << 1) < MaxIconSize))
4504 {
4505 windows->pan.width<<=1;
4506 windows->pan.height<<=1;
4507 }
4508 if (windows->pan.geometry != (char *) NULL)
4509 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
4510 &windows->pan.width,&windows->pan.height);
4511 window_changes.width=(int) windows->pan.width;
4512 window_changes.height=(int) windows->pan.height;
4513 size_hints=XAllocSizeHints();
4514 if (size_hints != (XSizeHints *) NULL)
4515 {
4516 /*
4517 Set new size hints.
4518 */
4519 size_hints->flags=PSize | PMinSize | PMaxSize;
4520 size_hints->width=window_changes.width;
4521 size_hints->height=window_changes.height;
4522 size_hints->min_width=size_hints->width;
4523 size_hints->min_height=size_hints->height;
4524 size_hints->max_width=size_hints->width;
4525 size_hints->max_height=size_hints->height;
4526 (void) XSetNormalHints(display,windows->pan.id,size_hints);
4527 (void) XFree((void *) size_hints);
4528 }
4529 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen,
4530 (unsigned int) (CWWidth | CWHeight),&window_changes);
4531 /*
4532 Update icon window configuration.
4533 */
4534 windows->icon.crop_geometry=windows->image.crop_geometry;
4535 XBestIconSize(display,&windows->icon,image);
4536 window_changes.width=(int) windows->icon.width;
4537 window_changes.height=(int) windows->icon.height;
4538 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen,
4539 (unsigned int) (CWWidth | CWHeight),&window_changes);
4540 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00004541 return(IsMagickTrue(status));
cristy3ed852e2009-09-05 21:47:34 +00004542}
4543
4544/*
4545%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4546% %
4547% %
4548% %
4549+ X C r o p I m a g e %
4550% %
4551% %
4552% %
4553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4554%
4555% XCropImage() allows the user to select a region of the image and crop, copy,
4556% or cut it. For copy or cut, the image can subsequently be composited onto
4557% the image with XPasteImage.
4558%
4559% The format of the XCropImage method is:
4560%
4561% MagickBooleanType XCropImage(Display *display,
4562% XResourceInfo *resource_info,XWindows *windows,Image *image,
cristy051718b2011-08-28 22:49:25 +00004563% const ClipboardMode mode,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004564%
4565% A description of each parameter follows:
4566%
4567% o display: Specifies a connection to an X server; returned from
4568% XOpenDisplay.
4569%
4570% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
4571%
4572% o windows: Specifies a pointer to a XWindows structure.
4573%
4574% o image: the image; returned from ReadImage.
4575%
4576% o mode: This unsigned value specified whether the image should be
4577% cropped, copied, or cut.
4578%
cristy051718b2011-08-28 22:49:25 +00004579% o exception: return any errors or warnings in this structure.
4580%
cristy3ed852e2009-09-05 21:47:34 +00004581*/
4582static MagickBooleanType XCropImage(Display *display,
4583 XResourceInfo *resource_info,XWindows *windows,Image *image,
cristy051718b2011-08-28 22:49:25 +00004584 const ClipboardMode mode,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004585{
4586 static const char
4587 *CropModeMenu[] =
4588 {
4589 "Help",
4590 "Dismiss",
4591 (char *) NULL
4592 },
4593 *RectifyModeMenu[] =
4594 {
4595 "Crop",
4596 "Help",
4597 "Dismiss",
4598 (char *) NULL
4599 };
4600
4601 static const ModeType
4602 CropCommands[] =
4603 {
4604 CropHelpCommand,
4605 CropDismissCommand
4606 },
4607 RectifyCommands[] =
4608 {
4609 RectifyCopyCommand,
4610 RectifyHelpCommand,
4611 RectifyDismissCommand
4612 };
4613
cristy49e2d862010-11-12 02:50:30 +00004614 CacheView
4615 *image_view;
4616
cristy3ed852e2009-09-05 21:47:34 +00004617 char
4618 command[MaxTextExtent],
4619 text[MaxTextExtent];
4620
4621 Cursor
4622 cursor;
4623
cristy3ed852e2009-09-05 21:47:34 +00004624 int
4625 id,
4626 x,
4627 y;
4628
4629 KeySym
4630 key_symbol;
4631
4632 Image
4633 *crop_image;
4634
cristya19f1d72012-08-07 18:24:38 +00004635 double
cristy3ed852e2009-09-05 21:47:34 +00004636 scale_factor;
4637
4638 RectangleInfo
4639 crop_info,
4640 highlight_info;
4641
cristy4c08aed2011-07-01 19:47:50 +00004642 register Quantum
cristy3ed852e2009-09-05 21:47:34 +00004643 *q;
4644
4645 unsigned int
4646 height,
4647 width;
4648
cristybb503372010-05-27 20:51:26 +00004649 size_t
cristy3ed852e2009-09-05 21:47:34 +00004650 state;
4651
4652 XEvent
4653 event;
4654
4655 /*
4656 Map Command widget.
4657 */
4658 switch (mode)
4659 {
4660 case CopyMode:
4661 {
4662 (void) CloneString(&windows->command.name,"Copy");
4663 break;
4664 }
4665 case CropMode:
4666 {
4667 (void) CloneString(&windows->command.name,"Crop");
4668 break;
4669 }
4670 case CutMode:
4671 {
4672 (void) CloneString(&windows->command.name,"Cut");
4673 break;
4674 }
4675 }
4676 RectifyModeMenu[0]=windows->command.name;
4677 windows->command.data=0;
4678 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL);
4679 (void) XMapRaised(display,windows->command.id);
4680 XClientMessage(display,windows->image.id,windows->im_protocols,
4681 windows->im_update_widget,CurrentTime);
4682 /*
4683 Track pointer until button 1 is pressed.
4684 */
4685 XQueryPosition(display,windows->image.id,&x,&y);
4686 (void) XSelectInput(display,windows->image.id,
4687 windows->image.attributes.event_mask | PointerMotionMask);
cristy49e2d862010-11-12 02:50:30 +00004688 crop_info.x=(ssize_t) windows->image.x+x;
4689 crop_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +00004690 crop_info.width=0;
4691 crop_info.height=0;
4692 cursor=XCreateFontCursor(display,XC_fleur);
4693 state=DefaultState;
4694 do
4695 {
anthony11d32022012-11-17 05:31:33 +00004696 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00004697 {
4698 /*
4699 Display pointer position.
4700 */
cristyb51dff52011-05-19 16:55:47 +00004701 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
cristyf2faecf2010-05-28 19:19:36 +00004702 (long) crop_info.x,(long) crop_info.y);
cristy3ed852e2009-09-05 21:47:34 +00004703 XInfoWidget(display,windows,text);
4704 }
4705 /*
4706 Wait for next event.
4707 */
cristy6710d842011-10-20 23:23:00 +00004708 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00004709 if (event.xany.window == windows->command.id)
4710 {
4711 /*
4712 Select a command from the Command widget.
4713 */
4714 id=XCommandWidget(display,windows,CropModeMenu,&event);
4715 if (id < 0)
4716 continue;
4717 switch (CropCommands[id])
4718 {
4719 case CropHelpCommand:
4720 {
4721 switch (mode)
4722 {
4723 case CopyMode:
4724 {
4725 XTextViewWidget(display,resource_info,windows,MagickFalse,
4726 "Help Viewer - Image Copy",ImageCopyHelp);
4727 break;
4728 }
4729 case CropMode:
4730 {
4731 XTextViewWidget(display,resource_info,windows,MagickFalse,
4732 "Help Viewer - Image Crop",ImageCropHelp);
4733 break;
4734 }
4735 case CutMode:
4736 {
4737 XTextViewWidget(display,resource_info,windows,MagickFalse,
4738 "Help Viewer - Image Cut",ImageCutHelp);
4739 break;
4740 }
4741 }
4742 break;
4743 }
4744 case CropDismissCommand:
4745 {
4746 /*
4747 Prematurely exit.
4748 */
4749 state|=EscapeState;
4750 state|=ExitState;
4751 break;
4752 }
4753 default:
4754 break;
4755 }
4756 continue;
4757 }
4758 switch (event.type)
4759 {
4760 case ButtonPress:
4761 {
4762 if (event.xbutton.button != Button1)
4763 break;
4764 if (event.xbutton.window != windows->image.id)
4765 break;
4766 /*
4767 Note first corner of cropping rectangle-- exit loop.
4768 */
4769 (void) XCheckDefineCursor(display,windows->image.id,cursor);
cristy49e2d862010-11-12 02:50:30 +00004770 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4771 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +00004772 state|=ExitState;
4773 break;
4774 }
4775 case ButtonRelease:
4776 break;
4777 case Expose:
4778 break;
4779 case KeyPress:
4780 {
4781 if (event.xkey.window != windows->image.id)
4782 break;
4783 /*
4784 Respond to a user key press.
4785 */
4786 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
4787 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
4788 switch ((int) key_symbol)
4789 {
4790 case XK_Escape:
4791 case XK_F20:
4792 {
4793 /*
4794 Prematurely exit.
4795 */
4796 state|=EscapeState;
4797 state|=ExitState;
4798 break;
4799 }
4800 case XK_F1:
4801 case XK_Help:
4802 {
4803 switch (mode)
4804 {
4805 case CopyMode:
4806 {
4807 XTextViewWidget(display,resource_info,windows,MagickFalse,
4808 "Help Viewer - Image Copy",ImageCopyHelp);
4809 break;
4810 }
4811 case CropMode:
4812 {
4813 XTextViewWidget(display,resource_info,windows,MagickFalse,
4814 "Help Viewer - Image Crop",ImageCropHelp);
4815 break;
4816 }
4817 case CutMode:
4818 {
4819 XTextViewWidget(display,resource_info,windows,MagickFalse,
4820 "Help Viewer - Image Cut",ImageCutHelp);
4821 break;
4822 }
4823 }
4824 break;
4825 }
4826 default:
4827 {
4828 (void) XBell(display,0);
4829 break;
4830 }
4831 }
4832 break;
4833 }
4834 case MotionNotify:
4835 {
4836 if (event.xmotion.window != windows->image.id)
4837 break;
4838 /*
4839 Map and unmap Info widget as text cursor crosses its boundaries.
4840 */
4841 x=event.xmotion.x;
4842 y=event.xmotion.y;
anthony11d32022012-11-17 05:31:33 +00004843 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00004844 {
4845 if ((x < (int) (windows->info.x+windows->info.width)) &&
4846 (y < (int) (windows->info.y+windows->info.height)))
4847 (void) XWithdrawWindow(display,windows->info.id,
4848 windows->info.screen);
4849 }
4850 else
4851 if ((x > (int) (windows->info.x+windows->info.width)) ||
4852 (y > (int) (windows->info.y+windows->info.height)))
4853 (void) XMapWindow(display,windows->info.id);
cristy49e2d862010-11-12 02:50:30 +00004854 crop_info.x=(ssize_t) windows->image.x+x;
4855 crop_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +00004856 break;
4857 }
4858 default:
4859 break;
4860 }
4861 } while ((state & ExitState) == 0);
4862 (void) XSelectInput(display,windows->image.id,
4863 windows->image.attributes.event_mask);
4864 if ((state & EscapeState) != 0)
4865 {
4866 /*
4867 User want to exit without cropping.
4868 */
4869 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
4870 (void) XFreeCursor(display,cursor);
4871 return(MagickTrue);
4872 }
4873 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
4874 do
4875 {
4876 /*
4877 Size rectangle as pointer moves until the mouse button is released.
4878 */
4879 x=(int) crop_info.x;
4880 y=(int) crop_info.y;
4881 crop_info.width=0;
4882 crop_info.height=0;
4883 state=DefaultState;
4884 do
4885 {
4886 highlight_info=crop_info;
4887 highlight_info.x=crop_info.x-windows->image.x;
4888 highlight_info.y=crop_info.y-windows->image.y;
4889 if ((highlight_info.width > 3) && (highlight_info.height > 3))
4890 {
4891 /*
4892 Display info and draw cropping rectangle.
4893 */
anthony11d32022012-11-17 05:31:33 +00004894 if( IfMagickFalse(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00004895 (void) XMapWindow(display,windows->info.id);
cristyb51dff52011-05-19 16:55:47 +00004896 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +00004897 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +00004898 crop_info.height,(double) crop_info.x,(double) crop_info.y);
cristy3ed852e2009-09-05 21:47:34 +00004899 XInfoWidget(display,windows,text);
4900 XHighlightRectangle(display,windows->image.id,
4901 windows->image.highlight_context,&highlight_info);
4902 }
4903 else
anthony11d32022012-11-17 05:31:33 +00004904 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00004905 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
4906 /*
4907 Wait for next event.
4908 */
cristy6710d842011-10-20 23:23:00 +00004909 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00004910 if ((highlight_info.width > 3) && (highlight_info.height > 3))
4911 XHighlightRectangle(display,windows->image.id,
4912 windows->image.highlight_context,&highlight_info);
4913 switch (event.type)
4914 {
4915 case ButtonPress:
4916 {
cristy49e2d862010-11-12 02:50:30 +00004917 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4918 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +00004919 break;
4920 }
4921 case ButtonRelease:
4922 {
4923 /*
4924 User has committed to cropping rectangle.
4925 */
cristy49e2d862010-11-12 02:50:30 +00004926 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
4927 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +00004928 XSetCursorState(display,windows,MagickFalse);
4929 state|=ExitState;
4930 windows->command.data=0;
4931 (void) XCommandWidget(display,windows,RectifyModeMenu,
4932 (XEvent *) NULL);
4933 break;
4934 }
4935 case Expose:
4936 break;
4937 case MotionNotify:
4938 {
cristy49e2d862010-11-12 02:50:30 +00004939 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x;
4940 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y;
cristy3ed852e2009-09-05 21:47:34 +00004941 }
4942 default:
4943 break;
4944 }
4945 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) ||
4946 ((state & ExitState) != 0))
4947 {
4948 /*
4949 Check boundary conditions.
4950 */
4951 if (crop_info.x < 0)
4952 crop_info.x=0;
4953 else
cristy49e2d862010-11-12 02:50:30 +00004954 if (crop_info.x > (ssize_t) windows->image.ximage->width)
4955 crop_info.x=(ssize_t) windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +00004956 if ((int) crop_info.x < x)
4957 crop_info.width=(unsigned int) (x-crop_info.x);
4958 else
4959 {
4960 crop_info.width=(unsigned int) (crop_info.x-x);
cristy49e2d862010-11-12 02:50:30 +00004961 crop_info.x=(ssize_t) x;
cristy3ed852e2009-09-05 21:47:34 +00004962 }
4963 if (crop_info.y < 0)
4964 crop_info.y=0;
4965 else
cristy49e2d862010-11-12 02:50:30 +00004966 if (crop_info.y > (ssize_t) windows->image.ximage->height)
4967 crop_info.y=(ssize_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +00004968 if ((int) crop_info.y < y)
4969 crop_info.height=(unsigned int) (y-crop_info.y);
4970 else
4971 {
4972 crop_info.height=(unsigned int) (crop_info.y-y);
cristy49e2d862010-11-12 02:50:30 +00004973 crop_info.y=(ssize_t) y;
cristy3ed852e2009-09-05 21:47:34 +00004974 }
4975 }
4976 } while ((state & ExitState) == 0);
4977 /*
4978 Wait for user to grab a corner of the rectangle or press return.
4979 */
4980 state=DefaultState;
4981 (void) XMapWindow(display,windows->info.id);
4982 do
4983 {
anthony11d32022012-11-17 05:31:33 +00004984 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00004985 {
4986 /*
4987 Display pointer position.
4988 */
cristyb51dff52011-05-19 16:55:47 +00004989 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +00004990 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +00004991 crop_info.height,(double) crop_info.x,(double) crop_info.y);
cristy3ed852e2009-09-05 21:47:34 +00004992 XInfoWidget(display,windows,text);
4993 }
4994 highlight_info=crop_info;
4995 highlight_info.x=crop_info.x-windows->image.x;
4996 highlight_info.y=crop_info.y-windows->image.y;
4997 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
4998 {
4999 state|=EscapeState;
5000 state|=ExitState;
5001 break;
5002 }
5003 XHighlightRectangle(display,windows->image.id,
5004 windows->image.highlight_context,&highlight_info);
cristy6710d842011-10-20 23:23:00 +00005005 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00005006 if (event.xany.window == windows->command.id)
5007 {
5008 /*
5009 Select a command from the Command widget.
5010 */
5011 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
5012 id=XCommandWidget(display,windows,RectifyModeMenu,&event);
5013 (void) XSetFunction(display,windows->image.highlight_context,
5014 GXinvert);
5015 XHighlightRectangle(display,windows->image.id,
5016 windows->image.highlight_context,&highlight_info);
5017 if (id >= 0)
5018 switch (RectifyCommands[id])
5019 {
5020 case RectifyCopyCommand:
5021 {
5022 state|=ExitState;
5023 break;
5024 }
5025 case RectifyHelpCommand:
5026 {
5027 (void) XSetFunction(display,windows->image.highlight_context,
5028 GXcopy);
5029 switch (mode)
5030 {
5031 case CopyMode:
5032 {
5033 XTextViewWidget(display,resource_info,windows,MagickFalse,
5034 "Help Viewer - Image Copy",ImageCopyHelp);
5035 break;
5036 }
5037 case CropMode:
5038 {
5039 XTextViewWidget(display,resource_info,windows,MagickFalse,
5040 "Help Viewer - Image Crop",ImageCropHelp);
5041 break;
5042 }
5043 case CutMode:
5044 {
5045 XTextViewWidget(display,resource_info,windows,MagickFalse,
5046 "Help Viewer - Image Cut",ImageCutHelp);
5047 break;
5048 }
5049 }
5050 (void) XSetFunction(display,windows->image.highlight_context,
5051 GXinvert);
5052 break;
5053 }
5054 case RectifyDismissCommand:
5055 {
5056 /*
5057 Prematurely exit.
5058 */
5059 state|=EscapeState;
5060 state|=ExitState;
5061 break;
5062 }
5063 default:
5064 break;
5065 }
5066 continue;
5067 }
5068 XHighlightRectangle(display,windows->image.id,
5069 windows->image.highlight_context,&highlight_info);
5070 switch (event.type)
5071 {
5072 case ButtonPress:
5073 {
5074 if (event.xbutton.button != Button1)
5075 break;
5076 if (event.xbutton.window != windows->image.id)
5077 break;
5078 x=windows->image.x+event.xbutton.x;
5079 y=windows->image.y+event.xbutton.y;
5080 if ((x < (int) (crop_info.x+RoiDelta)) &&
5081 (x > (int) (crop_info.x-RoiDelta)) &&
5082 (y < (int) (crop_info.y+RoiDelta)) &&
5083 (y > (int) (crop_info.y-RoiDelta)))
5084 {
cristybb503372010-05-27 20:51:26 +00005085 crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
5086 crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
cristy3ed852e2009-09-05 21:47:34 +00005087 state|=UpdateConfigurationState;
5088 break;
5089 }
5090 if ((x < (int) (crop_info.x+RoiDelta)) &&
5091 (x > (int) (crop_info.x-RoiDelta)) &&
5092 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
5093 (y > (int) (crop_info.y+crop_info.height-RoiDelta)))
5094 {
cristybb503372010-05-27 20:51:26 +00005095 crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
cristy3ed852e2009-09-05 21:47:34 +00005096 state|=UpdateConfigurationState;
5097 break;
5098 }
5099 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
5100 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
5101 (y < (int) (crop_info.y+RoiDelta)) &&
5102 (y > (int) (crop_info.y-RoiDelta)))
5103 {
cristybb503372010-05-27 20:51:26 +00005104 crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
cristy3ed852e2009-09-05 21:47:34 +00005105 state|=UpdateConfigurationState;
5106 break;
5107 }
5108 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
5109 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
5110 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
5111 (y > (int) (crop_info.y+crop_info.height-RoiDelta)))
5112 {
5113 state|=UpdateConfigurationState;
5114 break;
5115 }
5116 }
5117 case ButtonRelease:
5118 {
5119 if (event.xbutton.window == windows->pan.id)
5120 if ((highlight_info.x != crop_info.x-windows->image.x) ||
5121 (highlight_info.y != crop_info.y-windows->image.y))
5122 XHighlightRectangle(display,windows->image.id,
5123 windows->image.highlight_context,&highlight_info);
5124 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
5125 event.xbutton.time);
5126 break;
5127 }
5128 case Expose:
5129 {
5130 if (event.xexpose.window == windows->image.id)
5131 if (event.xexpose.count == 0)
5132 {
5133 event.xexpose.x=(int) highlight_info.x;
5134 event.xexpose.y=(int) highlight_info.y;
5135 event.xexpose.width=(int) highlight_info.width;
5136 event.xexpose.height=(int) highlight_info.height;
5137 XRefreshWindow(display,&windows->image,&event);
5138 }
5139 if (event.xexpose.window == windows->info.id)
5140 if (event.xexpose.count == 0)
5141 XInfoWidget(display,windows,text);
5142 break;
5143 }
5144 case KeyPress:
5145 {
5146 if (event.xkey.window != windows->image.id)
5147 break;
5148 /*
5149 Respond to a user key press.
5150 */
5151 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
5152 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5153 switch ((int) key_symbol)
5154 {
5155 case XK_Escape:
5156 case XK_F20:
5157 state|=EscapeState;
5158 case XK_Return:
5159 {
5160 state|=ExitState;
5161 break;
5162 }
5163 case XK_Home:
5164 case XK_KP_Home:
5165 {
cristy49e2d862010-11-12 02:50:30 +00005166 crop_info.x=(ssize_t) (windows->image.width/2L-
5167 crop_info.width/2L);
5168 crop_info.y=(ssize_t) (windows->image.height/2L-
5169 crop_info.height/2L);
cristy3ed852e2009-09-05 21:47:34 +00005170 break;
5171 }
5172 case XK_Left:
5173 case XK_KP_Left:
5174 {
5175 crop_info.x--;
5176 break;
5177 }
5178 case XK_Up:
5179 case XK_KP_Up:
5180 case XK_Next:
5181 {
5182 crop_info.y--;
5183 break;
5184 }
5185 case XK_Right:
5186 case XK_KP_Right:
5187 {
5188 crop_info.x++;
5189 break;
5190 }
5191 case XK_Prior:
5192 case XK_Down:
5193 case XK_KP_Down:
5194 {
5195 crop_info.y++;
5196 break;
5197 }
5198 case XK_F1:
5199 case XK_Help:
5200 {
5201 (void) XSetFunction(display,windows->image.highlight_context,
5202 GXcopy);
5203 switch (mode)
5204 {
5205 case CopyMode:
5206 {
5207 XTextViewWidget(display,resource_info,windows,MagickFalse,
5208 "Help Viewer - Image Copy",ImageCopyHelp);
5209 break;
5210 }
5211 case CropMode:
5212 {
5213 XTextViewWidget(display,resource_info,windows,MagickFalse,
5214 "Help Viewer - Image Cropg",ImageCropHelp);
5215 break;
5216 }
5217 case CutMode:
5218 {
5219 XTextViewWidget(display,resource_info,windows,MagickFalse,
5220 "Help Viewer - Image Cutg",ImageCutHelp);
5221 break;
5222 }
5223 }
5224 (void) XSetFunction(display,windows->image.highlight_context,
5225 GXinvert);
5226 break;
5227 }
5228 default:
5229 {
5230 (void) XBell(display,0);
5231 break;
5232 }
5233 }
5234 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
5235 event.xkey.time);
5236 break;
5237 }
5238 case KeyRelease:
5239 break;
5240 case MotionNotify:
5241 {
5242 if (event.xmotion.window != windows->image.id)
5243 break;
5244 /*
5245 Map and unmap Info widget as text cursor crosses its boundaries.
5246 */
5247 x=event.xmotion.x;
5248 y=event.xmotion.y;
anthony11d32022012-11-17 05:31:33 +00005249 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00005250 {
5251 if ((x < (int) (windows->info.x+windows->info.width)) &&
5252 (y < (int) (windows->info.y+windows->info.height)))
5253 (void) XWithdrawWindow(display,windows->info.id,
5254 windows->info.screen);
5255 }
5256 else
5257 if ((x > (int) (windows->info.x+windows->info.width)) ||
5258 (y > (int) (windows->info.y+windows->info.height)))
5259 (void) XMapWindow(display,windows->info.id);
cristy49e2d862010-11-12 02:50:30 +00005260 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x;
5261 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y;
cristy3ed852e2009-09-05 21:47:34 +00005262 break;
5263 }
5264 case SelectionRequest:
5265 {
5266 XSelectionEvent
5267 notify;
5268
5269 XSelectionRequestEvent
5270 *request;
5271
5272 /*
5273 Set primary selection.
5274 */
cristyb51dff52011-05-19 16:55:47 +00005275 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +00005276 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +00005277 crop_info.height,(double) crop_info.x,(double) crop_info.y);
cristy3ed852e2009-09-05 21:47:34 +00005278 request=(&(event.xselectionrequest));
5279 (void) XChangeProperty(request->display,request->requestor,
5280 request->property,request->target,8,PropModeReplace,
5281 (unsigned char *) text,(int) strlen(text));
5282 notify.type=SelectionNotify;
5283 notify.display=request->display;
5284 notify.requestor=request->requestor;
5285 notify.selection=request->selection;
5286 notify.target=request->target;
5287 notify.time=request->time;
5288 if (request->property == None)
5289 notify.property=request->target;
5290 else
5291 notify.property=request->property;
5292 (void) XSendEvent(request->display,request->requestor,False,0,
5293 (XEvent *) &notify);
5294 }
5295 default:
5296 break;
5297 }
5298 if ((state & UpdateConfigurationState) != 0)
5299 {
5300 (void) XPutBackEvent(display,&event);
5301 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5302 break;
5303 }
5304 } while ((state & ExitState) == 0);
5305 } while ((state & ExitState) == 0);
5306 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
5307 XSetCursorState(display,windows,MagickFalse);
5308 if ((state & EscapeState) != 0)
5309 return(MagickTrue);
5310 if (mode == CropMode)
5311 if (((int) crop_info.width != windows->image.ximage->width) ||
5312 ((int) crop_info.height != windows->image.ximage->height))
5313 {
5314 /*
5315 Reconfigure Image window as defined by cropping rectangle.
5316 */
5317 XSetCropGeometry(display,windows,&crop_info,image);
5318 windows->image.window_changes.width=(int) crop_info.width;
5319 windows->image.window_changes.height=(int) crop_info.height;
cristy051718b2011-08-28 22:49:25 +00005320 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00005321 return(MagickTrue);
5322 }
5323 /*
5324 Copy image before applying image transforms.
5325 */
5326 XSetCursorState(display,windows,MagickTrue);
5327 XCheckRefreshWindows(display,windows);
5328 width=(unsigned int) image->columns;
5329 height=(unsigned int) image->rows;
5330 x=0;
5331 y=0;
5332 if (windows->image.crop_geometry != (char *) NULL)
5333 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
cristya19f1d72012-08-07 18:24:38 +00005334 scale_factor=(double) width/windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +00005335 crop_info.x+=x;
cristy49e2d862010-11-12 02:50:30 +00005336 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +00005337 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
cristya19f1d72012-08-07 18:24:38 +00005338 scale_factor=(double) height/windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +00005339 crop_info.y+=y;
cristy49e2d862010-11-12 02:50:30 +00005340 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +00005341 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5);
cristy051718b2011-08-28 22:49:25 +00005342 crop_image=CropImage(image,&crop_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00005343 XSetCursorState(display,windows,MagickFalse);
5344 if (crop_image == (Image *) NULL)
5345 return(MagickFalse);
5346 if (resource_info->copy_image != (Image *) NULL)
5347 resource_info->copy_image=DestroyImage(resource_info->copy_image);
5348 resource_info->copy_image=crop_image;
5349 if (mode == CopyMode)
5350 {
cristy051718b2011-08-28 22:49:25 +00005351 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00005352 return(MagickTrue);
5353 }
5354 /*
5355 Cut image.
5356 */
anthony11d32022012-11-17 05:31:33 +00005357 if( IfMagickFalse(SetImageStorageClass(image,DirectClass,exception)) )
cristy3ed852e2009-09-05 21:47:34 +00005358 return(MagickFalse);
cristy8a46d822012-08-28 23:32:39 +00005359 image->alpha_trait=BlendPixelTrait;
cristy46ff2672012-12-14 15:32:26 +00005360 image_view=AcquireAuthenticCacheView(image,exception);
cristy49e2d862010-11-12 02:50:30 +00005361 for (y=0; y < (int) crop_info.height; y++)
cristy3ed852e2009-09-05 21:47:34 +00005362 {
cristy49e2d862010-11-12 02:50:30 +00005363 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y,
5364 crop_info.width,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00005365 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00005366 break;
5367 for (x=0; x < (int) crop_info.width; x++)
5368 {
cristy4c08aed2011-07-01 19:47:50 +00005369 SetPixelAlpha(image,TransparentAlpha,q);
cristyed231572011-07-14 02:18:59 +00005370 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00005371 }
anthony11d32022012-11-17 05:31:33 +00005372 if( IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) )
cristy3ed852e2009-09-05 21:47:34 +00005373 break;
5374 }
cristy49e2d862010-11-12 02:50:30 +00005375 image_view=DestroyCacheView(image_view);
cristy3ed852e2009-09-05 21:47:34 +00005376 /*
5377 Update image configuration.
5378 */
cristy6710d842011-10-20 23:23:00 +00005379 XConfigureImageColormap(display,resource_info,windows,image,exception);
cristy051718b2011-08-28 22:49:25 +00005380 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00005381 return(MagickTrue);
5382}
5383
5384/*
5385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5386% %
5387% %
5388% %
5389+ X D r a w I m a g e %
5390% %
5391% %
5392% %
5393%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5394%
5395% XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on
5396% the image.
5397%
5398% The format of the XDrawEditImage method is:
5399%
5400% MagickBooleanType XDrawEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00005401% XResourceInfo *resource_info,XWindows *windows,Image **image,
5402% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00005403%
5404% A description of each parameter follows:
5405%
5406% o display: Specifies a connection to an X server; returned from
5407% XOpenDisplay.
5408%
5409% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
5410%
5411% o windows: Specifies a pointer to a XWindows structure.
5412%
5413% o image: the image.
5414%
cristy051718b2011-08-28 22:49:25 +00005415% o exception: return any errors or warnings in this structure.
5416%
cristy3ed852e2009-09-05 21:47:34 +00005417*/
5418static MagickBooleanType XDrawEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00005419 XResourceInfo *resource_info,XWindows *windows,Image **image,
5420 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00005421{
5422 static const char
5423 *DrawMenu[] =
5424 {
5425 "Element",
5426 "Color",
5427 "Stipple",
5428 "Width",
5429 "Undo",
5430 "Help",
5431 "Dismiss",
5432 (char *) NULL
5433 };
5434
5435 static ElementType
5436 element = PointElement;
5437
5438 static const ModeType
5439 DrawCommands[] =
5440 {
5441 DrawElementCommand,
5442 DrawColorCommand,
5443 DrawStippleCommand,
5444 DrawWidthCommand,
5445 DrawUndoCommand,
5446 DrawHelpCommand,
5447 DrawDismissCommand
5448 };
5449
5450 static Pixmap
5451 stipple = (Pixmap) NULL;
5452
5453 static unsigned int
5454 pen_id = 0,
5455 line_width = 1;
5456
5457 char
5458 command[MaxTextExtent],
5459 text[MaxTextExtent];
5460
5461 Cursor
5462 cursor;
5463
5464 int
5465 entry,
5466 id,
5467 number_coordinates,
5468 x,
5469 y;
5470
cristya19f1d72012-08-07 18:24:38 +00005471 double
cristy3ed852e2009-09-05 21:47:34 +00005472 degrees;
5473
5474 MagickStatusType
5475 status;
5476
5477 RectangleInfo
5478 rectangle_info;
5479
5480 register int
5481 i;
5482
5483 unsigned int
5484 distance,
5485 height,
5486 max_coordinates,
5487 width;
5488
cristybb503372010-05-27 20:51:26 +00005489 size_t
cristy3ed852e2009-09-05 21:47:34 +00005490 state;
5491
5492 Window
5493 root_window;
5494
5495 XDrawInfo
5496 draw_info;
5497
5498 XEvent
5499 event;
5500
5501 XPoint
5502 *coordinate_info;
5503
5504 XSegment
5505 line_info;
5506
5507 /*
5508 Allocate polygon info.
5509 */
5510 max_coordinates=2048;
5511 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates,
5512 sizeof(*coordinate_info));
5513 if (coordinate_info == (XPoint *) NULL)
5514 {
cristy051718b2011-08-28 22:49:25 +00005515 (void) ThrowMagickException(exception,GetMagickModule(),
cristyefe601c2013-01-05 17:51:12 +00005516 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
cristy3ed852e2009-09-05 21:47:34 +00005517 return(MagickFalse);
5518 }
5519 /*
5520 Map Command widget.
5521 */
5522 (void) CloneString(&windows->command.name,"Draw");
5523 windows->command.data=4;
5524 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL);
5525 (void) XMapRaised(display,windows->command.id);
5526 XClientMessage(display,windows->image.id,windows->im_protocols,
5527 windows->im_update_widget,CurrentTime);
5528 /*
5529 Wait for first button press.
5530 */
5531 root_window=XRootWindow(display,XDefaultScreen(display));
5532 draw_info.stencil=OpaqueStencil;
5533 status=MagickTrue;
5534 cursor=XCreateFontCursor(display,XC_tcross);
5535 for ( ; ; )
5536 {
5537 XQueryPosition(display,windows->image.id,&x,&y);
5538 (void) XSelectInput(display,windows->image.id,
5539 windows->image.attributes.event_mask | PointerMotionMask);
5540 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5541 state=DefaultState;
5542 do
5543 {
anthony11d32022012-11-17 05:31:33 +00005544 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00005545 {
5546 /*
5547 Display pointer position.
5548 */
cristyb51dff52011-05-19 16:55:47 +00005549 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +00005550 x+windows->image.x,y+windows->image.y);
5551 XInfoWidget(display,windows,text);
5552 }
5553 /*
5554 Wait for next event.
5555 */
cristy6710d842011-10-20 23:23:00 +00005556 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00005557 if (event.xany.window == windows->command.id)
5558 {
5559 /*
5560 Select a command from the Command widget.
5561 */
5562 id=XCommandWidget(display,windows,DrawMenu,&event);
5563 if (id < 0)
5564 continue;
5565 switch (DrawCommands[id])
5566 {
5567 case DrawElementCommand:
5568 {
5569 static const char
5570 *Elements[] =
5571 {
5572 "point",
5573 "line",
5574 "rectangle",
5575 "fill rectangle",
5576 "circle",
5577 "fill circle",
5578 "ellipse",
5579 "fill ellipse",
5580 "polygon",
5581 "fill polygon",
5582 (char *) NULL,
5583 };
5584
5585 /*
5586 Select a command from the pop-up menu.
5587 */
5588 element=(ElementType) (XMenuWidget(display,windows,
5589 DrawMenu[id],Elements,command)+1);
5590 break;
5591 }
5592 case DrawColorCommand:
5593 {
5594 const char
5595 *ColorMenu[MaxNumberPens+1];
5596
5597 int
5598 pen_number;
5599
5600 MagickBooleanType
5601 transparent;
5602
5603 XColor
5604 color;
5605
5606 /*
5607 Initialize menu selections.
5608 */
5609 for (i=0; i < (int) (MaxNumberPens-2); i++)
5610 ColorMenu[i]=resource_info->pen_colors[i];
5611 ColorMenu[MaxNumberPens-2]="transparent";
5612 ColorMenu[MaxNumberPens-1]="Browser...";
5613 ColorMenu[MaxNumberPens]=(char *) NULL;
5614 /*
5615 Select a pen color from the pop-up menu.
5616 */
5617 pen_number=XMenuWidget(display,windows,DrawMenu[id],
5618 (const char **) ColorMenu,command);
5619 if (pen_number < 0)
5620 break;
5621 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue :
5622 MagickFalse;
anthony11d32022012-11-17 05:31:33 +00005623 if( IfMagickTrue(transparent) )
cristy3ed852e2009-09-05 21:47:34 +00005624 {
5625 draw_info.stencil=TransparentStencil;
5626 break;
5627 }
5628 if (pen_number == (MaxNumberPens-1))
5629 {
5630 static char
5631 color_name[MaxTextExtent] = "gray";
5632
5633 /*
5634 Select a pen color from a dialog.
5635 */
5636 resource_info->pen_colors[pen_number]=color_name;
5637 XColorBrowserWidget(display,windows,"Select",color_name);
5638 if (*color_name == '\0')
5639 break;
5640 }
5641 /*
5642 Set pen color.
5643 */
5644 (void) XParseColor(display,windows->map_info->colormap,
5645 resource_info->pen_colors[pen_number],&color);
5646 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
5647 (unsigned int) MaxColors,&color);
5648 windows->pixel_info->pen_colors[pen_number]=color;
5649 pen_id=(unsigned int) pen_number;
5650 draw_info.stencil=OpaqueStencil;
5651 break;
5652 }
5653 case DrawStippleCommand:
5654 {
5655 Image
5656 *stipple_image;
5657
5658 ImageInfo
5659 *image_info;
5660
5661 int
5662 status;
5663
5664 static char
5665 filename[MaxTextExtent] = "\0";
5666
5667 static const char
5668 *StipplesMenu[] =
5669 {
5670 "Brick",
5671 "Diagonal",
5672 "Scales",
5673 "Vertical",
5674 "Wavy",
5675 "Translucent",
5676 "Opaque",
5677 (char *) NULL,
5678 (char *) NULL,
5679 };
5680
5681 /*
5682 Select a command from the pop-up menu.
5683 */
5684 StipplesMenu[7]="Open...";
5685 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu,
5686 command);
5687 if (entry < 0)
5688 break;
5689 if (stipple != (Pixmap) NULL)
5690 (void) XFreePixmap(display,stipple);
5691 stipple=(Pixmap) NULL;
cristy3ed852e2009-09-05 21:47:34 +00005692 if (entry != 7)
5693 {
5694 switch (entry)
5695 {
5696 case 0:
5697 {
5698 stipple=XCreateBitmapFromData(display,root_window,
5699 (char *) BricksBitmap,BricksWidth,BricksHeight);
5700 break;
5701 }
5702 case 1:
5703 {
5704 stipple=XCreateBitmapFromData(display,root_window,
5705 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight);
5706 break;
5707 }
5708 case 2:
5709 {
5710 stipple=XCreateBitmapFromData(display,root_window,
5711 (char *) ScalesBitmap,ScalesWidth,ScalesHeight);
5712 break;
5713 }
5714 case 3:
5715 {
5716 stipple=XCreateBitmapFromData(display,root_window,
5717 (char *) VerticalBitmap,VerticalWidth,VerticalHeight);
5718 break;
5719 }
5720 case 4:
5721 {
5722 stipple=XCreateBitmapFromData(display,root_window,
5723 (char *) WavyBitmap,WavyWidth,WavyHeight);
5724 break;
5725 }
5726 case 5:
cristy3ed852e2009-09-05 21:47:34 +00005727 {
5728 stipple=XCreateBitmapFromData(display,root_window,
5729 (char *) HighlightBitmap,HighlightWidth,
5730 HighlightHeight);
5731 break;
5732 }
cristydd05beb2010-11-21 21:23:39 +00005733 case 6:
5734 default:
5735 {
5736 stipple=XCreateBitmapFromData(display,root_window,
5737 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight);
5738 break;
5739 }
cristy3ed852e2009-09-05 21:47:34 +00005740 }
5741 break;
5742 }
5743 XFileBrowserWidget(display,windows,"Stipple",filename);
5744 if (*filename == '\0')
5745 break;
5746 /*
5747 Read image.
5748 */
5749 XSetCursorState(display,windows,MagickTrue);
5750 XCheckRefreshWindows(display,windows);
5751 image_info=AcquireImageInfo();
5752 (void) CopyMagickString(image_info->filename,filename,
5753 MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00005754 stipple_image=ReadImage(image_info,exception);
5755 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00005756 XSetCursorState(display,windows,MagickFalse);
5757 if (stipple_image == (Image *) NULL)
5758 break;
5759 (void) AcquireUniqueFileResource(filename);
cristyb51dff52011-05-19 16:55:47 +00005760 (void) FormatLocaleString(stipple_image->filename,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00005761 "xbm:%s",filename);
cristy051718b2011-08-28 22:49:25 +00005762 (void) WriteImage(image_info,stipple_image,exception);
cristy3ed852e2009-09-05 21:47:34 +00005763 stipple_image=DestroyImage(stipple_image);
5764 image_info=DestroyImageInfo(image_info);
5765 status=XReadBitmapFile(display,root_window,filename,&width,
5766 &height,&stipple,&x,&y);
5767 (void) RelinquishUniqueFileResource(filename);
5768 if ((status != BitmapSuccess) != 0)
5769 XNoticeWidget(display,windows,"Unable to read X bitmap image:",
5770 filename);
5771 break;
5772 }
5773 case DrawWidthCommand:
5774 {
5775 static char
5776 width[MaxTextExtent] = "0";
5777
5778 static const char
5779 *WidthsMenu[] =
5780 {
5781 "1",
5782 "2",
5783 "4",
5784 "8",
5785 "16",
5786 "Dialog...",
5787 (char *) NULL,
5788 };
5789
5790 /*
5791 Select a command from the pop-up menu.
5792 */
5793 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu,
5794 command);
5795 if (entry < 0)
5796 break;
5797 if (entry != 5)
5798 {
cristydd05beb2010-11-21 21:23:39 +00005799 line_width=(unsigned int) StringToUnsignedLong(
5800 WidthsMenu[entry]);
cristy3ed852e2009-09-05 21:47:34 +00005801 break;
5802 }
5803 (void) XDialogWidget(display,windows,"Ok","Enter line width:",
5804 width);
5805 if (*width == '\0')
5806 break;
cristye27293e2009-12-18 02:53:20 +00005807 line_width=(unsigned int) StringToUnsignedLong(width);
cristy3ed852e2009-09-05 21:47:34 +00005808 break;
5809 }
5810 case DrawUndoCommand:
5811 {
5812 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
cristy051718b2011-08-28 22:49:25 +00005813 image,exception);
cristy3ed852e2009-09-05 21:47:34 +00005814 break;
5815 }
5816 case DrawHelpCommand:
5817 {
5818 XTextViewWidget(display,resource_info,windows,MagickFalse,
5819 "Help Viewer - Image Rotation",ImageDrawHelp);
5820 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5821 break;
5822 }
5823 case DrawDismissCommand:
5824 {
5825 /*
5826 Prematurely exit.
5827 */
5828 state|=EscapeState;
5829 state|=ExitState;
5830 break;
5831 }
5832 default:
5833 break;
5834 }
5835 (void) XCheckDefineCursor(display,windows->image.id,cursor);
5836 continue;
5837 }
5838 switch (event.type)
5839 {
5840 case ButtonPress:
5841 {
5842 if (event.xbutton.button != Button1)
5843 break;
5844 if (event.xbutton.window != windows->image.id)
5845 break;
5846 /*
5847 exit loop.
5848 */
5849 x=event.xbutton.x;
5850 y=event.xbutton.y;
5851 state|=ExitState;
5852 break;
5853 }
5854 case ButtonRelease:
5855 break;
5856 case Expose:
5857 break;
5858 case KeyPress:
5859 {
5860 KeySym
5861 key_symbol;
5862
5863 if (event.xkey.window != windows->image.id)
5864 break;
5865 /*
5866 Respond to a user key press.
5867 */
5868 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
5869 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
5870 switch ((int) key_symbol)
5871 {
5872 case XK_Escape:
5873 case XK_F20:
5874 {
5875 /*
5876 Prematurely exit.
5877 */
5878 state|=EscapeState;
5879 state|=ExitState;
5880 break;
5881 }
5882 case XK_F1:
5883 case XK_Help:
5884 {
5885 XTextViewWidget(display,resource_info,windows,MagickFalse,
5886 "Help Viewer - Image Rotation",ImageDrawHelp);
5887 break;
5888 }
5889 default:
5890 {
5891 (void) XBell(display,0);
5892 break;
5893 }
5894 }
5895 break;
5896 }
5897 case MotionNotify:
5898 {
5899 /*
5900 Map and unmap Info widget as text cursor crosses its boundaries.
5901 */
5902 x=event.xmotion.x;
5903 y=event.xmotion.y;
anthony11d32022012-11-17 05:31:33 +00005904 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00005905 {
5906 if ((x < (int) (windows->info.x+windows->info.width)) &&
5907 (y < (int) (windows->info.y+windows->info.height)))
5908 (void) XWithdrawWindow(display,windows->info.id,
5909 windows->info.screen);
5910 }
5911 else
5912 if ((x > (int) (windows->info.x+windows->info.width)) ||
5913 (y > (int) (windows->info.y+windows->info.height)))
5914 (void) XMapWindow(display,windows->info.id);
5915 break;
5916 }
5917 }
5918 } while ((state & ExitState) == 0);
5919 (void) XSelectInput(display,windows->image.id,
5920 windows->image.attributes.event_mask);
5921 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
5922 if ((state & EscapeState) != 0)
5923 break;
5924 /*
5925 Draw element as pointer moves until the button is released.
5926 */
5927 distance=0;
5928 degrees=0.0;
5929 line_info.x1=x;
5930 line_info.y1=y;
5931 line_info.x2=x;
5932 line_info.y2=y;
cristy49e2d862010-11-12 02:50:30 +00005933 rectangle_info.x=(ssize_t) x;
5934 rectangle_info.y=(ssize_t) y;
cristy3ed852e2009-09-05 21:47:34 +00005935 rectangle_info.width=0;
5936 rectangle_info.height=0;
5937 number_coordinates=1;
5938 coordinate_info->x=x;
5939 coordinate_info->y=y;
5940 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
5941 state=DefaultState;
5942 do
5943 {
5944 switch (element)
5945 {
5946 case PointElement:
5947 default:
5948 {
5949 if (number_coordinates > 1)
5950 {
5951 (void) XDrawLines(display,windows->image.id,
5952 windows->image.highlight_context,coordinate_info,
5953 number_coordinates,CoordModeOrigin);
cristyb51dff52011-05-19 16:55:47 +00005954 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d",
cristy3ed852e2009-09-05 21:47:34 +00005955 coordinate_info[number_coordinates-1].x,
5956 coordinate_info[number_coordinates-1].y);
5957 XInfoWidget(display,windows,text);
5958 }
5959 break;
5960 }
5961 case LineElement:
5962 {
5963 if (distance > 9)
5964 {
5965 /*
5966 Display angle of the line.
5967 */
5968 degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
5969 line_info.y1),(double) (line_info.x2-line_info.x1)));
cristyb51dff52011-05-19 16:55:47 +00005970 (void) FormatLocaleString(text,MaxTextExtent," %g",
cristy3ed852e2009-09-05 21:47:34 +00005971 (double) degrees);
5972 XInfoWidget(display,windows,text);
5973 XHighlightLine(display,windows->image.id,
5974 windows->image.highlight_context,&line_info);
5975 }
5976 else
anthony11d32022012-11-17 05:31:33 +00005977 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00005978 (void) XWithdrawWindow(display,windows->info.id,
5979 windows->info.screen);
5980 break;
5981 }
5982 case RectangleElement:
5983 case FillRectangleElement:
5984 {
5985 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
5986 {
5987 /*
5988 Display info and draw drawing rectangle.
5989 */
cristyb51dff52011-05-19 16:55:47 +00005990 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +00005991 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
cristye8c25f92010-06-03 00:53:06 +00005992 (double) rectangle_info.height,(double) rectangle_info.x,
5993 (double) rectangle_info.y);
cristy3ed852e2009-09-05 21:47:34 +00005994 XInfoWidget(display,windows,text);
5995 XHighlightRectangle(display,windows->image.id,
5996 windows->image.highlight_context,&rectangle_info);
5997 }
5998 else
anthony11d32022012-11-17 05:31:33 +00005999 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00006000 (void) XWithdrawWindow(display,windows->info.id,
6001 windows->info.screen);
6002 break;
6003 }
6004 case CircleElement:
6005 case FillCircleElement:
6006 case EllipseElement:
6007 case FillEllipseElement:
6008 {
6009 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6010 {
6011 /*
6012 Display info and draw drawing rectangle.
6013 */
cristyb51dff52011-05-19 16:55:47 +00006014 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +00006015 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
cristye8c25f92010-06-03 00:53:06 +00006016 (double) rectangle_info.height,(double) rectangle_info.x,
6017 (double) rectangle_info.y);
cristy3ed852e2009-09-05 21:47:34 +00006018 XInfoWidget(display,windows,text);
6019 XHighlightEllipse(display,windows->image.id,
6020 windows->image.highlight_context,&rectangle_info);
6021 }
6022 else
anthony11d32022012-11-17 05:31:33 +00006023 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00006024 (void) XWithdrawWindow(display,windows->info.id,
6025 windows->info.screen);
6026 break;
6027 }
6028 case PolygonElement:
6029 case FillPolygonElement:
6030 {
6031 if (number_coordinates > 1)
6032 (void) XDrawLines(display,windows->image.id,
6033 windows->image.highlight_context,coordinate_info,
6034 number_coordinates,CoordModeOrigin);
6035 if (distance > 9)
6036 {
6037 /*
6038 Display angle of the line.
6039 */
6040 degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
6041 line_info.y1),(double) (line_info.x2-line_info.x1)));
cristyb51dff52011-05-19 16:55:47 +00006042 (void) FormatLocaleString(text,MaxTextExtent," %g",
cristy3ed852e2009-09-05 21:47:34 +00006043 (double) degrees);
6044 XInfoWidget(display,windows,text);
6045 XHighlightLine(display,windows->image.id,
6046 windows->image.highlight_context,&line_info);
6047 }
6048 else
anthony11d32022012-11-17 05:31:33 +00006049 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00006050 (void) XWithdrawWindow(display,windows->info.id,
6051 windows->info.screen);
6052 break;
6053 }
6054 }
6055 /*
6056 Wait for next event.
6057 */
cristy6710d842011-10-20 23:23:00 +00006058 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00006059 switch (element)
6060 {
6061 case PointElement:
6062 default:
6063 {
6064 if (number_coordinates > 1)
6065 (void) XDrawLines(display,windows->image.id,
6066 windows->image.highlight_context,coordinate_info,
6067 number_coordinates,CoordModeOrigin);
6068 break;
6069 }
6070 case LineElement:
6071 {
6072 if (distance > 9)
6073 XHighlightLine(display,windows->image.id,
6074 windows->image.highlight_context,&line_info);
6075 break;
6076 }
6077 case RectangleElement:
6078 case FillRectangleElement:
6079 {
6080 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6081 XHighlightRectangle(display,windows->image.id,
6082 windows->image.highlight_context,&rectangle_info);
6083 break;
6084 }
6085 case CircleElement:
6086 case FillCircleElement:
6087 case EllipseElement:
6088 case FillEllipseElement:
6089 {
6090 if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
6091 XHighlightEllipse(display,windows->image.id,
6092 windows->image.highlight_context,&rectangle_info);
6093 break;
6094 }
6095 case PolygonElement:
6096 case FillPolygonElement:
6097 {
6098 if (number_coordinates > 1)
6099 (void) XDrawLines(display,windows->image.id,
6100 windows->image.highlight_context,coordinate_info,
6101 number_coordinates,CoordModeOrigin);
6102 if (distance > 9)
6103 XHighlightLine(display,windows->image.id,
6104 windows->image.highlight_context,&line_info);
6105 break;
6106 }
6107 }
6108 switch (event.type)
6109 {
6110 case ButtonPress:
6111 break;
6112 case ButtonRelease:
6113 {
6114 /*
6115 User has committed to element.
6116 */
6117 line_info.x2=event.xbutton.x;
6118 line_info.y2=event.xbutton.y;
cristy49e2d862010-11-12 02:50:30 +00006119 rectangle_info.x=(ssize_t) event.xbutton.x;
6120 rectangle_info.y=(ssize_t) event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +00006121 coordinate_info[number_coordinates].x=event.xbutton.x;
6122 coordinate_info[number_coordinates].y=event.xbutton.y;
6123 if (((element != PolygonElement) &&
6124 (element != FillPolygonElement)) || (distance <= 9))
6125 {
6126 state|=ExitState;
6127 break;
6128 }
6129 number_coordinates++;
6130 if (number_coordinates < (int) max_coordinates)
6131 {
6132 line_info.x1=event.xbutton.x;
6133 line_info.y1=event.xbutton.y;
6134 break;
6135 }
6136 max_coordinates<<=1;
6137 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
6138 max_coordinates,sizeof(*coordinate_info));
6139 if (coordinate_info == (XPoint *) NULL)
cristy051718b2011-08-28 22:49:25 +00006140 (void) ThrowMagickException(exception,GetMagickModule(),
cristyefe601c2013-01-05 17:51:12 +00006141 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
cristy3ed852e2009-09-05 21:47:34 +00006142 break;
6143 }
6144 case Expose:
6145 break;
6146 case MotionNotify:
6147 {
6148 if (event.xmotion.window != windows->image.id)
6149 break;
6150 if (element != PointElement)
6151 {
6152 line_info.x2=event.xmotion.x;
6153 line_info.y2=event.xmotion.y;
cristy49e2d862010-11-12 02:50:30 +00006154 rectangle_info.x=(ssize_t) event.xmotion.x;
6155 rectangle_info.y=(ssize_t) event.xmotion.y;
cristy3ed852e2009-09-05 21:47:34 +00006156 break;
6157 }
6158 coordinate_info[number_coordinates].x=event.xbutton.x;
6159 coordinate_info[number_coordinates].y=event.xbutton.y;
6160 number_coordinates++;
6161 if (number_coordinates < (int) max_coordinates)
6162 break;
6163 max_coordinates<<=1;
6164 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
6165 max_coordinates,sizeof(*coordinate_info));
6166 if (coordinate_info == (XPoint *) NULL)
cristy051718b2011-08-28 22:49:25 +00006167 (void) ThrowMagickException(exception,GetMagickModule(),
cristyefe601c2013-01-05 17:51:12 +00006168 ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
cristy3ed852e2009-09-05 21:47:34 +00006169 break;
6170 }
6171 default:
6172 break;
6173 }
6174 /*
6175 Check boundary conditions.
6176 */
6177 if (line_info.x2 < 0)
6178 line_info.x2=0;
6179 else
6180 if (line_info.x2 > (int) windows->image.width)
6181 line_info.x2=(short) windows->image.width;
6182 if (line_info.y2 < 0)
6183 line_info.y2=0;
6184 else
6185 if (line_info.y2 > (int) windows->image.height)
6186 line_info.y2=(short) windows->image.height;
6187 distance=(unsigned int)
6188 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+
6189 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1)));
6190 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) ||
6191 ((state & ExitState) != 0))
6192 {
6193 if (rectangle_info.x < 0)
6194 rectangle_info.x=0;
6195 else
cristy49e2d862010-11-12 02:50:30 +00006196 if (rectangle_info.x > (ssize_t) windows->image.width)
cristybb503372010-05-27 20:51:26 +00006197 rectangle_info.x=(ssize_t) windows->image.width;
cristy3ed852e2009-09-05 21:47:34 +00006198 if ((int) rectangle_info.x < x)
6199 rectangle_info.width=(unsigned int) (x-rectangle_info.x);
6200 else
6201 {
6202 rectangle_info.width=(unsigned int) (rectangle_info.x-x);
cristy49e2d862010-11-12 02:50:30 +00006203 rectangle_info.x=(ssize_t) x;
cristy3ed852e2009-09-05 21:47:34 +00006204 }
6205 if (rectangle_info.y < 0)
6206 rectangle_info.y=0;
6207 else
cristy49e2d862010-11-12 02:50:30 +00006208 if (rectangle_info.y > (ssize_t) windows->image.height)
cristybb503372010-05-27 20:51:26 +00006209 rectangle_info.y=(ssize_t) windows->image.height;
cristy3ed852e2009-09-05 21:47:34 +00006210 if ((int) rectangle_info.y < y)
6211 rectangle_info.height=(unsigned int) (y-rectangle_info.y);
6212 else
6213 {
6214 rectangle_info.height=(unsigned int) (rectangle_info.y-y);
cristy49e2d862010-11-12 02:50:30 +00006215 rectangle_info.y=(ssize_t) y;
cristy3ed852e2009-09-05 21:47:34 +00006216 }
6217 }
6218 } while ((state & ExitState) == 0);
6219 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
6220 if ((element == PointElement) || (element == PolygonElement) ||
6221 (element == FillPolygonElement))
6222 {
6223 /*
6224 Determine polygon bounding box.
6225 */
cristy49e2d862010-11-12 02:50:30 +00006226 rectangle_info.x=(ssize_t) coordinate_info->x;
6227 rectangle_info.y=(ssize_t) coordinate_info->y;
cristy3ed852e2009-09-05 21:47:34 +00006228 x=coordinate_info->x;
6229 y=coordinate_info->y;
6230 for (i=1; i < number_coordinates; i++)
6231 {
6232 if (coordinate_info[i].x > x)
6233 x=coordinate_info[i].x;
6234 if (coordinate_info[i].y > y)
6235 y=coordinate_info[i].y;
cristy49e2d862010-11-12 02:50:30 +00006236 if ((ssize_t) coordinate_info[i].x < rectangle_info.x)
6237 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0);
6238 if ((ssize_t) coordinate_info[i].y < rectangle_info.y)
6239 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0);
cristy3ed852e2009-09-05 21:47:34 +00006240 }
cristybb503372010-05-27 20:51:26 +00006241 rectangle_info.width=(size_t) (x-rectangle_info.x);
6242 rectangle_info.height=(size_t) (y-rectangle_info.y);
cristy3ed852e2009-09-05 21:47:34 +00006243 for (i=0; i < number_coordinates; i++)
6244 {
6245 coordinate_info[i].x-=rectangle_info.x;
6246 coordinate_info[i].y-=rectangle_info.y;
6247 }
6248 }
6249 else
6250 if (distance <= 9)
6251 continue;
6252 else
6253 if ((element == RectangleElement) ||
6254 (element == CircleElement) || (element == EllipseElement))
6255 {
6256 rectangle_info.width--;
6257 rectangle_info.height--;
6258 }
6259 /*
6260 Drawing is relative to image configuration.
6261 */
6262 draw_info.x=(int) rectangle_info.x;
6263 draw_info.y=(int) rectangle_info.y;
6264 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand,
cristy051718b2011-08-28 22:49:25 +00006265 image,exception);
cristy3ed852e2009-09-05 21:47:34 +00006266 width=(unsigned int) (*image)->columns;
6267 height=(unsigned int) (*image)->rows;
6268 x=0;
6269 y=0;
6270 if (windows->image.crop_geometry != (char *) NULL)
6271 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
6272 draw_info.x+=windows->image.x-(line_width/2);
6273 if (draw_info.x < 0)
6274 draw_info.x=0;
6275 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width);
6276 draw_info.y+=windows->image.y-(line_width/2);
6277 if (draw_info.y < 0)
6278 draw_info.y=0;
6279 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height;
6280 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1);
6281 if (draw_info.width > (unsigned int) (*image)->columns)
6282 draw_info.width=(unsigned int) (*image)->columns;
6283 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1);
6284 if (draw_info.height > (unsigned int) (*image)->rows)
6285 draw_info.height=(unsigned int) (*image)->rows;
cristyb51dff52011-05-19 16:55:47 +00006286 (void) FormatLocaleString(draw_info.geometry,MaxTextExtent,"%ux%u%+d%+d",
cristy3ed852e2009-09-05 21:47:34 +00006287 width*draw_info.width/windows->image.ximage->width,
6288 height*draw_info.height/windows->image.ximage->height,
6289 draw_info.x+x,draw_info.y+y);
6290 /*
6291 Initialize drawing attributes.
6292 */
6293 draw_info.degrees=0.0;
6294 draw_info.element=element;
6295 draw_info.stipple=stipple;
6296 draw_info.line_width=line_width;
6297 draw_info.line_info=line_info;
6298 if (line_info.x1 > (int) (line_width/2))
6299 draw_info.line_info.x1=(short) line_width/2;
6300 if (line_info.y1 > (int) (line_width/2))
6301 draw_info.line_info.y1=(short) line_width/2;
6302 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2));
6303 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2));
6304 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0))
6305 {
6306 draw_info.line_info.x2=(-draw_info.line_info.x2);
6307 draw_info.line_info.y2=(-draw_info.line_info.y2);
6308 }
6309 if (draw_info.line_info.x2 < 0)
6310 {
6311 draw_info.line_info.x2=(-draw_info.line_info.x2);
6312 Swap(draw_info.line_info.x1,draw_info.line_info.x2);
6313 }
6314 if (draw_info.line_info.y2 < 0)
6315 {
6316 draw_info.line_info.y2=(-draw_info.line_info.y2);
6317 Swap(draw_info.line_info.y1,draw_info.line_info.y2);
6318 }
6319 draw_info.rectangle_info=rectangle_info;
cristy49e2d862010-11-12 02:50:30 +00006320 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2))
cristybb503372010-05-27 20:51:26 +00006321 draw_info.rectangle_info.x=(ssize_t) line_width/2;
cristy49e2d862010-11-12 02:50:30 +00006322 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2))
cristybb503372010-05-27 20:51:26 +00006323 draw_info.rectangle_info.y=(ssize_t) line_width/2;
cristy3ed852e2009-09-05 21:47:34 +00006324 draw_info.number_coordinates=(unsigned int) number_coordinates;
6325 draw_info.coordinate_info=coordinate_info;
6326 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
6327 /*
6328 Draw element on image.
6329 */
6330 XSetCursorState(display,windows,MagickTrue);
6331 XCheckRefreshWindows(display,windows);
cristy6710d842011-10-20 23:23:00 +00006332 status=XDrawImage(display,windows->pixel_info,&draw_info,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00006333 XSetCursorState(display,windows,MagickFalse);
6334 /*
6335 Update image colormap and return to image drawing.
6336 */
cristy6710d842011-10-20 23:23:00 +00006337 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00006338 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00006339 }
6340 XSetCursorState(display,windows,MagickFalse);
6341 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info);
anthony11d32022012-11-17 05:31:33 +00006342 return(IsMagickTrue(status));
cristy3ed852e2009-09-05 21:47:34 +00006343}
6344
6345/*
6346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6347% %
6348% %
6349% %
6350+ X D r a w P a n R e c t a n g l e %
6351% %
6352% %
6353% %
6354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6355%
6356% XDrawPanRectangle() draws a rectangle in the pan window. The pan window
6357% displays a zoom image and the rectangle shows which portion of the image is
6358% displayed in the Image window.
6359%
6360% The format of the XDrawPanRectangle method is:
6361%
6362% XDrawPanRectangle(Display *display,XWindows *windows)
6363%
6364% A description of each parameter follows:
6365%
6366% o display: Specifies a connection to an X server; returned from
6367% XOpenDisplay.
6368%
6369% o windows: Specifies a pointer to a XWindows structure.
6370%
6371*/
6372static void XDrawPanRectangle(Display *display,XWindows *windows)
6373{
cristya19f1d72012-08-07 18:24:38 +00006374 double
cristy3ed852e2009-09-05 21:47:34 +00006375 scale_factor;
6376
6377 RectangleInfo
6378 highlight_info;
6379
6380 /*
6381 Determine dimensions of the panning rectangle.
6382 */
cristya19f1d72012-08-07 18:24:38 +00006383 scale_factor=(double) windows->pan.width/windows->image.ximage->width;
cristy49e2d862010-11-12 02:50:30 +00006384 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +00006385 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5);
cristya19f1d72012-08-07 18:24:38 +00006386 scale_factor=(double)
cristy3ed852e2009-09-05 21:47:34 +00006387 windows->pan.height/windows->image.ximage->height;
cristy49e2d862010-11-12 02:50:30 +00006388 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +00006389 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5);
6390 /*
6391 Display the panning rectangle.
6392 */
6393 (void) XClearWindow(display,windows->pan.id);
6394 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context,
6395 &highlight_info);
6396}
6397
6398/*
6399%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6400% %
6401% %
6402% %
6403+ X I m a g e C a c h e %
6404% %
6405% %
6406% %
6407%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6408%
6409% XImageCache() handles the creation, manipulation, and destruction of the
6410% image cache (undo and redo buffers).
6411%
6412% The format of the XImageCache method is:
6413%
6414% void XImageCache(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +00006415% XWindows *windows,const CommandType command,Image **image,
6416% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00006417%
6418% A description of each parameter follows:
6419%
6420% o display: Specifies a connection to an X server; returned from
6421% XOpenDisplay.
6422%
6423% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6424%
6425% o windows: Specifies a pointer to a XWindows structure.
6426%
6427% o command: Specifies a command to perform.
6428%
cristya9a86bb2011-01-13 01:11:00 +00006429% o image: the image; XImageCache may transform the image and return a new
6430% image pointer.
cristy3ed852e2009-09-05 21:47:34 +00006431%
cristy051718b2011-08-28 22:49:25 +00006432% o exception: return any errors or warnings in this structure.
6433%
cristy3ed852e2009-09-05 21:47:34 +00006434*/
6435static void XImageCache(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +00006436 XWindows *windows,const CommandType command,Image **image,
6437 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00006438{
6439 Image
6440 *cache_image;
6441
6442 static Image
6443 *redo_image = (Image *) NULL,
6444 *undo_image = (Image *) NULL;
6445
6446 switch (command)
6447 {
6448 case FreeBuffersCommand:
6449 {
6450 /*
6451 Free memory from the undo and redo cache.
6452 */
6453 while (undo_image != (Image *) NULL)
6454 {
6455 cache_image=undo_image;
6456 undo_image=GetPreviousImageInList(undo_image);
6457 cache_image->list=DestroyImage(cache_image->list);
6458 cache_image=DestroyImage(cache_image);
6459 }
6460 undo_image=NewImageList();
6461 if (redo_image != (Image *) NULL)
6462 redo_image=DestroyImage(redo_image);
6463 redo_image=NewImageList();
6464 return;
6465 }
6466 case UndoCommand:
6467 {
cristya9a86bb2011-01-13 01:11:00 +00006468 char
6469 image_geometry[MaxTextExtent];
6470
cristy3ed852e2009-09-05 21:47:34 +00006471 /*
6472 Undo the last image transformation.
6473 */
6474 if (undo_image == (Image *) NULL)
6475 {
6476 (void) XBell(display,0);
6477 return;
6478 }
6479 cache_image=undo_image;
6480 undo_image=GetPreviousImageInList(undo_image);
6481 windows->image.window_changes.width=(int) cache_image->columns;
6482 windows->image.window_changes.height=(int) cache_image->rows;
cristyb51dff52011-05-19 16:55:47 +00006483 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!",
cristya9a86bb2011-01-13 01:11:00 +00006484 windows->image.ximage->width,windows->image.ximage->height);
cristye941a752011-10-15 01:52:48 +00006485 (void) TransformImage(image,windows->image.crop_geometry,image_geometry,
6486 exception);
cristy3ed852e2009-09-05 21:47:34 +00006487 if (windows->image.crop_geometry != (char *) NULL)
cristye941a752011-10-15 01:52:48 +00006488 windows->image.crop_geometry=(char *) RelinquishMagickMemory(
6489 windows->image.crop_geometry);
cristy3ed852e2009-09-05 21:47:34 +00006490 windows->image.crop_geometry=cache_image->geometry;
6491 if (redo_image != (Image *) NULL)
6492 redo_image=DestroyImage(redo_image);
6493 redo_image=(*image);
6494 *image=cache_image->list;
6495 cache_image=DestroyImage(cache_image);
anthony11d32022012-11-17 05:31:33 +00006496 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00006497 return;
cristy6710d842011-10-20 23:23:00 +00006498 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00006499 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00006500 return;
6501 }
6502 case CutCommand:
6503 case PasteCommand:
6504 case ApplyCommand:
6505 case HalfSizeCommand:
6506 case OriginalSizeCommand:
6507 case DoubleSizeCommand:
6508 case ResizeCommand:
6509 case TrimCommand:
6510 case CropCommand:
6511 case ChopCommand:
6512 case FlipCommand:
6513 case FlopCommand:
6514 case RotateRightCommand:
6515 case RotateLeftCommand:
6516 case RotateCommand:
6517 case ShearCommand:
6518 case RollCommand:
6519 case NegateCommand:
6520 case ContrastStretchCommand:
6521 case SigmoidalContrastCommand:
6522 case NormalizeCommand:
6523 case EqualizeCommand:
6524 case HueCommand:
6525 case SaturationCommand:
6526 case BrightnessCommand:
6527 case GammaCommand:
6528 case SpiffCommand:
6529 case DullCommand:
6530 case GrayscaleCommand:
6531 case MapCommand:
6532 case QuantizeCommand:
6533 case DespeckleCommand:
6534 case EmbossCommand:
6535 case ReduceNoiseCommand:
6536 case AddNoiseCommand:
6537 case SharpenCommand:
6538 case BlurCommand:
6539 case ThresholdCommand:
6540 case EdgeDetectCommand:
6541 case SpreadCommand:
6542 case ShadeCommand:
6543 case RaiseCommand:
6544 case SegmentCommand:
6545 case SolarizeCommand:
6546 case SepiaToneCommand:
6547 case SwirlCommand:
6548 case ImplodeCommand:
6549 case VignetteCommand:
6550 case WaveCommand:
6551 case OilPaintCommand:
6552 case CharcoalDrawCommand:
6553 case AnnotateCommand:
6554 case AddBorderCommand:
6555 case AddFrameCommand:
6556 case CompositeCommand:
6557 case CommentCommand:
6558 case LaunchCommand:
6559 case RegionofInterestCommand:
6560 case SaveToUndoBufferCommand:
6561 case RedoCommand:
6562 {
6563 Image
6564 *previous_image;
6565
cristybb503372010-05-27 20:51:26 +00006566 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00006567 bytes;
6568
cristy101ab702011-10-13 13:06:32 +00006569 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelInfo));
cristy3ed852e2009-09-05 21:47:34 +00006570 if (undo_image != (Image *) NULL)
6571 {
6572 /*
cristya9a86bb2011-01-13 01:11:00 +00006573 Ensure the undo cache has enough memory available.
cristy3ed852e2009-09-05 21:47:34 +00006574 */
6575 previous_image=undo_image;
6576 while (previous_image != (Image *) NULL)
6577 {
6578 bytes+=previous_image->list->columns*previous_image->list->rows*
cristy101ab702011-10-13 13:06:32 +00006579 sizeof(PixelInfo);
cristybb503372010-05-27 20:51:26 +00006580 if (bytes <= (ssize_t) (resource_info->undo_cache << 20))
cristy3ed852e2009-09-05 21:47:34 +00006581 {
6582 previous_image=GetPreviousImageInList(previous_image);
6583 continue;
6584 }
6585 bytes-=previous_image->list->columns*previous_image->list->rows*
cristy101ab702011-10-13 13:06:32 +00006586 sizeof(PixelInfo);
cristy3ed852e2009-09-05 21:47:34 +00006587 if (previous_image == undo_image)
6588 undo_image=NewImageList();
6589 else
6590 previous_image->next->previous=NewImageList();
6591 break;
6592 }
6593 while (previous_image != (Image *) NULL)
6594 {
6595 /*
6596 Delete any excess memory from undo cache.
6597 */
6598 cache_image=previous_image;
6599 previous_image=GetPreviousImageInList(previous_image);
6600 cache_image->list=DestroyImage(cache_image->list);
6601 cache_image=DestroyImage(cache_image);
6602 }
6603 }
cristybb503372010-05-27 20:51:26 +00006604 if (bytes > (ssize_t) (resource_info->undo_cache << 20))
cristy3ed852e2009-09-05 21:47:34 +00006605 break;
6606 /*
6607 Save image before transformations are applied.
6608 */
cristy9950d572011-10-01 18:22:35 +00006609 cache_image=AcquireImage((ImageInfo *) NULL,exception);
cristy3ed852e2009-09-05 21:47:34 +00006610 if (cache_image == (Image *) NULL)
6611 break;
6612 XSetCursorState(display,windows,MagickTrue);
6613 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00006614 cache_image->list=CloneImage(*image,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +00006615 XSetCursorState(display,windows,MagickFalse);
6616 if (cache_image->list == (Image *) NULL)
6617 {
6618 cache_image=DestroyImage(cache_image);
6619 break;
6620 }
cristybb503372010-05-27 20:51:26 +00006621 cache_image->columns=(size_t) windows->image.ximage->width;
6622 cache_image->rows=(size_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +00006623 cache_image->geometry=windows->image.crop_geometry;
6624 if (windows->image.crop_geometry != (char *) NULL)
6625 {
6626 cache_image->geometry=AcquireString((char *) NULL);
6627 (void) CopyMagickString(cache_image->geometry,
6628 windows->image.crop_geometry,MaxTextExtent);
6629 }
6630 if (undo_image == (Image *) NULL)
6631 {
6632 undo_image=cache_image;
6633 break;
6634 }
6635 undo_image->next=cache_image;
6636 undo_image->next->previous=undo_image;
6637 undo_image=undo_image->next;
6638 break;
6639 }
6640 default:
6641 break;
6642 }
6643 if (command == RedoCommand)
6644 {
6645 /*
6646 Redo the last image transformation.
6647 */
6648 if (redo_image == (Image *) NULL)
6649 {
6650 (void) XBell(display,0);
6651 return;
6652 }
6653 windows->image.window_changes.width=(int) redo_image->columns;
6654 windows->image.window_changes.height=(int) redo_image->rows;
6655 if (windows->image.crop_geometry != (char *) NULL)
6656 windows->image.crop_geometry=(char *)
6657 RelinquishMagickMemory(windows->image.crop_geometry);
6658 windows->image.crop_geometry=redo_image->geometry;
6659 *image=DestroyImage(*image);
6660 *image=redo_image;
6661 redo_image=NewImageList();
anthony11d32022012-11-17 05:31:33 +00006662 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00006663 return;
cristy6710d842011-10-20 23:23:00 +00006664 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00006665 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00006666 return;
6667 }
6668 if (command != InfoCommand)
6669 return;
6670 /*
6671 Display image info.
6672 */
6673 XSetCursorState(display,windows,MagickTrue);
6674 XCheckRefreshWindows(display,windows);
cristy6710d842011-10-20 23:23:00 +00006675 XDisplayImageInfo(display,resource_info,windows,undo_image,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00006676 XSetCursorState(display,windows,MagickFalse);
6677}
6678
6679/*
6680%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6681% %
6682% %
6683% %
6684+ X I m a g e W i n d o w C o m m a n d %
6685% %
6686% %
6687% %
6688%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6689%
6690% XImageWindowCommand() makes a transform to the image or Image window as
6691% specified by a user menu button or keyboard command.
6692%
cristy051718b2011-08-28 22:49:25 +00006693% The format of the XImageWindowCommand method is:
cristy3ed852e2009-09-05 21:47:34 +00006694%
6695% CommandType XImageWindowCommand(Display *display,
6696% XResourceInfo *resource_info,XWindows *windows,
cristy051718b2011-08-28 22:49:25 +00006697% const MagickStatusType state,KeySym key_symbol,Image **image,
6698% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00006699%
6700% A description of each parameter follows:
6701%
6702% o nexus: Method XImageWindowCommand returns an image when the
6703% user chooses 'Open Image' from the command menu. Otherwise a null
6704% image is returned.
6705%
6706% o display: Specifies a connection to an X server; returned from
6707% XOpenDisplay.
6708%
6709% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
6710%
6711% o windows: Specifies a pointer to a XWindows structure.
6712%
6713% o state: key mask.
6714%
6715% o key_symbol: Specifies a command to perform.
6716%
cristy051718b2011-08-28 22:49:25 +00006717% o image: the image; XImageWIndowCommand may transform the image and
6718% return a new image pointer.
6719%
6720% o exception: return any errors or warnings in this structure.
cristy3ed852e2009-09-05 21:47:34 +00006721%
6722*/
6723static CommandType XImageWindowCommand(Display *display,
6724 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state,
cristy051718b2011-08-28 22:49:25 +00006725 KeySym key_symbol,Image **image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00006726{
6727 static char
6728 delta[MaxTextExtent] = "";
6729
6730 static const char
6731 Digits[] = "01234567890";
6732
6733 static KeySym
6734 last_symbol = XK_0;
6735
6736 if ((key_symbol >= XK_0) && (key_symbol <= XK_9))
6737 {
6738 if (((last_symbol < XK_0) || (last_symbol > XK_9)))
6739 {
6740 *delta='\0';
6741 resource_info->quantum=1;
6742 }
6743 last_symbol=key_symbol;
6744 delta[strlen(delta)+1]='\0';
6745 delta[strlen(delta)]=Digits[key_symbol-XK_0];
cristyf2f27272009-12-17 14:48:46 +00006746 resource_info->quantum=StringToLong(delta);
cristy3ed852e2009-09-05 21:47:34 +00006747 return(NullCommand);
6748 }
6749 last_symbol=key_symbol;
6750 if (resource_info->immutable)
6751 {
6752 /*
6753 Virtual image window has a restricted command set.
6754 */
6755 switch (key_symbol)
6756 {
6757 case XK_question:
6758 return(InfoCommand);
6759 case XK_p:
6760 case XK_Print:
6761 return(PrintCommand);
6762 case XK_space:
6763 return(NextCommand);
6764 case XK_q:
6765 case XK_Escape:
6766 return(QuitCommand);
6767 default:
6768 break;
6769 }
6770 return(NullCommand);
6771 }
6772 switch ((int) key_symbol)
6773 {
6774 case XK_o:
6775 {
6776 if ((state & ControlMask) == 0)
6777 break;
6778 return(OpenCommand);
6779 }
6780 case XK_space:
6781 return(NextCommand);
6782 case XK_BackSpace:
6783 return(FormerCommand);
6784 case XK_s:
6785 {
6786 if ((state & Mod1Mask) != 0)
6787 return(SwirlCommand);
6788 if ((state & ControlMask) == 0)
6789 return(ShearCommand);
6790 return(SaveCommand);
6791 }
6792 case XK_p:
6793 case XK_Print:
6794 {
6795 if ((state & Mod1Mask) != 0)
6796 return(OilPaintCommand);
6797 if ((state & Mod4Mask) != 0)
6798 return(ColorCommand);
6799 if ((state & ControlMask) == 0)
6800 return(NullCommand);
6801 return(PrintCommand);
6802 }
6803 case XK_d:
6804 {
6805 if ((state & Mod4Mask) != 0)
6806 return(DrawCommand);
6807 if ((state & ControlMask) == 0)
6808 return(NullCommand);
6809 return(DeleteCommand);
6810 }
6811 case XK_Select:
6812 {
6813 if ((state & ControlMask) == 0)
6814 return(NullCommand);
6815 return(SelectCommand);
6816 }
6817 case XK_n:
6818 {
6819 if ((state & ControlMask) == 0)
6820 return(NullCommand);
6821 return(NewCommand);
6822 }
6823 case XK_q:
6824 case XK_Escape:
6825 return(QuitCommand);
6826 case XK_z:
6827 case XK_Undo:
6828 {
6829 if ((state & ControlMask) == 0)
6830 return(NullCommand);
6831 return(UndoCommand);
6832 }
6833 case XK_r:
6834 case XK_Redo:
6835 {
6836 if ((state & ControlMask) == 0)
6837 return(RollCommand);
6838 return(RedoCommand);
6839 }
6840 case XK_x:
6841 {
6842 if ((state & ControlMask) == 0)
6843 return(NullCommand);
6844 return(CutCommand);
6845 }
6846 case XK_c:
6847 {
6848 if ((state & Mod1Mask) != 0)
6849 return(CharcoalDrawCommand);
6850 if ((state & ControlMask) == 0)
6851 return(CropCommand);
6852 return(CopyCommand);
6853 }
6854 case XK_v:
6855 case XK_Insert:
6856 {
6857 if ((state & Mod4Mask) != 0)
6858 return(CompositeCommand);
6859 if ((state & ControlMask) == 0)
6860 return(FlipCommand);
6861 return(PasteCommand);
6862 }
6863 case XK_less:
6864 return(HalfSizeCommand);
6865 case XK_minus:
6866 return(OriginalSizeCommand);
6867 case XK_greater:
6868 return(DoubleSizeCommand);
6869 case XK_percent:
6870 return(ResizeCommand);
6871 case XK_at:
6872 return(RefreshCommand);
6873 case XK_bracketleft:
6874 return(ChopCommand);
6875 case XK_h:
6876 return(FlopCommand);
6877 case XK_slash:
6878 return(RotateRightCommand);
6879 case XK_backslash:
6880 return(RotateLeftCommand);
6881 case XK_asterisk:
6882 return(RotateCommand);
6883 case XK_t:
6884 return(TrimCommand);
6885 case XK_H:
6886 return(HueCommand);
6887 case XK_S:
6888 return(SaturationCommand);
6889 case XK_L:
6890 return(BrightnessCommand);
6891 case XK_G:
6892 return(GammaCommand);
6893 case XK_C:
6894 return(SpiffCommand);
6895 case XK_Z:
6896 return(DullCommand);
6897 case XK_N:
6898 return(NormalizeCommand);
6899 case XK_equal:
6900 return(EqualizeCommand);
6901 case XK_asciitilde:
6902 return(NegateCommand);
6903 case XK_period:
6904 return(GrayscaleCommand);
6905 case XK_numbersign:
6906 return(QuantizeCommand);
6907 case XK_F2:
6908 return(DespeckleCommand);
6909 case XK_F3:
6910 return(EmbossCommand);
6911 case XK_F4:
6912 return(ReduceNoiseCommand);
6913 case XK_F5:
6914 return(AddNoiseCommand);
6915 case XK_F6:
6916 return(SharpenCommand);
6917 case XK_F7:
6918 return(BlurCommand);
6919 case XK_F8:
6920 return(ThresholdCommand);
6921 case XK_F9:
6922 return(EdgeDetectCommand);
6923 case XK_F10:
6924 return(SpreadCommand);
6925 case XK_F11:
6926 return(ShadeCommand);
6927 case XK_F12:
6928 return(RaiseCommand);
6929 case XK_F13:
6930 return(SegmentCommand);
6931 case XK_i:
6932 {
6933 if ((state & Mod1Mask) == 0)
6934 return(NullCommand);
6935 return(ImplodeCommand);
6936 }
6937 case XK_w:
6938 {
6939 if ((state & Mod1Mask) == 0)
6940 return(NullCommand);
6941 return(WaveCommand);
6942 }
6943 case XK_m:
6944 {
6945 if ((state & Mod4Mask) == 0)
6946 return(NullCommand);
6947 return(MatteCommand);
6948 }
6949 case XK_b:
6950 {
6951 if ((state & Mod4Mask) == 0)
6952 return(NullCommand);
6953 return(AddBorderCommand);
6954 }
6955 case XK_f:
6956 {
6957 if ((state & Mod4Mask) == 0)
6958 return(NullCommand);
6959 return(AddFrameCommand);
6960 }
6961 case XK_exclam:
6962 {
6963 if ((state & Mod4Mask) == 0)
6964 return(NullCommand);
6965 return(CommentCommand);
6966 }
6967 case XK_a:
6968 {
6969 if ((state & Mod1Mask) != 0)
6970 return(ApplyCommand);
6971 if ((state & Mod4Mask) != 0)
6972 return(AnnotateCommand);
6973 if ((state & ControlMask) == 0)
6974 return(NullCommand);
6975 return(RegionofInterestCommand);
6976 }
6977 case XK_question:
6978 return(InfoCommand);
6979 case XK_plus:
6980 return(ZoomCommand);
6981 case XK_P:
6982 {
6983 if ((state & ShiftMask) == 0)
6984 return(NullCommand);
6985 return(ShowPreviewCommand);
6986 }
6987 case XK_Execute:
6988 return(LaunchCommand);
6989 case XK_F1:
6990 return(HelpCommand);
6991 case XK_Find:
6992 return(BrowseDocumentationCommand);
6993 case XK_Menu:
6994 {
6995 (void) XMapRaised(display,windows->command.id);
6996 return(NullCommand);
6997 }
6998 case XK_Next:
6999 case XK_Prior:
7000 case XK_Home:
7001 case XK_KP_Home:
7002 {
7003 XTranslateImage(display,windows,*image,key_symbol);
7004 return(NullCommand);
7005 }
7006 case XK_Up:
7007 case XK_KP_Up:
7008 case XK_Down:
7009 case XK_KP_Down:
7010 case XK_Left:
7011 case XK_KP_Left:
7012 case XK_Right:
7013 case XK_KP_Right:
7014 {
7015 if ((state & Mod1Mask) != 0)
7016 {
7017 RectangleInfo
7018 crop_info;
7019
7020 /*
7021 Trim one pixel from edge of image.
7022 */
7023 crop_info.x=0;
7024 crop_info.y=0;
cristybb503372010-05-27 20:51:26 +00007025 crop_info.width=(size_t) windows->image.ximage->width;
7026 crop_info.height=(size_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +00007027 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up))
7028 {
7029 if (resource_info->quantum >= (int) crop_info.height)
7030 resource_info->quantum=(int) crop_info.height-1;
7031 crop_info.height-=resource_info->quantum;
7032 }
7033 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down))
7034 {
7035 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y))
7036 resource_info->quantum=(int) (crop_info.height-crop_info.y-1);
7037 crop_info.y+=resource_info->quantum;
7038 crop_info.height-=resource_info->quantum;
7039 }
7040 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left))
7041 {
7042 if (resource_info->quantum >= (int) crop_info.width)
7043 resource_info->quantum=(int) crop_info.width-1;
7044 crop_info.width-=resource_info->quantum;
7045 }
7046 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right))
7047 {
7048 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x))
7049 resource_info->quantum=(int) (crop_info.width-crop_info.x-1);
7050 crop_info.x+=resource_info->quantum;
7051 crop_info.width-=resource_info->quantum;
7052 }
7053 if ((int) (windows->image.x+windows->image.width) >
7054 (int) crop_info.width)
7055 windows->image.x=(int) (crop_info.width-windows->image.width);
7056 if ((int) (windows->image.y+windows->image.height) >
7057 (int) crop_info.height)
7058 windows->image.y=(int) (crop_info.height-windows->image.height);
7059 XSetCropGeometry(display,windows,&crop_info,*image);
7060 windows->image.window_changes.width=(int) crop_info.width;
7061 windows->image.window_changes.height=(int) crop_info.height;
7062 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None);
cristy051718b2011-08-28 22:49:25 +00007063 (void) XConfigureImage(display,resource_info,windows,*image,
7064 exception);
cristy3ed852e2009-09-05 21:47:34 +00007065 return(NullCommand);
7066 }
7067 XTranslateImage(display,windows,*image,key_symbol);
7068 return(NullCommand);
7069 }
7070 default:
7071 return(NullCommand);
7072 }
7073 return(NullCommand);
7074}
7075
7076/*
7077%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7078% %
7079% %
7080% %
7081+ X M a g i c k C o m m a n d %
7082% %
7083% %
7084% %
7085%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
7086%
7087% XMagickCommand() makes a transform to the image or Image window as
7088% specified by a user menu button or keyboard command.
7089%
7090% The format of the XMagickCommand method is:
7091%
7092% Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +00007093% XWindows *windows,const CommandType command,Image **image,
7094% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00007095%
7096% A description of each parameter follows:
7097%
cristy3ed852e2009-09-05 21:47:34 +00007098% o display: Specifies a connection to an X server; returned from
7099% XOpenDisplay.
7100%
7101% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
7102%
7103% o windows: Specifies a pointer to a XWindows structure.
7104%
7105% o command: Specifies a command to perform.
7106%
cristy051718b2011-08-28 22:49:25 +00007107% o image: the image; XMagickCommand may transform the image and return a
7108% new image pointer.
7109%
7110% o exception: return any errors or warnings in this structure.
cristy3ed852e2009-09-05 21:47:34 +00007111%
7112*/
7113static Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +00007114 XWindows *windows,const CommandType command,Image **image,
7115 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00007116{
7117 char
7118 filename[MaxTextExtent],
7119 geometry[MaxTextExtent],
7120 modulate_factors[MaxTextExtent];
7121
7122 GeometryInfo
7123 geometry_info;
7124
7125 Image
7126 *nexus;
7127
7128 ImageInfo
7129 *image_info;
7130
7131 int
7132 x,
7133 y;
7134
7135 MagickStatusType
7136 flags,
7137 status;
7138
7139 QuantizeInfo
7140 quantize_info;
7141
7142 RectangleInfo
7143 page_geometry;
7144
7145 register int
7146 i;
7147
7148 static char
7149 color[MaxTextExtent] = "gray";
7150
7151 unsigned int
7152 height,
7153 width;
7154
7155 /*
7156 Process user command.
7157 */
7158 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007159 XImageCache(display,resource_info,windows,command,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007160 nexus=NewImageList();
7161 windows->image.window_changes.width=windows->image.ximage->width;
7162 windows->image.window_changes.height=windows->image.ximage->height;
7163 image_info=CloneImageInfo(resource_info->image_info);
7164 SetGeometryInfo(&geometry_info);
7165 GetQuantizeInfo(&quantize_info);
7166 switch (command)
7167 {
7168 case OpenCommand:
7169 {
7170 /*
7171 Load image.
7172 */
7173 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
7174 break;
7175 }
7176 case NextCommand:
7177 {
7178 /*
7179 Display next image.
7180 */
7181 for (i=0; i < resource_info->quantum; i++)
7182 XClientMessage(display,windows->image.id,windows->im_protocols,
7183 windows->im_next_image,CurrentTime);
7184 break;
7185 }
7186 case FormerCommand:
7187 {
7188 /*
7189 Display former image.
7190 */
7191 for (i=0; i < resource_info->quantum; i++)
7192 XClientMessage(display,windows->image.id,windows->im_protocols,
7193 windows->im_former_image,CurrentTime);
7194 break;
7195 }
7196 case SelectCommand:
7197 {
7198 int
7199 status;
7200
7201 /*
7202 Select image.
7203 */
cristy8a5d7f42013-01-06 15:24:33 +00007204 if (*resource_info->home_directory == '\0')
7205 (void) CopyMagickString(resource_info->home_directory,".",
7206 MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +00007207 status=chdir(resource_info->home_directory);
7208 if (status == -1)
cristy051718b2011-08-28 22:49:25 +00007209 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
7210 "UnableToOpenFile","%s",resource_info->home_directory);
cristy3ed852e2009-09-05 21:47:34 +00007211 nexus=XOpenImage(display,resource_info,windows,MagickTrue);
7212 break;
7213 }
7214 case SaveCommand:
7215 {
7216 /*
7217 Save image.
7218 */
cristy051718b2011-08-28 22:49:25 +00007219 status=XSaveImage(display,resource_info,windows,*image,exception);
anthony11d32022012-11-17 05:31:33 +00007220 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00007221 {
cristyc663dbd2011-09-16 19:43:14 +00007222 char
7223 message[MaxTextExtent];
7224
7225 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s",
7226 exception->reason != (char *) NULL ? exception->reason : "",
7227 exception->description != (char *) NULL ? exception->description :
7228 "");
7229 XNoticeWidget(display,windows,"Unable to save file:",message);
cristy3ed852e2009-09-05 21:47:34 +00007230 break;
7231 }
7232 break;
7233 }
7234 case PrintCommand:
7235 {
7236 /*
7237 Print image.
7238 */
cristy051718b2011-08-28 22:49:25 +00007239 status=XPrintImage(display,resource_info,windows,*image,exception);
anthony11d32022012-11-17 05:31:33 +00007240 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00007241 {
cristyc663dbd2011-09-16 19:43:14 +00007242 char
7243 message[MaxTextExtent];
7244
7245 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s",
7246 exception->reason != (char *) NULL ? exception->reason : "",
7247 exception->description != (char *) NULL ? exception->description :
7248 "");
7249 XNoticeWidget(display,windows,"Unable to print file:",message);
cristy3ed852e2009-09-05 21:47:34 +00007250 break;
7251 }
7252 break;
7253 }
7254 case DeleteCommand:
7255 {
7256 static char
7257 filename[MaxTextExtent] = "\0";
7258
7259 /*
7260 Delete image file.
7261 */
7262 XFileBrowserWidget(display,windows,"Delete",filename);
7263 if (*filename == '\0')
7264 break;
anthony11d32022012-11-17 05:31:33 +00007265 status=IsMagickTrue(remove_utf8(filename));
7266 if( IfMagickTrue(status) )
cristy3ed852e2009-09-05 21:47:34 +00007267 XNoticeWidget(display,windows,"Unable to delete image file:",filename);
7268 break;
7269 }
7270 case NewCommand:
7271 {
7272 int
7273 status;
7274
7275 static char
7276 color[MaxTextExtent] = "gray",
7277 geometry[MaxTextExtent] = "640x480";
7278
7279 static const char
7280 *format = "gradient";
7281
7282 /*
7283 Query user for canvas geometry.
7284 */
7285 status=XDialogWidget(display,windows,"New","Enter image geometry:",
7286 geometry);
7287 if (*geometry == '\0')
7288 break;
7289 if (status == 0)
7290 format="xc";
7291 XColorBrowserWidget(display,windows,"Select",color);
7292 if (*color == '\0')
7293 break;
7294 /*
7295 Create canvas.
7296 */
cristyb51dff52011-05-19 16:55:47 +00007297 (void) FormatLocaleString(image_info->filename,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00007298 "%s:%s",format,color);
7299 (void) CloneString(&image_info->size,geometry);
cristy051718b2011-08-28 22:49:25 +00007300 nexus=ReadImage(image_info,exception);
7301 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00007302 XClientMessage(display,windows->image.id,windows->im_protocols,
7303 windows->im_next_image,CurrentTime);
7304 break;
7305 }
7306 case VisualDirectoryCommand:
7307 {
7308 /*
7309 Visual Image directory.
7310 */
cristy051718b2011-08-28 22:49:25 +00007311 nexus=XVisualDirectoryImage(display,resource_info,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +00007312 break;
7313 }
7314 case QuitCommand:
7315 {
7316 /*
7317 exit program.
7318 */
anthony11d32022012-11-17 05:31:33 +00007319 if( IfMagickFalse(resource_info->confirm_exit) )
cristy3ed852e2009-09-05 21:47:34 +00007320 XClientMessage(display,windows->image.id,windows->im_protocols,
7321 windows->im_exit,CurrentTime);
7322 else
7323 {
7324 int
7325 status;
7326
7327 /*
7328 Confirm program exit.
7329 */
7330 status=XConfirmWidget(display,windows,"Do you really want to exit",
7331 resource_info->client_name);
7332 if (status > 0)
7333 XClientMessage(display,windows->image.id,windows->im_protocols,
7334 windows->im_exit,CurrentTime);
7335 }
7336 break;
7337 }
7338 case CutCommand:
7339 {
7340 /*
7341 Cut image.
7342 */
cristy051718b2011-08-28 22:49:25 +00007343 (void) XCropImage(display,resource_info,windows,*image,CutMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00007344 break;
7345 }
7346 case CopyCommand:
7347 {
7348 /*
7349 Copy image.
7350 */
cristy051718b2011-08-28 22:49:25 +00007351 (void) XCropImage(display,resource_info,windows,*image,CopyMode,
7352 exception);
cristy3ed852e2009-09-05 21:47:34 +00007353 break;
7354 }
7355 case PasteCommand:
7356 {
7357 /*
7358 Paste image.
7359 */
cristy051718b2011-08-28 22:49:25 +00007360 status=XPasteImage(display,resource_info,windows,*image,exception);
anthony11d32022012-11-17 05:31:33 +00007361 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00007362 {
7363 XNoticeWidget(display,windows,"Unable to paste X image",
7364 (*image)->filename);
7365 break;
7366 }
7367 break;
7368 }
7369 case HalfSizeCommand:
7370 {
7371 /*
7372 Half image size.
7373 */
7374 windows->image.window_changes.width=windows->image.ximage->width/2;
7375 windows->image.window_changes.height=windows->image.ximage->height/2;
cristy051718b2011-08-28 22:49:25 +00007376 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007377 break;
7378 }
7379 case OriginalSizeCommand:
7380 {
7381 /*
7382 Original image size.
7383 */
7384 windows->image.window_changes.width=(int) (*image)->columns;
7385 windows->image.window_changes.height=(int) (*image)->rows;
cristy051718b2011-08-28 22:49:25 +00007386 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007387 break;
7388 }
7389 case DoubleSizeCommand:
7390 {
7391 /*
7392 Double the image size.
7393 */
7394 windows->image.window_changes.width=windows->image.ximage->width << 1;
7395 windows->image.window_changes.height=windows->image.ximage->height << 1;
cristy051718b2011-08-28 22:49:25 +00007396 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007397 break;
7398 }
7399 case ResizeCommand:
7400 {
7401 int
7402 status;
7403
cristybb503372010-05-27 20:51:26 +00007404 size_t
cristy3ed852e2009-09-05 21:47:34 +00007405 height,
7406 width;
7407
cristy9d314ff2011-03-09 01:30:28 +00007408 ssize_t
7409 x,
7410 y;
7411
cristy3ed852e2009-09-05 21:47:34 +00007412 /*
7413 Resize image.
7414 */
cristybb503372010-05-27 20:51:26 +00007415 width=(size_t) windows->image.ximage->width;
7416 height=(size_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +00007417 x=0;
7418 y=0;
cristyb51dff52011-05-19 16:55:47 +00007419 (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g+0+0",
cristye8c25f92010-06-03 00:53:06 +00007420 (double) width,(double) height);
cristy3ed852e2009-09-05 21:47:34 +00007421 status=XDialogWidget(display,windows,"Resize",
7422 "Enter resize geometry (e.g. 640x480, 200%):",geometry);
7423 if (*geometry == '\0')
7424 break;
7425 if (status == 0)
7426 (void) ConcatenateMagickString(geometry,"!",MaxTextExtent);
7427 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
7428 windows->image.window_changes.width=(int) width;
7429 windows->image.window_changes.height=(int) height;
cristy051718b2011-08-28 22:49:25 +00007430 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007431 break;
7432 }
7433 case ApplyCommand:
7434 {
7435 char
7436 image_geometry[MaxTextExtent];
7437
7438 if ((windows->image.crop_geometry == (char *) NULL) &&
7439 ((int) (*image)->columns == windows->image.ximage->width) &&
7440 ((int) (*image)->rows == windows->image.ximage->height))
7441 break;
7442 /*
7443 Apply size transforms to image.
7444 */
7445 XSetCursorState(display,windows,MagickTrue);
7446 XCheckRefreshWindows(display,windows);
7447 /*
7448 Crop and/or scale displayed image.
7449 */
cristyb51dff52011-05-19 16:55:47 +00007450 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!",
cristy3ed852e2009-09-05 21:47:34 +00007451 windows->image.ximage->width,windows->image.ximage->height);
cristye941a752011-10-15 01:52:48 +00007452 (void) TransformImage(image,windows->image.crop_geometry,image_geometry,
7453 exception);
cristy3ed852e2009-09-05 21:47:34 +00007454 if (windows->image.crop_geometry != (char *) NULL)
cristye941a752011-10-15 01:52:48 +00007455 windows->image.crop_geometry=(char *) RelinquishMagickMemory(
7456 windows->image.crop_geometry);
cristy3ed852e2009-09-05 21:47:34 +00007457 windows->image.x=0;
7458 windows->image.y=0;
cristy6710d842011-10-20 23:23:00 +00007459 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007460 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007461 break;
7462 }
7463 case RefreshCommand:
7464 {
cristy051718b2011-08-28 22:49:25 +00007465 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007466 break;
7467 }
7468 case RestoreCommand:
7469 {
7470 /*
7471 Restore Image window to its original size.
7472 */
7473 if ((windows->image.width == (unsigned int) (*image)->columns) &&
7474 (windows->image.height == (unsigned int) (*image)->rows) &&
7475 (windows->image.crop_geometry == (char *) NULL))
7476 {
7477 (void) XBell(display,0);
7478 break;
7479 }
7480 windows->image.window_changes.width=(int) (*image)->columns;
7481 windows->image.window_changes.height=(int) (*image)->rows;
7482 if (windows->image.crop_geometry != (char *) NULL)
7483 {
7484 windows->image.crop_geometry=(char *)
7485 RelinquishMagickMemory(windows->image.crop_geometry);
7486 windows->image.crop_geometry=(char *) NULL;
7487 windows->image.x=0;
7488 windows->image.y=0;
7489 }
cristy6710d842011-10-20 23:23:00 +00007490 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007491 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007492 break;
7493 }
7494 case CropCommand:
7495 {
7496 /*
7497 Crop image.
7498 */
cristy051718b2011-08-28 22:49:25 +00007499 (void) XCropImage(display,resource_info,windows,*image,CropMode,
7500 exception);
cristy3ed852e2009-09-05 21:47:34 +00007501 break;
7502 }
7503 case ChopCommand:
7504 {
7505 /*
7506 Chop image.
7507 */
cristy051718b2011-08-28 22:49:25 +00007508 status=XChopImage(display,resource_info,windows,image,exception);
anthony11d32022012-11-17 05:31:33 +00007509 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00007510 {
7511 XNoticeWidget(display,windows,"Unable to cut X image",
7512 (*image)->filename);
7513 break;
7514 }
7515 break;
7516 }
7517 case FlopCommand:
7518 {
7519 Image
7520 *flop_image;
7521
7522 /*
7523 Flop image scanlines.
7524 */
7525 XSetCursorState(display,windows,MagickTrue);
7526 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007527 flop_image=FlopImage(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007528 if (flop_image != (Image *) NULL)
7529 {
7530 *image=DestroyImage(*image);
7531 *image=flop_image;
7532 }
cristy051718b2011-08-28 22:49:25 +00007533 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00007534 XSetCursorState(display,windows,MagickFalse);
7535 if (windows->image.crop_geometry != (char *) NULL)
7536 {
7537 /*
7538 Flop crop geometry.
7539 */
7540 width=(unsigned int) (*image)->columns;
7541 height=(unsigned int) (*image)->rows;
7542 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7543 &width,&height);
cristyb51dff52011-05-19 16:55:47 +00007544 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00007545 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y);
7546 }
anthony11d32022012-11-17 05:31:33 +00007547 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007548 break;
cristy051718b2011-08-28 22:49:25 +00007549 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007550 break;
7551 }
7552 case FlipCommand:
7553 {
7554 Image
7555 *flip_image;
7556
7557 /*
7558 Flip image scanlines.
7559 */
7560 XSetCursorState(display,windows,MagickTrue);
7561 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007562 flip_image=FlipImage(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007563 if (flip_image != (Image *) NULL)
7564 {
7565 *image=DestroyImage(*image);
7566 *image=flip_image;
7567 }
cristy051718b2011-08-28 22:49:25 +00007568 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00007569 XSetCursorState(display,windows,MagickFalse);
7570 if (windows->image.crop_geometry != (char *) NULL)
7571 {
7572 /*
7573 Flip crop geometry.
7574 */
7575 width=(unsigned int) (*image)->columns;
7576 height=(unsigned int) (*image)->rows;
7577 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
7578 &width,&height);
cristyb51dff52011-05-19 16:55:47 +00007579 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00007580 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y);
7581 }
anthony11d32022012-11-17 05:31:33 +00007582 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007583 break;
cristy051718b2011-08-28 22:49:25 +00007584 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007585 break;
7586 }
7587 case RotateRightCommand:
7588 {
7589 /*
7590 Rotate image 90 degrees clockwise.
7591 */
cristy051718b2011-08-28 22:49:25 +00007592 status=XRotateImage(display,resource_info,windows,90.0,image,exception);
anthony11d32022012-11-17 05:31:33 +00007593 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00007594 {
7595 XNoticeWidget(display,windows,"Unable to rotate X image",
7596 (*image)->filename);
7597 break;
7598 }
7599 break;
7600 }
7601 case RotateLeftCommand:
7602 {
7603 /*
7604 Rotate image 90 degrees counter-clockwise.
7605 */
cristy051718b2011-08-28 22:49:25 +00007606 status=XRotateImage(display,resource_info,windows,-90.0,image,exception);
anthony11d32022012-11-17 05:31:33 +00007607 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00007608 {
7609 XNoticeWidget(display,windows,"Unable to rotate X image",
7610 (*image)->filename);
7611 break;
7612 }
7613 break;
7614 }
7615 case RotateCommand:
7616 {
7617 /*
7618 Rotate image.
7619 */
cristy051718b2011-08-28 22:49:25 +00007620 status=XRotateImage(display,resource_info,windows,0.0,image,exception);
anthony11d32022012-11-17 05:31:33 +00007621 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00007622 {
7623 XNoticeWidget(display,windows,"Unable to rotate X image",
7624 (*image)->filename);
7625 break;
7626 }
7627 break;
7628 }
7629 case ShearCommand:
7630 {
7631 Image
7632 *shear_image;
7633
7634 static char
7635 geometry[MaxTextExtent] = "45.0x45.0";
7636
7637 /*
7638 Query user for shear color and geometry.
7639 */
7640 XColorBrowserWidget(display,windows,"Select",color);
7641 if (*color == '\0')
7642 break;
7643 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:",
7644 geometry);
7645 if (*geometry == '\0')
7646 break;
7647 /*
7648 Shear image.
7649 */
cristy051718b2011-08-28 22:49:25 +00007650 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
7651 exception);
cristy3ed852e2009-09-05 21:47:34 +00007652 XSetCursorState(display,windows,MagickTrue);
7653 XCheckRefreshWindows(display,windows);
cristy9950d572011-10-01 18:22:35 +00007654 (void) QueryColorCompliance(color,AllCompliance,
7655 &(*image)->background_color,exception);
cristy3ed852e2009-09-05 21:47:34 +00007656 flags=ParseGeometry(geometry,&geometry_info);
7657 if ((flags & SigmaValue) == 0)
7658 geometry_info.sigma=geometry_info.rho;
7659 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma,
cristy051718b2011-08-28 22:49:25 +00007660 exception);
cristy3ed852e2009-09-05 21:47:34 +00007661 if (shear_image != (Image *) NULL)
7662 {
7663 *image=DestroyImage(*image);
7664 *image=shear_image;
7665 }
cristy051718b2011-08-28 22:49:25 +00007666 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00007667 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00007668 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007669 break;
7670 windows->image.window_changes.width=(int) (*image)->columns;
7671 windows->image.window_changes.height=(int) (*image)->rows;
cristy6710d842011-10-20 23:23:00 +00007672 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007673 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007674 break;
7675 }
7676 case RollCommand:
7677 {
7678 Image
7679 *roll_image;
7680
7681 static char
7682 geometry[MaxTextExtent] = "+2+2";
7683
7684 /*
7685 Query user for the roll geometry.
7686 */
7687 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:",
7688 geometry);
7689 if (*geometry == '\0')
7690 break;
7691 /*
7692 Roll image.
7693 */
cristy051718b2011-08-28 22:49:25 +00007694 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
7695 exception);
cristy3ed852e2009-09-05 21:47:34 +00007696 XSetCursorState(display,windows,MagickTrue);
7697 XCheckRefreshWindows(display,windows);
7698 (void) ParsePageGeometry(*image,geometry,&page_geometry,
cristy051718b2011-08-28 22:49:25 +00007699 exception);
cristy3ed852e2009-09-05 21:47:34 +00007700 roll_image=RollImage(*image,page_geometry.x,page_geometry.y,
cristy051718b2011-08-28 22:49:25 +00007701 exception);
cristy3ed852e2009-09-05 21:47:34 +00007702 if (roll_image != (Image *) NULL)
7703 {
7704 *image=DestroyImage(*image);
7705 *image=roll_image;
7706 }
cristy051718b2011-08-28 22:49:25 +00007707 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00007708 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00007709 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007710 break;
7711 windows->image.window_changes.width=(int) (*image)->columns;
7712 windows->image.window_changes.height=(int) (*image)->rows;
cristy6710d842011-10-20 23:23:00 +00007713 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007714 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007715 break;
7716 }
7717 case TrimCommand:
7718 {
7719 static char
7720 fuzz[MaxTextExtent];
7721
7722 /*
7723 Query user for the fuzz factor.
7724 */
cristyb51dff52011-05-19 16:55:47 +00007725 (void) FormatLocaleString(fuzz,MaxTextExtent,"%g%%",100.0*
cristy8cd5b312010-01-07 01:10:24 +00007726 (*image)->fuzz/(QuantumRange+1.0));
cristy3ed852e2009-09-05 21:47:34 +00007727 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz);
7728 if (*fuzz == '\0')
7729 break;
cristydbdd0e32011-11-04 23:29:40 +00007730 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+1.0);
cristy3ed852e2009-09-05 21:47:34 +00007731 /*
7732 Trim image.
7733 */
cristy051718b2011-08-28 22:49:25 +00007734 status=XTrimImage(display,resource_info,windows,*image,exception);
anthony11d32022012-11-17 05:31:33 +00007735 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00007736 {
7737 XNoticeWidget(display,windows,"Unable to trim X image",
7738 (*image)->filename);
7739 break;
7740 }
7741 break;
7742 }
7743 case HueCommand:
7744 {
7745 static char
7746 hue_percent[MaxTextExtent] = "110";
7747
7748 /*
7749 Query user for percent hue change.
7750 */
7751 (void) XDialogWidget(display,windows,"Apply",
7752 "Enter percent change in image hue (0-200):",hue_percent);
7753 if (*hue_percent == '\0')
7754 break;
7755 /*
7756 Vary the image hue.
7757 */
7758 XSetCursorState(display,windows,MagickTrue);
7759 XCheckRefreshWindows(display,windows);
7760 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent);
7761 (void) ConcatenateMagickString(modulate_factors,hue_percent,
7762 MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00007763 (void) ModulateImage(*image,modulate_factors,exception);
cristy3ed852e2009-09-05 21:47:34 +00007764 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00007765 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007766 break;
cristy6710d842011-10-20 23:23:00 +00007767 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007768 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007769 break;
7770 }
7771 case SaturationCommand:
7772 {
7773 static char
7774 saturation_percent[MaxTextExtent] = "110";
7775
7776 /*
7777 Query user for percent saturation change.
7778 */
7779 (void) XDialogWidget(display,windows,"Apply",
7780 "Enter percent change in color saturation (0-200):",saturation_percent);
7781 if (*saturation_percent == '\0')
7782 break;
7783 /*
7784 Vary color saturation.
7785 */
7786 XSetCursorState(display,windows,MagickTrue);
7787 XCheckRefreshWindows(display,windows);
7788 (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent);
7789 (void) ConcatenateMagickString(modulate_factors,saturation_percent,
7790 MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00007791 (void) ModulateImage(*image,modulate_factors,exception);
cristy3ed852e2009-09-05 21:47:34 +00007792 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00007793 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007794 break;
cristy6710d842011-10-20 23:23:00 +00007795 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007796 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007797 break;
7798 }
7799 case BrightnessCommand:
7800 {
7801 static char
7802 brightness_percent[MaxTextExtent] = "110";
7803
7804 /*
7805 Query user for percent brightness change.
7806 */
7807 (void) XDialogWidget(display,windows,"Apply",
7808 "Enter percent change in color brightness (0-200):",brightness_percent);
7809 if (*brightness_percent == '\0')
7810 break;
7811 /*
7812 Vary the color brightness.
7813 */
7814 XSetCursorState(display,windows,MagickTrue);
7815 XCheckRefreshWindows(display,windows);
7816 (void) CopyMagickString(modulate_factors,brightness_percent,
7817 MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00007818 (void) ModulateImage(*image,modulate_factors,exception);
cristy3ed852e2009-09-05 21:47:34 +00007819 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00007820 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007821 break;
cristy6710d842011-10-20 23:23:00 +00007822 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007823 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007824 break;
7825 }
7826 case GammaCommand:
7827 {
7828 static char
7829 factor[MaxTextExtent] = "1.6";
7830
7831 /*
7832 Query user for gamma value.
7833 */
7834 (void) XDialogWidget(display,windows,"Gamma",
cristy50fbc382011-07-07 02:19:17 +00007835 "Enter gamma value (e.g. 1.2):",factor);
cristy3ed852e2009-09-05 21:47:34 +00007836 if (*factor == '\0')
7837 break;
7838 /*
7839 Gamma correct image.
7840 */
7841 XSetCursorState(display,windows,MagickTrue);
7842 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007843 (void) GammaImage(*image,atof(factor),exception);
cristy3ed852e2009-09-05 21:47:34 +00007844 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00007845 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007846 break;
cristy6710d842011-10-20 23:23:00 +00007847 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007848 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007849 break;
7850 }
7851 case SpiffCommand:
7852 {
7853 /*
7854 Sharpen the image contrast.
7855 */
7856 XSetCursorState(display,windows,MagickTrue);
7857 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007858 (void) ContrastImage(*image,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +00007859 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00007860 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007861 break;
cristy6710d842011-10-20 23:23:00 +00007862 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007863 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007864 break;
7865 }
7866 case DullCommand:
7867 {
7868 /*
7869 Dull the image contrast.
7870 */
7871 XSetCursorState(display,windows,MagickTrue);
7872 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007873 (void) ContrastImage(*image,MagickFalse,exception);
cristy3ed852e2009-09-05 21:47:34 +00007874 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00007875 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007876 break;
cristy6710d842011-10-20 23:23:00 +00007877 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007878 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007879 break;
7880 }
7881 case ContrastStretchCommand:
7882 {
7883 double
7884 black_point,
7885 white_point;
7886
7887 static char
7888 levels[MaxTextExtent] = "1%";
7889
7890 /*
7891 Query user for gamma value.
7892 */
7893 (void) XDialogWidget(display,windows,"Contrast Stretch",
7894 "Enter black and white points:",levels);
7895 if (*levels == '\0')
7896 break;
7897 /*
7898 Contrast stretch image.
7899 */
7900 XSetCursorState(display,windows,MagickTrue);
7901 XCheckRefreshWindows(display,windows);
7902 flags=ParseGeometry(levels,&geometry_info);
7903 black_point=geometry_info.rho;
7904 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point;
7905 if ((flags & PercentValue) != 0)
7906 {
7907 black_point*=(double) (*image)->columns*(*image)->rows/100.0;
7908 white_point*=(double) (*image)->columns*(*image)->rows/100.0;
7909 }
cristya19f1d72012-08-07 18:24:38 +00007910 white_point=(double) (*image)->columns*(*image)->rows-white_point;
cristye23ec9d2011-08-16 18:15:40 +00007911 (void) ContrastStretchImage(*image,black_point,white_point,
cristy051718b2011-08-28 22:49:25 +00007912 exception);
cristy3ed852e2009-09-05 21:47:34 +00007913 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00007914 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007915 break;
cristy6710d842011-10-20 23:23:00 +00007916 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007917 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007918 break;
7919 }
7920 case SigmoidalContrastCommand:
7921 {
cristy9ee60942011-07-06 14:54:38 +00007922 GeometryInfo
7923 geometry_info;
7924
7925 MagickStatusType
7926 flags;
7927
cristy3ed852e2009-09-05 21:47:34 +00007928 static char
7929 levels[MaxTextExtent] = "3x50%";
7930
7931 /*
7932 Query user for gamma value.
7933 */
7934 (void) XDialogWidget(display,windows,"Sigmoidal Contrast",
7935 "Enter contrast and midpoint:",levels);
7936 if (*levels == '\0')
7937 break;
7938 /*
7939 Contrast stretch image.
7940 */
7941 XSetCursorState(display,windows,MagickTrue);
7942 XCheckRefreshWindows(display,windows);
cristy9ee60942011-07-06 14:54:38 +00007943 flags=ParseGeometry(levels,&geometry_info);
7944 if ((flags & SigmaValue) == 0)
7945 geometry_info.sigma=1.0*QuantumRange/2.0;
7946 if ((flags & PercentValue) != 0)
7947 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0;
7948 (void) SigmoidalContrastImage(*image,MagickTrue,geometry_info.rho,
cristy051718b2011-08-28 22:49:25 +00007949 geometry_info.sigma,exception);
cristy3ed852e2009-09-05 21:47:34 +00007950 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00007951 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007952 break;
cristy6710d842011-10-20 23:23:00 +00007953 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007954 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007955 break;
7956 }
7957 case NormalizeCommand:
7958 {
7959 /*
7960 Perform histogram normalization on the image.
7961 */
7962 XSetCursorState(display,windows,MagickTrue);
7963 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007964 (void) NormalizeImage(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007965 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00007966 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007967 break;
cristy6710d842011-10-20 23:23:00 +00007968 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007969 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007970 break;
7971 }
7972 case EqualizeCommand:
7973 {
7974 /*
7975 Perform histogram equalization on the image.
7976 */
7977 XSetCursorState(display,windows,MagickTrue);
7978 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007979 (void) EqualizeImage(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007980 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00007981 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007982 break;
cristy6710d842011-10-20 23:23:00 +00007983 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007984 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00007985 break;
7986 }
7987 case NegateCommand:
7988 {
7989 /*
7990 Negate colors in image.
7991 */
7992 XSetCursorState(display,windows,MagickTrue);
7993 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00007994 (void) NegateImage(*image,MagickFalse,exception);
cristy3ed852e2009-09-05 21:47:34 +00007995 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00007996 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00007997 break;
cristy6710d842011-10-20 23:23:00 +00007998 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00007999 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008000 break;
8001 }
8002 case GrayscaleCommand:
8003 {
8004 /*
8005 Convert image to grayscale.
8006 */
8007 XSetCursorState(display,windows,MagickTrue);
8008 XCheckRefreshWindows(display,windows);
cristy8a46d822012-08-28 23:32:39 +00008009 (void) SetImageType(*image,(*image)->alpha_trait != BlendPixelTrait ?
cristy018f07f2011-09-04 21:15:19 +00008010 GrayscaleType : GrayscaleMatteType,exception);
cristy3ed852e2009-09-05 21:47:34 +00008011 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00008012 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008013 break;
cristy6710d842011-10-20 23:23:00 +00008014 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008015 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008016 break;
8017 }
8018 case MapCommand:
8019 {
8020 Image
8021 *affinity_image;
8022
8023 static char
8024 filename[MaxTextExtent] = "\0";
8025
8026 /*
8027 Request image file name from user.
8028 */
8029 XFileBrowserWidget(display,windows,"Map",filename);
8030 if (*filename == '\0')
8031 break;
8032 /*
8033 Map image.
8034 */
8035 XSetCursorState(display,windows,MagickTrue);
8036 XCheckRefreshWindows(display,windows);
8037 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00008038 affinity_image=ReadImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00008039 if (affinity_image != (Image *) NULL)
8040 {
cristy018f07f2011-09-04 21:15:19 +00008041 (void) RemapImage(&quantize_info,*image,affinity_image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008042 affinity_image=DestroyImage(affinity_image);
8043 }
cristy051718b2011-08-28 22:49:25 +00008044 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008045 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00008046 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008047 break;
cristy6710d842011-10-20 23:23:00 +00008048 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008049 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008050 break;
8051 }
8052 case QuantizeCommand:
8053 {
8054 int
8055 status;
8056
8057 static char
8058 colors[MaxTextExtent] = "256";
8059
8060 /*
8061 Query user for maximum number of colors.
8062 */
8063 status=XDialogWidget(display,windows,"Quantize",
8064 "Maximum number of colors:",colors);
8065 if (*colors == '\0')
8066 break;
8067 /*
8068 Color reduce the image.
8069 */
8070 XSetCursorState(display,windows,MagickTrue);
8071 XCheckRefreshWindows(display,windows);
cristye27293e2009-12-18 02:53:20 +00008072 quantize_info.number_colors=StringToUnsignedLong(colors);
cristycbda6112012-05-27 20:57:16 +00008073 quantize_info.dither_method=status != 0 ? RiemersmaDitherMethod :
8074 NoDitherMethod;
cristy018f07f2011-09-04 21:15:19 +00008075 (void) QuantizeImage(&quantize_info,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008076 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00008077 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008078 break;
cristy6710d842011-10-20 23:23:00 +00008079 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008080 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008081 break;
8082 }
8083 case DespeckleCommand:
8084 {
8085 Image
8086 *despeckle_image;
8087
8088 /*
8089 Despeckle image.
8090 */
8091 XSetCursorState(display,windows,MagickTrue);
8092 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +00008093 despeckle_image=DespeckleImage(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008094 if (despeckle_image != (Image *) NULL)
8095 {
8096 *image=DestroyImage(*image);
8097 *image=despeckle_image;
8098 }
cristy051718b2011-08-28 22:49:25 +00008099 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008100 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00008101 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008102 break;
cristy6710d842011-10-20 23:23:00 +00008103 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008104 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008105 break;
8106 }
8107 case EmbossCommand:
8108 {
8109 Image
8110 *emboss_image;
8111
8112 static char
8113 radius[MaxTextExtent] = "0.0x1.0";
8114
8115 /*
8116 Query user for emboss radius.
8117 */
8118 (void) XDialogWidget(display,windows,"Emboss",
8119 "Enter the emboss radius and standard deviation:",radius);
8120 if (*radius == '\0')
8121 break;
8122 /*
8123 Reduce noise in the image.
8124 */
8125 XSetCursorState(display,windows,MagickTrue);
8126 XCheckRefreshWindows(display,windows);
8127 flags=ParseGeometry(radius,&geometry_info);
8128 if ((flags & SigmaValue) == 0)
8129 geometry_info.sigma=1.0;
8130 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma,
cristy051718b2011-08-28 22:49:25 +00008131 exception);
cristy3ed852e2009-09-05 21:47:34 +00008132 if (emboss_image != (Image *) NULL)
8133 {
8134 *image=DestroyImage(*image);
8135 *image=emboss_image;
8136 }
cristy051718b2011-08-28 22:49:25 +00008137 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008138 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00008139 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008140 break;
cristy6710d842011-10-20 23:23:00 +00008141 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008142 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008143 break;
8144 }
8145 case ReduceNoiseCommand:
8146 {
8147 Image
8148 *noise_image;
8149
8150 static char
8151 radius[MaxTextExtent] = "0";
8152
8153 /*
8154 Query user for noise radius.
8155 */
8156 (void) XDialogWidget(display,windows,"Reduce Noise",
8157 "Enter the noise radius:",radius);
8158 if (*radius == '\0')
8159 break;
8160 /*
8161 Reduce noise in the image.
8162 */
8163 XSetCursorState(display,windows,MagickTrue);
8164 XCheckRefreshWindows(display,windows);
8165 flags=ParseGeometry(radius,&geometry_info);
cristy95c38342011-03-18 22:39:51 +00008166 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t)
cristy051718b2011-08-28 22:49:25 +00008167 geometry_info.rho,(size_t) geometry_info.rho,exception);
cristy3ed852e2009-09-05 21:47:34 +00008168 if (noise_image != (Image *) NULL)
8169 {
8170 *image=DestroyImage(*image);
8171 *image=noise_image;
8172 }
cristy051718b2011-08-28 22:49:25 +00008173 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008174 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00008175 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008176 break;
cristy6710d842011-10-20 23:23:00 +00008177 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008178 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008179 break;
8180 }
8181 case AddNoiseCommand:
8182 {
8183 char
8184 **noises;
8185
8186 Image
8187 *noise_image;
8188
8189 static char
8190 noise_type[MaxTextExtent] = "Gaussian";
8191
8192 /*
8193 Add noise to the image.
8194 */
cristy042ee782011-04-22 18:48:30 +00008195 noises=GetCommandOptions(MagickNoiseOptions);
cristy3ed852e2009-09-05 21:47:34 +00008196 if (noises == (char **) NULL)
8197 break;
8198 XListBrowserWidget(display,windows,&windows->widget,
8199 (const char **) noises,"Add Noise",
8200 "Select a type of noise to add to your image:",noise_type);
8201 noises=DestroyStringList(noises);
8202 if (*noise_type == '\0')
8203 break;
8204 XSetCursorState(display,windows,MagickTrue);
8205 XCheckRefreshWindows(display,windows);
cristy042ee782011-04-22 18:48:30 +00008206 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption(
cristy9ed1f812011-10-08 02:00:08 +00008207 MagickNoiseOptions,MagickFalse,noise_type),1.0,exception);
cristy3ed852e2009-09-05 21:47:34 +00008208 if (noise_image != (Image *) NULL)
8209 {
8210 *image=DestroyImage(*image);
8211 *image=noise_image;
8212 }
cristy051718b2011-08-28 22:49:25 +00008213 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008214 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00008215 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008216 break;
cristy6710d842011-10-20 23:23:00 +00008217 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008218 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008219 break;
8220 }
8221 case SharpenCommand:
8222 {
8223 Image
8224 *sharp_image;
8225
8226 static char
8227 radius[MaxTextExtent] = "0.0x1.0";
8228
8229 /*
8230 Query user for sharpen radius.
8231 */
8232 (void) XDialogWidget(display,windows,"Sharpen",
8233 "Enter the sharpen radius and standard deviation:",radius);
8234 if (*radius == '\0')
8235 break;
8236 /*
8237 Sharpen image scanlines.
8238 */
8239 XSetCursorState(display,windows,MagickTrue);
8240 XCheckRefreshWindows(display,windows);
8241 flags=ParseGeometry(radius,&geometry_info);
8242 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma,
cristyaa2c16c2012-03-25 22:21:35 +00008243 exception);
cristy3ed852e2009-09-05 21:47:34 +00008244 if (sharp_image != (Image *) NULL)
8245 {
8246 *image=DestroyImage(*image);
8247 *image=sharp_image;
8248 }
cristy051718b2011-08-28 22:49:25 +00008249 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008250 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00008251 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008252 break;
cristy6710d842011-10-20 23:23:00 +00008253 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008254 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008255 break;
8256 }
8257 case BlurCommand:
8258 {
8259 Image
8260 *blur_image;
8261
8262 static char
8263 radius[MaxTextExtent] = "0.0x1.0";
8264
8265 /*
8266 Query user for blur radius.
8267 */
8268 (void) XDialogWidget(display,windows,"Blur",
8269 "Enter the blur radius and standard deviation:",radius);
8270 if (*radius == '\0')
8271 break;
8272 /*
8273 Blur an image.
8274 */
8275 XSetCursorState(display,windows,MagickTrue);
8276 XCheckRefreshWindows(display,windows);
8277 flags=ParseGeometry(radius,&geometry_info);
8278 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma,
cristyaa2c16c2012-03-25 22:21:35 +00008279 exception);
cristy3ed852e2009-09-05 21:47:34 +00008280 if (blur_image != (Image *) NULL)
8281 {
8282 *image=DestroyImage(*image);
8283 *image=blur_image;
8284 }
cristy051718b2011-08-28 22:49:25 +00008285 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008286 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00008287 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008288 break;
cristy6710d842011-10-20 23:23:00 +00008289 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008290 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008291 break;
8292 }
8293 case ThresholdCommand:
8294 {
8295 double
8296 threshold;
8297
8298 static char
8299 factor[MaxTextExtent] = "128";
8300
8301 /*
8302 Query user for threshold value.
8303 */
8304 (void) XDialogWidget(display,windows,"Threshold",
8305 "Enter threshold value:",factor);
8306 if (*factor == '\0')
8307 break;
8308 /*
8309 Gamma correct image.
8310 */
8311 XSetCursorState(display,windows,MagickTrue);
8312 XCheckRefreshWindows(display,windows);
cristy9b34e302011-11-05 02:15:45 +00008313 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
cristye941a752011-10-15 01:52:48 +00008314 (void) BilevelImage(*image,threshold,exception);
cristy3ed852e2009-09-05 21:47:34 +00008315 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00008316 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008317 break;
cristy6710d842011-10-20 23:23:00 +00008318 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008319 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008320 break;
8321 }
8322 case EdgeDetectCommand:
8323 {
8324 Image
8325 *edge_image;
8326
8327 static char
8328 radius[MaxTextExtent] = "0";
8329
8330 /*
8331 Query user for edge factor.
8332 */
8333 (void) XDialogWidget(display,windows,"Detect Edges",
8334 "Enter the edge detect radius:",radius);
8335 if (*radius == '\0')
8336 break;
8337 /*
8338 Detect edge in image.
8339 */
8340 XSetCursorState(display,windows,MagickTrue);
8341 XCheckRefreshWindows(display,windows);
8342 flags=ParseGeometry(radius,&geometry_info);
cristy8ae632d2011-09-05 17:29:53 +00008343 edge_image=EdgeImage(*image,geometry_info.rho,geometry_info.sigma,
8344 exception);
cristy3ed852e2009-09-05 21:47:34 +00008345 if (edge_image != (Image *) NULL)
8346 {
8347 *image=DestroyImage(*image);
8348 *image=edge_image;
8349 }
cristy051718b2011-08-28 22:49:25 +00008350 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008351 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00008352 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008353 break;
cristy6710d842011-10-20 23:23:00 +00008354 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008355 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008356 break;
8357 }
8358 case SpreadCommand:
8359 {
8360 Image
8361 *spread_image;
8362
8363 static char
8364 amount[MaxTextExtent] = "2";
8365
8366 /*
8367 Query user for spread amount.
8368 */
8369 (void) XDialogWidget(display,windows,"Spread",
8370 "Enter the displacement amount:",amount);
8371 if (*amount == '\0')
8372 break;
8373 /*
8374 Displace image pixels by a random amount.
8375 */
8376 XSetCursorState(display,windows,MagickTrue);
8377 XCheckRefreshWindows(display,windows);
8378 flags=ParseGeometry(amount,&geometry_info);
cristy8ae632d2011-09-05 17:29:53 +00008379 spread_image=EdgeImage(*image,geometry_info.rho,geometry_info.sigma,
8380 exception);
cristy3ed852e2009-09-05 21:47:34 +00008381 if (spread_image != (Image *) NULL)
8382 {
8383 *image=DestroyImage(*image);
8384 *image=spread_image;
8385 }
cristy051718b2011-08-28 22:49:25 +00008386 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008387 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00008388 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008389 break;
cristy6710d842011-10-20 23:23:00 +00008390 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008391 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008392 break;
8393 }
8394 case ShadeCommand:
8395 {
8396 Image
8397 *shade_image;
8398
8399 int
8400 status;
8401
8402 static char
8403 geometry[MaxTextExtent] = "30x30";
8404
8405 /*
8406 Query user for the shade geometry.
8407 */
8408 status=XDialogWidget(display,windows,"Shade",
8409 "Enter the azimuth and elevation of the light source:",geometry);
8410 if (*geometry == '\0')
8411 break;
8412 /*
8413 Shade image pixels.
8414 */
8415 XSetCursorState(display,windows,MagickTrue);
8416 XCheckRefreshWindows(display,windows);
8417 flags=ParseGeometry(geometry,&geometry_info);
8418 if ((flags & SigmaValue) == 0)
8419 geometry_info.sigma=1.0;
anthony11d32022012-11-17 05:31:33 +00008420 shade_image=ShadeImage(*image,IsMagickTrue(status),
cristy051718b2011-08-28 22:49:25 +00008421 geometry_info.rho,geometry_info.sigma,exception);
cristy3ed852e2009-09-05 21:47:34 +00008422 if (shade_image != (Image *) NULL)
8423 {
8424 *image=DestroyImage(*image);
8425 *image=shade_image;
8426 }
cristy051718b2011-08-28 22:49:25 +00008427 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008428 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00008429 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008430 break;
cristy6710d842011-10-20 23:23:00 +00008431 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008432 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008433 break;
8434 }
8435 case RaiseCommand:
8436 {
8437 static char
8438 bevel_width[MaxTextExtent] = "10";
8439
8440 /*
8441 Query user for bevel width.
8442 */
8443 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width);
8444 if (*bevel_width == '\0')
8445 break;
8446 /*
8447 Raise an image.
8448 */
cristy051718b2011-08-28 22:49:25 +00008449 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8450 exception);
cristy3ed852e2009-09-05 21:47:34 +00008451 XSetCursorState(display,windows,MagickTrue);
8452 XCheckRefreshWindows(display,windows);
8453 (void) ParsePageGeometry(*image,bevel_width,&page_geometry,
cristy051718b2011-08-28 22:49:25 +00008454 exception);
8455 (void) RaiseImage(*image,&page_geometry,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +00008456 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00008457 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008458 break;
cristy6710d842011-10-20 23:23:00 +00008459 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008460 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008461 break;
8462 }
8463 case SegmentCommand:
8464 {
8465 static char
8466 threshold[MaxTextExtent] = "1.0x1.5";
8467
8468 /*
8469 Query user for smoothing threshold.
8470 */
8471 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:",
8472 threshold);
8473 if (*threshold == '\0')
8474 break;
8475 /*
8476 Segment an image.
8477 */
8478 XSetCursorState(display,windows,MagickTrue);
8479 XCheckRefreshWindows(display,windows);
8480 flags=ParseGeometry(threshold,&geometry_info);
8481 if ((flags & SigmaValue) == 0)
8482 geometry_info.sigma=1.0;
cristyd3d9c5d2012-02-15 22:58:57 +00008483 (void) SegmentImage(*image,sRGBColorspace,MagickFalse,geometry_info.rho,
cristy018f07f2011-09-04 21:15:19 +00008484 geometry_info.sigma,exception);
cristy3ed852e2009-09-05 21:47:34 +00008485 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00008486 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008487 break;
cristy6710d842011-10-20 23:23:00 +00008488 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008489 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008490 break;
8491 }
8492 case SepiaToneCommand:
8493 {
8494 double
8495 threshold;
8496
8497 Image
8498 *sepia_image;
8499
8500 static char
8501 factor[MaxTextExtent] = "80%";
8502
8503 /*
8504 Query user for sepia-tone factor.
8505 */
8506 (void) XDialogWidget(display,windows,"Sepia Tone",
8507 "Enter the sepia tone factor (0 - 99.9%):",factor);
8508 if (*factor == '\0')
8509 break;
8510 /*
8511 Sepia tone image pixels.
8512 */
8513 XSetCursorState(display,windows,MagickTrue);
8514 XCheckRefreshWindows(display,windows);
cristy9b34e302011-11-05 02:15:45 +00008515 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
cristy051718b2011-08-28 22:49:25 +00008516 sepia_image=SepiaToneImage(*image,threshold,exception);
cristy3ed852e2009-09-05 21:47:34 +00008517 if (sepia_image != (Image *) NULL)
8518 {
8519 *image=DestroyImage(*image);
8520 *image=sepia_image;
8521 }
cristy051718b2011-08-28 22:49:25 +00008522 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008523 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00008524 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008525 break;
cristy6710d842011-10-20 23:23:00 +00008526 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008527 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008528 break;
8529 }
8530 case SolarizeCommand:
8531 {
8532 double
8533 threshold;
8534
8535 static char
8536 factor[MaxTextExtent] = "60%";
8537
8538 /*
8539 Query user for solarize factor.
8540 */
8541 (void) XDialogWidget(display,windows,"Solarize",
8542 "Enter the solarize factor (0 - 99.9%):",factor);
8543 if (*factor == '\0')
8544 break;
8545 /*
8546 Solarize image pixels.
8547 */
8548 XSetCursorState(display,windows,MagickTrue);
8549 XCheckRefreshWindows(display,windows);
cristy9b34e302011-11-05 02:15:45 +00008550 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
cristy5cbc0162011-08-29 00:36:28 +00008551 (void) SolarizeImage(*image,threshold,exception);
cristy3ed852e2009-09-05 21:47:34 +00008552 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00008553 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008554 break;
cristy6710d842011-10-20 23:23:00 +00008555 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008556 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008557 break;
8558 }
8559 case SwirlCommand:
8560 {
8561 Image
8562 *swirl_image;
8563
8564 static char
8565 degrees[MaxTextExtent] = "60";
8566
8567 /*
8568 Query user for swirl angle.
8569 */
8570 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:",
8571 degrees);
8572 if (*degrees == '\0')
8573 break;
8574 /*
8575 Swirl image pixels about the center.
8576 */
8577 XSetCursorState(display,windows,MagickTrue);
8578 XCheckRefreshWindows(display,windows);
8579 flags=ParseGeometry(degrees,&geometry_info);
cristy76f512e2011-09-12 01:26:56 +00008580 swirl_image=SwirlImage(*image,geometry_info.rho,(*image)->interpolate,
8581 exception);
cristy3ed852e2009-09-05 21:47:34 +00008582 if (swirl_image != (Image *) NULL)
8583 {
8584 *image=DestroyImage(*image);
8585 *image=swirl_image;
8586 }
cristy051718b2011-08-28 22:49:25 +00008587 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008588 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00008589 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008590 break;
cristy6710d842011-10-20 23:23:00 +00008591 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008592 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008593 break;
8594 }
8595 case ImplodeCommand:
8596 {
8597 Image
8598 *implode_image;
8599
8600 static char
8601 factor[MaxTextExtent] = "0.3";
8602
8603 /*
8604 Query user for implode factor.
8605 */
8606 (void) XDialogWidget(display,windows,"Implode",
8607 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor);
8608 if (*factor == '\0')
8609 break;
8610 /*
8611 Implode image pixels about the center.
8612 */
8613 XSetCursorState(display,windows,MagickTrue);
8614 XCheckRefreshWindows(display,windows);
8615 flags=ParseGeometry(factor,&geometry_info);
cristy76f512e2011-09-12 01:26:56 +00008616 implode_image=ImplodeImage(*image,geometry_info.rho,(*image)->interpolate,
8617 exception);
cristy3ed852e2009-09-05 21:47:34 +00008618 if (implode_image != (Image *) NULL)
8619 {
8620 *image=DestroyImage(*image);
8621 *image=implode_image;
8622 }
cristy051718b2011-08-28 22:49:25 +00008623 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008624 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00008625 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008626 break;
cristy6710d842011-10-20 23:23:00 +00008627 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008628 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008629 break;
8630 }
8631 case VignetteCommand:
8632 {
8633 Image
8634 *vignette_image;
8635
8636 static char
8637 geometry[MaxTextExtent] = "0x20";
8638
8639 /*
8640 Query user for the vignette geometry.
8641 */
8642 (void) XDialogWidget(display,windows,"Vignette",
8643 "Enter the radius, sigma, and x and y offsets:",geometry);
8644 if (*geometry == '\0')
8645 break;
8646 /*
8647 Soften the edges of the image in vignette style
8648 */
8649 XSetCursorState(display,windows,MagickTrue);
8650 XCheckRefreshWindows(display,windows);
8651 flags=ParseGeometry(geometry,&geometry_info);
8652 if ((flags & SigmaValue) == 0)
8653 geometry_info.sigma=1.0;
8654 if ((flags & XiValue) == 0)
8655 geometry_info.xi=0.1*(*image)->columns;
8656 if ((flags & PsiValue) == 0)
8657 geometry_info.psi=0.1*(*image)->rows;
cristyaa2c16c2012-03-25 22:21:35 +00008658 vignette_image=VignetteImage(*image,geometry_info.rho,0.0,(ssize_t)
8659 ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-0.5),
8660 exception);
cristy3ed852e2009-09-05 21:47:34 +00008661 if (vignette_image != (Image *) NULL)
8662 {
8663 *image=DestroyImage(*image);
8664 *image=vignette_image;
8665 }
cristy051718b2011-08-28 22:49:25 +00008666 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008667 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00008668 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008669 break;
cristy6710d842011-10-20 23:23:00 +00008670 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008671 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008672 break;
8673 }
8674 case WaveCommand:
8675 {
8676 Image
8677 *wave_image;
8678
8679 static char
8680 geometry[MaxTextExtent] = "25x150";
8681
8682 /*
8683 Query user for the wave geometry.
8684 */
8685 (void) XDialogWidget(display,windows,"Wave",
8686 "Enter the amplitude and length of the wave:",geometry);
8687 if (*geometry == '\0')
8688 break;
8689 /*
cristycee97112010-05-28 00:44:52 +00008690 Alter an image along a sine wave.
cristy3ed852e2009-09-05 21:47:34 +00008691 */
8692 XSetCursorState(display,windows,MagickTrue);
8693 XCheckRefreshWindows(display,windows);
8694 flags=ParseGeometry(geometry,&geometry_info);
8695 if ((flags & SigmaValue) == 0)
8696 geometry_info.sigma=1.0;
8697 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma,
cristy5c4e2582011-09-11 19:21:03 +00008698 (*image)->interpolate,exception);
cristy3ed852e2009-09-05 21:47:34 +00008699 if (wave_image != (Image *) NULL)
8700 {
8701 *image=DestroyImage(*image);
8702 *image=wave_image;
8703 }
cristy051718b2011-08-28 22:49:25 +00008704 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008705 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00008706 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008707 break;
cristy6710d842011-10-20 23:23:00 +00008708 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008709 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008710 break;
8711 }
8712 case OilPaintCommand:
8713 {
8714 Image
8715 *paint_image;
8716
8717 static char
8718 radius[MaxTextExtent] = "0";
8719
8720 /*
8721 Query user for circular neighborhood radius.
8722 */
8723 (void) XDialogWidget(display,windows,"Oil Paint",
8724 "Enter the mask radius:",radius);
8725 if (*radius == '\0')
8726 break;
8727 /*
8728 OilPaint image scanlines.
8729 */
8730 XSetCursorState(display,windows,MagickTrue);
8731 XCheckRefreshWindows(display,windows);
8732 flags=ParseGeometry(radius,&geometry_info);
cristy14973ba2011-08-27 23:48:07 +00008733 paint_image=OilPaintImage(*image,geometry_info.rho,geometry_info.sigma,
cristy051718b2011-08-28 22:49:25 +00008734 exception);
cristy3ed852e2009-09-05 21:47:34 +00008735 if (paint_image != (Image *) NULL)
8736 {
8737 *image=DestroyImage(*image);
8738 *image=paint_image;
8739 }
cristy051718b2011-08-28 22:49:25 +00008740 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008741 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00008742 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008743 break;
cristy6710d842011-10-20 23:23:00 +00008744 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008745 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008746 break;
8747 }
8748 case CharcoalDrawCommand:
8749 {
8750 Image
8751 *charcoal_image;
8752
8753 static char
8754 radius[MaxTextExtent] = "0x1";
8755
8756 /*
8757 Query user for charcoal radius.
8758 */
8759 (void) XDialogWidget(display,windows,"Charcoal Draw",
8760 "Enter the charcoal radius and sigma:",radius);
8761 if (*radius == '\0')
8762 break;
8763 /*
8764 Charcoal the image.
8765 */
cristy051718b2011-08-28 22:49:25 +00008766 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8767 exception);
cristy3ed852e2009-09-05 21:47:34 +00008768 XSetCursorState(display,windows,MagickTrue);
8769 XCheckRefreshWindows(display,windows);
8770 flags=ParseGeometry(radius,&geometry_info);
8771 if ((flags & SigmaValue) == 0)
8772 geometry_info.sigma=geometry_info.rho;
8773 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma,
cristyaa2c16c2012-03-25 22:21:35 +00008774 exception);
cristy3ed852e2009-09-05 21:47:34 +00008775 if (charcoal_image != (Image *) NULL)
8776 {
8777 *image=DestroyImage(*image);
8778 *image=charcoal_image;
8779 }
cristy051718b2011-08-28 22:49:25 +00008780 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008781 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00008782 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008783 break;
cristy6710d842011-10-20 23:23:00 +00008784 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008785 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008786 break;
8787 }
8788 case AnnotateCommand:
8789 {
8790 /*
8791 Annotate the image with text.
8792 */
cristy051718b2011-08-28 22:49:25 +00008793 status=XAnnotateEditImage(display,resource_info,windows,*image,exception);
anthony11d32022012-11-17 05:31:33 +00008794 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00008795 {
8796 XNoticeWidget(display,windows,"Unable to annotate X image",
8797 (*image)->filename);
8798 break;
8799 }
8800 break;
8801 }
8802 case DrawCommand:
8803 {
8804 /*
8805 Draw image.
8806 */
cristy051718b2011-08-28 22:49:25 +00008807 status=XDrawEditImage(display,resource_info,windows,image,exception);
anthony11d32022012-11-17 05:31:33 +00008808 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00008809 {
8810 XNoticeWidget(display,windows,"Unable to draw on the X image",
8811 (*image)->filename);
8812 break;
8813 }
8814 break;
8815 }
8816 case ColorCommand:
8817 {
8818 /*
8819 Color edit.
8820 */
cristy051718b2011-08-28 22:49:25 +00008821 status=XColorEditImage(display,resource_info,windows,image,exception);
anthony11d32022012-11-17 05:31:33 +00008822 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00008823 {
8824 XNoticeWidget(display,windows,"Unable to pixel edit X image",
8825 (*image)->filename);
8826 break;
8827 }
8828 break;
8829 }
8830 case MatteCommand:
8831 {
8832 /*
8833 Matte edit.
8834 */
cristy051718b2011-08-28 22:49:25 +00008835 status=XMatteEditImage(display,resource_info,windows,image,exception);
anthony11d32022012-11-17 05:31:33 +00008836 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00008837 {
8838 XNoticeWidget(display,windows,"Unable to matte edit X image",
8839 (*image)->filename);
8840 break;
8841 }
8842 break;
8843 }
8844 case CompositeCommand:
8845 {
8846 /*
8847 Composite image.
8848 */
cristy051718b2011-08-28 22:49:25 +00008849 status=XCompositeImage(display,resource_info,windows,*image,
8850 exception);
anthony11d32022012-11-17 05:31:33 +00008851 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00008852 {
8853 XNoticeWidget(display,windows,"Unable to composite X image",
8854 (*image)->filename);
8855 break;
8856 }
8857 break;
8858 }
8859 case AddBorderCommand:
8860 {
8861 Image
8862 *border_image;
8863
8864 static char
8865 geometry[MaxTextExtent] = "6x6";
8866
8867 /*
8868 Query user for border color and geometry.
8869 */
8870 XColorBrowserWidget(display,windows,"Select",color);
8871 if (*color == '\0')
8872 break;
8873 (void) XDialogWidget(display,windows,"Add Border",
8874 "Enter border geometry:",geometry);
8875 if (*geometry == '\0')
8876 break;
8877 /*
8878 Add a border to the image.
8879 */
cristy051718b2011-08-28 22:49:25 +00008880 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8881 exception);
cristy3ed852e2009-09-05 21:47:34 +00008882 XSetCursorState(display,windows,MagickTrue);
8883 XCheckRefreshWindows(display,windows);
cristy9950d572011-10-01 18:22:35 +00008884 (void) QueryColorCompliance(color,AllCompliance,&(*image)->border_color,
cristy051718b2011-08-28 22:49:25 +00008885 exception);
cristy3ed852e2009-09-05 21:47:34 +00008886 (void) ParsePageGeometry(*image,geometry,&page_geometry,
cristy051718b2011-08-28 22:49:25 +00008887 exception);
cristy633f0c62011-09-15 13:27:36 +00008888 border_image=BorderImage(*image,&page_geometry,(*image)->compose,
8889 exception);
cristy3ed852e2009-09-05 21:47:34 +00008890 if (border_image != (Image *) NULL)
8891 {
8892 *image=DestroyImage(*image);
8893 *image=border_image;
8894 }
cristy051718b2011-08-28 22:49:25 +00008895 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008896 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00008897 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008898 break;
8899 windows->image.window_changes.width=(int) (*image)->columns;
8900 windows->image.window_changes.height=(int) (*image)->rows;
cristy6710d842011-10-20 23:23:00 +00008901 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008902 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008903 break;
8904 }
8905 case AddFrameCommand:
8906 {
8907 FrameInfo
8908 frame_info;
8909
8910 Image
8911 *frame_image;
8912
8913 static char
8914 geometry[MaxTextExtent] = "6x6";
8915
8916 /*
8917 Query user for frame color and geometry.
8918 */
8919 XColorBrowserWidget(display,windows,"Select",color);
8920 if (*color == '\0')
8921 break;
8922 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:",
8923 geometry);
8924 if (*geometry == '\0')
8925 break;
8926 /*
8927 Surround image with an ornamental border.
8928 */
cristy051718b2011-08-28 22:49:25 +00008929 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
8930 exception);
cristy3ed852e2009-09-05 21:47:34 +00008931 XSetCursorState(display,windows,MagickTrue);
8932 XCheckRefreshWindows(display,windows);
cristy9950d572011-10-01 18:22:35 +00008933 (void) QueryColorCompliance(color,AllCompliance,&(*image)->matte_color,
cristy051718b2011-08-28 22:49:25 +00008934 exception);
cristy3ed852e2009-09-05 21:47:34 +00008935 (void) ParsePageGeometry(*image,geometry,&page_geometry,
cristy051718b2011-08-28 22:49:25 +00008936 exception);
cristy3ed852e2009-09-05 21:47:34 +00008937 frame_info.width=page_geometry.width;
8938 frame_info.height=page_geometry.height;
8939 frame_info.outer_bevel=page_geometry.x;
8940 frame_info.inner_bevel=page_geometry.y;
cristybb503372010-05-27 20:51:26 +00008941 frame_info.x=(ssize_t) frame_info.width;
8942 frame_info.y=(ssize_t) frame_info.height;
cristy3ed852e2009-09-05 21:47:34 +00008943 frame_info.width=(*image)->columns+2*frame_info.width;
8944 frame_info.height=(*image)->rows+2*frame_info.height;
cristy633f0c62011-09-15 13:27:36 +00008945 frame_image=FrameImage(*image,&frame_info,(*image)->compose,exception);
cristy3ed852e2009-09-05 21:47:34 +00008946 if (frame_image != (Image *) NULL)
8947 {
8948 *image=DestroyImage(*image);
8949 *image=frame_image;
8950 }
cristy051718b2011-08-28 22:49:25 +00008951 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00008952 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +00008953 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +00008954 break;
8955 windows->image.window_changes.width=(int) (*image)->columns;
8956 windows->image.window_changes.height=(int) (*image)->rows;
cristy6710d842011-10-20 23:23:00 +00008957 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00008958 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00008959 break;
8960 }
8961 case CommentCommand:
8962 {
8963 const char
8964 *value;
8965
8966 FILE
8967 *file;
8968
8969 int
8970 unique_file;
8971
8972 /*
8973 Edit image comment.
8974 */
8975 unique_file=AcquireUniqueFileResource(image_info->filename);
8976 if (unique_file == -1)
8977 XNoticeWidget(display,windows,"Unable to edit image comment",
8978 image_info->filename);
cristyd15e6592011-10-15 00:13:06 +00008979 value=GetImageProperty(*image,"comment",exception);
cristy3ed852e2009-09-05 21:47:34 +00008980 if (value == (char *) NULL)
8981 unique_file=close(unique_file)-1;
8982 else
8983 {
8984 register const char
8985 *p;
8986
8987 file=fdopen(unique_file,"w");
8988 if (file == (FILE *) NULL)
8989 {
8990 XNoticeWidget(display,windows,"Unable to edit image comment",
8991 image_info->filename);
8992 break;
8993 }
8994 for (p=value; *p != '\0'; p++)
8995 (void) fputc((int) *p,file);
8996 (void) fputc('\n',file);
8997 (void) fclose(file);
8998 }
8999 XSetCursorState(display,windows,MagickTrue);
9000 XCheckRefreshWindows(display,windows);
9001 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL,
cristy051718b2011-08-28 22:49:25 +00009002 exception);
anthony11d32022012-11-17 05:31:33 +00009003 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00009004 XNoticeWidget(display,windows,"Unable to edit image comment",
9005 (char *) NULL);
9006 else
9007 {
9008 char
9009 *comment;
9010
cristy051718b2011-08-28 22:49:25 +00009011 comment=FileToString(image_info->filename,~0UL,exception);
cristy3ed852e2009-09-05 21:47:34 +00009012 if (comment != (char *) NULL)
9013 {
cristyd15e6592011-10-15 00:13:06 +00009014 (void) SetImageProperty(*image,"comment",comment,exception);
cristy3ed852e2009-09-05 21:47:34 +00009015 (*image)->taint=MagickTrue;
9016 }
9017 }
9018 (void) RelinquishUniqueFileResource(image_info->filename);
9019 XSetCursorState(display,windows,MagickFalse);
9020 break;
9021 }
9022 case LaunchCommand:
9023 {
9024 /*
9025 Launch program.
9026 */
9027 XSetCursorState(display,windows,MagickTrue);
9028 XCheckRefreshWindows(display,windows);
9029 (void) AcquireUniqueFilename(filename);
cristyb51dff52011-05-19 16:55:47 +00009030 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"launch:%s",
cristy3ed852e2009-09-05 21:47:34 +00009031 filename);
cristy051718b2011-08-28 22:49:25 +00009032 status=WriteImage(image_info,*image,exception);
anthony11d32022012-11-17 05:31:33 +00009033 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00009034 XNoticeWidget(display,windows,"Unable to launch image editor",
9035 (char *) NULL);
9036 else
9037 {
cristy051718b2011-08-28 22:49:25 +00009038 nexus=ReadImage(resource_info->image_info,exception);
9039 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +00009040 XClientMessage(display,windows->image.id,windows->im_protocols,
9041 windows->im_next_image,CurrentTime);
9042 }
9043 (void) RelinquishUniqueFileResource(filename);
9044 XSetCursorState(display,windows,MagickFalse);
9045 break;
9046 }
9047 case RegionofInterestCommand:
9048 {
9049 /*
9050 Apply an image processing technique to a region of interest.
9051 */
cristy051718b2011-08-28 22:49:25 +00009052 (void) XROIImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009053 break;
9054 }
9055 case InfoCommand:
9056 break;
9057 case ZoomCommand:
9058 {
9059 /*
9060 Zoom image.
9061 */
anthony11d32022012-11-17 05:31:33 +00009062 if( IfMagickTrue(windows->magnify.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00009063 (void) XRaiseWindow(display,windows->magnify.id);
9064 else
9065 {
9066 /*
9067 Make magnify image.
9068 */
9069 XSetCursorState(display,windows,MagickTrue);
9070 (void) XMapRaised(display,windows->magnify.id);
9071 XSetCursorState(display,windows,MagickFalse);
9072 }
9073 break;
9074 }
9075 case ShowPreviewCommand:
9076 {
9077 char
9078 **previews;
9079
9080 Image
9081 *preview_image;
9082
9083 static char
9084 preview_type[MaxTextExtent] = "Gamma";
9085
9086 /*
9087 Select preview type from menu.
9088 */
cristy042ee782011-04-22 18:48:30 +00009089 previews=GetCommandOptions(MagickPreviewOptions);
cristy3ed852e2009-09-05 21:47:34 +00009090 if (previews == (char **) NULL)
9091 break;
9092 XListBrowserWidget(display,windows,&windows->widget,
9093 (const char **) previews,"Preview",
9094 "Select an enhancement, effect, or F/X:",preview_type);
9095 previews=DestroyStringList(previews);
9096 if (*preview_type == '\0')
9097 break;
9098 /*
9099 Show image preview.
9100 */
9101 XSetCursorState(display,windows,MagickTrue);
9102 XCheckRefreshWindows(display,windows);
9103 image_info->preview_type=(PreviewType)
cristy042ee782011-04-22 18:48:30 +00009104 ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type);
cristybb503372010-05-27 20:51:26 +00009105 image_info->group=(ssize_t) windows->image.id;
cristy3ed852e2009-09-05 21:47:34 +00009106 (void) DeleteImageProperty(*image,"label");
cristyd15e6592011-10-15 00:13:06 +00009107 (void) SetImageProperty(*image,"label","Preview",exception);
cristy3ed852e2009-09-05 21:47:34 +00009108 (void) AcquireUniqueFilename(filename);
cristyb51dff52011-05-19 16:55:47 +00009109 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"preview:%s",
cristy3ed852e2009-09-05 21:47:34 +00009110 filename);
cristy051718b2011-08-28 22:49:25 +00009111 status=WriteImage(image_info,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009112 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00009113 preview_image=ReadImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00009114 (void) RelinquishUniqueFileResource(filename);
9115 if (preview_image == (Image *) NULL)
9116 break;
cristyb51dff52011-05-19 16:55:47 +00009117 (void) FormatLocaleString(preview_image->filename,MaxTextExtent,"show:%s",
cristy3ed852e2009-09-05 21:47:34 +00009118 filename);
cristy051718b2011-08-28 22:49:25 +00009119 status=WriteImage(image_info,preview_image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009120 preview_image=DestroyImage(preview_image);
anthony11d32022012-11-17 05:31:33 +00009121 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00009122 XNoticeWidget(display,windows,"Unable to show image preview",
9123 (*image)->filename);
9124 XDelay(display,1500);
9125 XSetCursorState(display,windows,MagickFalse);
9126 break;
9127 }
9128 case ShowHistogramCommand:
9129 {
9130 Image
9131 *histogram_image;
9132
9133 /*
9134 Show image histogram.
9135 */
9136 XSetCursorState(display,windows,MagickTrue);
9137 XCheckRefreshWindows(display,windows);
cristybb503372010-05-27 20:51:26 +00009138 image_info->group=(ssize_t) windows->image.id;
cristy3ed852e2009-09-05 21:47:34 +00009139 (void) DeleteImageProperty(*image,"label");
cristyd15e6592011-10-15 00:13:06 +00009140 (void) SetImageProperty(*image,"label","Histogram",exception);
cristy3ed852e2009-09-05 21:47:34 +00009141 (void) AcquireUniqueFilename(filename);
cristyb51dff52011-05-19 16:55:47 +00009142 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"histogram:%s",
cristy3ed852e2009-09-05 21:47:34 +00009143 filename);
cristy051718b2011-08-28 22:49:25 +00009144 status=WriteImage(image_info,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009145 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00009146 histogram_image=ReadImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00009147 (void) RelinquishUniqueFileResource(filename);
9148 if (histogram_image == (Image *) NULL)
9149 break;
cristyb51dff52011-05-19 16:55:47 +00009150 (void) FormatLocaleString(histogram_image->filename,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00009151 "show:%s",filename);
cristy051718b2011-08-28 22:49:25 +00009152 status=WriteImage(image_info,histogram_image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009153 histogram_image=DestroyImage(histogram_image);
anthony11d32022012-11-17 05:31:33 +00009154 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00009155 XNoticeWidget(display,windows,"Unable to show histogram",
9156 (*image)->filename);
9157 XDelay(display,1500);
9158 XSetCursorState(display,windows,MagickFalse);
9159 break;
9160 }
9161 case ShowMatteCommand:
9162 {
9163 Image
9164 *matte_image;
9165
cristy8a46d822012-08-28 23:32:39 +00009166 if ((*image)->alpha_trait != BlendPixelTrait)
cristy3ed852e2009-09-05 21:47:34 +00009167 {
9168 XNoticeWidget(display,windows,
9169 "Image does not have any matte information",(*image)->filename);
9170 break;
9171 }
9172 /*
9173 Show image matte.
9174 */
9175 XSetCursorState(display,windows,MagickTrue);
9176 XCheckRefreshWindows(display,windows);
cristybb503372010-05-27 20:51:26 +00009177 image_info->group=(ssize_t) windows->image.id;
cristy3ed852e2009-09-05 21:47:34 +00009178 (void) DeleteImageProperty(*image,"label");
cristyd15e6592011-10-15 00:13:06 +00009179 (void) SetImageProperty(*image,"label","Matte",exception);
cristy3ed852e2009-09-05 21:47:34 +00009180 (void) AcquireUniqueFilename(filename);
cristyb51dff52011-05-19 16:55:47 +00009181 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"matte:%s",
cristy3ed852e2009-09-05 21:47:34 +00009182 filename);
cristy051718b2011-08-28 22:49:25 +00009183 status=WriteImage(image_info,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009184 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +00009185 matte_image=ReadImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00009186 (void) RelinquishUniqueFileResource(filename);
9187 if (matte_image == (Image *) NULL)
9188 break;
cristyb51dff52011-05-19 16:55:47 +00009189 (void) FormatLocaleString(matte_image->filename,MaxTextExtent,"show:%s",
cristy3ed852e2009-09-05 21:47:34 +00009190 filename);
cristy051718b2011-08-28 22:49:25 +00009191 status=WriteImage(image_info,matte_image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009192 matte_image=DestroyImage(matte_image);
anthony11d32022012-11-17 05:31:33 +00009193 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00009194 XNoticeWidget(display,windows,"Unable to show matte",
9195 (*image)->filename);
9196 XDelay(display,1500);
9197 XSetCursorState(display,windows,MagickFalse);
9198 break;
9199 }
9200 case BackgroundCommand:
9201 {
9202 /*
9203 Background image.
9204 */
cristy051718b2011-08-28 22:49:25 +00009205 status=XBackgroundImage(display,resource_info,windows,image,exception);
anthony11d32022012-11-17 05:31:33 +00009206 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00009207 break;
cristy051718b2011-08-28 22:49:25 +00009208 nexus=CloneImage(*image,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +00009209 if (nexus != (Image *) NULL)
9210 XClientMessage(display,windows->image.id,windows->im_protocols,
9211 windows->im_next_image,CurrentTime);
9212 break;
9213 }
9214 case SlideShowCommand:
9215 {
9216 static char
9217 delay[MaxTextExtent] = "5";
9218
9219 /*
9220 Display next image after pausing.
9221 */
9222 (void) XDialogWidget(display,windows,"Slide Show",
9223 "Pause how many 1/100ths of a second between images:",delay);
9224 if (*delay == '\0')
9225 break;
cristye27293e2009-12-18 02:53:20 +00009226 resource_info->delay=StringToUnsignedLong(delay);
cristy3ed852e2009-09-05 21:47:34 +00009227 XClientMessage(display,windows->image.id,windows->im_protocols,
9228 windows->im_next_image,CurrentTime);
9229 break;
9230 }
9231 case PreferencesCommand:
9232 {
9233 /*
9234 Set user preferences.
9235 */
9236 status=XPreferencesWidget(display,resource_info,windows);
anthony11d32022012-11-17 05:31:33 +00009237 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00009238 break;
cristy051718b2011-08-28 22:49:25 +00009239 nexus=CloneImage(*image,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +00009240 if (nexus != (Image *) NULL)
9241 XClientMessage(display,windows->image.id,windows->im_protocols,
9242 windows->im_next_image,CurrentTime);
9243 break;
9244 }
9245 case HelpCommand:
9246 {
9247 /*
9248 User requested help.
9249 */
9250 XTextViewWidget(display,resource_info,windows,MagickFalse,
9251 "Help Viewer - Display",DisplayHelp);
9252 break;
9253 }
9254 case BrowseDocumentationCommand:
9255 {
9256 Atom
9257 mozilla_atom;
9258
9259 Window
9260 mozilla_window,
9261 root_window;
9262
9263 /*
9264 Browse the ImageMagick documentation.
9265 */
9266 root_window=XRootWindow(display,XDefaultScreen(display));
9267 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse);
9268 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom);
9269 if (mozilla_window != (Window) NULL)
9270 {
9271 char
9272 command[MaxTextExtent],
9273 *url;
9274
9275 /*
9276 Display documentation using Netscape remote control.
9277 */
9278 url=GetMagickHomeURL();
cristyb51dff52011-05-19 16:55:47 +00009279 (void) FormatLocaleString(command,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00009280 "openurl(%s,new-tab)",url);
9281 url=DestroyString(url);
9282 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse);
9283 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING,
9284 8,PropModeReplace,(unsigned char *) command,(int) strlen(command));
9285 XSetCursorState(display,windows,MagickFalse);
9286 break;
9287 }
9288 XSetCursorState(display,windows,MagickTrue);
9289 XCheckRefreshWindows(display,windows);
9290 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL,
cristy051718b2011-08-28 22:49:25 +00009291 exception);
anthony11d32022012-11-17 05:31:33 +00009292 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00009293 XNoticeWidget(display,windows,"Unable to browse documentation",
9294 (char *) NULL);
9295 XDelay(display,1500);
9296 XSetCursorState(display,windows,MagickFalse);
9297 break;
9298 }
9299 case VersionCommand:
9300 {
cristybb503372010-05-27 20:51:26 +00009301 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL),
cristy3ed852e2009-09-05 21:47:34 +00009302 GetMagickCopyright());
9303 break;
9304 }
9305 case SaveToUndoBufferCommand:
9306 break;
9307 default:
9308 {
9309 (void) XBell(display,0);
9310 break;
9311 }
9312 }
9313 image_info=DestroyImageInfo(image_info);
9314 return(nexus);
9315}
9316
9317/*
9318%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9319% %
9320% %
9321% %
9322+ X M a g n i f y I m a g e %
9323% %
9324% %
9325% %
9326%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9327%
9328% XMagnifyImage() magnifies portions of the image as indicated by the pointer.
9329% The magnified portion is displayed in a separate window.
9330%
9331% The format of the XMagnifyImage method is:
9332%
cristy6710d842011-10-20 23:23:00 +00009333% void XMagnifyImage(Display *display,XWindows *windows,XEvent *event,
9334% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009335%
9336% A description of each parameter follows:
9337%
9338% o display: Specifies a connection to an X server; returned from
9339% XOpenDisplay.
9340%
9341% o windows: Specifies a pointer to a XWindows structure.
9342%
9343% o event: Specifies a pointer to a XEvent structure. If it is NULL,
9344% the entire image is refreshed.
9345%
cristy6710d842011-10-20 23:23:00 +00009346% o exception: return any errors or warnings in this structure.
9347%
cristy3ed852e2009-09-05 21:47:34 +00009348*/
cristy6710d842011-10-20 23:23:00 +00009349static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event,
9350 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009351{
9352 char
9353 text[MaxTextExtent];
9354
9355 register int
9356 x,
9357 y;
9358
cristybb503372010-05-27 20:51:26 +00009359 size_t
cristy3ed852e2009-09-05 21:47:34 +00009360 state;
9361
9362 /*
9363 Update magnified image until the mouse button is released.
9364 */
9365 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor);
9366 state=DefaultState;
9367 x=event->xbutton.x;
9368 y=event->xbutton.y;
cristy49e2d862010-11-12 02:50:30 +00009369 windows->magnify.x=(int) windows->image.x+x;
9370 windows->magnify.y=(int) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +00009371 do
9372 {
9373 /*
9374 Map and unmap Info widget as text cursor crosses its boundaries.
9375 */
anthony11d32022012-11-17 05:31:33 +00009376 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00009377 {
9378 if ((x < (int) (windows->info.x+windows->info.width)) &&
9379 (y < (int) (windows->info.y+windows->info.height)))
9380 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
9381 }
9382 else
9383 if ((x > (int) (windows->info.x+windows->info.width)) ||
9384 (y > (int) (windows->info.y+windows->info.height)))
9385 (void) XMapWindow(display,windows->info.id);
anthony11d32022012-11-17 05:31:33 +00009386 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00009387 {
9388 /*
9389 Display pointer position.
9390 */
cristyb51dff52011-05-19 16:55:47 +00009391 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +00009392 windows->magnify.x,windows->magnify.y);
9393 XInfoWidget(display,windows,text);
9394 }
9395 /*
9396 Wait for next event.
9397 */
cristy6710d842011-10-20 23:23:00 +00009398 XScreenEvent(display,windows,event,exception);
cristy3ed852e2009-09-05 21:47:34 +00009399 switch (event->type)
9400 {
9401 case ButtonPress:
9402 break;
9403 case ButtonRelease:
9404 {
9405 /*
9406 User has finished magnifying image.
9407 */
9408 x=event->xbutton.x;
9409 y=event->xbutton.y;
9410 state|=ExitState;
9411 break;
9412 }
9413 case Expose:
9414 break;
9415 case MotionNotify:
9416 {
9417 x=event->xmotion.x;
9418 y=event->xmotion.y;
9419 break;
9420 }
9421 default:
9422 break;
9423 }
9424 /*
9425 Check boundary conditions.
9426 */
9427 if (x < 0)
9428 x=0;
9429 else
9430 if (x >= (int) windows->image.width)
9431 x=(int) windows->image.width-1;
9432 if (y < 0)
9433 y=0;
9434 else
9435 if (y >= (int) windows->image.height)
9436 y=(int) windows->image.height-1;
9437 } while ((state & ExitState) == 0);
9438 /*
9439 Display magnified image.
9440 */
9441 XSetCursorState(display,windows,MagickFalse);
9442}
9443
9444/*
9445%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9446% %
9447% %
9448% %
9449+ X M a g n i f y W i n d o w C o m m a n d %
9450% %
9451% %
9452% %
9453%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9454%
9455% XMagnifyWindowCommand() moves the image within an Magnify window by one
9456% pixel as specified by the key symbol.
9457%
9458% The format of the XMagnifyWindowCommand method is:
9459%
9460% void XMagnifyWindowCommand(Display *display,XWindows *windows,
cristy6710d842011-10-20 23:23:00 +00009461% const MagickStatusType state,const KeySym key_symbol,
9462% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009463%
9464% A description of each parameter follows:
9465%
9466% o display: Specifies a connection to an X server; returned from
9467% XOpenDisplay.
9468%
9469% o windows: Specifies a pointer to a XWindows structure.
9470%
9471% o state: key mask.
9472%
9473% o key_symbol: Specifies a KeySym which indicates which side of the image
9474% to trim.
9475%
cristy6710d842011-10-20 23:23:00 +00009476% o exception: return any errors or warnings in this structure.
9477%
cristy3ed852e2009-09-05 21:47:34 +00009478*/
9479static void XMagnifyWindowCommand(Display *display,XWindows *windows,
cristy6710d842011-10-20 23:23:00 +00009480 const MagickStatusType state,const KeySym key_symbol,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009481{
9482 unsigned int
9483 quantum;
9484
9485 /*
9486 User specified a magnify factor or position.
9487 */
9488 quantum=1;
9489 if ((state & Mod1Mask) != 0)
9490 quantum=10;
9491 switch ((int) key_symbol)
9492 {
9493 case QuitCommand:
9494 {
9495 (void) XWithdrawWindow(display,windows->magnify.id,
9496 windows->magnify.screen);
9497 break;
9498 }
9499 case XK_Home:
9500 case XK_KP_Home:
9501 {
9502 windows->magnify.x=(int) windows->image.width/2;
9503 windows->magnify.y=(int) windows->image.height/2;
9504 break;
9505 }
9506 case XK_Left:
9507 case XK_KP_Left:
9508 {
9509 if (windows->magnify.x > 0)
9510 windows->magnify.x-=quantum;
9511 break;
9512 }
9513 case XK_Up:
9514 case XK_KP_Up:
9515 {
9516 if (windows->magnify.y > 0)
9517 windows->magnify.y-=quantum;
9518 break;
9519 }
9520 case XK_Right:
9521 case XK_KP_Right:
9522 {
9523 if (windows->magnify.x < (int) (windows->image.ximage->width-1))
9524 windows->magnify.x+=quantum;
9525 break;
9526 }
9527 case XK_Down:
9528 case XK_KP_Down:
9529 {
9530 if (windows->magnify.y < (int) (windows->image.ximage->height-1))
9531 windows->magnify.y+=quantum;
9532 break;
9533 }
9534 case XK_0:
9535 case XK_1:
9536 case XK_2:
9537 case XK_3:
9538 case XK_4:
9539 case XK_5:
9540 case XK_6:
9541 case XK_7:
9542 case XK_8:
9543 case XK_9:
9544 {
9545 windows->magnify.data=(key_symbol-XK_0);
9546 break;
9547 }
9548 case XK_KP_0:
9549 case XK_KP_1:
9550 case XK_KP_2:
9551 case XK_KP_3:
9552 case XK_KP_4:
9553 case XK_KP_5:
9554 case XK_KP_6:
9555 case XK_KP_7:
9556 case XK_KP_8:
9557 case XK_KP_9:
9558 {
9559 windows->magnify.data=(key_symbol-XK_KP_0);
9560 break;
9561 }
9562 default:
9563 break;
9564 }
cristy6710d842011-10-20 23:23:00 +00009565 XMakeMagnifyImage(display,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +00009566}
9567
9568/*
9569%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9570% %
9571% %
9572% %
9573+ X M a k e P a n I m a g e %
9574% %
9575% %
9576% %
9577%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9578%
9579% XMakePanImage() creates a thumbnail of the image and displays it in the Pan
9580% icon window.
9581%
9582% The format of the XMakePanImage method is:
9583%
9584% void XMakePanImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +00009585% XWindows *windows,Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009586%
9587% A description of each parameter follows:
9588%
9589% o display: Specifies a connection to an X server; returned from
9590% XOpenDisplay.
9591%
9592% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9593%
9594% o windows: Specifies a pointer to a XWindows structure.
9595%
9596% o image: the image.
9597%
cristy051718b2011-08-28 22:49:25 +00009598% o exception: return any errors or warnings in this structure.
9599%
cristy3ed852e2009-09-05 21:47:34 +00009600*/
9601static void XMakePanImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +00009602 XWindows *windows,Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009603{
9604 MagickStatusType
9605 status;
9606
9607 /*
9608 Create and display image for panning icon.
9609 */
9610 XSetCursorState(display,windows,MagickTrue);
9611 XCheckRefreshWindows(display,windows);
cristy49e2d862010-11-12 02:50:30 +00009612 windows->pan.x=(int) windows->image.x;
9613 windows->pan.y=(int) windows->image.y;
cristy3ed852e2009-09-05 21:47:34 +00009614 status=XMakeImage(display,resource_info,&windows->pan,image,
cristy051718b2011-08-28 22:49:25 +00009615 windows->pan.width,windows->pan.height,exception);
anthony11d32022012-11-17 05:31:33 +00009616 if( IfMagickFalse(status) )
cristy051718b2011-08-28 22:49:25 +00009617 ThrowXWindowFatalException(ResourceLimitError,
9618 "MemoryAllocationFailed",image->filename);
cristy3ed852e2009-09-05 21:47:34 +00009619 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
9620 windows->pan.pixmap);
9621 (void) XClearWindow(display,windows->pan.id);
9622 XDrawPanRectangle(display,windows);
9623 XSetCursorState(display,windows,MagickFalse);
9624}
9625
9626/*
9627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9628% %
9629% %
9630% %
9631+ X M a t t a E d i t I m a g e %
9632% %
9633% %
9634% %
9635%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9636%
9637% XMatteEditImage() allows the user to interactively change the Matte channel
9638% of an image. If the image is PseudoClass it is promoted to DirectClass
9639% before the matte information is stored.
9640%
9641% The format of the XMatteEditImage method is:
9642%
9643% MagickBooleanType XMatteEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00009644% XResourceInfo *resource_info,XWindows *windows,Image **image,
9645% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009646%
9647% A description of each parameter follows:
9648%
9649% o display: Specifies a connection to an X server; returned from
9650% XOpenDisplay.
9651%
9652% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
9653%
9654% o windows: Specifies a pointer to a XWindows structure.
9655%
9656% o image: the image; returned from ReadImage.
9657%
cristy051718b2011-08-28 22:49:25 +00009658% o exception: return any errors or warnings in this structure.
9659%
cristy3ed852e2009-09-05 21:47:34 +00009660*/
9661static MagickBooleanType XMatteEditImage(Display *display,
cristy051718b2011-08-28 22:49:25 +00009662 XResourceInfo *resource_info,XWindows *windows,Image **image,
9663 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00009664{
9665 static char
9666 matte[MaxTextExtent] = "0";
9667
9668 static const char
9669 *MatteEditMenu[] =
9670 {
9671 "Method",
9672 "Border Color",
9673 "Fuzz",
9674 "Matte Value",
9675 "Undo",
9676 "Help",
9677 "Dismiss",
9678 (char *) NULL
9679 };
9680
9681 static const ModeType
9682 MatteEditCommands[] =
9683 {
9684 MatteEditMethod,
9685 MatteEditBorderCommand,
9686 MatteEditFuzzCommand,
9687 MatteEditValueCommand,
9688 MatteEditUndoCommand,
9689 MatteEditHelpCommand,
9690 MatteEditDismissCommand
9691 };
9692
9693 static PaintMethod
9694 method = PointMethod;
9695
9696 static XColor
9697 border_color = { 0, 0, 0, 0, 0, 0 };
9698
9699 char
9700 command[MaxTextExtent],
9701 text[MaxTextExtent];
9702
9703 Cursor
9704 cursor;
9705
9706 int
9707 entry,
9708 id,
9709 x,
9710 x_offset,
9711 y,
9712 y_offset;
9713
9714 register int
9715 i;
9716
cristy4c08aed2011-07-01 19:47:50 +00009717 register Quantum
cristy3ed852e2009-09-05 21:47:34 +00009718 *q;
9719
9720 unsigned int
9721 height,
9722 width;
9723
cristybb503372010-05-27 20:51:26 +00009724 size_t
cristy3ed852e2009-09-05 21:47:34 +00009725 state;
9726
9727 XEvent
9728 event;
9729
9730 /*
9731 Map Command widget.
9732 */
9733 (void) CloneString(&windows->command.name,"Matte Edit");
9734 windows->command.data=4;
9735 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL);
9736 (void) XMapRaised(display,windows->command.id);
9737 XClientMessage(display,windows->image.id,windows->im_protocols,
9738 windows->im_update_widget,CurrentTime);
9739 /*
9740 Make cursor.
9741 */
9742 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
9743 resource_info->background_color,resource_info->foreground_color);
9744 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9745 /*
9746 Track pointer until button 1 is pressed.
9747 */
9748 XQueryPosition(display,windows->image.id,&x,&y);
9749 (void) XSelectInput(display,windows->image.id,
9750 windows->image.attributes.event_mask | PointerMotionMask);
9751 state=DefaultState;
9752 do
9753 {
anthony11d32022012-11-17 05:31:33 +00009754 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +00009755 {
9756 /*
9757 Display pointer position.
9758 */
cristyb51dff52011-05-19 16:55:47 +00009759 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +00009760 x+windows->image.x,y+windows->image.y);
9761 XInfoWidget(display,windows,text);
9762 }
9763 /*
9764 Wait for next event.
9765 */
cristy6710d842011-10-20 23:23:00 +00009766 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +00009767 if (event.xany.window == windows->command.id)
9768 {
9769 /*
9770 Select a command from the Command widget.
9771 */
9772 id=XCommandWidget(display,windows,MatteEditMenu,&event);
9773 if (id < 0)
9774 {
9775 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9776 continue;
9777 }
9778 switch (MatteEditCommands[id])
9779 {
9780 case MatteEditMethod:
9781 {
9782 char
9783 **methods;
9784
9785 /*
9786 Select a method from the pop-up menu.
9787 */
cristy042ee782011-04-22 18:48:30 +00009788 methods=GetCommandOptions(MagickMethodOptions);
cristy3ed852e2009-09-05 21:47:34 +00009789 if (methods == (char **) NULL)
9790 break;
9791 entry=XMenuWidget(display,windows,MatteEditMenu[id],
9792 (const char **) methods,command);
9793 if (entry >= 0)
cristy042ee782011-04-22 18:48:30 +00009794 method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
cristy3ed852e2009-09-05 21:47:34 +00009795 MagickFalse,methods[entry]);
9796 methods=DestroyStringList(methods);
9797 break;
9798 }
9799 case MatteEditBorderCommand:
9800 {
9801 const char
9802 *ColorMenu[MaxNumberPens];
9803
9804 int
9805 pen_number;
9806
9807 /*
9808 Initialize menu selections.
9809 */
9810 for (i=0; i < (int) (MaxNumberPens-2); i++)
9811 ColorMenu[i]=resource_info->pen_colors[i];
9812 ColorMenu[MaxNumberPens-2]="Browser...";
9813 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
9814 /*
9815 Select a pen color from the pop-up menu.
9816 */
9817 pen_number=XMenuWidget(display,windows,MatteEditMenu[id],
9818 (const char **) ColorMenu,command);
9819 if (pen_number < 0)
9820 break;
9821 if (pen_number == (MaxNumberPens-2))
9822 {
9823 static char
9824 color_name[MaxTextExtent] = "gray";
9825
9826 /*
9827 Select a pen color from a dialog.
9828 */
9829 resource_info->pen_colors[pen_number]=color_name;
9830 XColorBrowserWidget(display,windows,"Select",color_name);
9831 if (*color_name == '\0')
9832 break;
9833 }
9834 /*
9835 Set border color.
9836 */
9837 (void) XParseColor(display,windows->map_info->colormap,
9838 resource_info->pen_colors[pen_number],&border_color);
9839 break;
9840 }
9841 case MatteEditFuzzCommand:
9842 {
9843 static char
9844 fuzz[MaxTextExtent];
9845
9846 static const char
9847 *FuzzMenu[] =
9848 {
9849 "0%",
9850 "2%",
9851 "5%",
9852 "10%",
9853 "15%",
9854 "Dialog...",
9855 (char *) NULL,
9856 };
9857
9858 /*
9859 Select a command from the pop-up menu.
9860 */
9861 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu,
9862 command);
9863 if (entry < 0)
9864 break;
9865 if (entry != 5)
9866 {
cristydbdd0e32011-11-04 23:29:40 +00009867 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double)
cristy4c08aed2011-07-01 19:47:50 +00009868 QuantumRange+1.0);
cristy3ed852e2009-09-05 21:47:34 +00009869 break;
9870 }
9871 (void) CopyMagickString(fuzz,"20%",MaxTextExtent);
9872 (void) XDialogWidget(display,windows,"Ok",
9873 "Enter fuzz factor (0.0 - 99.9%):",fuzz);
9874 if (*fuzz == '\0')
9875 break;
9876 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent);
cristy9b34e302011-11-05 02:15:45 +00009877 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+
9878 1.0);
cristy3ed852e2009-09-05 21:47:34 +00009879 break;
9880 }
9881 case MatteEditValueCommand:
9882 {
9883 static char
9884 message[MaxTextExtent];
9885
9886 static const char
9887 *MatteMenu[] =
9888 {
9889 "Opaque",
9890 "Transparent",
9891 "Dialog...",
9892 (char *) NULL,
9893 };
9894
9895 /*
9896 Select a command from the pop-up menu.
9897 */
9898 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu,
9899 command);
9900 if (entry < 0)
9901 break;
9902 if (entry != 2)
9903 {
cristyb51dff52011-05-19 16:55:47 +00009904 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat,
cristy4c08aed2011-07-01 19:47:50 +00009905 OpaqueAlpha);
cristy3ed852e2009-09-05 21:47:34 +00009906 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0)
cristyb51dff52011-05-19 16:55:47 +00009907 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat,
cristy4c08aed2011-07-01 19:47:50 +00009908 (Quantum) TransparentAlpha);
cristy3ed852e2009-09-05 21:47:34 +00009909 break;
9910 }
cristyb51dff52011-05-19 16:55:47 +00009911 (void) FormatLocaleString(message,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +00009912 "Enter matte value (0 - " QuantumFormat "):",(Quantum)
9913 QuantumRange);
9914 (void) XDialogWidget(display,windows,"Matte",message,matte);
9915 if (*matte == '\0')
9916 break;
9917 break;
9918 }
9919 case MatteEditUndoCommand:
9920 {
9921 (void) XMagickCommand(display,resource_info,windows,UndoCommand,
cristy051718b2011-08-28 22:49:25 +00009922 image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009923 break;
9924 }
9925 case MatteEditHelpCommand:
9926 {
9927 XTextViewWidget(display,resource_info,windows,MagickFalse,
9928 "Help Viewer - Matte Edit",ImageMatteEditHelp);
9929 break;
9930 }
9931 case MatteEditDismissCommand:
9932 {
9933 /*
9934 Prematurely exit.
9935 */
9936 state|=EscapeState;
9937 state|=ExitState;
9938 break;
9939 }
9940 default:
9941 break;
9942 }
9943 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9944 continue;
9945 }
9946 switch (event.type)
9947 {
9948 case ButtonPress:
9949 {
9950 if (event.xbutton.button != Button1)
9951 break;
9952 if ((event.xbutton.window != windows->image.id) &&
9953 (event.xbutton.window != windows->magnify.id))
9954 break;
9955 /*
9956 Update matte data.
9957 */
9958 x=event.xbutton.x;
9959 y=event.xbutton.y;
9960 (void) XMagickCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +00009961 SaveToUndoBufferCommand,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009962 state|=UpdateConfigurationState;
9963 break;
9964 }
9965 case ButtonRelease:
9966 {
9967 if (event.xbutton.button != Button1)
9968 break;
9969 if ((event.xbutton.window != windows->image.id) &&
9970 (event.xbutton.window != windows->magnify.id))
9971 break;
9972 /*
9973 Update colormap information.
9974 */
9975 x=event.xbutton.x;
9976 y=event.xbutton.y;
cristy6710d842011-10-20 23:23:00 +00009977 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy051718b2011-08-28 22:49:25 +00009978 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +00009979 XInfoWidget(display,windows,text);
9980 (void) XCheckDefineCursor(display,windows->image.id,cursor);
9981 state&=(~UpdateConfigurationState);
9982 break;
9983 }
9984 case Expose:
9985 break;
9986 case KeyPress:
9987 {
9988 char
9989 command[MaxTextExtent];
9990
9991 KeySym
9992 key_symbol;
9993
9994 if (event.xkey.window == windows->magnify.id)
9995 {
9996 Window
9997 window;
9998
9999 window=windows->magnify.id;
10000 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
10001 }
10002 if (event.xkey.window != windows->image.id)
10003 break;
10004 /*
10005 Respond to a user key press.
10006 */
10007 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
10008 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
10009 switch ((int) key_symbol)
10010 {
10011 case XK_Escape:
10012 case XK_F20:
10013 {
10014 /*
10015 Prematurely exit.
10016 */
10017 state|=ExitState;
10018 break;
10019 }
10020 case XK_F1:
10021 case XK_Help:
10022 {
10023 XTextViewWidget(display,resource_info,windows,MagickFalse,
10024 "Help Viewer - Matte Edit",ImageMatteEditHelp);
10025 break;
10026 }
10027 default:
10028 {
10029 (void) XBell(display,0);
10030 break;
10031 }
10032 }
10033 break;
10034 }
10035 case MotionNotify:
10036 {
10037 /*
10038 Map and unmap Info widget as cursor crosses its boundaries.
10039 */
10040 x=event.xmotion.x;
10041 y=event.xmotion.y;
anthony11d32022012-11-17 05:31:33 +000010042 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000010043 {
10044 if ((x < (int) (windows->info.x+windows->info.width)) &&
10045 (y < (int) (windows->info.y+windows->info.height)))
10046 (void) XWithdrawWindow(display,windows->info.id,
10047 windows->info.screen);
10048 }
10049 else
10050 if ((x > (int) (windows->info.x+windows->info.width)) ||
10051 (y > (int) (windows->info.y+windows->info.height)))
10052 (void) XMapWindow(display,windows->info.id);
10053 break;
10054 }
10055 default:
10056 break;
10057 }
10058 if (event.xany.window == windows->magnify.id)
10059 {
10060 x=windows->magnify.x-windows->image.x;
10061 y=windows->magnify.y-windows->image.y;
10062 }
10063 x_offset=x;
10064 y_offset=y;
10065 if ((state & UpdateConfigurationState) != 0)
10066 {
cristy49e2d862010-11-12 02:50:30 +000010067 CacheView
10068 *image_view;
10069
cristy3ed852e2009-09-05 21:47:34 +000010070 int
10071 x,
10072 y;
10073
10074 /*
10075 Matte edit is relative to image configuration.
10076 */
10077 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
10078 MagickTrue);
10079 XPutPixel(windows->image.ximage,x_offset,y_offset,
10080 windows->pixel_info->background_color.pixel);
10081 width=(unsigned int) (*image)->columns;
10082 height=(unsigned int) (*image)->rows;
10083 x=0;
10084 y=0;
10085 if (windows->image.crop_geometry != (char *) NULL)
cristy4c08aed2011-07-01 19:47:50 +000010086 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,
10087 &height);
10088 x_offset=(int) (width*(windows->image.x+x_offset)/
10089 windows->image.ximage->width+x);
10090 y_offset=(int) (height*(windows->image.y+y_offset)/
10091 windows->image.ximage->height+y);
cristy3ed852e2009-09-05 21:47:34 +000010092 if ((x_offset < 0) || (y_offset < 0))
10093 continue;
10094 if ((x_offset >= (int) (*image)->columns) ||
10095 (y_offset >= (int) (*image)->rows))
10096 continue;
anthony11d32022012-11-17 05:31:33 +000010097 if( IfMagickFalse(SetImageStorageClass(*image,DirectClass,exception)) )
cristy3ed852e2009-09-05 21:47:34 +000010098 return(MagickFalse);
cristy8a46d822012-08-28 23:32:39 +000010099 if ((*image)->alpha_trait != BlendPixelTrait)
cristycd515282011-12-27 01:40:49 +000010100 (void) SetImageAlphaChannel(*image,OpaqueAlphaChannel,exception);
cristy6f5395d2012-12-14 18:30:30 +000010101 image_view=AcquireAuthenticCacheView(*image,exception);
cristy3ed852e2009-09-05 21:47:34 +000010102 switch (method)
10103 {
10104 case PointMethod:
10105 default:
10106 {
10107 /*
10108 Update matte information using point algorithm.
10109 */
cristy49e2d862010-11-12 02:50:30 +000010110 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,
10111 (ssize_t) y_offset,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +000010112 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +000010113 break;
cristy4c08aed2011-07-01 19:47:50 +000010114 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
cristy49e2d862010-11-12 02:50:30 +000010115 (void) SyncCacheViewAuthenticPixels(image_view,exception);
cristy3ed852e2009-09-05 21:47:34 +000010116 break;
10117 }
10118 case ReplaceMethod:
10119 {
cristy101ab702011-10-13 13:06:32 +000010120 PixelInfo
cristy4c08aed2011-07-01 19:47:50 +000010121 pixel,
cristy3ed852e2009-09-05 21:47:34 +000010122 target;
10123
10124 /*
10125 Update matte information using replace algorithm.
10126 */
cristyf05d4942012-03-17 16:26:09 +000010127 (void) GetOneCacheViewVirtualPixelInfo(image_view,(ssize_t)
10128 x_offset,(ssize_t) y_offset,&target,exception);
cristy49e2d862010-11-12 02:50:30 +000010129 for (y=0; y < (int) (*image)->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +000010130 {
cristy49e2d862010-11-12 02:50:30 +000010131 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
cristy051718b2011-08-28 22:49:25 +000010132 (*image)->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +000010133 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +000010134 break;
10135 for (x=0; x < (int) (*image)->columns; x++)
10136 {
cristy101ab702011-10-13 13:06:32 +000010137 GetPixelInfoPixel(*image,q,&pixel);
10138 if (IsFuzzyEquivalencePixelInfo(&pixel,&target))
cristy4c08aed2011-07-01 19:47:50 +000010139 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
cristyed231572011-07-14 02:18:59 +000010140 q+=GetPixelChannels(*image);
cristy3ed852e2009-09-05 21:47:34 +000010141 }
anthony11d32022012-11-17 05:31:33 +000010142 if( IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) )
cristy3ed852e2009-09-05 21:47:34 +000010143 break;
10144 }
10145 break;
10146 }
10147 case FloodfillMethod:
10148 case FillToBorderMethod:
10149 {
cristybd5a96c2011-08-21 00:04:26 +000010150 ChannelType
10151 channel_mask;
10152
cristy3ed852e2009-09-05 21:47:34 +000010153 DrawInfo
10154 *draw_info;
10155
cristy4c08aed2011-07-01 19:47:50 +000010156 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +000010157 target;
10158
10159 /*
10160 Update matte information using floodfill algorithm.
10161 */
cristy3aa93752011-12-18 15:54:24 +000010162 (void) GetOneVirtualPixelInfo(*image,
cristy52010022011-10-21 18:07:37 +000010163 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t)
10164 y_offset,&target,exception);
cristy3ed852e2009-09-05 21:47:34 +000010165 if (method == FillToBorderMethod)
10166 {
cristya19f1d72012-08-07 18:24:38 +000010167 target.red=(double) ScaleShortToQuantum(
cristy4c08aed2011-07-01 19:47:50 +000010168 border_color.red);
cristya19f1d72012-08-07 18:24:38 +000010169 target.green=(double) ScaleShortToQuantum(
cristy4c08aed2011-07-01 19:47:50 +000010170 border_color.green);
cristya19f1d72012-08-07 18:24:38 +000010171 target.blue=(double) ScaleShortToQuantum(
cristy4c08aed2011-07-01 19:47:50 +000010172 border_color.blue);
cristy3ed852e2009-09-05 21:47:34 +000010173 }
10174 draw_info=CloneDrawInfo(resource_info->image_info,
10175 (DrawInfo *) NULL);
cristya19f1d72012-08-07 18:24:38 +000010176 draw_info->fill.alpha=(double) ClampToQuantum(
cristye42f6582012-02-11 17:59:50 +000010177 StringToDouble(matte,(char **) NULL));
cristyaeded782012-09-11 23:39:36 +000010178 channel_mask=SetImageChannelMask(*image,AlphaChannel);
cristyd42d9952011-07-08 14:21:50 +000010179 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t)
anthony11d32022012-11-17 05:31:33 +000010180 x_offset,(ssize_t) y_offset,
10181 IsMagickFalse(method == FloodfillMethod),exception);
cristycf1296e2012-08-26 23:40:49 +000010182 (void) SetPixelChannelMask(*image,channel_mask);
cristy3ed852e2009-09-05 21:47:34 +000010183 draw_info=DestroyDrawInfo(draw_info);
10184 break;
10185 }
10186 case ResetMethod:
10187 {
10188 /*
10189 Update matte information using reset algorithm.
10190 */
anthony11d32022012-11-17 05:31:33 +000010191 if( IfMagickFalse(SetImageStorageClass(*image,DirectClass,exception)) )
cristy3ed852e2009-09-05 21:47:34 +000010192 return(MagickFalse);
cristy49e2d862010-11-12 02:50:30 +000010193 for (y=0; y < (int) (*image)->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +000010194 {
cristy49e2d862010-11-12 02:50:30 +000010195 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
10196 (*image)->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +000010197 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +000010198 break;
10199 for (x=0; x < (int) (*image)->columns; x++)
10200 {
cristy4c08aed2011-07-01 19:47:50 +000010201 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q);
cristyed231572011-07-14 02:18:59 +000010202 q+=GetPixelChannels(*image);
cristy3ed852e2009-09-05 21:47:34 +000010203 }
anthony11d32022012-11-17 05:31:33 +000010204 if( IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) )
cristy3ed852e2009-09-05 21:47:34 +000010205 break;
10206 }
cristy4c08aed2011-07-01 19:47:50 +000010207 if (StringToLong(matte) == (long) OpaqueAlpha)
cristy8a46d822012-08-28 23:32:39 +000010208 (*image)->alpha_trait=UndefinedPixelTrait;
cristy3ed852e2009-09-05 21:47:34 +000010209 break;
10210 }
10211 }
cristy49e2d862010-11-12 02:50:30 +000010212 image_view=DestroyCacheView(image_view);
cristy3ed852e2009-09-05 21:47:34 +000010213 state&=(~UpdateConfigurationState);
10214 }
10215 } while ((state & ExitState) == 0);
10216 (void) XSelectInput(display,windows->image.id,
10217 windows->image.attributes.event_mask);
10218 XSetCursorState(display,windows,MagickFalse);
10219 (void) XFreeCursor(display,cursor);
10220 return(MagickTrue);
10221}
10222
10223/*
10224%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10225% %
10226% %
10227% %
10228+ X O p e n I m a g e %
10229% %
10230% %
10231% %
10232%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10233%
10234% XOpenImage() loads an image from a file.
10235%
10236% The format of the XOpenImage method is:
10237%
10238% Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10239% XWindows *windows,const unsigned int command)
10240%
10241% A description of each parameter follows:
10242%
10243% o display: Specifies a connection to an X server; returned from
10244% XOpenDisplay.
10245%
10246% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10247%
10248% o windows: Specifies a pointer to a XWindows structure.
10249%
10250% o command: A value other than zero indicates that the file is selected
10251% from the command line argument list.
10252%
10253*/
10254static Image *XOpenImage(Display *display,XResourceInfo *resource_info,
10255 XWindows *windows,const MagickBooleanType command)
10256{
10257 const MagickInfo
10258 *magick_info;
10259
10260 ExceptionInfo
10261 *exception;
10262
10263 Image
10264 *nexus;
10265
10266 ImageInfo
10267 *image_info;
10268
10269 static char
10270 filename[MaxTextExtent] = "\0";
10271
10272 /*
10273 Request file name from user.
10274 */
anthony11d32022012-11-17 05:31:33 +000010275 if( IfMagickFalse(command) )
cristy3ed852e2009-09-05 21:47:34 +000010276 XFileBrowserWidget(display,windows,"Open",filename);
10277 else
10278 {
10279 char
10280 **filelist,
10281 **files;
10282
10283 int
10284 count,
10285 status;
10286
10287 register int
10288 i,
10289 j;
10290
10291 /*
10292 Select next image from the command line.
10293 */
10294 status=XGetCommand(display,windows->image.id,&files,&count);
10295 if (status == 0)
10296 {
10297 ThrowXWindowFatalException(XServerError,"UnableToGetProperty","...");
10298 return((Image *) NULL);
10299 }
10300 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist));
10301 if (filelist == (char **) NULL)
10302 {
10303 ThrowXWindowFatalException(ResourceLimitError,
10304 "MemoryAllocationFailed","...");
10305 (void) XFreeStringList(files);
10306 return((Image *) NULL);
10307 }
10308 j=0;
10309 for (i=1; i < count; i++)
10310 if (*files[i] != '-')
10311 filelist[j++]=files[i];
10312 filelist[j]=(char *) NULL;
10313 XListBrowserWidget(display,windows,&windows->widget,
10314 (const char **) filelist,"Load","Select Image to Load:",filename);
10315 filelist=(char **) RelinquishMagickMemory(filelist);
10316 (void) XFreeStringList(files);
10317 }
10318 if (*filename == '\0')
10319 return((Image *) NULL);
10320 image_info=CloneImageInfo(resource_info->image_info);
10321 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL,
10322 (void *) NULL);
10323 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
10324 exception=AcquireExceptionInfo();
cristyd965a422010-03-03 17:47:35 +000010325 (void) SetImageInfo(image_info,0,exception);
cristy3ed852e2009-09-05 21:47:34 +000010326 if (LocaleCompare(image_info->magick,"X") == 0)
10327 {
10328 char
10329 seconds[MaxTextExtent];
10330
10331 /*
10332 User may want to delay the X server screen grab.
10333 */
10334 (void) CopyMagickString(seconds,"0",MaxTextExtent);
10335 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:",
10336 seconds);
10337 if (*seconds == '\0')
10338 return((Image *) NULL);
cristybb503372010-05-27 20:51:26 +000010339 XDelay(display,(size_t) (1000*StringToLong(seconds)));
cristy3ed852e2009-09-05 21:47:34 +000010340 }
10341 magick_info=GetMagickInfo(image_info->magick,exception);
10342 if ((magick_info != (const MagickInfo *) NULL) &&
anthony11d32022012-11-17 05:31:33 +000010343 IfMagickTrue(magick_info->raw))
cristy3ed852e2009-09-05 21:47:34 +000010344 {
10345 char
10346 geometry[MaxTextExtent];
10347
10348 /*
10349 Request image size from the user.
10350 */
10351 (void) CopyMagickString(geometry,"512x512",MaxTextExtent);
10352 if (image_info->size != (char *) NULL)
10353 (void) CopyMagickString(geometry,image_info->size,MaxTextExtent);
10354 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:",
10355 geometry);
10356 (void) CloneString(&image_info->size,geometry);
10357 }
10358 /*
10359 Load the image.
10360 */
10361 XSetCursorState(display,windows,MagickTrue);
10362 XCheckRefreshWindows(display,windows);
10363 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
10364 nexus=ReadImage(image_info,exception);
10365 CatchException(exception);
10366 XSetCursorState(display,windows,MagickFalse);
10367 if (nexus != (Image *) NULL)
10368 XClientMessage(display,windows->image.id,windows->im_protocols,
10369 windows->im_next_image,CurrentTime);
10370 else
10371 {
10372 char
10373 *text,
10374 **textlist;
10375
10376 /*
10377 Unknown image format.
10378 */
10379 text=FileToString(filename,~0,exception);
10380 if (text == (char *) NULL)
10381 return((Image *) NULL);
10382 textlist=StringToList(text);
10383 if (textlist != (char **) NULL)
10384 {
10385 char
10386 title[MaxTextExtent];
10387
10388 register int
10389 i;
10390
cristyb51dff52011-05-19 16:55:47 +000010391 (void) FormatLocaleString(title,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +000010392 "Unknown format: %s",filename);
10393 XTextViewWidget(display,resource_info,windows,MagickTrue,title,
10394 (const char **) textlist);
10395 for (i=0; textlist[i] != (char *) NULL; i++)
10396 textlist[i]=DestroyString(textlist[i]);
10397 textlist=(char **) RelinquishMagickMemory(textlist);
10398 }
10399 text=DestroyString(text);
10400 }
10401 exception=DestroyExceptionInfo(exception);
10402 image_info=DestroyImageInfo(image_info);
10403 return(nexus);
10404}
10405
10406/*
10407%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10408% %
10409% %
10410% %
10411+ X P a n I m a g e %
10412% %
10413% %
10414% %
10415%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10416%
10417% XPanImage() pans the image until the mouse button is released.
10418%
10419% The format of the XPanImage method is:
10420%
cristy6710d842011-10-20 23:23:00 +000010421% void XPanImage(Display *display,XWindows *windows,XEvent *event,
10422% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000010423%
10424% A description of each parameter follows:
10425%
10426% o display: Specifies a connection to an X server; returned from
10427% XOpenDisplay.
10428%
10429% o windows: Specifies a pointer to a XWindows structure.
10430%
10431% o event: Specifies a pointer to a XEvent structure. If it is NULL,
10432% the entire image is refreshed.
10433%
cristy6710d842011-10-20 23:23:00 +000010434% o exception: return any errors or warnings in this structure.
10435%
cristy3ed852e2009-09-05 21:47:34 +000010436*/
cristy6710d842011-10-20 23:23:00 +000010437static void XPanImage(Display *display,XWindows *windows,XEvent *event,
10438 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000010439{
10440 char
10441 text[MaxTextExtent];
10442
10443 Cursor
10444 cursor;
10445
cristya19f1d72012-08-07 18:24:38 +000010446 double
cristy3ed852e2009-09-05 21:47:34 +000010447 x_factor,
10448 y_factor;
10449
10450 RectangleInfo
10451 pan_info;
10452
cristybb503372010-05-27 20:51:26 +000010453 size_t
cristy3ed852e2009-09-05 21:47:34 +000010454 state;
10455
10456 /*
10457 Define cursor.
10458 */
10459 if ((windows->image.ximage->width > (int) windows->image.width) &&
10460 (windows->image.ximage->height > (int) windows->image.height))
10461 cursor=XCreateFontCursor(display,XC_fleur);
10462 else
10463 if (windows->image.ximage->width > (int) windows->image.width)
10464 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow);
10465 else
10466 if (windows->image.ximage->height > (int) windows->image.height)
10467 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow);
10468 else
10469 cursor=XCreateFontCursor(display,XC_arrow);
10470 (void) XCheckDefineCursor(display,windows->pan.id,cursor);
10471 /*
10472 Pan image as pointer moves until the mouse button is released.
10473 */
cristya19f1d72012-08-07 18:24:38 +000010474 x_factor=(double) windows->image.ximage->width/windows->pan.width;
10475 y_factor=(double) windows->image.ximage->height/windows->pan.height;
cristy3ed852e2009-09-05 21:47:34 +000010476 pan_info.width=windows->pan.width*windows->image.width/
10477 windows->image.ximage->width;
10478 pan_info.height=windows->pan.height*windows->image.height/
10479 windows->image.ximage->height;
10480 pan_info.x=0;
10481 pan_info.y=0;
10482 state=UpdateConfigurationState;
10483 do
10484 {
10485 switch (event->type)
10486 {
10487 case ButtonPress:
10488 {
10489 /*
10490 User choose an initial pan location.
10491 */
cristy49e2d862010-11-12 02:50:30 +000010492 pan_info.x=(ssize_t) event->xbutton.x;
10493 pan_info.y=(ssize_t) event->xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000010494 state|=UpdateConfigurationState;
10495 break;
10496 }
10497 case ButtonRelease:
10498 {
10499 /*
10500 User has finished panning the image.
10501 */
cristy49e2d862010-11-12 02:50:30 +000010502 pan_info.x=(ssize_t) event->xbutton.x;
10503 pan_info.y=(ssize_t) event->xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000010504 state|=UpdateConfigurationState | ExitState;
10505 break;
10506 }
10507 case MotionNotify:
10508 {
cristy49e2d862010-11-12 02:50:30 +000010509 pan_info.x=(ssize_t) event->xmotion.x;
10510 pan_info.y=(ssize_t) event->xmotion.y;
cristy3ed852e2009-09-05 21:47:34 +000010511 state|=UpdateConfigurationState;
10512 }
10513 default:
10514 break;
10515 }
10516 if ((state & UpdateConfigurationState) != 0)
10517 {
10518 /*
10519 Check boundary conditions.
10520 */
cristy49e2d862010-11-12 02:50:30 +000010521 if (pan_info.x < (ssize_t) (pan_info.width/2))
cristy3ed852e2009-09-05 21:47:34 +000010522 pan_info.x=0;
10523 else
cristy49e2d862010-11-12 02:50:30 +000010524 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2)));
cristy3ed852e2009-09-05 21:47:34 +000010525 if (pan_info.x < 0)
10526 pan_info.x=0;
10527 else
10528 if ((int) (pan_info.x+windows->image.width) >
10529 windows->image.ximage->width)
cristybb503372010-05-27 20:51:26 +000010530 pan_info.x=(ssize_t)
cristy3ed852e2009-09-05 21:47:34 +000010531 (windows->image.ximage->width-windows->image.width);
cristybb503372010-05-27 20:51:26 +000010532 if (pan_info.y < (ssize_t) (pan_info.height/2))
cristy3ed852e2009-09-05 21:47:34 +000010533 pan_info.y=0;
10534 else
cristybb503372010-05-27 20:51:26 +000010535 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2)));
cristy3ed852e2009-09-05 21:47:34 +000010536 if (pan_info.y < 0)
10537 pan_info.y=0;
10538 else
10539 if ((int) (pan_info.y+windows->image.height) >
10540 windows->image.ximage->height)
cristybb503372010-05-27 20:51:26 +000010541 pan_info.y=(ssize_t)
cristy3ed852e2009-09-05 21:47:34 +000010542 (windows->image.ximage->height-windows->image.height);
10543 if ((windows->image.x != (int) pan_info.x) ||
10544 (windows->image.y != (int) pan_info.y))
10545 {
10546 /*
10547 Display image pan offset.
10548 */
10549 windows->image.x=(int) pan_info.x;
10550 windows->image.y=(int) pan_info.y;
cristyb51dff52011-05-19 16:55:47 +000010551 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +000010552 windows->image.width,windows->image.height,windows->image.x,
10553 windows->image.y);
10554 XInfoWidget(display,windows,text);
10555 /*
10556 Refresh Image window.
10557 */
10558 XDrawPanRectangle(display,windows);
10559 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
10560 }
10561 state&=(~UpdateConfigurationState);
10562 }
10563 /*
10564 Wait for next event.
10565 */
10566 if ((state & ExitState) == 0)
cristy6710d842011-10-20 23:23:00 +000010567 XScreenEvent(display,windows,event,exception);
cristy3ed852e2009-09-05 21:47:34 +000010568 } while ((state & ExitState) == 0);
10569 /*
10570 Restore cursor.
10571 */
10572 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor);
10573 (void) XFreeCursor(display,cursor);
10574 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
10575}
10576
10577/*
10578%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10579% %
10580% %
10581% %
10582+ X P a s t e I m a g e %
10583% %
10584% %
10585% %
10586%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10587%
10588% XPasteImage() pastes an image previously saved with XCropImage in the X
10589% window image at a location the user chooses with the pointer.
10590%
10591% The format of the XPasteImage method is:
10592%
10593% MagickBooleanType XPasteImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000010594% XResourceInfo *resource_info,XWindows *windows,Image *image,
10595% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000010596%
10597% A description of each parameter follows:
10598%
10599% o display: Specifies a connection to an X server; returned from
10600% XOpenDisplay.
10601%
10602% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10603%
10604% o windows: Specifies a pointer to a XWindows structure.
10605%
10606% o image: the image; returned from ReadImage.
10607%
cristy051718b2011-08-28 22:49:25 +000010608% o exception: return any errors or warnings in this structure.
10609%
cristy3ed852e2009-09-05 21:47:34 +000010610*/
10611static MagickBooleanType XPasteImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000010612 XResourceInfo *resource_info,XWindows *windows,Image *image,
10613 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000010614{
10615 static const char
10616 *PasteMenu[] =
10617 {
10618 "Operator",
10619 "Help",
10620 "Dismiss",
10621 (char *) NULL
10622 };
10623
10624 static const ModeType
10625 PasteCommands[] =
10626 {
10627 PasteOperatorsCommand,
10628 PasteHelpCommand,
10629 PasteDismissCommand
10630 };
10631
10632 static CompositeOperator
10633 compose = CopyCompositeOp;
10634
10635 char
10636 text[MaxTextExtent];
10637
10638 Cursor
10639 cursor;
10640
10641 Image
10642 *paste_image;
10643
10644 int
10645 entry,
10646 id,
10647 x,
10648 y;
10649
cristya19f1d72012-08-07 18:24:38 +000010650 double
cristy3ed852e2009-09-05 21:47:34 +000010651 scale_factor;
10652
10653 RectangleInfo
10654 highlight_info,
10655 paste_info;
10656
10657 unsigned int
10658 height,
10659 width;
10660
cristybb503372010-05-27 20:51:26 +000010661 size_t
cristy3ed852e2009-09-05 21:47:34 +000010662 state;
10663
10664 XEvent
10665 event;
10666
10667 /*
10668 Copy image.
10669 */
10670 if (resource_info->copy_image == (Image *) NULL)
10671 return(MagickFalse);
cristy051718b2011-08-28 22:49:25 +000010672 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +000010673 /*
10674 Map Command widget.
10675 */
10676 (void) CloneString(&windows->command.name,"Paste");
10677 windows->command.data=1;
10678 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL);
10679 (void) XMapRaised(display,windows->command.id);
10680 XClientMessage(display,windows->image.id,windows->im_protocols,
10681 windows->im_update_widget,CurrentTime);
10682 /*
10683 Track pointer until button 1 is pressed.
10684 */
10685 XSetCursorState(display,windows,MagickFalse);
10686 XQueryPosition(display,windows->image.id,&x,&y);
10687 (void) XSelectInput(display,windows->image.id,
10688 windows->image.attributes.event_mask | PointerMotionMask);
cristy49e2d862010-11-12 02:50:30 +000010689 paste_info.x=(ssize_t) windows->image.x+x;
10690 paste_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +000010691 paste_info.width=0;
10692 paste_info.height=0;
10693 cursor=XCreateFontCursor(display,XC_ul_angle);
10694 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
10695 state=DefaultState;
10696 do
10697 {
anthony11d32022012-11-17 05:31:33 +000010698 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000010699 {
10700 /*
10701 Display pointer position.
10702 */
cristyb51dff52011-05-19 16:55:47 +000010703 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
cristyf2faecf2010-05-28 19:19:36 +000010704 (long) paste_info.x,(long) paste_info.y);
cristy3ed852e2009-09-05 21:47:34 +000010705 XInfoWidget(display,windows,text);
10706 }
10707 highlight_info=paste_info;
10708 highlight_info.x=paste_info.x-windows->image.x;
10709 highlight_info.y=paste_info.y-windows->image.y;
10710 XHighlightRectangle(display,windows->image.id,
10711 windows->image.highlight_context,&highlight_info);
10712 /*
10713 Wait for next event.
10714 */
cristy6710d842011-10-20 23:23:00 +000010715 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000010716 XHighlightRectangle(display,windows->image.id,
10717 windows->image.highlight_context,&highlight_info);
10718 if (event.xany.window == windows->command.id)
10719 {
10720 /*
10721 Select a command from the Command widget.
10722 */
10723 id=XCommandWidget(display,windows,PasteMenu,&event);
10724 if (id < 0)
10725 continue;
10726 switch (PasteCommands[id])
10727 {
10728 case PasteOperatorsCommand:
10729 {
10730 char
10731 command[MaxTextExtent],
10732 **operators;
10733
10734 /*
10735 Select a command from the pop-up menu.
10736 */
cristy042ee782011-04-22 18:48:30 +000010737 operators=GetCommandOptions(MagickComposeOptions);
cristy3ed852e2009-09-05 21:47:34 +000010738 if (operators == (char **) NULL)
10739 break;
10740 entry=XMenuWidget(display,windows,PasteMenu[id],
10741 (const char **) operators,command);
10742 if (entry >= 0)
cristy042ee782011-04-22 18:48:30 +000010743 compose=(CompositeOperator) ParseCommandOption(
cristy3ed852e2009-09-05 21:47:34 +000010744 MagickComposeOptions,MagickFalse,operators[entry]);
10745 operators=DestroyStringList(operators);
10746 break;
10747 }
10748 case PasteHelpCommand:
10749 {
10750 XTextViewWidget(display,resource_info,windows,MagickFalse,
10751 "Help Viewer - Image Composite",ImagePasteHelp);
10752 break;
10753 }
10754 case PasteDismissCommand:
10755 {
10756 /*
10757 Prematurely exit.
10758 */
10759 state|=EscapeState;
10760 state|=ExitState;
10761 break;
10762 }
10763 default:
10764 break;
10765 }
10766 continue;
10767 }
10768 switch (event.type)
10769 {
10770 case ButtonPress:
10771 {
anthony11d32022012-11-17 05:31:33 +000010772 if( IfMagickTrue(image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000010773 (void) LogMagickEvent(X11Event,GetMagickModule(),
10774 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
10775 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10776 if (event.xbutton.button != Button1)
10777 break;
10778 if (event.xbutton.window != windows->image.id)
10779 break;
10780 /*
10781 Paste rectangle is relative to image configuration.
10782 */
10783 width=(unsigned int) image->columns;
10784 height=(unsigned int) image->rows;
10785 x=0;
10786 y=0;
10787 if (windows->image.crop_geometry != (char *) NULL)
10788 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
10789 &width,&height);
cristya19f1d72012-08-07 18:24:38 +000010790 scale_factor=(double) windows->image.ximage->width/width;
cristy3ed852e2009-09-05 21:47:34 +000010791 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5);
cristya19f1d72012-08-07 18:24:38 +000010792 scale_factor=(double) windows->image.ximage->height/height;
cristy3ed852e2009-09-05 21:47:34 +000010793 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5);
10794 (void) XCheckDefineCursor(display,windows->image.id,cursor);
cristy49e2d862010-11-12 02:50:30 +000010795 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10796 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000010797 break;
10798 }
10799 case ButtonRelease:
10800 {
anthony11d32022012-11-17 05:31:33 +000010801 if( IfMagickTrue(image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000010802 (void) LogMagickEvent(X11Event,GetMagickModule(),
10803 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
10804 event.xbutton.button,event.xbutton.x,event.xbutton.y);
10805 if (event.xbutton.button != Button1)
10806 break;
10807 if (event.xbutton.window != windows->image.id)
10808 break;
10809 if ((paste_info.width != 0) && (paste_info.height != 0))
10810 {
10811 /*
10812 User has selected the location of the paste image.
10813 */
cristy49e2d862010-11-12 02:50:30 +000010814 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
10815 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000010816 state|=ExitState;
10817 }
10818 break;
10819 }
10820 case Expose:
10821 break;
10822 case KeyPress:
10823 {
10824 char
10825 command[MaxTextExtent];
10826
10827 KeySym
10828 key_symbol;
10829
10830 int
10831 length;
10832
10833 if (event.xkey.window != windows->image.id)
10834 break;
10835 /*
10836 Respond to a user key press.
10837 */
10838 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
10839 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
10840 *(command+length)='\0';
anthony11d32022012-11-17 05:31:33 +000010841 if( IfMagickTrue(image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000010842 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristyf2faecf2010-05-28 19:19:36 +000010843 "Key press: 0x%lx (%s)",(long) key_symbol,command);
cristy3ed852e2009-09-05 21:47:34 +000010844 switch ((int) key_symbol)
10845 {
10846 case XK_Escape:
10847 case XK_F20:
10848 {
10849 /*
10850 Prematurely exit.
10851 */
10852 paste_image=DestroyImage(paste_image);
10853 state|=EscapeState;
10854 state|=ExitState;
10855 break;
10856 }
10857 case XK_F1:
10858 case XK_Help:
10859 {
10860 (void) XSetFunction(display,windows->image.highlight_context,
10861 GXcopy);
10862 XTextViewWidget(display,resource_info,windows,MagickFalse,
10863 "Help Viewer - Image Composite",ImagePasteHelp);
10864 (void) XSetFunction(display,windows->image.highlight_context,
10865 GXinvert);
10866 break;
10867 }
10868 default:
10869 {
10870 (void) XBell(display,0);
10871 break;
10872 }
10873 }
10874 break;
10875 }
10876 case MotionNotify:
10877 {
10878 /*
10879 Map and unmap Info widget as text cursor crosses its boundaries.
10880 */
10881 x=event.xmotion.x;
10882 y=event.xmotion.y;
anthony11d32022012-11-17 05:31:33 +000010883 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000010884 {
10885 if ((x < (int) (windows->info.x+windows->info.width)) &&
10886 (y < (int) (windows->info.y+windows->info.height)))
10887 (void) XWithdrawWindow(display,windows->info.id,
10888 windows->info.screen);
10889 }
10890 else
10891 if ((x > (int) (windows->info.x+windows->info.width)) ||
10892 (y > (int) (windows->info.y+windows->info.height)))
10893 (void) XMapWindow(display,windows->info.id);
cristy49e2d862010-11-12 02:50:30 +000010894 paste_info.x=(ssize_t) windows->image.x+x;
10895 paste_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +000010896 break;
10897 }
10898 default:
10899 {
anthony11d32022012-11-17 05:31:33 +000010900 if( IfMagickTrue(image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000010901 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
10902 event.type);
10903 break;
10904 }
10905 }
10906 } while ((state & ExitState) == 0);
10907 (void) XSelectInput(display,windows->image.id,
10908 windows->image.attributes.event_mask);
10909 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
10910 XSetCursorState(display,windows,MagickFalse);
10911 (void) XFreeCursor(display,cursor);
10912 if ((state & EscapeState) != 0)
10913 return(MagickTrue);
10914 /*
10915 Image pasting is relative to image configuration.
10916 */
10917 XSetCursorState(display,windows,MagickTrue);
10918 XCheckRefreshWindows(display,windows);
10919 width=(unsigned int) image->columns;
10920 height=(unsigned int) image->rows;
10921 x=0;
10922 y=0;
10923 if (windows->image.crop_geometry != (char *) NULL)
10924 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
cristya19f1d72012-08-07 18:24:38 +000010925 scale_factor=(double) width/windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +000010926 paste_info.x+=x;
cristy49e2d862010-11-12 02:50:30 +000010927 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +000010928 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5);
cristya19f1d72012-08-07 18:24:38 +000010929 scale_factor=(double) height/windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +000010930 paste_info.y+=y;
cristy49e2d862010-11-12 02:50:30 +000010931 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5);
cristy3ed852e2009-09-05 21:47:34 +000010932 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5);
10933 /*
10934 Paste image with X Image window.
10935 */
cristy39172402012-03-30 13:04:39 +000010936 (void) CompositeImage(image,paste_image,compose,MagickTrue,paste_info.x,
cristyfeb3e962012-03-29 17:25:55 +000010937 paste_info.y,exception);
cristy3ed852e2009-09-05 21:47:34 +000010938 paste_image=DestroyImage(paste_image);
10939 XSetCursorState(display,windows,MagickFalse);
10940 /*
10941 Update image colormap.
10942 */
cristy6710d842011-10-20 23:23:00 +000010943 XConfigureImageColormap(display,resource_info,windows,image,exception);
cristy051718b2011-08-28 22:49:25 +000010944 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +000010945 return(MagickTrue);
10946}
10947
10948/*
10949%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10950% %
10951% %
10952% %
10953+ X P r i n t I m a g e %
10954% %
10955% %
10956% %
10957%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10958%
10959% XPrintImage() prints an image to a Postscript printer.
10960%
10961% The format of the XPrintImage method is:
10962%
10963% MagickBooleanType XPrintImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000010964% XResourceInfo *resource_info,XWindows *windows,Image *image,
10965% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000010966%
10967% A description of each parameter follows:
10968%
10969% o display: Specifies a connection to an X server; returned from
10970% XOpenDisplay.
10971%
10972% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
10973%
10974% o windows: Specifies a pointer to a XWindows structure.
10975%
10976% o image: the image.
10977%
cristy051718b2011-08-28 22:49:25 +000010978% o exception: return any errors or warnings in this structure.
10979%
cristy3ed852e2009-09-05 21:47:34 +000010980*/
10981static MagickBooleanType XPrintImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000010982 XResourceInfo *resource_info,XWindows *windows,Image *image,
10983 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000010984{
10985 char
10986 filename[MaxTextExtent],
10987 geometry[MaxTextExtent];
10988
10989 Image
10990 *print_image;
10991
10992 ImageInfo
10993 *image_info;
10994
10995 MagickStatusType
10996 status;
10997
10998 /*
10999 Request Postscript page geometry from user.
11000 */
11001 image_info=CloneImageInfo(resource_info->image_info);
cristyb51dff52011-05-19 16:55:47 +000011002 (void) FormatLocaleString(geometry,MaxTextExtent,"Letter");
cristy3ed852e2009-09-05 21:47:34 +000011003 if (image_info->page != (char *) NULL)
11004 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
11005 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
11006 "Select Postscript Page Geometry:",geometry);
11007 if (*geometry == '\0')
11008 return(MagickTrue);
11009 image_info->page=GetPageGeometry(geometry);
11010 /*
11011 Apply image transforms.
11012 */
11013 XSetCursorState(display,windows,MagickTrue);
11014 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +000011015 print_image=CloneImage(image,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +000011016 if (print_image == (Image *) NULL)
11017 return(MagickFalse);
cristyb51dff52011-05-19 16:55:47 +000011018 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!",
cristy3ed852e2009-09-05 21:47:34 +000011019 windows->image.ximage->width,windows->image.ximage->height);
cristye941a752011-10-15 01:52:48 +000011020 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry,
11021 exception);
cristy3ed852e2009-09-05 21:47:34 +000011022 /*
11023 Print image.
11024 */
11025 (void) AcquireUniqueFilename(filename);
cristyb51dff52011-05-19 16:55:47 +000011026 (void) FormatLocaleString(print_image->filename,MaxTextExtent,"print:%s",
cristy3ed852e2009-09-05 21:47:34 +000011027 filename);
cristy051718b2011-08-28 22:49:25 +000011028 status=WriteImage(image_info,print_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000011029 (void) RelinquishUniqueFileResource(filename);
11030 print_image=DestroyImage(print_image);
11031 image_info=DestroyImageInfo(image_info);
11032 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +000011033 return(IsMagickTrue(status));
cristy3ed852e2009-09-05 21:47:34 +000011034}
11035
11036/*
11037%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11038% %
11039% %
11040% %
11041+ X R O I I m a g e %
11042% %
11043% %
11044% %
11045%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11046%
11047% XROIImage() applies an image processing technique to a region of interest.
11048%
11049% The format of the XROIImage method is:
11050%
11051% MagickBooleanType XROIImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000011052% XResourceInfo *resource_info,XWindows *windows,Image **image,
11053% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000011054%
11055% A description of each parameter follows:
11056%
11057% o display: Specifies a connection to an X server; returned from
11058% XOpenDisplay.
11059%
11060% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
11061%
11062% o windows: Specifies a pointer to a XWindows structure.
11063%
11064% o image: the image; returned from ReadImage.
11065%
cristy051718b2011-08-28 22:49:25 +000011066% o exception: return any errors or warnings in this structure.
11067%
cristy3ed852e2009-09-05 21:47:34 +000011068*/
11069static MagickBooleanType XROIImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000011070 XResourceInfo *resource_info,XWindows *windows,Image **image,
11071 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000011072{
11073#define ApplyMenus 7
11074
11075 static const char
11076 *ROIMenu[] =
11077 {
11078 "Help",
11079 "Dismiss",
11080 (char *) NULL
11081 },
11082 *ApplyMenu[] =
11083 {
11084 "File",
11085 "Edit",
11086 "Transform",
11087 "Enhance",
11088 "Effects",
11089 "F/X",
11090 "Miscellany",
11091 "Help",
11092 "Dismiss",
11093 (char *) NULL
11094 },
11095 *FileMenu[] =
11096 {
11097 "Save...",
11098 "Print...",
11099 (char *) NULL
11100 },
11101 *EditMenu[] =
11102 {
11103 "Undo",
11104 "Redo",
11105 (char *) NULL
11106 },
11107 *TransformMenu[] =
11108 {
11109 "Flop",
11110 "Flip",
11111 "Rotate Right",
11112 "Rotate Left",
11113 (char *) NULL
11114 },
11115 *EnhanceMenu[] =
11116 {
11117 "Hue...",
11118 "Saturation...",
11119 "Brightness...",
11120 "Gamma...",
11121 "Spiff",
11122 "Dull",
11123 "Contrast Stretch...",
11124 "Sigmoidal Contrast...",
11125 "Normalize",
11126 "Equalize",
11127 "Negate",
11128 "Grayscale",
11129 "Map...",
11130 "Quantize...",
11131 (char *) NULL
11132 },
11133 *EffectsMenu[] =
11134 {
11135 "Despeckle",
11136 "Emboss",
11137 "Reduce Noise",
11138 "Add Noise",
11139 "Sharpen...",
11140 "Blur...",
11141 "Threshold...",
11142 "Edge Detect...",
11143 "Spread...",
11144 "Shade...",
11145 "Raise...",
11146 "Segment...",
11147 (char *) NULL
11148 },
11149 *FXMenu[] =
11150 {
11151 "Solarize...",
11152 "Sepia Tone...",
11153 "Swirl...",
11154 "Implode...",
11155 "Vignette...",
11156 "Wave...",
11157 "Oil Paint...",
11158 "Charcoal Draw...",
11159 (char *) NULL
11160 },
11161 *MiscellanyMenu[] =
11162 {
11163 "Image Info",
11164 "Zoom Image",
11165 "Show Preview...",
11166 "Show Histogram",
11167 "Show Matte",
11168 (char *) NULL
11169 };
11170
11171 static const char
11172 **Menus[ApplyMenus] =
11173 {
11174 FileMenu,
11175 EditMenu,
11176 TransformMenu,
11177 EnhanceMenu,
11178 EffectsMenu,
11179 FXMenu,
11180 MiscellanyMenu
11181 };
11182
11183 static const CommandType
11184 ApplyCommands[] =
11185 {
11186 NullCommand,
11187 NullCommand,
11188 NullCommand,
11189 NullCommand,
11190 NullCommand,
11191 NullCommand,
11192 NullCommand,
11193 HelpCommand,
11194 QuitCommand
11195 },
11196 FileCommands[] =
11197 {
11198 SaveCommand,
11199 PrintCommand
11200 },
11201 EditCommands[] =
11202 {
11203 UndoCommand,
11204 RedoCommand
11205 },
11206 TransformCommands[] =
11207 {
11208 FlopCommand,
11209 FlipCommand,
11210 RotateRightCommand,
11211 RotateLeftCommand
11212 },
11213 EnhanceCommands[] =
11214 {
11215 HueCommand,
11216 SaturationCommand,
11217 BrightnessCommand,
11218 GammaCommand,
11219 SpiffCommand,
11220 DullCommand,
11221 ContrastStretchCommand,
11222 SigmoidalContrastCommand,
11223 NormalizeCommand,
11224 EqualizeCommand,
11225 NegateCommand,
11226 GrayscaleCommand,
11227 MapCommand,
11228 QuantizeCommand
11229 },
11230 EffectsCommands[] =
11231 {
11232 DespeckleCommand,
11233 EmbossCommand,
11234 ReduceNoiseCommand,
11235 AddNoiseCommand,
11236 SharpenCommand,
11237 BlurCommand,
11238 EdgeDetectCommand,
11239 SpreadCommand,
11240 ShadeCommand,
11241 RaiseCommand,
11242 SegmentCommand
11243 },
11244 FXCommands[] =
11245 {
11246 SolarizeCommand,
11247 SepiaToneCommand,
11248 SwirlCommand,
11249 ImplodeCommand,
11250 VignetteCommand,
11251 WaveCommand,
11252 OilPaintCommand,
11253 CharcoalDrawCommand
11254 },
11255 MiscellanyCommands[] =
11256 {
11257 InfoCommand,
11258 ZoomCommand,
11259 ShowPreviewCommand,
11260 ShowHistogramCommand,
11261 ShowMatteCommand
11262 },
11263 ROICommands[] =
11264 {
11265 ROIHelpCommand,
11266 ROIDismissCommand
11267 };
11268
11269 static const CommandType
11270 *Commands[ApplyMenus] =
11271 {
11272 FileCommands,
11273 EditCommands,
11274 TransformCommands,
11275 EnhanceCommands,
11276 EffectsCommands,
11277 FXCommands,
11278 MiscellanyCommands
11279 };
11280
11281 char
11282 command[MaxTextExtent],
11283 text[MaxTextExtent];
11284
11285 CommandType
11286 command_type;
11287
11288 Cursor
11289 cursor;
11290
11291 Image
11292 *roi_image;
11293
11294 int
11295 entry,
11296 id,
11297 x,
11298 y;
11299
cristya19f1d72012-08-07 18:24:38 +000011300 double
cristy3ed852e2009-09-05 21:47:34 +000011301 scale_factor;
11302
11303 MagickProgressMonitor
11304 progress_monitor;
11305
11306 RectangleInfo
11307 crop_info,
11308 highlight_info,
11309 roi_info;
11310
11311 unsigned int
11312 height,
11313 width;
11314
cristybb503372010-05-27 20:51:26 +000011315 size_t
cristy3ed852e2009-09-05 21:47:34 +000011316 state;
11317
11318 XEvent
11319 event;
11320
11321 /*
11322 Map Command widget.
11323 */
11324 (void) CloneString(&windows->command.name,"ROI");
11325 windows->command.data=0;
11326 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL);
11327 (void) XMapRaised(display,windows->command.id);
11328 XClientMessage(display,windows->image.id,windows->im_protocols,
11329 windows->im_update_widget,CurrentTime);
11330 /*
11331 Track pointer until button 1 is pressed.
11332 */
11333 XQueryPosition(display,windows->image.id,&x,&y);
11334 (void) XSelectInput(display,windows->image.id,
11335 windows->image.attributes.event_mask | PointerMotionMask);
cristy49e2d862010-11-12 02:50:30 +000011336 roi_info.x=(ssize_t) windows->image.x+x;
11337 roi_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +000011338 roi_info.width=0;
11339 roi_info.height=0;
11340 cursor=XCreateFontCursor(display,XC_fleur);
11341 state=DefaultState;
11342 do
11343 {
anthony11d32022012-11-17 05:31:33 +000011344 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000011345 {
11346 /*
11347 Display pointer position.
11348 */
cristyb51dff52011-05-19 16:55:47 +000011349 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
cristyf2faecf2010-05-28 19:19:36 +000011350 (long) roi_info.x,(long) roi_info.y);
cristy3ed852e2009-09-05 21:47:34 +000011351 XInfoWidget(display,windows,text);
11352 }
11353 /*
11354 Wait for next event.
11355 */
cristy6710d842011-10-20 23:23:00 +000011356 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000011357 if (event.xany.window == windows->command.id)
11358 {
11359 /*
11360 Select a command from the Command widget.
11361 */
11362 id=XCommandWidget(display,windows,ROIMenu,&event);
11363 if (id < 0)
11364 continue;
11365 switch (ROICommands[id])
11366 {
11367 case ROIHelpCommand:
11368 {
11369 XTextViewWidget(display,resource_info,windows,MagickFalse,
11370 "Help Viewer - Region of Interest",ImageROIHelp);
11371 break;
11372 }
11373 case ROIDismissCommand:
11374 {
11375 /*
11376 Prematurely exit.
11377 */
11378 state|=EscapeState;
11379 state|=ExitState;
11380 break;
11381 }
11382 default:
11383 break;
11384 }
11385 continue;
11386 }
11387 switch (event.type)
11388 {
11389 case ButtonPress:
11390 {
11391 if (event.xbutton.button != Button1)
11392 break;
11393 if (event.xbutton.window != windows->image.id)
11394 break;
11395 /*
11396 Note first corner of region of interest rectangle-- exit loop.
11397 */
11398 (void) XCheckDefineCursor(display,windows->image.id,cursor);
cristy49e2d862010-11-12 02:50:30 +000011399 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11400 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000011401 state|=ExitState;
11402 break;
11403 }
11404 case ButtonRelease:
11405 break;
11406 case Expose:
11407 break;
11408 case KeyPress:
11409 {
11410 KeySym
11411 key_symbol;
11412
11413 if (event.xkey.window != windows->image.id)
11414 break;
11415 /*
11416 Respond to a user key press.
11417 */
11418 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11419 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11420 switch ((int) key_symbol)
11421 {
11422 case XK_Escape:
11423 case XK_F20:
11424 {
11425 /*
11426 Prematurely exit.
11427 */
11428 state|=EscapeState;
11429 state|=ExitState;
11430 break;
11431 }
11432 case XK_F1:
11433 case XK_Help:
11434 {
11435 XTextViewWidget(display,resource_info,windows,MagickFalse,
11436 "Help Viewer - Region of Interest",ImageROIHelp);
11437 break;
11438 }
11439 default:
11440 {
11441 (void) XBell(display,0);
11442 break;
11443 }
11444 }
11445 break;
11446 }
11447 case MotionNotify:
11448 {
11449 /*
11450 Map and unmap Info widget as text cursor crosses its boundaries.
11451 */
11452 x=event.xmotion.x;
11453 y=event.xmotion.y;
anthony11d32022012-11-17 05:31:33 +000011454 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000011455 {
11456 if ((x < (int) (windows->info.x+windows->info.width)) &&
11457 (y < (int) (windows->info.y+windows->info.height)))
11458 (void) XWithdrawWindow(display,windows->info.id,
11459 windows->info.screen);
11460 }
11461 else
11462 if ((x > (int) (windows->info.x+windows->info.width)) ||
11463 (y > (int) (windows->info.y+windows->info.height)))
11464 (void) XMapWindow(display,windows->info.id);
cristy49e2d862010-11-12 02:50:30 +000011465 roi_info.x=(ssize_t) windows->image.x+x;
11466 roi_info.y=(ssize_t) windows->image.y+y;
cristy3ed852e2009-09-05 21:47:34 +000011467 break;
11468 }
11469 default:
11470 break;
11471 }
11472 } while ((state & ExitState) == 0);
11473 (void) XSelectInput(display,windows->image.id,
11474 windows->image.attributes.event_mask);
11475 if ((state & EscapeState) != 0)
11476 {
11477 /*
11478 User want to exit without region of interest.
11479 */
11480 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11481 (void) XFreeCursor(display,cursor);
11482 return(MagickTrue);
11483 }
11484 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
11485 do
11486 {
11487 /*
11488 Size rectangle as pointer moves until the mouse button is released.
11489 */
11490 x=(int) roi_info.x;
11491 y=(int) roi_info.y;
11492 roi_info.width=0;
11493 roi_info.height=0;
11494 state=DefaultState;
11495 do
11496 {
11497 highlight_info=roi_info;
11498 highlight_info.x=roi_info.x-windows->image.x;
11499 highlight_info.y=roi_info.y-windows->image.y;
11500 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11501 {
11502 /*
11503 Display info and draw region of interest rectangle.
11504 */
anthony11d32022012-11-17 05:31:33 +000011505 if( IfMagickFalse(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000011506 (void) XMapWindow(display,windows->info.id);
cristyb51dff52011-05-19 16:55:47 +000011507 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +000011508 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +000011509 roi_info.height,(double) roi_info.x,(double) roi_info.y);
cristy3ed852e2009-09-05 21:47:34 +000011510 XInfoWidget(display,windows,text);
11511 XHighlightRectangle(display,windows->image.id,
11512 windows->image.highlight_context,&highlight_info);
11513 }
11514 else
anthony11d32022012-11-17 05:31:33 +000011515 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000011516 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
11517 /*
11518 Wait for next event.
11519 */
cristy6710d842011-10-20 23:23:00 +000011520 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000011521 if ((highlight_info.width > 3) && (highlight_info.height > 3))
11522 XHighlightRectangle(display,windows->image.id,
11523 windows->image.highlight_context,&highlight_info);
11524 switch (event.type)
11525 {
11526 case ButtonPress:
11527 {
cristy49e2d862010-11-12 02:50:30 +000011528 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11529 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000011530 break;
11531 }
11532 case ButtonRelease:
11533 {
11534 /*
11535 User has committed to region of interest rectangle.
11536 */
cristy49e2d862010-11-12 02:50:30 +000011537 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
11538 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
cristy3ed852e2009-09-05 21:47:34 +000011539 XSetCursorState(display,windows,MagickFalse);
11540 state|=ExitState;
11541 if (LocaleCompare(windows->command.name,"Apply") == 0)
11542 break;
11543 (void) CloneString(&windows->command.name,"Apply");
11544 windows->command.data=ApplyMenus;
11545 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL);
11546 break;
11547 }
11548 case Expose:
11549 break;
11550 case MotionNotify:
11551 {
cristy49e2d862010-11-12 02:50:30 +000011552 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11553 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
cristy3ed852e2009-09-05 21:47:34 +000011554 }
11555 default:
11556 break;
11557 }
11558 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) ||
11559 ((state & ExitState) != 0))
11560 {
11561 /*
11562 Check boundary conditions.
11563 */
11564 if (roi_info.x < 0)
11565 roi_info.x=0;
11566 else
cristy49e2d862010-11-12 02:50:30 +000011567 if (roi_info.x > (ssize_t) windows->image.ximage->width)
11568 roi_info.x=(ssize_t) windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +000011569 if ((int) roi_info.x < x)
11570 roi_info.width=(unsigned int) (x-roi_info.x);
11571 else
11572 {
11573 roi_info.width=(unsigned int) (roi_info.x-x);
cristy49e2d862010-11-12 02:50:30 +000011574 roi_info.x=(ssize_t) x;
cristy3ed852e2009-09-05 21:47:34 +000011575 }
11576 if (roi_info.y < 0)
11577 roi_info.y=0;
11578 else
cristy49e2d862010-11-12 02:50:30 +000011579 if (roi_info.y > (ssize_t) windows->image.ximage->height)
11580 roi_info.y=(ssize_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +000011581 if ((int) roi_info.y < y)
11582 roi_info.height=(unsigned int) (y-roi_info.y);
11583 else
11584 {
11585 roi_info.height=(unsigned int) (roi_info.y-y);
cristy49e2d862010-11-12 02:50:30 +000011586 roi_info.y=(ssize_t) y;
cristy3ed852e2009-09-05 21:47:34 +000011587 }
11588 }
11589 } while ((state & ExitState) == 0);
11590 /*
11591 Wait for user to grab a corner of the rectangle or press return.
11592 */
11593 state=DefaultState;
11594 command_type=NullCommand;
11595 (void) XMapWindow(display,windows->info.id);
11596 do
11597 {
anthony11d32022012-11-17 05:31:33 +000011598 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000011599 {
11600 /*
11601 Display pointer position.
11602 */
cristyb51dff52011-05-19 16:55:47 +000011603 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +000011604 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +000011605 roi_info.height,(double) roi_info.x,(double) roi_info.y);
cristy3ed852e2009-09-05 21:47:34 +000011606 XInfoWidget(display,windows,text);
11607 }
11608 highlight_info=roi_info;
11609 highlight_info.x=roi_info.x-windows->image.x;
11610 highlight_info.y=roi_info.y-windows->image.y;
11611 if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
11612 {
11613 state|=EscapeState;
11614 state|=ExitState;
11615 break;
11616 }
11617 if ((state & UpdateRegionState) != 0)
11618 {
11619 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11620 switch (command_type)
11621 {
11622 case UndoCommand:
11623 case RedoCommand:
11624 {
11625 (void) XMagickCommand(display,resource_info,windows,command_type,
cristy051718b2011-08-28 22:49:25 +000011626 image,exception);
cristy3ed852e2009-09-05 21:47:34 +000011627 break;
11628 }
11629 default:
11630 {
11631 /*
11632 Region of interest is relative to image configuration.
11633 */
11634 progress_monitor=SetImageProgressMonitor(*image,
11635 (MagickProgressMonitor) NULL,(*image)->client_data);
11636 crop_info=roi_info;
11637 width=(unsigned int) (*image)->columns;
11638 height=(unsigned int) (*image)->rows;
11639 x=0;
11640 y=0;
11641 if (windows->image.crop_geometry != (char *) NULL)
11642 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
11643 &width,&height);
cristya19f1d72012-08-07 18:24:38 +000011644 scale_factor=(double) width/windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +000011645 crop_info.x+=x;
cristy49e2d862010-11-12 02:50:30 +000011646 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +000011647 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
cristya19f1d72012-08-07 18:24:38 +000011648 scale_factor=(double)
cristy3ed852e2009-09-05 21:47:34 +000011649 height/windows->image.ximage->height;
11650 crop_info.y+=y;
cristy49e2d862010-11-12 02:50:30 +000011651 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +000011652 crop_info.height=(unsigned int)
11653 (scale_factor*crop_info.height+0.5);
cristy051718b2011-08-28 22:49:25 +000011654 roi_image=CropImage(*image,&crop_info,exception);
cristy3ed852e2009-09-05 21:47:34 +000011655 (void) SetImageProgressMonitor(*image,progress_monitor,
11656 (*image)->client_data);
11657 if (roi_image == (Image *) NULL)
11658 continue;
11659 /*
11660 Apply image processing technique to the region of interest.
11661 */
11662 windows->image.orphan=MagickTrue;
11663 (void) XMagickCommand(display,resource_info,windows,command_type,
cristy051718b2011-08-28 22:49:25 +000011664 &roi_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000011665 progress_monitor=SetImageProgressMonitor(*image,
11666 (MagickProgressMonitor) NULL,(*image)->client_data);
11667 (void) XMagickCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000011668 SaveToUndoBufferCommand,image,exception);
cristy3ed852e2009-09-05 21:47:34 +000011669 windows->image.orphan=MagickFalse;
cristyfeb3e962012-03-29 17:25:55 +000011670 (void) CompositeImage(*image,roi_image,CopyCompositeOp,
cristy39172402012-03-30 13:04:39 +000011671 MagickTrue,crop_info.x,crop_info.y,exception);
cristy3ed852e2009-09-05 21:47:34 +000011672 roi_image=DestroyImage(roi_image);
11673 (void) SetImageProgressMonitor(*image,progress_monitor,
11674 (*image)->client_data);
11675 break;
11676 }
11677 }
11678 if (command_type != InfoCommand)
11679 {
cristy6710d842011-10-20 23:23:00 +000011680 XConfigureImageColormap(display,resource_info,windows,*image,
11681 exception);
11682 (void) XConfigureImage(display,resource_info,windows,*image,
11683 exception);
cristy3ed852e2009-09-05 21:47:34 +000011684 }
11685 XCheckRefreshWindows(display,windows);
11686 XInfoWidget(display,windows,text);
11687 (void) XSetFunction(display,windows->image.highlight_context,
11688 GXinvert);
11689 state&=(~UpdateRegionState);
11690 }
11691 XHighlightRectangle(display,windows->image.id,
11692 windows->image.highlight_context,&highlight_info);
cristy6710d842011-10-20 23:23:00 +000011693 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000011694 if (event.xany.window == windows->command.id)
11695 {
11696 /*
11697 Select a command from the Command widget.
11698 */
11699 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11700 command_type=NullCommand;
11701 id=XCommandWidget(display,windows,ApplyMenu,&event);
11702 if (id >= 0)
11703 {
11704 (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent);
11705 command_type=ApplyCommands[id];
11706 if (id < ApplyMenus)
11707 {
11708 /*
11709 Select a command from a pop-up menu.
11710 */
11711 entry=XMenuWidget(display,windows,ApplyMenu[id],
11712 (const char **) Menus[id],command);
11713 if (entry >= 0)
11714 {
11715 (void) CopyMagickString(command,Menus[id][entry],
11716 MaxTextExtent);
11717 command_type=Commands[id][entry];
11718 }
11719 }
11720 }
11721 (void) XSetFunction(display,windows->image.highlight_context,
11722 GXinvert);
11723 XHighlightRectangle(display,windows->image.id,
11724 windows->image.highlight_context,&highlight_info);
11725 if (command_type == HelpCommand)
11726 {
11727 (void) XSetFunction(display,windows->image.highlight_context,
11728 GXcopy);
11729 XTextViewWidget(display,resource_info,windows,MagickFalse,
11730 "Help Viewer - Region of Interest",ImageROIHelp);
11731 (void) XSetFunction(display,windows->image.highlight_context,
11732 GXinvert);
11733 continue;
11734 }
11735 if (command_type == QuitCommand)
11736 {
11737 /*
11738 exit.
11739 */
11740 state|=EscapeState;
11741 state|=ExitState;
11742 continue;
11743 }
11744 if (command_type != NullCommand)
11745 state|=UpdateRegionState;
11746 continue;
11747 }
11748 XHighlightRectangle(display,windows->image.id,
11749 windows->image.highlight_context,&highlight_info);
11750 switch (event.type)
11751 {
11752 case ButtonPress:
11753 {
11754 x=windows->image.x;
11755 y=windows->image.y;
11756 if (event.xbutton.button != Button1)
11757 break;
11758 if (event.xbutton.window != windows->image.id)
11759 break;
11760 x=windows->image.x+event.xbutton.x;
11761 y=windows->image.y+event.xbutton.y;
11762 if ((x < (int) (roi_info.x+RoiDelta)) &&
11763 (x > (int) (roi_info.x-RoiDelta)) &&
11764 (y < (int) (roi_info.y+RoiDelta)) &&
11765 (y > (int) (roi_info.y-RoiDelta)))
11766 {
cristybb503372010-05-27 20:51:26 +000011767 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
11768 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
cristy3ed852e2009-09-05 21:47:34 +000011769 state|=UpdateConfigurationState;
11770 break;
11771 }
11772 if ((x < (int) (roi_info.x+RoiDelta)) &&
11773 (x > (int) (roi_info.x-RoiDelta)) &&
11774 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11775 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11776 {
cristybb503372010-05-27 20:51:26 +000011777 roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
cristy3ed852e2009-09-05 21:47:34 +000011778 state|=UpdateConfigurationState;
11779 break;
11780 }
11781 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11782 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11783 (y < (int) (roi_info.y+RoiDelta)) &&
11784 (y > (int) (roi_info.y-RoiDelta)))
11785 {
cristybb503372010-05-27 20:51:26 +000011786 roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
cristy3ed852e2009-09-05 21:47:34 +000011787 state|=UpdateConfigurationState;
11788 break;
11789 }
11790 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
11791 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
11792 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
11793 (y > (int) (roi_info.y+roi_info.height-RoiDelta)))
11794 {
11795 state|=UpdateConfigurationState;
11796 break;
11797 }
11798 }
11799 case ButtonRelease:
11800 {
11801 if (event.xbutton.window == windows->pan.id)
11802 if ((highlight_info.x != crop_info.x-windows->image.x) ||
11803 (highlight_info.y != crop_info.y-windows->image.y))
11804 XHighlightRectangle(display,windows->image.id,
11805 windows->image.highlight_context,&highlight_info);
11806 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11807 event.xbutton.time);
11808 break;
11809 }
11810 case Expose:
11811 {
11812 if (event.xexpose.window == windows->image.id)
11813 if (event.xexpose.count == 0)
11814 {
11815 event.xexpose.x=(int) highlight_info.x;
11816 event.xexpose.y=(int) highlight_info.y;
11817 event.xexpose.width=(int) highlight_info.width;
11818 event.xexpose.height=(int) highlight_info.height;
11819 XRefreshWindow(display,&windows->image,&event);
11820 }
11821 if (event.xexpose.window == windows->info.id)
11822 if (event.xexpose.count == 0)
11823 XInfoWidget(display,windows,text);
11824 break;
11825 }
11826 case KeyPress:
11827 {
11828 KeySym
11829 key_symbol;
11830
11831 if (event.xkey.window != windows->image.id)
11832 break;
11833 /*
11834 Respond to a user key press.
11835 */
11836 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
11837 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
11838 switch ((int) key_symbol)
11839 {
11840 case XK_Shift_L:
11841 case XK_Shift_R:
11842 break;
11843 case XK_Escape:
11844 case XK_F20:
11845 state|=EscapeState;
11846 case XK_Return:
11847 {
11848 state|=ExitState;
11849 break;
11850 }
11851 case XK_Home:
11852 case XK_KP_Home:
11853 {
cristybb503372010-05-27 20:51:26 +000011854 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L);
cristy49e2d862010-11-12 02:50:30 +000011855 roi_info.y=(ssize_t) (windows->image.height/2L-
11856 roi_info.height/2L);
cristy3ed852e2009-09-05 21:47:34 +000011857 break;
11858 }
11859 case XK_Left:
11860 case XK_KP_Left:
11861 {
11862 roi_info.x--;
11863 break;
11864 }
11865 case XK_Up:
11866 case XK_KP_Up:
11867 case XK_Next:
11868 {
11869 roi_info.y--;
11870 break;
11871 }
11872 case XK_Right:
11873 case XK_KP_Right:
11874 {
11875 roi_info.x++;
11876 break;
11877 }
11878 case XK_Prior:
11879 case XK_Down:
11880 case XK_KP_Down:
11881 {
11882 roi_info.y++;
11883 break;
11884 }
11885 case XK_F1:
11886 case XK_Help:
11887 {
11888 (void) XSetFunction(display,windows->image.highlight_context,
11889 GXcopy);
11890 XTextViewWidget(display,resource_info,windows,MagickFalse,
11891 "Help Viewer - Region of Interest",ImageROIHelp);
11892 (void) XSetFunction(display,windows->image.highlight_context,
11893 GXinvert);
11894 break;
11895 }
11896 default:
11897 {
11898 command_type=XImageWindowCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000011899 event.xkey.state,key_symbol,image,exception);
cristy3ed852e2009-09-05 21:47:34 +000011900 if (command_type != NullCommand)
11901 state|=UpdateRegionState;
11902 break;
11903 }
11904 }
11905 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
11906 event.xkey.time);
11907 break;
11908 }
11909 case KeyRelease:
11910 break;
11911 case MotionNotify:
11912 {
11913 if (event.xbutton.window != windows->image.id)
11914 break;
11915 /*
11916 Map and unmap Info widget as text cursor crosses its boundaries.
11917 */
11918 x=event.xmotion.x;
11919 y=event.xmotion.y;
anthony11d32022012-11-17 05:31:33 +000011920 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000011921 {
11922 if ((x < (int) (windows->info.x+windows->info.width)) &&
11923 (y < (int) (windows->info.y+windows->info.height)))
11924 (void) XWithdrawWindow(display,windows->info.id,
11925 windows->info.screen);
11926 }
11927 else
11928 if ((x > (int) (windows->info.x+windows->info.width)) ||
11929 (y > (int) (windows->info.y+windows->info.height)))
11930 (void) XMapWindow(display,windows->info.id);
cristy49e2d862010-11-12 02:50:30 +000011931 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
11932 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
cristy3ed852e2009-09-05 21:47:34 +000011933 break;
11934 }
11935 case SelectionRequest:
11936 {
11937 XSelectionEvent
11938 notify;
11939
11940 XSelectionRequestEvent
11941 *request;
11942
11943 /*
11944 Set primary selection.
11945 */
cristyb51dff52011-05-19 16:55:47 +000011946 (void) FormatLocaleString(text,MaxTextExtent,
cristy6d8abba2010-06-03 01:10:47 +000011947 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
cristye8c25f92010-06-03 00:53:06 +000011948 roi_info.height,(double) roi_info.x,(double) roi_info.y);
cristy3ed852e2009-09-05 21:47:34 +000011949 request=(&(event.xselectionrequest));
11950 (void) XChangeProperty(request->display,request->requestor,
11951 request->property,request->target,8,PropModeReplace,
11952 (unsigned char *) text,(int) strlen(text));
11953 notify.type=SelectionNotify;
11954 notify.display=request->display;
11955 notify.requestor=request->requestor;
11956 notify.selection=request->selection;
11957 notify.target=request->target;
11958 notify.time=request->time;
11959 if (request->property == None)
11960 notify.property=request->target;
11961 else
11962 notify.property=request->property;
11963 (void) XSendEvent(request->display,request->requestor,False,0,
11964 (XEvent *) &notify);
11965 }
11966 default:
11967 break;
11968 }
11969 if ((state & UpdateConfigurationState) != 0)
11970 {
11971 (void) XPutBackEvent(display,&event);
11972 (void) XCheckDefineCursor(display,windows->image.id,cursor);
11973 break;
11974 }
11975 } while ((state & ExitState) == 0);
11976 } while ((state & ExitState) == 0);
11977 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
11978 XSetCursorState(display,windows,MagickFalse);
11979 if ((state & EscapeState) != 0)
11980 return(MagickTrue);
11981 return(MagickTrue);
11982}
11983
11984/*
11985%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11986% %
11987% %
11988% %
11989+ X R o t a t e I m a g e %
11990% %
11991% %
11992% %
11993%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11994%
11995% XRotateImage() rotates the X image. If the degrees parameter if zero, the
11996% rotation angle is computed from the slope of a line drawn by the user.
11997%
11998% The format of the XRotateImage method is:
11999%
12000% MagickBooleanType XRotateImage(Display *display,
12001% XResourceInfo *resource_info,XWindows *windows,double degrees,
cristy051718b2011-08-28 22:49:25 +000012002% Image **image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000012003%
12004% A description of each parameter follows:
12005%
12006% o display: Specifies a connection to an X server; returned from
12007% XOpenDisplay.
12008%
12009% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12010%
12011% o windows: Specifies a pointer to a XWindows structure.
12012%
12013% o degrees: Specifies the number of degrees to rotate the image.
12014%
12015% o image: the image.
12016%
cristy051718b2011-08-28 22:49:25 +000012017% o exception: return any errors or warnings in this structure.
12018%
cristy3ed852e2009-09-05 21:47:34 +000012019*/
12020static MagickBooleanType XRotateImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000012021 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image,
12022 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000012023{
12024 static const char
12025 *RotateMenu[] =
12026 {
12027 "Pixel Color",
12028 "Direction",
12029 "Help",
12030 "Dismiss",
12031 (char *) NULL
12032 };
12033
12034 static ModeType
12035 direction = HorizontalRotateCommand;
12036
12037 static const ModeType
12038 DirectionCommands[] =
12039 {
12040 HorizontalRotateCommand,
12041 VerticalRotateCommand
12042 },
12043 RotateCommands[] =
12044 {
12045 RotateColorCommand,
12046 RotateDirectionCommand,
12047 RotateHelpCommand,
12048 RotateDismissCommand
12049 };
12050
12051 static unsigned int
12052 pen_id = 0;
12053
12054 char
12055 command[MaxTextExtent],
12056 text[MaxTextExtent];
12057
12058 Image
12059 *rotate_image;
12060
12061 int
12062 id,
12063 x,
12064 y;
12065
cristya19f1d72012-08-07 18:24:38 +000012066 double
cristy3ed852e2009-09-05 21:47:34 +000012067 normalized_degrees;
12068
12069 register int
12070 i;
12071
12072 unsigned int
12073 height,
12074 rotations,
12075 width;
12076
12077 if (degrees == 0.0)
12078 {
12079 unsigned int
12080 distance;
12081
cristybb503372010-05-27 20:51:26 +000012082 size_t
cristy3ed852e2009-09-05 21:47:34 +000012083 state;
12084
12085 XEvent
12086 event;
12087
12088 XSegment
12089 rotate_info;
12090
12091 /*
12092 Map Command widget.
12093 */
12094 (void) CloneString(&windows->command.name,"Rotate");
12095 windows->command.data=2;
12096 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL);
12097 (void) XMapRaised(display,windows->command.id);
12098 XClientMessage(display,windows->image.id,windows->im_protocols,
12099 windows->im_update_widget,CurrentTime);
12100 /*
12101 Wait for first button press.
12102 */
12103 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
12104 XQueryPosition(display,windows->image.id,&x,&y);
12105 rotate_info.x1=x;
12106 rotate_info.y1=y;
12107 rotate_info.x2=x;
12108 rotate_info.y2=y;
12109 state=DefaultState;
12110 do
12111 {
12112 XHighlightLine(display,windows->image.id,
12113 windows->image.highlight_context,&rotate_info);
12114 /*
12115 Wait for next event.
12116 */
cristy6710d842011-10-20 23:23:00 +000012117 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000012118 XHighlightLine(display,windows->image.id,
12119 windows->image.highlight_context,&rotate_info);
12120 if (event.xany.window == windows->command.id)
12121 {
12122 /*
12123 Select a command from the Command widget.
12124 */
12125 id=XCommandWidget(display,windows,RotateMenu,&event);
12126 if (id < 0)
12127 continue;
12128 (void) XSetFunction(display,windows->image.highlight_context,
12129 GXcopy);
12130 switch (RotateCommands[id])
12131 {
12132 case RotateColorCommand:
12133 {
12134 const char
12135 *ColorMenu[MaxNumberPens];
12136
12137 int
12138 pen_number;
12139
12140 XColor
12141 color;
12142
12143 /*
12144 Initialize menu selections.
12145 */
12146 for (i=0; i < (int) (MaxNumberPens-2); i++)
12147 ColorMenu[i]=resource_info->pen_colors[i];
12148 ColorMenu[MaxNumberPens-2]="Browser...";
12149 ColorMenu[MaxNumberPens-1]=(const char *) NULL;
12150 /*
12151 Select a pen color from the pop-up menu.
12152 */
12153 pen_number=XMenuWidget(display,windows,RotateMenu[id],
12154 (const char **) ColorMenu,command);
12155 if (pen_number < 0)
12156 break;
12157 if (pen_number == (MaxNumberPens-2))
12158 {
12159 static char
12160 color_name[MaxTextExtent] = "gray";
12161
12162 /*
12163 Select a pen color from a dialog.
12164 */
12165 resource_info->pen_colors[pen_number]=color_name;
12166 XColorBrowserWidget(display,windows,"Select",color_name);
12167 if (*color_name == '\0')
12168 break;
12169 }
12170 /*
12171 Set pen color.
12172 */
12173 (void) XParseColor(display,windows->map_info->colormap,
12174 resource_info->pen_colors[pen_number],&color);
12175 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
12176 (unsigned int) MaxColors,&color);
12177 windows->pixel_info->pen_colors[pen_number]=color;
12178 pen_id=(unsigned int) pen_number;
12179 break;
12180 }
12181 case RotateDirectionCommand:
12182 {
12183 static const char
12184 *Directions[] =
12185 {
12186 "horizontal",
12187 "vertical",
12188 (char *) NULL,
12189 };
12190
12191 /*
12192 Select a command from the pop-up menu.
12193 */
12194 id=XMenuWidget(display,windows,RotateMenu[id],
12195 Directions,command);
12196 if (id >= 0)
12197 direction=DirectionCommands[id];
12198 break;
12199 }
12200 case RotateHelpCommand:
12201 {
12202 XTextViewWidget(display,resource_info,windows,MagickFalse,
12203 "Help Viewer - Image Rotation",ImageRotateHelp);
12204 break;
12205 }
12206 case RotateDismissCommand:
12207 {
12208 /*
12209 Prematurely exit.
12210 */
12211 state|=EscapeState;
12212 state|=ExitState;
12213 break;
12214 }
12215 default:
12216 break;
12217 }
12218 (void) XSetFunction(display,windows->image.highlight_context,
12219 GXinvert);
12220 continue;
12221 }
12222 switch (event.type)
12223 {
12224 case ButtonPress:
12225 {
12226 if (event.xbutton.button != Button1)
12227 break;
12228 if (event.xbutton.window != windows->image.id)
12229 break;
12230 /*
12231 exit loop.
12232 */
12233 (void) XSetFunction(display,windows->image.highlight_context,
12234 GXcopy);
12235 rotate_info.x1=event.xbutton.x;
12236 rotate_info.y1=event.xbutton.y;
12237 state|=ExitState;
12238 break;
12239 }
12240 case ButtonRelease:
12241 break;
12242 case Expose:
12243 break;
12244 case KeyPress:
12245 {
12246 char
12247 command[MaxTextExtent];
12248
12249 KeySym
12250 key_symbol;
12251
12252 if (event.xkey.window != windows->image.id)
12253 break;
12254 /*
12255 Respond to a user key press.
12256 */
12257 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
12258 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
12259 switch ((int) key_symbol)
12260 {
12261 case XK_Escape:
12262 case XK_F20:
12263 {
12264 /*
12265 Prematurely exit.
12266 */
12267 state|=EscapeState;
12268 state|=ExitState;
12269 break;
12270 }
12271 case XK_F1:
12272 case XK_Help:
12273 {
12274 (void) XSetFunction(display,windows->image.highlight_context,
12275 GXcopy);
12276 XTextViewWidget(display,resource_info,windows,MagickFalse,
12277 "Help Viewer - Image Rotation",ImageRotateHelp);
12278 (void) XSetFunction(display,windows->image.highlight_context,
12279 GXinvert);
12280 break;
12281 }
12282 default:
12283 {
12284 (void) XBell(display,0);
12285 break;
12286 }
12287 }
12288 break;
12289 }
12290 case MotionNotify:
12291 {
12292 rotate_info.x1=event.xmotion.x;
12293 rotate_info.y1=event.xmotion.y;
12294 }
12295 }
12296 rotate_info.x2=rotate_info.x1;
12297 rotate_info.y2=rotate_info.y1;
12298 if (direction == HorizontalRotateCommand)
12299 rotate_info.x2+=32;
12300 else
12301 rotate_info.y2-=32;
12302 } while ((state & ExitState) == 0);
12303 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12304 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12305 if ((state & EscapeState) != 0)
12306 return(MagickTrue);
12307 /*
12308 Draw line as pointer moves until the mouse button is released.
12309 */
12310 distance=0;
12311 (void) XSetFunction(display,windows->image.highlight_context,GXinvert);
12312 state=DefaultState;
12313 do
12314 {
12315 if (distance > 9)
12316 {
12317 /*
12318 Display info and draw rotation line.
12319 */
anthony11d32022012-11-17 05:31:33 +000012320 if( IfMagickFalse(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000012321 (void) XMapWindow(display,windows->info.id);
cristyb51dff52011-05-19 16:55:47 +000012322 (void) FormatLocaleString(text,MaxTextExtent," %g",
cristy3ed852e2009-09-05 21:47:34 +000012323 direction == VerticalRotateCommand ? degrees-90.0 : degrees);
12324 XInfoWidget(display,windows,text);
12325 XHighlightLine(display,windows->image.id,
12326 windows->image.highlight_context,&rotate_info);
12327 }
12328 else
anthony11d32022012-11-17 05:31:33 +000012329 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000012330 (void) XWithdrawWindow(display,windows->info.id,
12331 windows->info.screen);
12332 /*
12333 Wait for next event.
12334 */
cristy6710d842011-10-20 23:23:00 +000012335 XScreenEvent(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000012336 if (distance > 9)
12337 XHighlightLine(display,windows->image.id,
12338 windows->image.highlight_context,&rotate_info);
12339 switch (event.type)
12340 {
12341 case ButtonPress:
12342 break;
12343 case ButtonRelease:
12344 {
12345 /*
12346 User has committed to rotation line.
12347 */
12348 rotate_info.x2=event.xbutton.x;
12349 rotate_info.y2=event.xbutton.y;
12350 state|=ExitState;
12351 break;
12352 }
12353 case Expose:
12354 break;
12355 case MotionNotify:
12356 {
12357 rotate_info.x2=event.xmotion.x;
12358 rotate_info.y2=event.xmotion.y;
12359 }
12360 default:
12361 break;
12362 }
12363 /*
12364 Check boundary conditions.
12365 */
12366 if (rotate_info.x2 < 0)
12367 rotate_info.x2=0;
12368 else
12369 if (rotate_info.x2 > (int) windows->image.width)
12370 rotate_info.x2=(short) windows->image.width;
12371 if (rotate_info.y2 < 0)
12372 rotate_info.y2=0;
12373 else
12374 if (rotate_info.y2 > (int) windows->image.height)
12375 rotate_info.y2=(short) windows->image.height;
12376 /*
12377 Compute rotation angle from the slope of the line.
12378 */
12379 degrees=0.0;
12380 distance=(unsigned int)
12381 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+
12382 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1));
12383 if (distance > 9)
12384 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2-
12385 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1)));
12386 } while ((state & ExitState) == 0);
12387 (void) XSetFunction(display,windows->image.highlight_context,GXcopy);
12388 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12389 if (distance <= 9)
12390 return(MagickTrue);
12391 }
12392 if (direction == VerticalRotateCommand)
12393 degrees-=90.0;
12394 if (degrees == 0.0)
12395 return(MagickTrue);
12396 /*
12397 Rotate image.
12398 */
12399 normalized_degrees=degrees;
12400 while (normalized_degrees < -45.0)
12401 normalized_degrees+=360.0;
12402 for (rotations=0; normalized_degrees > 45.0; rotations++)
12403 normalized_degrees-=90.0;
12404 if (normalized_degrees != 0.0)
cristy051718b2011-08-28 22:49:25 +000012405 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image,
12406 exception);
cristy3ed852e2009-09-05 21:47:34 +000012407 XSetCursorState(display,windows,MagickTrue);
12408 XCheckRefreshWindows(display,windows);
cristye42f6582012-02-11 17:59:50 +000012409 (*image)->background_color.red=(double) ScaleShortToQuantum(
cristy3ed852e2009-09-05 21:47:34 +000012410 windows->pixel_info->pen_colors[pen_id].red);
cristye42f6582012-02-11 17:59:50 +000012411 (*image)->background_color.green=(double) ScaleShortToQuantum(
cristy3ed852e2009-09-05 21:47:34 +000012412 windows->pixel_info->pen_colors[pen_id].green);
cristye42f6582012-02-11 17:59:50 +000012413 (*image)->background_color.blue=(double) ScaleShortToQuantum(
cristy3ed852e2009-09-05 21:47:34 +000012414 windows->pixel_info->pen_colors[pen_id].blue);
cristy051718b2011-08-28 22:49:25 +000012415 rotate_image=RotateImage(*image,degrees,exception);
cristy3ed852e2009-09-05 21:47:34 +000012416 XSetCursorState(display,windows,MagickFalse);
12417 if (rotate_image == (Image *) NULL)
12418 return(MagickFalse);
12419 *image=DestroyImage(*image);
12420 *image=rotate_image;
12421 if (windows->image.crop_geometry != (char *) NULL)
12422 {
12423 /*
12424 Rotate crop geometry.
12425 */
12426 width=(unsigned int) (*image)->columns;
12427 height=(unsigned int) (*image)->rows;
12428 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12429 switch (rotations % 4)
12430 {
12431 default:
12432 case 0:
12433 break;
12434 case 1:
12435 {
12436 /*
12437 Rotate 90 degrees.
12438 */
cristyb51dff52011-05-19 16:55:47 +000012439 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +000012440 "%ux%u%+d%+d",height,width,(int) (*image)->columns-
12441 (int) height-y,x);
12442 break;
12443 }
12444 case 2:
12445 {
12446 /*
12447 Rotate 180 degrees.
12448 */
cristyb51dff52011-05-19 16:55:47 +000012449 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +000012450 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y);
12451 break;
12452 }
12453 case 3:
12454 {
12455 /*
12456 Rotate 270 degrees.
12457 */
cristyb51dff52011-05-19 16:55:47 +000012458 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +000012459 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x);
12460 break;
12461 }
12462 }
12463 }
anthony11d32022012-11-17 05:31:33 +000012464 if( IfMagickTrue(windows->image.orphan) )
cristy3ed852e2009-09-05 21:47:34 +000012465 return(MagickTrue);
12466 if (normalized_degrees != 0.0)
12467 {
12468 /*
12469 Update image colormap.
12470 */
12471 windows->image.window_changes.width=(int) (*image)->columns;
12472 windows->image.window_changes.height=(int) (*image)->rows;
12473 if (windows->image.crop_geometry != (char *) NULL)
12474 {
12475 /*
12476 Obtain dimensions of image from crop geometry.
12477 */
12478 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,
12479 &width,&height);
12480 windows->image.window_changes.width=(int) width;
12481 windows->image.window_changes.height=(int) height;
12482 }
cristy6710d842011-10-20 23:23:00 +000012483 XConfigureImageColormap(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +000012484 }
12485 else
12486 if (((rotations % 4) == 1) || ((rotations % 4) == 3))
12487 {
12488 windows->image.window_changes.width=windows->image.ximage->height;
12489 windows->image.window_changes.height=windows->image.ximage->width;
12490 }
12491 /*
12492 Update image configuration.
12493 */
cristy051718b2011-08-28 22:49:25 +000012494 (void) XConfigureImage(display,resource_info,windows,*image,exception);
cristy3ed852e2009-09-05 21:47:34 +000012495 return(MagickTrue);
12496}
12497
12498/*
12499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12500% %
12501% %
12502% %
12503+ X S a v e I m a g e %
12504% %
12505% %
12506% %
12507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12508%
12509% XSaveImage() saves an image to a file.
12510%
12511% The format of the XSaveImage method is:
12512%
12513% MagickBooleanType XSaveImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000012514% XResourceInfo *resource_info,XWindows *windows,Image *image,
12515% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000012516%
12517% A description of each parameter follows:
12518%
12519% o display: Specifies a connection to an X server; returned from
12520% XOpenDisplay.
12521%
12522% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
12523%
12524% o windows: Specifies a pointer to a XWindows structure.
12525%
12526% o image: the image.
12527%
cristy051718b2011-08-28 22:49:25 +000012528% o exception: return any errors or warnings in this structure.
12529%
cristy3ed852e2009-09-05 21:47:34 +000012530*/
12531static MagickBooleanType XSaveImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000012532 XResourceInfo *resource_info,XWindows *windows,Image *image,
12533 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000012534{
12535 char
12536 filename[MaxTextExtent],
12537 geometry[MaxTextExtent];
12538
12539 Image
12540 *save_image;
12541
12542 ImageInfo
12543 *image_info;
12544
12545 MagickStatusType
12546 status;
12547
12548 /*
12549 Request file name from user.
12550 */
12551 if (resource_info->write_filename != (char *) NULL)
12552 (void) CopyMagickString(filename,resource_info->write_filename,
12553 MaxTextExtent);
12554 else
12555 {
12556 char
12557 path[MaxTextExtent];
12558
12559 int
12560 status;
12561
12562 GetPathComponent(image->filename,HeadPath,path);
12563 GetPathComponent(image->filename,TailPath,filename);
cristy0da1d642011-08-29 16:53:16 +000012564 if (*path != '\0')
12565 {
12566 status=chdir(path);
12567 if (status == -1)
12568 (void) ThrowMagickException(exception,GetMagickModule(),
12569 FileOpenError,"UnableToOpenFile","%s",path);
12570 }
cristy3ed852e2009-09-05 21:47:34 +000012571 }
12572 XFileBrowserWidget(display,windows,"Save",filename);
12573 if (*filename == '\0')
12574 return(MagickTrue);
anthony11d32022012-11-17 05:31:33 +000012575 if( IfMagickTrue(IsPathAccessible(filename)) )
cristy3ed852e2009-09-05 21:47:34 +000012576 {
12577 int
12578 status;
12579
12580 /*
12581 File exists-- seek user's permission before overwriting.
12582 */
12583 status=XConfirmWidget(display,windows,"Overwrite",filename);
12584 if (status <= 0)
12585 return(MagickTrue);
12586 }
12587 image_info=CloneImageInfo(resource_info->image_info);
12588 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +000012589 (void) SetImageInfo(image_info,1,exception);
cristy3ed852e2009-09-05 21:47:34 +000012590 if ((LocaleCompare(image_info->magick,"JPEG") == 0) ||
12591 (LocaleCompare(image_info->magick,"JPG") == 0))
12592 {
12593 char
12594 quality[MaxTextExtent];
12595
12596 int
12597 status;
12598
12599 /*
12600 Request JPEG quality from user.
12601 */
cristyb51dff52011-05-19 16:55:47 +000012602 (void) FormatLocaleString(quality,MaxTextExtent,"%.20g",(double)
cristyf2faecf2010-05-28 19:19:36 +000012603 image->quality);
cristy3ed852e2009-09-05 21:47:34 +000012604 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
12605 quality);
12606 if (*quality == '\0')
12607 return(MagickTrue);
cristye27293e2009-12-18 02:53:20 +000012608 image->quality=StringToUnsignedLong(quality);
cristy3ed852e2009-09-05 21:47:34 +000012609 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace;
12610 }
12611 if ((LocaleCompare(image_info->magick,"EPS") == 0) ||
12612 (LocaleCompare(image_info->magick,"PDF") == 0) ||
12613 (LocaleCompare(image_info->magick,"PS") == 0) ||
12614 (LocaleCompare(image_info->magick,"PS2") == 0))
12615 {
12616 char
12617 geometry[MaxTextExtent];
12618
12619 /*
12620 Request page geometry from user.
12621 */
cristyb93d9e72009-09-12 20:02:21 +000012622 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +000012623 if (LocaleCompare(image_info->magick,"PDF") == 0)
cristyb93d9e72009-09-12 20:02:21 +000012624 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +000012625 if (image_info->page != (char *) NULL)
12626 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
12627 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
12628 "Select page geometry:",geometry);
12629 if (*geometry != '\0')
12630 image_info->page=GetPageGeometry(geometry);
12631 }
12632 /*
12633 Apply image transforms.
12634 */
12635 XSetCursorState(display,windows,MagickTrue);
12636 XCheckRefreshWindows(display,windows);
cristy051718b2011-08-28 22:49:25 +000012637 save_image=CloneImage(image,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +000012638 if (save_image == (Image *) NULL)
12639 return(MagickFalse);
cristyb51dff52011-05-19 16:55:47 +000012640 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!",
cristy3ed852e2009-09-05 21:47:34 +000012641 windows->image.ximage->width,windows->image.ximage->height);
cristye941a752011-10-15 01:52:48 +000012642 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry,
12643 exception);
cristy3ed852e2009-09-05 21:47:34 +000012644 /*
12645 Write image.
12646 */
12647 (void) CopyMagickString(save_image->filename,filename,MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +000012648 status=WriteImage(image_info,save_image,exception);
anthony11d32022012-11-17 05:31:33 +000012649 if( IfMagickTrue(status) )
cristy3ed852e2009-09-05 21:47:34 +000012650 image->taint=MagickFalse;
12651 save_image=DestroyImage(save_image);
12652 image_info=DestroyImageInfo(image_info);
12653 XSetCursorState(display,windows,MagickFalse);
anthony11d32022012-11-17 05:31:33 +000012654 return(IsMagickTrue(status));
cristy3ed852e2009-09-05 21:47:34 +000012655}
12656
12657/*
12658%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12659% %
12660% %
12661% %
12662+ X S c r e e n E v e n t %
12663% %
12664% %
12665% %
12666%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12667%
12668% XScreenEvent() handles global events associated with the Pan and Magnify
12669% windows.
12670%
12671% The format of the XScreenEvent function is:
12672%
cristy6710d842011-10-20 23:23:00 +000012673% void XScreenEvent(Display *display,XWindows *windows,XEvent *event,
12674% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000012675%
12676% A description of each parameter follows:
12677%
12678% o display: Specifies a pointer to the Display structure; returned from
12679% XOpenDisplay.
12680%
12681% o windows: Specifies a pointer to a XWindows structure.
12682%
12683% o event: Specifies a pointer to a X11 XEvent structure.
12684%
cristy6710d842011-10-20 23:23:00 +000012685% o exception: return any errors or warnings in this structure.
cristy3ed852e2009-09-05 21:47:34 +000012686%
12687*/
12688
12689#if defined(__cplusplus) || defined(c_plusplus)
12690extern "C" {
12691#endif
12692
12693static int XPredicate(Display *magick_unused(display),XEvent *event,char *data)
12694{
12695 register XWindows
12696 *windows;
12697
12698 windows=(XWindows *) data;
12699 if ((event->type == ClientMessage) &&
12700 (event->xclient.window == windows->image.id))
12701 return(MagickFalse);
12702 return(MagickTrue);
12703}
12704
12705#if defined(__cplusplus) || defined(c_plusplus)
12706}
12707#endif
12708
cristy6710d842011-10-20 23:23:00 +000012709static void XScreenEvent(Display *display,XWindows *windows,XEvent *event,
12710 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000012711{
12712 register int
12713 x,
12714 y;
12715
12716 (void) XIfEvent(display,event,XPredicate,(char *) windows);
12717 if (event->xany.window == windows->command.id)
12718 return;
12719 switch (event->type)
12720 {
12721 case ButtonPress:
12722 case ButtonRelease:
12723 {
12724 if ((event->xbutton.button == Button3) &&
12725 (event->xbutton.state & Mod1Mask))
12726 {
12727 /*
12728 Convert Alt-Button3 to Button2.
12729 */
12730 event->xbutton.button=Button2;
12731 event->xbutton.state&=(~Mod1Mask);
12732 }
12733 if (event->xbutton.window == windows->backdrop.id)
12734 {
12735 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent,
12736 event->xbutton.time);
12737 break;
12738 }
12739 if (event->xbutton.window == windows->pan.id)
12740 {
cristy6710d842011-10-20 23:23:00 +000012741 XPanImage(display,windows,event,exception);
cristy3ed852e2009-09-05 21:47:34 +000012742 break;
12743 }
12744 if (event->xbutton.window == windows->image.id)
12745 if (event->xbutton.button == Button2)
12746 {
12747 /*
12748 Update magnified image.
12749 */
12750 x=event->xbutton.x;
12751 y=event->xbutton.y;
12752 if (x < 0)
12753 x=0;
12754 else
12755 if (x >= (int) windows->image.width)
12756 x=(int) (windows->image.width-1);
cristy49e2d862010-11-12 02:50:30 +000012757 windows->magnify.x=(int) windows->image.x+x;
cristy3ed852e2009-09-05 21:47:34 +000012758 if (y < 0)
12759 y=0;
12760 else
12761 if (y >= (int) windows->image.height)
12762 y=(int) (windows->image.height-1);
12763 windows->magnify.y=windows->image.y+y;
anthony11d32022012-11-17 05:31:33 +000012764 if( IfMagickFalse(windows->magnify.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000012765 (void) XMapRaised(display,windows->magnify.id);
cristy6710d842011-10-20 23:23:00 +000012766 XMakeMagnifyImage(display,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +000012767 if (event->type == ButtonRelease)
12768 (void) XWithdrawWindow(display,windows->info.id,
12769 windows->info.screen);
12770 break;
12771 }
12772 break;
12773 }
12774 case ClientMessage:
12775 {
12776 /*
12777 If client window delete message, exit.
12778 */
12779 if (event->xclient.message_type != windows->wm_protocols)
12780 break;
cristyecd0ab52010-05-30 14:59:20 +000012781 if (*event->xclient.data.l != (long) windows->wm_delete_window)
cristy3ed852e2009-09-05 21:47:34 +000012782 break;
12783 if (event->xclient.window == windows->magnify.id)
12784 {
12785 (void) XWithdrawWindow(display,windows->magnify.id,
12786 windows->magnify.screen);
12787 break;
12788 }
12789 break;
12790 }
12791 case ConfigureNotify:
12792 {
12793 if (event->xconfigure.window == windows->magnify.id)
12794 {
12795 unsigned int
12796 magnify;
12797
12798 /*
12799 Magnify window has a new configuration.
12800 */
12801 windows->magnify.width=(unsigned int) event->xconfigure.width;
12802 windows->magnify.height=(unsigned int) event->xconfigure.height;
anthony11d32022012-11-17 05:31:33 +000012803 if( IfMagickFalse(windows->magnify.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000012804 break;
12805 magnify=1;
12806 while ((int) magnify <= event->xconfigure.width)
12807 magnify<<=1;
12808 while ((int) magnify <= event->xconfigure.height)
12809 magnify<<=1;
12810 magnify>>=1;
12811 if (((int) magnify != event->xconfigure.width) ||
12812 ((int) magnify != event->xconfigure.height))
12813 {
12814 XWindowChanges
12815 window_changes;
12816
12817 window_changes.width=(int) magnify;
12818 window_changes.height=(int) magnify;
12819 (void) XReconfigureWMWindow(display,windows->magnify.id,
12820 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
12821 &window_changes);
12822 break;
12823 }
cristy6710d842011-10-20 23:23:00 +000012824 XMakeMagnifyImage(display,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +000012825 break;
12826 }
12827 break;
12828 }
12829 case Expose:
12830 {
12831 if (event->xexpose.window == windows->image.id)
12832 {
12833 XRefreshWindow(display,&windows->image,event);
12834 break;
12835 }
12836 if (event->xexpose.window == windows->pan.id)
12837 if (event->xexpose.count == 0)
12838 {
12839 XDrawPanRectangle(display,windows);
12840 break;
12841 }
12842 if (event->xexpose.window == windows->magnify.id)
12843 if (event->xexpose.count == 0)
12844 {
cristy6710d842011-10-20 23:23:00 +000012845 XMakeMagnifyImage(display,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +000012846 break;
12847 }
12848 break;
12849 }
12850 case KeyPress:
12851 {
12852 char
12853 command[MaxTextExtent];
12854
12855 KeySym
12856 key_symbol;
12857
12858 if (event->xkey.window != windows->magnify.id)
12859 break;
12860 /*
12861 Respond to a user key press.
12862 */
12863 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int)
12864 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
cristy6710d842011-10-20 23:23:00 +000012865 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol,
12866 exception);
cristy3ed852e2009-09-05 21:47:34 +000012867 break;
12868 }
12869 case MapNotify:
12870 {
12871 if (event->xmap.window == windows->magnify.id)
12872 {
12873 windows->magnify.mapped=MagickTrue;
12874 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
12875 break;
12876 }
12877 if (event->xmap.window == windows->info.id)
12878 {
12879 windows->info.mapped=MagickTrue;
12880 break;
12881 }
12882 break;
12883 }
12884 case MotionNotify:
12885 {
12886 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ;
12887 if (event->xmotion.window == windows->image.id)
anthony11d32022012-11-17 05:31:33 +000012888 if( IfMagickTrue(windows->magnify.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000012889 {
12890 /*
12891 Update magnified image.
12892 */
12893 x=event->xmotion.x;
12894 y=event->xmotion.y;
12895 if (x < 0)
12896 x=0;
12897 else
12898 if (x >= (int) windows->image.width)
12899 x=(int) (windows->image.width-1);
cristy49e2d862010-11-12 02:50:30 +000012900 windows->magnify.x=(int) windows->image.x+x;
cristy3ed852e2009-09-05 21:47:34 +000012901 if (y < 0)
12902 y=0;
12903 else
12904 if (y >= (int) windows->image.height)
12905 y=(int) (windows->image.height-1);
12906 windows->magnify.y=windows->image.y+y;
cristy6710d842011-10-20 23:23:00 +000012907 XMakeMagnifyImage(display,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +000012908 }
12909 break;
12910 }
12911 case UnmapNotify:
12912 {
12913 if (event->xunmap.window == windows->magnify.id)
12914 {
12915 windows->magnify.mapped=MagickFalse;
12916 break;
12917 }
12918 if (event->xunmap.window == windows->info.id)
12919 {
12920 windows->info.mapped=MagickFalse;
12921 break;
12922 }
12923 break;
12924 }
12925 default:
12926 break;
12927 }
12928}
12929
12930/*
12931%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12932% %
12933% %
12934% %
12935+ X S e t C r o p G e o m e t r y %
12936% %
12937% %
12938% %
12939%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12940%
12941% XSetCropGeometry() accepts a cropping geometry relative to the Image window
12942% and translates it to a cropping geometry relative to the image.
12943%
12944% The format of the XSetCropGeometry method is:
12945%
12946% void XSetCropGeometry(Display *display,XWindows *windows,
12947% RectangleInfo *crop_info,Image *image)
12948%
12949% A description of each parameter follows:
12950%
12951% o display: Specifies a connection to an X server; returned from
12952% XOpenDisplay.
12953%
12954% o windows: Specifies a pointer to a XWindows structure.
12955%
12956% o crop_info: A pointer to a RectangleInfo that defines a region of the
12957% Image window to crop.
12958%
12959% o image: the image.
12960%
12961*/
12962static void XSetCropGeometry(Display *display,XWindows *windows,
12963 RectangleInfo *crop_info,Image *image)
12964{
12965 char
12966 text[MaxTextExtent];
12967
12968 int
12969 x,
12970 y;
12971
cristya19f1d72012-08-07 18:24:38 +000012972 double
cristy3ed852e2009-09-05 21:47:34 +000012973 scale_factor;
12974
12975 unsigned int
12976 height,
12977 width;
12978
anthony11d32022012-11-17 05:31:33 +000012979 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000012980 {
12981 /*
12982 Display info on cropping rectangle.
12983 */
cristyb51dff52011-05-19 16:55:47 +000012984 (void) FormatLocaleString(text,MaxTextExtent," %.20gx%.20g%+.20g%+.20g",
cristye8c25f92010-06-03 00:53:06 +000012985 (double) crop_info->width,(double) crop_info->height,(double)
12986 crop_info->x,(double) crop_info->y);
cristy3ed852e2009-09-05 21:47:34 +000012987 XInfoWidget(display,windows,text);
12988 }
12989 /*
12990 Cropping geometry is relative to any previous crop geometry.
12991 */
12992 x=0;
12993 y=0;
12994 width=(unsigned int) image->columns;
12995 height=(unsigned int) image->rows;
12996 if (windows->image.crop_geometry != (char *) NULL)
12997 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
12998 else
12999 windows->image.crop_geometry=AcquireString((char *) NULL);
13000 /*
13001 Define the crop geometry string from the cropping rectangle.
13002 */
cristya19f1d72012-08-07 18:24:38 +000013003 scale_factor=(double) width/windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +000013004 if (crop_info->x > 0)
13005 x+=(int) (scale_factor*crop_info->x+0.5);
13006 width=(unsigned int) (scale_factor*crop_info->width+0.5);
13007 if (width == 0)
13008 width=1;
cristya19f1d72012-08-07 18:24:38 +000013009 scale_factor=(double) height/windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +000013010 if (crop_info->y > 0)
13011 y+=(int) (scale_factor*crop_info->y+0.5);
13012 height=(unsigned int) (scale_factor*crop_info->height+0.5);
13013 if (height == 0)
13014 height=1;
cristyb51dff52011-05-19 16:55:47 +000013015 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +000013016 "%ux%u%+d%+d",width,height,x,y);
13017}
13018
13019/*
13020%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13021% %
13022% %
13023% %
13024+ X T i l e I m a g e %
13025% %
13026% %
13027% %
13028%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13029%
13030% XTileImage() loads or deletes a selected tile from a visual image directory.
13031% The load or delete command is chosen from a menu.
13032%
13033% The format of the XTileImage method is:
13034%
13035% Image *XTileImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +000013036% XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013037%
13038% A description of each parameter follows:
13039%
13040% o tile_image: XTileImage reads or deletes the tile image
13041% and returns it. A null image is returned if an error occurs.
13042%
13043% o display: Specifies a connection to an X server; returned from
13044% XOpenDisplay.
13045%
13046% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13047%
13048% o windows: Specifies a pointer to a XWindows structure.
13049%
13050% o image: the image; returned from ReadImage.
13051%
13052% o event: Specifies a pointer to a XEvent structure. If it is NULL,
13053% the entire image is refreshed.
13054%
cristy051718b2011-08-28 22:49:25 +000013055% o exception: return any errors or warnings in this structure.
13056%
cristy3ed852e2009-09-05 21:47:34 +000013057*/
13058static Image *XTileImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +000013059 XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013060{
13061 static const char
13062 *VerbMenu[] =
13063 {
13064 "Load",
13065 "Next",
13066 "Former",
13067 "Delete",
13068 "Update",
13069 (char *) NULL,
13070 };
13071
13072 static const ModeType
13073 TileCommands[] =
13074 {
13075 TileLoadCommand,
13076 TileNextCommand,
13077 TileFormerCommand,
13078 TileDeleteCommand,
13079 TileUpdateCommand
13080 };
13081
13082 char
13083 command[MaxTextExtent],
13084 filename[MaxTextExtent];
13085
13086 Image
13087 *tile_image;
13088
13089 int
13090 id,
13091 status,
13092 tile,
13093 x,
13094 y;
13095
cristya19f1d72012-08-07 18:24:38 +000013096 double
cristy3ed852e2009-09-05 21:47:34 +000013097 scale_factor;
13098
13099 register char
13100 *p,
13101 *q;
13102
13103 register int
13104 i;
13105
13106 unsigned int
13107 height,
13108 width;
13109
13110 /*
13111 Tile image is relative to montage image configuration.
13112 */
13113 x=0;
13114 y=0;
13115 width=(unsigned int) image->columns;
13116 height=(unsigned int) image->rows;
13117 if (windows->image.crop_geometry != (char *) NULL)
13118 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
cristya19f1d72012-08-07 18:24:38 +000013119 scale_factor=(double) width/windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +000013120 event->xbutton.x+=windows->image.x;
13121 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5);
cristya19f1d72012-08-07 18:24:38 +000013122 scale_factor=(double) height/windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +000013123 event->xbutton.y+=windows->image.y;
13124 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5);
13125 /*
13126 Determine size and location of each tile in the visual image directory.
13127 */
13128 width=(unsigned int) image->columns;
13129 height=(unsigned int) image->rows;
13130 x=0;
13131 y=0;
13132 (void) XParseGeometry(image->montage,&x,&y,&width,&height);
13133 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+
13134 (event->xbutton.x-x)/width;
13135 if (tile < 0)
13136 {
13137 /*
13138 Button press is outside any tile.
13139 */
13140 (void) XBell(display,0);
13141 return((Image *) NULL);
13142 }
13143 /*
13144 Determine file name from the tile directory.
13145 */
13146 p=image->directory;
13147 for (i=tile; (i != 0) && (*p != '\0'); )
13148 {
13149 if (*p == '\n')
13150 i--;
13151 p++;
13152 }
13153 if (*p == '\0')
13154 {
13155 /*
13156 Button press is outside any tile.
13157 */
13158 (void) XBell(display,0);
13159 return((Image *) NULL);
13160 }
13161 /*
13162 Select a command from the pop-up menu.
13163 */
13164 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command);
13165 if (id < 0)
13166 return((Image *) NULL);
13167 q=p;
13168 while ((*q != '\n') && (*q != '\0'))
13169 q++;
13170 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13171 /*
13172 Perform command for the selected tile.
13173 */
13174 XSetCursorState(display,windows,MagickTrue);
13175 XCheckRefreshWindows(display,windows);
13176 tile_image=NewImageList();
13177 switch (TileCommands[id])
13178 {
13179 case TileLoadCommand:
13180 {
13181 /*
13182 Load tile image.
13183 */
13184 XCheckRefreshWindows(display,windows);
13185 (void) CopyMagickString(resource_info->image_info->magick,"MIFF",
13186 MaxTextExtent);
13187 (void) CopyMagickString(resource_info->image_info->filename,filename,
13188 MaxTextExtent);
cristy051718b2011-08-28 22:49:25 +000013189 tile_image=ReadImage(resource_info->image_info,exception);
13190 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +000013191 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13192 break;
13193 }
13194 case TileNextCommand:
13195 {
13196 /*
13197 Display next image.
13198 */
13199 XClientMessage(display,windows->image.id,windows->im_protocols,
13200 windows->im_next_image,CurrentTime);
13201 break;
13202 }
13203 case TileFormerCommand:
13204 {
13205 /*
13206 Display former image.
13207 */
13208 XClientMessage(display,windows->image.id,windows->im_protocols,
13209 windows->im_former_image,CurrentTime);
13210 break;
13211 }
13212 case TileDeleteCommand:
13213 {
13214 /*
13215 Delete tile image.
13216 */
anthony11d32022012-11-17 05:31:33 +000013217 if( IfMagickFalse(IsPathAccessible(filename)) )
cristy3ed852e2009-09-05 21:47:34 +000013218 {
13219 XNoticeWidget(display,windows,"Image file does not exist:",filename);
13220 break;
13221 }
13222 status=XConfirmWidget(display,windows,"Really delete tile",filename);
13223 if (status <= 0)
13224 break;
anthony11d32022012-11-17 05:31:33 +000013225 status=IsMagickTrue(remove_utf8(filename));
13226 if( IfMagickTrue(status) )
cristy3ed852e2009-09-05 21:47:34 +000013227 {
13228 XNoticeWidget(display,windows,"Unable to delete image file:",
13229 filename);
13230 break;
13231 }
13232 }
13233 case TileUpdateCommand:
13234 {
cristy3ed852e2009-09-05 21:47:34 +000013235 int
13236 x_offset,
13237 y_offset;
13238
cristy101ab702011-10-13 13:06:32 +000013239 PixelInfo
cristy3ed852e2009-09-05 21:47:34 +000013240 pixel;
13241
13242 register int
13243 j;
13244
cristy4c08aed2011-07-01 19:47:50 +000013245 register Quantum
cristy3ed852e2009-09-05 21:47:34 +000013246 *s;
13247
13248 /*
13249 Ensure all the images exist.
13250 */
13251 tile=0;
cristy101ab702011-10-13 13:06:32 +000013252 GetPixelInfo(image,&pixel);
cristy3ed852e2009-09-05 21:47:34 +000013253 for (p=image->directory; *p != '\0'; p++)
13254 {
cristyf7c25522010-11-15 01:25:14 +000013255 CacheView
13256 *image_view;
13257
cristy3ed852e2009-09-05 21:47:34 +000013258 q=p;
13259 while ((*q != '\n') && (*q != '\0'))
13260 q++;
13261 (void) CopyMagickString(filename,p,(size_t) (q-p+1));
13262 p=q;
anthony11d32022012-11-17 05:31:33 +000013263 if( IfMagickTrue(IsPathAccessible(filename)) )
cristy3ed852e2009-09-05 21:47:34 +000013264 {
13265 tile++;
13266 continue;
13267 }
13268 /*
13269 Overwrite tile with background color.
13270 */
13271 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x);
13272 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y);
cristy46ff2672012-12-14 15:32:26 +000013273 image_view=AcquireAuthenticCacheView(image,exception);
cristyf05d4942012-03-17 16:26:09 +000013274 (void) GetOneCacheViewVirtualPixelInfo(image_view,0,0,&pixel,exception);
cristy3ed852e2009-09-05 21:47:34 +000013275 for (i=0; i < (int) height; i++)
13276 {
cristy49e2d862010-11-12 02:50:30 +000013277 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t)
13278 y_offset+i,width,1,exception);
cristy4c08aed2011-07-01 19:47:50 +000013279 if (s == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +000013280 break;
13281 for (j=0; j < (int) width; j++)
cristy4c08aed2011-07-01 19:47:50 +000013282 {
cristy803640d2011-11-17 02:11:32 +000013283 SetPixelInfoPixel(image,&pixel,s);
cristyed231572011-07-14 02:18:59 +000013284 s+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +000013285 }
anthony11d32022012-11-17 05:31:33 +000013286 if( IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) )
cristy3ed852e2009-09-05 21:47:34 +000013287 break;
13288 }
cristyca1628f2010-11-15 01:17:49 +000013289 image_view=DestroyCacheView(image_view);
cristy3ed852e2009-09-05 21:47:34 +000013290 tile++;
13291 }
13292 windows->image.window_changes.width=(int) image->columns;
13293 windows->image.window_changes.height=(int) image->rows;
cristy6710d842011-10-20 23:23:00 +000013294 XConfigureImageColormap(display,resource_info,windows,image,exception);
cristy051718b2011-08-28 22:49:25 +000013295 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +000013296 break;
13297 }
13298 default:
13299 break;
13300 }
13301 XSetCursorState(display,windows,MagickFalse);
13302 return(tile_image);
13303}
13304
13305/*
13306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13307% %
13308% %
13309% %
13310+ X T r a n s l a t e I m a g e %
13311% %
13312% %
13313% %
13314%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13315%
13316% XTranslateImage() translates the image within an Image window by one pixel
anthonye5b39652012-04-21 05:37:29 +000013317% as specified by the key symbol. If the image has a montage string the
cristy3ed852e2009-09-05 21:47:34 +000013318% translation is respect to the width and height contained within the string.
13319%
13320% The format of the XTranslateImage method is:
13321%
13322% void XTranslateImage(Display *display,XWindows *windows,
13323% Image *image,const KeySym key_symbol)
13324%
13325% A description of each parameter follows:
13326%
13327% o display: Specifies a connection to an X server; returned from
13328% XOpenDisplay.
13329%
13330% o windows: Specifies a pointer to a XWindows structure.
13331%
13332% o image: the image.
13333%
13334% o key_symbol: Specifies a KeySym which indicates which side of the image
13335% to trim.
13336%
13337*/
13338static void XTranslateImage(Display *display,XWindows *windows,
13339 Image *image,const KeySym key_symbol)
13340{
13341 char
13342 text[MaxTextExtent];
13343
13344 int
13345 x,
13346 y;
13347
13348 unsigned int
13349 x_offset,
13350 y_offset;
13351
13352 /*
13353 User specified a pan position offset.
13354 */
13355 x_offset=windows->image.width;
13356 y_offset=windows->image.height;
13357 if (image->montage != (char *) NULL)
13358 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset);
13359 switch ((int) key_symbol)
13360 {
13361 case XK_Home:
13362 case XK_KP_Home:
13363 {
13364 windows->image.x=(int) windows->image.width/2;
13365 windows->image.y=(int) windows->image.height/2;
13366 break;
13367 }
13368 case XK_Left:
13369 case XK_KP_Left:
13370 {
13371 windows->image.x-=x_offset;
13372 break;
13373 }
13374 case XK_Next:
13375 case XK_Up:
13376 case XK_KP_Up:
13377 {
13378 windows->image.y-=y_offset;
13379 break;
13380 }
13381 case XK_Right:
13382 case XK_KP_Right:
13383 {
13384 windows->image.x+=x_offset;
13385 break;
13386 }
13387 case XK_Prior:
13388 case XK_Down:
13389 case XK_KP_Down:
13390 {
13391 windows->image.y+=y_offset;
13392 break;
13393 }
13394 default:
13395 return;
13396 }
13397 /*
13398 Check boundary conditions.
13399 */
13400 if (windows->image.x < 0)
13401 windows->image.x=0;
13402 else
13403 if ((int) (windows->image.x+windows->image.width) >
13404 windows->image.ximage->width)
cristy49e2d862010-11-12 02:50:30 +000013405 windows->image.x=(int) windows->image.ximage->width-windows->image.width;
cristy3ed852e2009-09-05 21:47:34 +000013406 if (windows->image.y < 0)
13407 windows->image.y=0;
13408 else
13409 if ((int) (windows->image.y+windows->image.height) >
13410 windows->image.ximage->height)
cristy49e2d862010-11-12 02:50:30 +000013411 windows->image.y=(int) windows->image.ximage->height-windows->image.height;
cristy3ed852e2009-09-05 21:47:34 +000013412 /*
13413 Refresh Image window.
13414 */
cristyb51dff52011-05-19 16:55:47 +000013415 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ",
cristy3ed852e2009-09-05 21:47:34 +000013416 windows->image.width,windows->image.height,windows->image.x,
13417 windows->image.y);
13418 XInfoWidget(display,windows,text);
13419 XCheckRefreshWindows(display,windows);
13420 XDrawPanRectangle(display,windows);
13421 XRefreshWindow(display,&windows->image,(XEvent *) NULL);
13422 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
13423}
13424
13425/*
13426%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13427% %
13428% %
13429% %
13430+ X T r i m I m a g e %
13431% %
13432% %
13433% %
13434%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13435%
13436% XTrimImage() trims the edges from the Image window.
13437%
13438% The format of the XTrimImage method is:
13439%
13440% MagickBooleanType XTrimImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000013441% XResourceInfo *resource_info,XWindows *windows,Image *image,
13442% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013443%
13444% A description of each parameter follows:
13445%
13446% o display: Specifies a connection to an X server; returned from
13447% XOpenDisplay.
13448%
13449% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13450%
13451% o windows: Specifies a pointer to a XWindows structure.
13452%
13453% o image: the image.
13454%
cristy051718b2011-08-28 22:49:25 +000013455% o exception: return any errors or warnings in this structure.
13456%
cristy3ed852e2009-09-05 21:47:34 +000013457*/
13458static MagickBooleanType XTrimImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000013459 XResourceInfo *resource_info,XWindows *windows,Image *image,
13460 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013461{
13462 RectangleInfo
13463 trim_info;
13464
13465 register int
13466 x,
13467 y;
13468
cristybb503372010-05-27 20:51:26 +000013469 size_t
cristy3ed852e2009-09-05 21:47:34 +000013470 background,
13471 pixel;
13472
13473 /*
13474 Trim edges from image.
13475 */
13476 XSetCursorState(display,windows,MagickTrue);
13477 XCheckRefreshWindows(display,windows);
13478 /*
13479 Crop the left edge.
13480 */
13481 background=XGetPixel(windows->image.ximage,0,0);
cristybb503372010-05-27 20:51:26 +000013482 trim_info.width=(size_t) windows->image.ximage->width;
cristy3ed852e2009-09-05 21:47:34 +000013483 for (x=0; x < windows->image.ximage->width; x++)
13484 {
13485 for (y=0; y < windows->image.ximage->height; y++)
13486 {
13487 pixel=XGetPixel(windows->image.ximage,x,y);
13488 if (pixel != background)
13489 break;
13490 }
13491 if (y < windows->image.ximage->height)
13492 break;
13493 }
cristy49e2d862010-11-12 02:50:30 +000013494 trim_info.x=(ssize_t) x;
13495 if (trim_info.x == (ssize_t) windows->image.ximage->width)
cristy3ed852e2009-09-05 21:47:34 +000013496 {
13497 XSetCursorState(display,windows,MagickFalse);
13498 return(MagickFalse);
13499 }
13500 /*
13501 Crop the right edge.
13502 */
13503 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0);
13504 for (x=windows->image.ximage->width-1; x != 0; x--)
13505 {
13506 for (y=0; y < windows->image.ximage->height; y++)
13507 {
13508 pixel=XGetPixel(windows->image.ximage,x,y);
13509 if (pixel != background)
13510 break;
13511 }
13512 if (y < windows->image.ximage->height)
13513 break;
13514 }
cristybb503372010-05-27 20:51:26 +000013515 trim_info.width=(size_t) (x-trim_info.x+1);
cristy3ed852e2009-09-05 21:47:34 +000013516 /*
13517 Crop the top edge.
13518 */
13519 background=XGetPixel(windows->image.ximage,0,0);
cristybb503372010-05-27 20:51:26 +000013520 trim_info.height=(size_t) windows->image.ximage->height;
cristy3ed852e2009-09-05 21:47:34 +000013521 for (y=0; y < windows->image.ximage->height; y++)
13522 {
13523 for (x=0; x < windows->image.ximage->width; x++)
13524 {
13525 pixel=XGetPixel(windows->image.ximage,x,y);
13526 if (pixel != background)
13527 break;
13528 }
13529 if (x < windows->image.ximage->width)
13530 break;
13531 }
cristy49e2d862010-11-12 02:50:30 +000013532 trim_info.y=(ssize_t) y;
cristy3ed852e2009-09-05 21:47:34 +000013533 /*
13534 Crop the bottom edge.
13535 */
13536 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1);
13537 for (y=windows->image.ximage->height-1; y != 0; y--)
13538 {
13539 for (x=0; x < windows->image.ximage->width; x++)
13540 {
13541 pixel=XGetPixel(windows->image.ximage,x,y);
13542 if (pixel != background)
13543 break;
13544 }
13545 if (x < windows->image.ximage->width)
13546 break;
13547 }
cristybb503372010-05-27 20:51:26 +000013548 trim_info.height=(size_t) y-trim_info.y+1;
cristy3ed852e2009-09-05 21:47:34 +000013549 if (((unsigned int) trim_info.width != windows->image.width) ||
13550 ((unsigned int) trim_info.height != windows->image.height))
13551 {
13552 /*
13553 Reconfigure Image window as defined by the trimming rectangle.
13554 */
13555 XSetCropGeometry(display,windows,&trim_info,image);
13556 windows->image.window_changes.width=(int) trim_info.width;
13557 windows->image.window_changes.height=(int) trim_info.height;
cristy051718b2011-08-28 22:49:25 +000013558 (void) XConfigureImage(display,resource_info,windows,image,exception);
cristy3ed852e2009-09-05 21:47:34 +000013559 }
13560 XSetCursorState(display,windows,MagickFalse);
13561 return(MagickTrue);
13562}
13563
13564/*
13565%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13566% %
13567% %
13568% %
13569+ X V i s u a l D i r e c t o r y I m a g e %
13570% %
13571% %
13572% %
13573%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13574%
13575% XVisualDirectoryImage() creates a Visual Image Directory.
13576%
13577% The format of the XVisualDirectoryImage method is:
13578%
13579% Image *XVisualDirectoryImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000013580% XResourceInfo *resource_info,XWindows *windows,
13581% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013582%
13583% A description of each parameter follows:
13584%
cristy3ed852e2009-09-05 21:47:34 +000013585% o display: Specifies a connection to an X server; returned from
13586% XOpenDisplay.
13587%
13588% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13589%
13590% o windows: Specifies a pointer to a XWindows structure.
13591%
cristy051718b2011-08-28 22:49:25 +000013592% o exception: return any errors or warnings in this structure.
13593%
cristy3ed852e2009-09-05 21:47:34 +000013594*/
13595static Image *XVisualDirectoryImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000013596 XResourceInfo *resource_info,XWindows *windows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013597{
13598#define TileImageTag "Scale/Image"
13599#define XClientName "montage"
13600
13601 char
13602 **filelist;
13603
cristy3ed852e2009-09-05 21:47:34 +000013604 Image
13605 *images,
13606 *montage_image,
13607 *next_image,
13608 *thumbnail_image;
13609
13610 ImageInfo
13611 *read_info;
13612
13613 int
13614 number_files;
13615
13616 MagickBooleanType
13617 backdrop;
13618
13619 MagickStatusType
13620 status;
13621
13622 MontageInfo
13623 *montage_info;
13624
13625 RectangleInfo
13626 geometry;
13627
13628 register int
13629 i;
13630
13631 static char
13632 filename[MaxTextExtent] = "\0",
13633 filenames[MaxTextExtent] = "*";
13634
13635 XResourceInfo
13636 background_resources;
13637
13638 /*
13639 Request file name from user.
13640 */
13641 XFileBrowserWidget(display,windows,"Directory",filenames);
13642 if (*filenames == '\0')
13643 return((Image *) NULL);
13644 /*
13645 Expand the filenames.
13646 */
cristy73bd4a52010-10-05 11:24:23 +000013647 filelist=(char **) AcquireMagickMemory(sizeof(*filelist));
cristy3ed852e2009-09-05 21:47:34 +000013648 if (filelist == (char **) NULL)
13649 {
13650 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
13651 filenames);
13652 return((Image *) NULL);
13653 }
13654 number_files=1;
13655 filelist[0]=filenames;
13656 status=ExpandFilenames(&number_files,&filelist);
anthony11d32022012-11-17 05:31:33 +000013657 if( IfMagickFalse(status) || (number_files == 0))
cristy3ed852e2009-09-05 21:47:34 +000013658 {
13659 if (number_files == 0)
13660 ThrowXWindowFatalException(ImageError,"NoImagesWereFound",filenames)
13661 else
13662 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
13663 filenames);
13664 return((Image *) NULL);
13665 }
13666 /*
13667 Set image background resources.
13668 */
13669 background_resources=(*resource_info);
13670 background_resources.window_id=AcquireString("");
cristyb51dff52011-05-19 16:55:47 +000013671 (void) FormatLocaleString(background_resources.window_id,MaxTextExtent,
cristy3ed852e2009-09-05 21:47:34 +000013672 "0x%lx",windows->image.id);
13673 background_resources.backdrop=MagickTrue;
13674 /*
13675 Read each image and convert them to a tile.
13676 */
anthony11d32022012-11-17 05:31:33 +000013677 backdrop=IsMagickTrue( (windows->visual_info->klass == TrueColor) ||
13678 (windows->visual_info->klass == DirectColor) );
cristy3ed852e2009-09-05 21:47:34 +000013679 read_info=CloneImageInfo(resource_info->image_info);
cristy9ce61202010-11-24 00:38:37 +000013680 (void) SetImageOption(read_info,"jpeg:size","120x120");
13681 (void) CloneString(&read_info->size,DefaultTileGeometry);
cristy3ed852e2009-09-05 21:47:34 +000013682 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL,
13683 (void *) NULL);
13684 images=NewImageList();
cristy3ed852e2009-09-05 21:47:34 +000013685 XSetCursorState(display,windows,MagickTrue);
13686 XCheckRefreshWindows(display,windows);
cristy49e2d862010-11-12 02:50:30 +000013687 for (i=0; i < (int) number_files; i++)
cristy3ed852e2009-09-05 21:47:34 +000013688 {
13689 (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent);
13690 filelist[i]=DestroyString(filelist[i]);
13691 *read_info->magick='\0';
cristy3ed852e2009-09-05 21:47:34 +000013692 next_image=ReadImage(read_info,exception);
13693 CatchException(exception);
13694 if (next_image != (Image *) NULL)
13695 {
13696 (void) DeleteImageProperty(next_image,"label");
cristy77619442010-11-24 00:27:23 +000013697 (void) SetImageProperty(next_image,"label",InterpretImageProperties(
cristyd15e6592011-10-15 00:13:06 +000013698 read_info,next_image,DefaultTileLabel,exception),exception);
cristy3ed852e2009-09-05 21:47:34 +000013699 (void) ParseRegionGeometry(next_image,read_info->size,&geometry,
13700 exception);
13701 thumbnail_image=ThumbnailImage(next_image,geometry.width,
13702 geometry.height,exception);
13703 if (thumbnail_image != (Image *) NULL)
13704 {
13705 next_image=DestroyImage(next_image);
13706 next_image=thumbnail_image;
13707 }
13708 if (backdrop)
13709 {
13710 (void) XDisplayBackgroundImage(display,&background_resources,
cristy051718b2011-08-28 22:49:25 +000013711 next_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000013712 XSetCursorState(display,windows,MagickTrue);
13713 }
13714 AppendImageToList(&images,next_image);
13715 if (images->progress_monitor != (MagickProgressMonitor) NULL)
13716 {
13717 MagickBooleanType
13718 proceed;
13719
13720 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i,
13721 (MagickSizeType) number_files);
anthony11d32022012-11-17 05:31:33 +000013722 if( IfMagickFalse(proceed) )
cristy3ed852e2009-09-05 21:47:34 +000013723 break;
13724 }
13725 }
13726 }
cristy3ed852e2009-09-05 21:47:34 +000013727 filelist=(char **) RelinquishMagickMemory(filelist);
cristy3ed852e2009-09-05 21:47:34 +000013728 if (images == (Image *) NULL)
13729 {
cristy8d52fca2010-11-24 00:45:05 +000013730 read_info=DestroyImageInfo(read_info);
cristy3ed852e2009-09-05 21:47:34 +000013731 XSetCursorState(display,windows,MagickFalse);
13732 ThrowXWindowFatalException(ImageError,"NoImagesWereLoaded",filenames);
13733 return((Image *) NULL);
13734 }
13735 /*
13736 Create the Visual Image Directory.
13737 */
cristy8d52fca2010-11-24 00:45:05 +000013738 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL);
13739 montage_info->pointsize=10;
cristy3ed852e2009-09-05 21:47:34 +000013740 if (resource_info->font != (char *) NULL)
13741 (void) CloneString(&montage_info->font,resource_info->font);
13742 (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent);
cristy8d52fca2010-11-24 00:45:05 +000013743 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList(
cristy051718b2011-08-28 22:49:25 +000013744 images),exception);
cristy3ed852e2009-09-05 21:47:34 +000013745 images=DestroyImageList(images);
cristy8d52fca2010-11-24 00:45:05 +000013746 montage_info=DestroyMontageInfo(montage_info);
13747 read_info=DestroyImageInfo(read_info);
cristy3ed852e2009-09-05 21:47:34 +000013748 XSetCursorState(display,windows,MagickFalse);
13749 if (montage_image == (Image *) NULL)
13750 return(montage_image);
13751 XClientMessage(display,windows->image.id,windows->im_protocols,
13752 windows->im_next_image,CurrentTime);
13753 return(montage_image);
13754}
13755
13756/*
13757%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13758% %
13759% %
13760% %
13761% X D i s p l a y B a c k g r o u n d I m a g e %
13762% %
13763% %
13764% %
13765%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13766%
13767% XDisplayBackgroundImage() displays an image in the background of a window.
13768%
13769% The format of the XDisplayBackgroundImage method is:
13770%
13771% MagickBooleanType XDisplayBackgroundImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000013772% XResourceInfo *resource_info,Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013773%
13774% A description of each parameter follows:
13775%
13776% o display: Specifies a connection to an X server; returned from
13777% XOpenDisplay.
13778%
13779% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
13780%
13781% o image: the image.
13782%
cristy051718b2011-08-28 22:49:25 +000013783% o exception: return any errors or warnings in this structure.
13784%
cristy3ed852e2009-09-05 21:47:34 +000013785*/
13786MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display,
cristy051718b2011-08-28 22:49:25 +000013787 XResourceInfo *resource_info,Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000013788{
13789 char
13790 geometry[MaxTextExtent],
13791 visual_type[MaxTextExtent];
13792
13793 int
13794 height,
13795 status,
13796 width;
13797
13798 RectangleInfo
13799 geometry_info;
13800
13801 static XPixelInfo
13802 pixel;
13803
13804 static XStandardColormap
13805 *map_info;
13806
13807 static XVisualInfo
13808 *visual_info = (XVisualInfo *) NULL;
13809
13810 static XWindowInfo
13811 window_info;
13812
cristybb503372010-05-27 20:51:26 +000013813 size_t
cristy3ed852e2009-09-05 21:47:34 +000013814 delay;
13815
13816 Window
13817 root_window;
13818
13819 XGCValues
13820 context_values;
13821
13822 XResourceInfo
13823 resources;
13824
13825 XWindowAttributes
13826 window_attributes;
13827
13828 /*
13829 Determine target window.
13830 */
13831 assert(image != (Image *) NULL);
13832 assert(image->signature == MagickSignature);
anthony11d32022012-11-17 05:31:33 +000013833 if( IfMagickTrue(image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000013834 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
13835 resources=(*resource_info);
13836 window_info.id=(Window) NULL;
13837 root_window=XRootWindow(display,XDefaultScreen(display));
13838 if (LocaleCompare(resources.window_id,"root") == 0)
13839 window_info.id=root_window;
13840 else
13841 {
13842 if (isdigit((unsigned char) *resources.window_id) != 0)
13843 window_info.id=XWindowByID(display,root_window,
13844 (Window) strtol((char *) resources.window_id,(char **) NULL,0));
13845 if (window_info.id == (Window) NULL)
13846 window_info.id=XWindowByName(display,root_window,resources.window_id);
13847 }
13848 if (window_info.id == (Window) NULL)
13849 {
13850 ThrowXWindowFatalException(XServerError,"NoWindowWithSpecifiedIDExists",
13851 resources.window_id);
13852 return(MagickFalse);
13853 }
13854 /*
13855 Determine window visual id.
13856 */
13857 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display));
13858 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display));
13859 (void) CopyMagickString(visual_type,"default",MaxTextExtent);
13860 status=XGetWindowAttributes(display,window_info.id,&window_attributes);
13861 if (status != 0)
cristyb51dff52011-05-19 16:55:47 +000013862 (void) FormatLocaleString(visual_type,MaxTextExtent,"0x%lx",
cristy3ed852e2009-09-05 21:47:34 +000013863 XVisualIDFromVisual(window_attributes.visual));
13864 if (visual_info == (XVisualInfo *) NULL)
13865 {
13866 /*
13867 Allocate standard colormap.
13868 */
13869 map_info=XAllocStandardColormap();
13870 if (map_info == (XStandardColormap *) NULL)
13871 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
13872 image->filename);
13873 map_info->colormap=(Colormap) NULL;
cristyf2faecf2010-05-28 19:19:36 +000013874 pixel.pixels=(unsigned long *) NULL;
cristy3ed852e2009-09-05 21:47:34 +000013875 /*
13876 Initialize visual info.
13877 */
13878 resources.map_type=(char *) NULL;
13879 resources.visual_type=visual_type;
13880 visual_info=XBestVisualInfo(display,map_info,&resources);
13881 if (visual_info == (XVisualInfo *) NULL)
13882 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual",
13883 resources.visual_type);
13884 /*
13885 Initialize window info.
13886 */
13887 window_info.ximage=(XImage *) NULL;
13888 window_info.matte_image=(XImage *) NULL;
13889 window_info.pixmap=(Pixmap) NULL;
13890 window_info.matte_pixmap=(Pixmap) NULL;
13891 }
13892 /*
13893 Free previous root colors.
13894 */
13895 if (window_info.id == root_window)
13896 (void) XDestroyWindowColors(display,root_window);
13897 /*
13898 Initialize Standard Colormap.
13899 */
13900 resources.colormap=SharedColormap;
cristy6710d842011-10-20 23:23:00 +000013901 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel,
13902 exception);
cristy3ed852e2009-09-05 21:47:34 +000013903 /*
13904 Graphic context superclass.
13905 */
13906 context_values.background=pixel.background_color.pixel;
13907 context_values.foreground=pixel.foreground_color.pixel;
13908 pixel.annotate_context=XCreateGC(display,window_info.id,
cristybb503372010-05-27 20:51:26 +000013909 (size_t) (GCBackground | GCForeground),&context_values);
cristy3ed852e2009-09-05 21:47:34 +000013910 if (pixel.annotate_context == (GC) NULL)
13911 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
13912 image->filename);
13913 /*
13914 Initialize Image window attributes.
13915 */
13916 window_info.name=AcquireString("\0");
13917 window_info.icon_name=AcquireString("\0");
13918 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL,
13919 &resources,&window_info);
13920 /*
13921 Create the X image.
13922 */
13923 window_info.width=(unsigned int) image->columns;
13924 window_info.height=(unsigned int) image->rows;
13925 if ((image->columns != window_info.width) ||
13926 (image->rows != window_info.height))
13927 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13928 image->filename);
cristyb51dff52011-05-19 16:55:47 +000013929 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>",
cristy3ed852e2009-09-05 21:47:34 +000013930 window_attributes.width,window_attributes.height);
13931 geometry_info.width=window_info.width;
13932 geometry_info.height=window_info.height;
cristyecd0ab52010-05-30 14:59:20 +000013933 geometry_info.x=(ssize_t) window_info.x;
13934 geometry_info.y=(ssize_t) window_info.y;
cristy3ed852e2009-09-05 21:47:34 +000013935 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
13936 &geometry_info.width,&geometry_info.height);
13937 window_info.width=(unsigned int) geometry_info.width;
13938 window_info.height=(unsigned int) geometry_info.height;
13939 window_info.x=(int) geometry_info.x;
13940 window_info.y=(int) geometry_info.y;
13941 status=XMakeImage(display,&resources,&window_info,image,window_info.width,
cristy051718b2011-08-28 22:49:25 +000013942 window_info.height,exception);
anthony11d32022012-11-17 05:31:33 +000013943 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +000013944 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
13945 image->filename);
13946 window_info.x=0;
13947 window_info.y=0;
anthony11d32022012-11-17 05:31:33 +000013948 if( IfMagickTrue(image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000013949 {
13950 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +000013951 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene,
13952 (double) image->columns,(double) image->rows);
cristy3ed852e2009-09-05 21:47:34 +000013953 if (image->colors != 0)
cristye8c25f92010-06-03 00:53:06 +000013954 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
13955 image->colors);
cristy3ed852e2009-09-05 21:47:34 +000013956 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick);
13957 }
13958 /*
13959 Adjust image dimensions as specified by backdrop or geometry options.
13960 */
13961 width=(int) window_info.width;
13962 height=(int) window_info.height;
anthony11d32022012-11-17 05:31:33 +000013963 if( IfMagickTrue(resources.backdrop) )
cristy3ed852e2009-09-05 21:47:34 +000013964 {
13965 /*
13966 Center image on window.
13967 */
13968 window_info.x=(window_attributes.width/2)-
13969 (window_info.ximage->width/2);
13970 window_info.y=(window_attributes.height/2)-
13971 (window_info.ximage->height/2);
13972 width=window_attributes.width;
13973 height=window_attributes.height;
13974 }
13975 if ((resources.image_geometry != (char *) NULL) &&
13976 (*resources.image_geometry != '\0'))
13977 {
13978 char
13979 default_geometry[MaxTextExtent];
13980
13981 int
13982 flags,
13983 gravity;
13984
13985 XSizeHints
13986 *size_hints;
13987
13988 /*
13989 User specified geometry.
13990 */
13991 size_hints=XAllocSizeHints();
13992 if (size_hints == (XSizeHints *) NULL)
13993 ThrowXWindowFatalException(ResourceLimitFatalError,
13994 "MemoryAllocationFailed",image->filename);
13995 size_hints->flags=0L;
cristyb51dff52011-05-19 16:55:47 +000013996 (void) FormatLocaleString(default_geometry,MaxTextExtent,"%dx%d",
cristy3ed852e2009-09-05 21:47:34 +000013997 width,height);
13998 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry,
13999 default_geometry,window_info.border_width,size_hints,&window_info.x,
14000 &window_info.y,&width,&height,&gravity);
14001 if (flags & (XValue | YValue))
14002 {
14003 width=window_attributes.width;
14004 height=window_attributes.height;
14005 }
14006 (void) XFree((void *) size_hints);
14007 }
14008 /*
14009 Create the X pixmap.
14010 */
14011 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width,
14012 (unsigned int) height,window_info.depth);
14013 if (window_info.pixmap == (Pixmap) NULL)
14014 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
14015 image->filename);
14016 /*
14017 Display pixmap on the window.
14018 */
14019 if (((unsigned int) width > window_info.width) ||
14020 ((unsigned int) height > window_info.height))
14021 (void) XFillRectangle(display,window_info.pixmap,
14022 window_info.annotate_context,0,0,(unsigned int) width,
14023 (unsigned int) height);
14024 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
14025 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int)
14026 window_info.width,(unsigned int) window_info.height);
14027 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
14028 (void) XClearWindow(display,window_info.id);
14029 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L);
14030 XDelay(display,delay == 0UL ? 10UL : delay);
14031 (void) XSync(display,MagickFalse);
anthony11d32022012-11-17 05:31:33 +000014032 return(IsMagickTrue(window_info.id == root_window));
cristy3ed852e2009-09-05 21:47:34 +000014033}
14034
14035/*
14036%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14037% %
14038% %
14039% %
14040+ X D i s p l a y I m a g e %
14041% %
14042% %
14043% %
14044%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14045%
14046% XDisplayImage() displays an image via X11. A new image is created and
14047% returned if the user interactively transforms the displayed image.
14048%
14049% The format of the XDisplayImage method is:
14050%
14051% Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +000014052% char **argv,int argc,Image **image,size_t *state,
14053% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000014054%
14055% A description of each parameter follows:
14056%
14057% o nexus: Method XDisplayImage returns an image when the
14058% user chooses 'Open Image' from the command menu or picks a tile
14059% from the image directory. Otherwise a null image is returned.
14060%
14061% o display: Specifies a connection to an X server; returned from
14062% XOpenDisplay.
14063%
14064% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
14065%
14066% o argv: Specifies the application's argument list.
14067%
14068% o argc: Specifies the number of arguments.
14069%
14070% o image: Specifies an address to an address of an Image structure;
14071%
cristy051718b2011-08-28 22:49:25 +000014072% o exception: return any errors or warnings in this structure.
14073%
cristy3ed852e2009-09-05 21:47:34 +000014074*/
14075MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
cristy051718b2011-08-28 22:49:25 +000014076 char **argv,int argc,Image **image,size_t *state,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000014077{
14078#define MagnifySize 256 /* must be a power of 2 */
14079#define MagickMenus 10
14080#define MagickTitle "Commands"
14081
14082 static const char
14083 *CommandMenu[] =
14084 {
14085 "File",
14086 "Edit",
14087 "View",
14088 "Transform",
14089 "Enhance",
14090 "Effects",
14091 "F/X",
14092 "Image Edit",
14093 "Miscellany",
14094 "Help",
14095 (char *) NULL
14096 },
14097 *FileMenu[] =
14098 {
14099 "Open...",
14100 "Next",
14101 "Former",
14102 "Select...",
14103 "Save...",
14104 "Print...",
14105 "Delete...",
14106 "New...",
14107 "Visual Directory...",
14108 "Quit",
14109 (char *) NULL
14110 },
14111 *EditMenu[] =
14112 {
14113 "Undo",
14114 "Redo",
14115 "Cut",
14116 "Copy",
14117 "Paste",
14118 (char *) NULL
14119 },
14120 *ViewMenu[] =
14121 {
14122 "Half Size",
14123 "Original Size",
14124 "Double Size",
14125 "Resize...",
14126 "Apply",
14127 "Refresh",
14128 "Restore",
14129 (char *) NULL
14130 },
14131 *TransformMenu[] =
14132 {
14133 "Crop",
14134 "Chop",
14135 "Flop",
14136 "Flip",
14137 "Rotate Right",
14138 "Rotate Left",
14139 "Rotate...",
14140 "Shear...",
14141 "Roll...",
14142 "Trim Edges",
14143 (char *) NULL
14144 },
14145 *EnhanceMenu[] =
14146 {
14147 "Hue...",
14148 "Saturation...",
14149 "Brightness...",
14150 "Gamma...",
14151 "Spiff",
14152 "Dull",
14153 "Contrast Stretch...",
14154 "Sigmoidal Contrast...",
14155 "Normalize",
14156 "Equalize",
14157 "Negate",
14158 "Grayscale",
14159 "Map...",
14160 "Quantize...",
14161 (char *) NULL
14162 },
14163 *EffectsMenu[] =
14164 {
14165 "Despeckle",
14166 "Emboss",
14167 "Reduce Noise",
14168 "Add Noise...",
14169 "Sharpen...",
14170 "Blur...",
14171 "Threshold...",
14172 "Edge Detect...",
14173 "Spread...",
14174 "Shade...",
14175 "Raise...",
14176 "Segment...",
14177 (char *) NULL
14178 },
14179 *FXMenu[] =
14180 {
14181 "Solarize...",
14182 "Sepia Tone...",
14183 "Swirl...",
14184 "Implode...",
14185 "Vignette...",
14186 "Wave...",
14187 "Oil Paint...",
14188 "Charcoal Draw...",
14189 (char *) NULL
14190 },
14191 *ImageEditMenu[] =
14192 {
14193 "Annotate...",
14194 "Draw...",
14195 "Color...",
14196 "Matte...",
14197 "Composite...",
14198 "Add Border...",
14199 "Add Frame...",
14200 "Comment...",
14201 "Launch...",
14202 "Region of Interest...",
14203 (char *) NULL
14204 },
14205 *MiscellanyMenu[] =
14206 {
14207 "Image Info",
14208 "Zoom Image",
14209 "Show Preview...",
14210 "Show Histogram",
14211 "Show Matte",
14212 "Background...",
14213 "Slide Show...",
14214 "Preferences...",
14215 (char *) NULL
14216 },
14217 *HelpMenu[] =
14218 {
14219 "Overview",
14220 "Browse Documentation",
14221 "About Display",
14222 (char *) NULL
14223 },
14224 *ShortCutsMenu[] =
14225 {
14226 "Next",
14227 "Former",
14228 "Open...",
14229 "Save...",
14230 "Print...",
14231 "Undo",
14232 "Restore",
14233 "Image Info",
14234 "Quit",
14235 (char *) NULL
14236 },
14237 *VirtualMenu[] =
14238 {
14239 "Image Info",
14240 "Print",
14241 "Next",
14242 "Quit",
14243 (char *) NULL
14244 };
14245
14246 static const char
14247 **Menus[MagickMenus] =
14248 {
14249 FileMenu,
14250 EditMenu,
14251 ViewMenu,
14252 TransformMenu,
14253 EnhanceMenu,
14254 EffectsMenu,
14255 FXMenu,
14256 ImageEditMenu,
14257 MiscellanyMenu,
14258 HelpMenu
14259 };
14260
14261 static CommandType
14262 CommandMenus[] =
14263 {
14264 NullCommand,
14265 NullCommand,
14266 NullCommand,
14267 NullCommand,
14268 NullCommand,
14269 NullCommand,
14270 NullCommand,
14271 NullCommand,
14272 NullCommand,
14273 NullCommand,
14274 },
14275 FileCommands[] =
14276 {
14277 OpenCommand,
14278 NextCommand,
14279 FormerCommand,
14280 SelectCommand,
14281 SaveCommand,
14282 PrintCommand,
14283 DeleteCommand,
14284 NewCommand,
14285 VisualDirectoryCommand,
14286 QuitCommand
14287 },
14288 EditCommands[] =
14289 {
14290 UndoCommand,
14291 RedoCommand,
14292 CutCommand,
14293 CopyCommand,
14294 PasteCommand
14295 },
14296 ViewCommands[] =
14297 {
14298 HalfSizeCommand,
14299 OriginalSizeCommand,
14300 DoubleSizeCommand,
14301 ResizeCommand,
14302 ApplyCommand,
14303 RefreshCommand,
14304 RestoreCommand
14305 },
14306 TransformCommands[] =
14307 {
14308 CropCommand,
14309 ChopCommand,
14310 FlopCommand,
14311 FlipCommand,
14312 RotateRightCommand,
14313 RotateLeftCommand,
14314 RotateCommand,
14315 ShearCommand,
14316 RollCommand,
14317 TrimCommand
14318 },
14319 EnhanceCommands[] =
14320 {
14321 HueCommand,
14322 SaturationCommand,
14323 BrightnessCommand,
14324 GammaCommand,
14325 SpiffCommand,
14326 DullCommand,
14327 ContrastStretchCommand,
14328 SigmoidalContrastCommand,
14329 NormalizeCommand,
14330 EqualizeCommand,
14331 NegateCommand,
14332 GrayscaleCommand,
14333 MapCommand,
14334 QuantizeCommand
14335 },
14336 EffectsCommands[] =
14337 {
14338 DespeckleCommand,
14339 EmbossCommand,
14340 ReduceNoiseCommand,
14341 AddNoiseCommand,
14342 SharpenCommand,
14343 BlurCommand,
14344 ThresholdCommand,
14345 EdgeDetectCommand,
14346 SpreadCommand,
14347 ShadeCommand,
14348 RaiseCommand,
14349 SegmentCommand
14350 },
14351 FXCommands[] =
14352 {
14353 SolarizeCommand,
14354 SepiaToneCommand,
14355 SwirlCommand,
14356 ImplodeCommand,
14357 VignetteCommand,
14358 WaveCommand,
14359 OilPaintCommand,
14360 CharcoalDrawCommand
14361 },
14362 ImageEditCommands[] =
14363 {
14364 AnnotateCommand,
14365 DrawCommand,
14366 ColorCommand,
14367 MatteCommand,
14368 CompositeCommand,
14369 AddBorderCommand,
14370 AddFrameCommand,
14371 CommentCommand,
14372 LaunchCommand,
14373 RegionofInterestCommand
14374 },
14375 MiscellanyCommands[] =
14376 {
14377 InfoCommand,
14378 ZoomCommand,
14379 ShowPreviewCommand,
14380 ShowHistogramCommand,
14381 ShowMatteCommand,
14382 BackgroundCommand,
14383 SlideShowCommand,
14384 PreferencesCommand
14385 },
14386 HelpCommands[] =
14387 {
14388 HelpCommand,
14389 BrowseDocumentationCommand,
14390 VersionCommand
14391 },
14392 ShortCutsCommands[] =
14393 {
14394 NextCommand,
14395 FormerCommand,
14396 OpenCommand,
14397 SaveCommand,
14398 PrintCommand,
14399 UndoCommand,
14400 RestoreCommand,
14401 InfoCommand,
14402 QuitCommand
14403 },
14404 VirtualCommands[] =
14405 {
14406 InfoCommand,
14407 PrintCommand,
14408 NextCommand,
14409 QuitCommand
14410 };
14411
14412 static CommandType
14413 *Commands[MagickMenus] =
14414 {
14415 FileCommands,
14416 EditCommands,
14417 ViewCommands,
14418 TransformCommands,
14419 EnhanceCommands,
14420 EffectsCommands,
14421 FXCommands,
14422 ImageEditCommands,
14423 MiscellanyCommands,
14424 HelpCommands
14425 };
14426
14427 char
14428 command[MaxTextExtent],
cristy00976d82011-02-20 20:31:28 +000014429 *directory,
cristy3ed852e2009-09-05 21:47:34 +000014430 geometry[MaxTextExtent],
14431 resource_name[MaxTextExtent];
14432
14433 CommandType
14434 command_type;
14435
14436 Image
14437 *display_image,
14438 *nexus;
14439
14440 int
14441 entry,
14442 id;
14443
14444 KeySym
14445 key_symbol;
14446
14447 MagickStatusType
14448 context_mask,
14449 status;
14450
14451 RectangleInfo
14452 geometry_info;
14453
14454 register int
14455 i;
14456
14457 static char
14458 working_directory[MaxTextExtent];
14459
14460 static XPoint
14461 vid_info;
14462
14463 static XWindowInfo
14464 *magick_windows[MaxXWindows];
14465
14466 static unsigned int
14467 number_windows;
14468
14469 struct stat
14470 attributes;
14471
14472 time_t
14473 timer,
14474 timestamp,
14475 update_time;
14476
14477 unsigned int
14478 height,
14479 width;
14480
cristybb503372010-05-27 20:51:26 +000014481 size_t
cristy3ed852e2009-09-05 21:47:34 +000014482 delay;
14483
14484 WarningHandler
14485 warning_handler;
14486
14487 Window
14488 root_window;
14489
14490 XClassHint
14491 *class_hints;
14492
14493 XEvent
14494 event;
14495
14496 XFontStruct
14497 *font_info;
14498
14499 XGCValues
14500 context_values;
14501
14502 XPixelInfo
14503 *icon_pixel,
14504 *pixel;
14505
14506 XResourceInfo
14507 *icon_resources;
14508
14509 XStandardColormap
14510 *icon_map,
14511 *map_info;
14512
14513 XVisualInfo
14514 *icon_visual,
14515 *visual_info;
14516
14517 XWindowChanges
14518 window_changes;
14519
14520 XWindows
14521 *windows;
14522
14523 XWMHints
14524 *manager_hints;
14525
14526 assert(image != (Image **) NULL);
14527 assert((*image)->signature == MagickSignature);
anthony11d32022012-11-17 05:31:33 +000014528 if( IfMagickTrue((*image)->debug) )
cristy3ed852e2009-09-05 21:47:34 +000014529 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
14530 display_image=(*image);
14531 warning_handler=(WarningHandler) NULL;
14532 windows=XSetWindows((XWindows *) ~0);
14533 if (windows != (XWindows *) NULL)
14534 {
14535 int
14536 status;
14537
cristy8a5d7f42013-01-06 15:24:33 +000014538 if (*working_directory == '\0')
14539 (void) CopyMagickString(working_directory,".",MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +000014540 status=chdir(working_directory);
14541 if (status == -1)
cristy051718b2011-08-28 22:49:25 +000014542 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
14543 "UnableToOpenFile","%s",working_directory);
cristy3ed852e2009-09-05 21:47:34 +000014544 warning_handler=resource_info->display_warnings ?
14545 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
14546 warning_handler=resource_info->display_warnings ?
14547 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
14548 }
14549 else
14550 {
14551 /*
14552 Allocate windows structure.
14553 */
14554 resource_info->colors=display_image->colors;
14555 windows=XSetWindows(XInitializeWindows(display,resource_info));
14556 if (windows == (XWindows *) NULL)
14557 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow",
14558 (*image)->filename);
14559 /*
14560 Initialize window id's.
14561 */
14562 number_windows=0;
14563 magick_windows[number_windows++]=(&windows->icon);
14564 magick_windows[number_windows++]=(&windows->backdrop);
14565 magick_windows[number_windows++]=(&windows->image);
14566 magick_windows[number_windows++]=(&windows->info);
14567 magick_windows[number_windows++]=(&windows->command);
14568 magick_windows[number_windows++]=(&windows->widget);
14569 magick_windows[number_windows++]=(&windows->popup);
14570 magick_windows[number_windows++]=(&windows->magnify);
14571 magick_windows[number_windows++]=(&windows->pan);
14572 for (i=0; i < (int) number_windows; i++)
14573 magick_windows[i]->id=(Window) NULL;
14574 vid_info.x=0;
14575 vid_info.y=0;
14576 }
14577 /*
14578 Initialize font info.
14579 */
14580 if (windows->font_info != (XFontStruct *) NULL)
14581 (void) XFreeFont(display,windows->font_info);
14582 windows->font_info=XBestFont(display,resource_info,MagickFalse);
14583 if (windows->font_info == (XFontStruct *) NULL)
14584 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont",
14585 resource_info->font);
14586 /*
14587 Initialize Standard Colormap.
14588 */
14589 map_info=windows->map_info;
14590 icon_map=windows->icon_map;
14591 visual_info=windows->visual_info;
14592 icon_visual=windows->icon_visual;
14593 pixel=windows->pixel_info;
14594 icon_pixel=windows->icon_pixel;
14595 font_info=windows->font_info;
14596 icon_resources=windows->icon_resources;
14597 class_hints=windows->class_hints;
14598 manager_hints=windows->manager_hints;
14599 root_window=XRootWindow(display,visual_info->screen);
14600 nexus=NewImageList();
anthony11d32022012-11-17 05:31:33 +000014601 if( IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000014602 {
14603 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +000014604 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename,
14605 (double) display_image->scene,(double) display_image->columns,
14606 (double) display_image->rows);
cristy3ed852e2009-09-05 21:47:34 +000014607 if (display_image->colors != 0)
cristye8c25f92010-06-03 00:53:06 +000014608 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
14609 display_image->colors);
cristy3ed852e2009-09-05 21:47:34 +000014610 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
14611 display_image->magick);
14612 }
14613 XMakeStandardColormap(display,visual_info,resource_info,display_image,
cristy6710d842011-10-20 23:23:00 +000014614 map_info,pixel,exception);
cristy3ed852e2009-09-05 21:47:34 +000014615 display_image->taint=MagickFalse;
14616 /*
14617 Initialize graphic context.
14618 */
14619 windows->context.id=(Window) NULL;
14620 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14621 resource_info,&windows->context);
14622 (void) CloneString(&class_hints->res_name,resource_info->client_name);
14623 (void) CloneString(&class_hints->res_class,resource_info->client_name);
14624 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]);
14625 manager_hints->flags=InputHint | StateHint;
14626 manager_hints->input=MagickFalse;
14627 manager_hints->initial_state=WithdrawnState;
14628 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14629 &windows->context);
anthony11d32022012-11-17 05:31:33 +000014630 if( IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000014631 (void) LogMagickEvent(X11Event,GetMagickModule(),
14632 "Window id: 0x%lx (context)",windows->context.id);
14633 context_values.background=pixel->background_color.pixel;
14634 context_values.font=font_info->fid;
14635 context_values.foreground=pixel->foreground_color.pixel;
14636 context_values.graphics_exposures=MagickFalse;
14637 context_mask=(MagickStatusType)
14638 (GCBackground | GCFont | GCForeground | GCGraphicsExposures);
14639 if (pixel->annotate_context != (GC) NULL)
14640 (void) XFreeGC(display,pixel->annotate_context);
14641 pixel->annotate_context=XCreateGC(display,windows->context.id,
14642 context_mask,&context_values);
14643 if (pixel->annotate_context == (GC) NULL)
14644 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14645 display_image->filename);
14646 context_values.background=pixel->depth_color.pixel;
14647 if (pixel->widget_context != (GC) NULL)
14648 (void) XFreeGC(display,pixel->widget_context);
14649 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask,
14650 &context_values);
14651 if (pixel->widget_context == (GC) NULL)
14652 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14653 display_image->filename);
14654 context_values.background=pixel->foreground_color.pixel;
14655 context_values.foreground=pixel->background_color.pixel;
14656 context_values.plane_mask=context_values.background ^
14657 context_values.foreground;
14658 if (pixel->highlight_context != (GC) NULL)
14659 (void) XFreeGC(display,pixel->highlight_context);
14660 pixel->highlight_context=XCreateGC(display,windows->context.id,
cristybb503372010-05-27 20:51:26 +000014661 (size_t) (context_mask | GCPlaneMask),&context_values);
cristy3ed852e2009-09-05 21:47:34 +000014662 if (pixel->highlight_context == (GC) NULL)
14663 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14664 display_image->filename);
14665 (void) XDestroyWindow(display,windows->context.id);
14666 /*
14667 Initialize icon window.
14668 */
14669 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL,
14670 icon_resources,&windows->icon);
14671 windows->icon.geometry=resource_info->icon_geometry;
14672 XBestIconSize(display,&windows->icon,display_image);
14673 windows->icon.attributes.colormap=XDefaultColormap(display,
14674 icon_visual->screen);
14675 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask;
14676 manager_hints->flags=InputHint | StateHint;
14677 manager_hints->input=MagickFalse;
14678 manager_hints->initial_state=IconicState;
14679 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14680 &windows->icon);
anthony11d32022012-11-17 05:31:33 +000014681 if( IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000014682 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)",
14683 windows->icon.id);
14684 /*
14685 Initialize graphic context for icon window.
14686 */
14687 if (icon_pixel->annotate_context != (GC) NULL)
14688 (void) XFreeGC(display,icon_pixel->annotate_context);
14689 context_values.background=icon_pixel->background_color.pixel;
14690 context_values.foreground=icon_pixel->foreground_color.pixel;
14691 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id,
cristybb503372010-05-27 20:51:26 +000014692 (size_t) (GCBackground | GCForeground),&context_values);
cristy3ed852e2009-09-05 21:47:34 +000014693 if (icon_pixel->annotate_context == (GC) NULL)
14694 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
14695 display_image->filename);
14696 windows->icon.annotate_context=icon_pixel->annotate_context;
14697 /*
14698 Initialize Image window.
14699 */
14700 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14701 &windows->image);
14702 windows->image.shape=MagickTrue; /* non-rectangular shape hint */
anthony11d32022012-11-17 05:31:33 +000014703 if( IfMagickFalse(resource_info->use_shared_memory) )
cristy3ed852e2009-09-05 21:47:34 +000014704 windows->image.shared_memory=MagickFalse;
14705 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState))
14706 {
14707 char
14708 *title;
14709
14710 title=InterpretImageProperties(resource_info->image_info,display_image,
cristy018f07f2011-09-04 21:15:19 +000014711 resource_info->title,exception);
cristy3ed852e2009-09-05 21:47:34 +000014712 (void) CopyMagickString(windows->image.name,title,MaxTextExtent);
14713 (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent);
14714 title=DestroyString(title);
14715 }
14716 else
14717 {
14718 char
14719 filename[MaxTextExtent];
14720
14721 /*
14722 Window name is the base of the filename.
14723 */
14724 GetPathComponent(display_image->magick_filename,TailPath,filename);
cristy9a48b172011-09-20 17:41:05 +000014725 if (display_image->scene == 0)
cristyb51dff52011-05-19 16:55:47 +000014726 (void) FormatLocaleString(windows->image.name,MaxTextExtent,
cristy40a08ad2010-02-09 02:27:44 +000014727 "%s: %s",MagickPackageName,filename);
cristy3ed852e2009-09-05 21:47:34 +000014728 else
cristyb51dff52011-05-19 16:55:47 +000014729 (void) FormatLocaleString(windows->image.name,MaxTextExtent,
cristy04d55062011-03-15 18:58:50 +000014730 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename,
14731 (double) display_image->scene,(double) GetImageListLength(
14732 display_image));
cristy3ed852e2009-09-05 21:47:34 +000014733 (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent);
14734 }
14735 if (resource_info->immutable)
14736 windows->image.immutable=MagickTrue;
14737 windows->image.use_pixmap=resource_info->use_pixmap;
14738 windows->image.geometry=resource_info->image_geometry;
cristyb51dff52011-05-19 16:55:47 +000014739 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!",
cristy3ed852e2009-09-05 21:47:34 +000014740 XDisplayWidth(display,visual_info->screen),
14741 XDisplayHeight(display,visual_info->screen));
14742 geometry_info.width=display_image->columns;
14743 geometry_info.height=display_image->rows;
14744 geometry_info.x=0;
14745 geometry_info.y=0;
14746 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
14747 &geometry_info.width,&geometry_info.height);
14748 windows->image.width=(unsigned int) geometry_info.width;
14749 windows->image.height=(unsigned int) geometry_info.height;
14750 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14751 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14752 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14753 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask;
14754 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14755 resource_info,&windows->backdrop);
14756 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL))
14757 {
14758 /*
14759 Initialize backdrop window.
14760 */
14761 windows->backdrop.x=0;
14762 windows->backdrop.y=0;
cristy40a08ad2010-02-09 02:27:44 +000014763 (void) CloneString(&windows->backdrop.name,"Backdrop");
cristybb503372010-05-27 20:51:26 +000014764 windows->backdrop.flags=(size_t) (USSize | USPosition);
cristy3ed852e2009-09-05 21:47:34 +000014765 windows->backdrop.width=(unsigned int)
14766 XDisplayWidth(display,visual_info->screen);
14767 windows->backdrop.height=(unsigned int)
14768 XDisplayHeight(display,visual_info->screen);
14769 windows->backdrop.border_width=0;
14770 windows->backdrop.immutable=MagickTrue;
14771 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask |
14772 ButtonReleaseMask;
14773 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask |
14774 StructureNotifyMask;
14775 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14776 manager_hints->icon_window=windows->icon.id;
14777 manager_hints->input=MagickTrue;
14778 manager_hints->initial_state=resource_info->iconic ? IconicState :
14779 NormalState;
14780 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14781 &windows->backdrop);
anthony11d32022012-11-17 05:31:33 +000014782 if( IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000014783 (void) LogMagickEvent(X11Event,GetMagickModule(),
14784 "Window id: 0x%lx (backdrop)",windows->backdrop.id);
14785 (void) XMapWindow(display,windows->backdrop.id);
14786 (void) XClearWindow(display,windows->backdrop.id);
14787 if (windows->image.id != (Window) NULL)
14788 {
14789 (void) XDestroyWindow(display,windows->image.id);
14790 windows->image.id=(Window) NULL;
14791 }
14792 /*
14793 Position image in the center the backdrop.
14794 */
14795 windows->image.flags|=USPosition;
14796 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)-
14797 (windows->image.width/2);
14798 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)-
14799 (windows->image.height/2);
14800 }
14801 manager_hints->flags=IconWindowHint | InputHint | StateHint;
14802 manager_hints->icon_window=windows->icon.id;
14803 manager_hints->input=MagickTrue;
14804 manager_hints->initial_state=resource_info->iconic ? IconicState :
14805 NormalState;
14806 if (windows->group_leader.id != (Window) NULL)
14807 {
14808 /*
14809 Follow the leader.
14810 */
14811 manager_hints->flags|=WindowGroupHint;
14812 manager_hints->window_group=windows->group_leader.id;
14813 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask);
anthony11d32022012-11-17 05:31:33 +000014814 if( IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000014815 (void) LogMagickEvent(X11Event,GetMagickModule(),
14816 "Window id: 0x%lx (group leader)",windows->group_leader.id);
14817 }
14818 XMakeWindow(display,
14819 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window),
14820 argv,argc,class_hints,manager_hints,&windows->image);
14821 (void) XChangeProperty(display,windows->image.id,windows->im_protocols,
14822 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0);
14823 if (windows->group_leader.id != (Window) NULL)
14824 (void) XSetTransientForHint(display,windows->image.id,
14825 windows->group_leader.id);
anthony11d32022012-11-17 05:31:33 +000014826 if( IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000014827 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)",
14828 windows->image.id);
14829 /*
14830 Initialize Info widget.
14831 */
14832 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
14833 &windows->info);
14834 (void) CloneString(&windows->info.name,"Info");
14835 (void) CloneString(&windows->info.icon_name,"Info");
14836 windows->info.border_width=1;
14837 windows->info.x=2;
14838 windows->info.y=2;
14839 windows->info.flags|=PPosition;
14840 windows->info.attributes.win_gravity=UnmapGravity;
14841 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask |
14842 StructureNotifyMask;
14843 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14844 manager_hints->input=MagickFalse;
14845 manager_hints->initial_state=NormalState;
14846 manager_hints->window_group=windows->image.id;
14847 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints,
14848 &windows->info);
14849 windows->info.highlight_stipple=XCreateBitmapFromData(display,
14850 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14851 windows->info.shadow_stipple=XCreateBitmapFromData(display,
14852 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14853 (void) XSetTransientForHint(display,windows->info.id,windows->image.id);
anthony11d32022012-11-17 05:31:33 +000014854 if( IfMagickTrue(windows->image.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000014855 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
anthony11d32022012-11-17 05:31:33 +000014856 if( IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000014857 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)",
14858 windows->info.id);
14859 /*
14860 Initialize Command widget.
14861 */
14862 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14863 resource_info,&windows->command);
14864 windows->command.data=MagickMenus;
14865 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL);
cristyb51dff52011-05-19 16:55:47 +000014866 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.command",
cristy3ed852e2009-09-05 21:47:34 +000014867 resource_info->client_name);
14868 windows->command.geometry=XGetResourceClass(resource_info->resource_database,
14869 resource_name,"geometry",(char *) NULL);
14870 (void) CloneString(&windows->command.name,MagickTitle);
14871 windows->command.border_width=0;
14872 windows->command.flags|=PPosition;
14873 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14874 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask |
14875 OwnerGrabButtonMask | StructureNotifyMask;
14876 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14877 manager_hints->input=MagickTrue;
14878 manager_hints->initial_state=NormalState;
14879 manager_hints->window_group=windows->image.id;
14880 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14881 &windows->command);
14882 windows->command.highlight_stipple=XCreateBitmapFromData(display,
14883 windows->command.id,(char *) HighlightBitmap,HighlightWidth,
14884 HighlightHeight);
14885 windows->command.shadow_stipple=XCreateBitmapFromData(display,
14886 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14887 (void) XSetTransientForHint(display,windows->command.id,windows->image.id);
anthony11d32022012-11-17 05:31:33 +000014888 if( IfMagickTrue(windows->command.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000014889 (void) XMapRaised(display,windows->command.id);
anthony11d32022012-11-17 05:31:33 +000014890 if( IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000014891 (void) LogMagickEvent(X11Event,GetMagickModule(),
14892 "Window id: 0x%lx (command)",windows->command.id);
14893 /*
14894 Initialize Widget window.
14895 */
14896 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14897 resource_info,&windows->widget);
cristyb51dff52011-05-19 16:55:47 +000014898 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.widget",
cristy3ed852e2009-09-05 21:47:34 +000014899 resource_info->client_name);
14900 windows->widget.geometry=XGetResourceClass(resource_info->resource_database,
14901 resource_name,"geometry",(char *) NULL);
14902 windows->widget.border_width=0;
14903 windows->widget.flags|=PPosition;
14904 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14905 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14906 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
14907 StructureNotifyMask;
14908 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14909 manager_hints->input=MagickTrue;
14910 manager_hints->initial_state=NormalState;
14911 manager_hints->window_group=windows->image.id;
14912 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14913 &windows->widget);
14914 windows->widget.highlight_stipple=XCreateBitmapFromData(display,
14915 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14916 windows->widget.shadow_stipple=XCreateBitmapFromData(display,
14917 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14918 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id);
anthony11d32022012-11-17 05:31:33 +000014919 if( IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000014920 (void) LogMagickEvent(X11Event,GetMagickModule(),
14921 "Window id: 0x%lx (widget)",windows->widget.id);
14922 /*
14923 Initialize popup window.
14924 */
14925 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14926 resource_info,&windows->popup);
14927 windows->popup.border_width=0;
14928 windows->popup.flags|=PPosition;
14929 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
14930 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
14931 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask;
14932 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14933 manager_hints->input=MagickTrue;
14934 manager_hints->initial_state=NormalState;
14935 manager_hints->window_group=windows->image.id;
14936 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14937 &windows->popup);
14938 windows->popup.highlight_stipple=XCreateBitmapFromData(display,
14939 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
14940 windows->popup.shadow_stipple=XCreateBitmapFromData(display,
14941 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
14942 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id);
anthony11d32022012-11-17 05:31:33 +000014943 if( IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000014944 (void) LogMagickEvent(X11Event,GetMagickModule(),
14945 "Window id: 0x%lx (pop up)",windows->popup.id);
14946 /*
14947 Initialize Magnify window and cursor.
14948 */
14949 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14950 resource_info,&windows->magnify);
anthony11d32022012-11-17 05:31:33 +000014951 if( IfMagickFalse(resource_info->use_shared_memory) )
cristy3ed852e2009-09-05 21:47:34 +000014952 windows->magnify.shared_memory=MagickFalse;
cristyb51dff52011-05-19 16:55:47 +000014953 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.magnify",
cristy3ed852e2009-09-05 21:47:34 +000014954 resource_info->client_name);
14955 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database,
14956 resource_name,"geometry",(char *) NULL);
cristyb51dff52011-05-19 16:55:47 +000014957 (void) FormatLocaleString(windows->magnify.name,MaxTextExtent,"Magnify %uX",
cristy3ed852e2009-09-05 21:47:34 +000014958 resource_info->magnify);
14959 if (windows->magnify.cursor != (Cursor) NULL)
14960 (void) XFreeCursor(display,windows->magnify.cursor);
14961 windows->magnify.cursor=XMakeCursor(display,windows->image.id,
14962 map_info->colormap,resource_info->background_color,
14963 resource_info->foreground_color);
14964 if (windows->magnify.cursor == (Cursor) NULL)
14965 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor",
14966 display_image->filename);
14967 windows->magnify.width=MagnifySize;
14968 windows->magnify.height=MagnifySize;
14969 windows->magnify.flags|=PPosition;
14970 windows->magnify.min_width=MagnifySize;
14971 windows->magnify.min_height=MagnifySize;
14972 windows->magnify.width_inc=MagnifySize;
14973 windows->magnify.height_inc=MagnifySize;
14974 windows->magnify.data=resource_info->magnify;
14975 windows->magnify.attributes.cursor=windows->magnify.cursor;
14976 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask |
14977 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask |
14978 StructureNotifyMask;
14979 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
14980 manager_hints->input=MagickTrue;
14981 manager_hints->initial_state=NormalState;
14982 manager_hints->window_group=windows->image.id;
14983 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
14984 &windows->magnify);
anthony11d32022012-11-17 05:31:33 +000014985 if( IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000014986 (void) LogMagickEvent(X11Event,GetMagickModule(),
14987 "Window id: 0x%lx (magnify)",windows->magnify.id);
14988 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id);
14989 /*
14990 Initialize panning window.
14991 */
14992 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
14993 resource_info,&windows->pan);
14994 (void) CloneString(&windows->pan.name,"Pan Icon");
14995 windows->pan.width=windows->icon.width;
14996 windows->pan.height=windows->icon.height;
cristyb51dff52011-05-19 16:55:47 +000014997 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.pan",
cristy3ed852e2009-09-05 21:47:34 +000014998 resource_info->client_name);
14999 windows->pan.geometry=XGetResourceClass(resource_info->resource_database,
15000 resource_name,"geometry",(char *) NULL);
15001 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
15002 &windows->pan.width,&windows->pan.height);
15003 windows->pan.flags|=PPosition;
15004 windows->pan.immutable=MagickTrue;
15005 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
15006 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask |
15007 StructureNotifyMask;
15008 manager_hints->flags=InputHint | StateHint | WindowGroupHint;
15009 manager_hints->input=MagickFalse;
15010 manager_hints->initial_state=NormalState;
15011 manager_hints->window_group=windows->image.id;
15012 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
15013 &windows->pan);
anthony11d32022012-11-17 05:31:33 +000015014 if( IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000015015 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)",
15016 windows->pan.id);
15017 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id);
anthony11d32022012-11-17 05:31:33 +000015018 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000015019 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
anthony11d32022012-11-17 05:31:33 +000015020 if( IfMagickFalse(windows->image.mapped) ||
cristy3ed852e2009-09-05 21:47:34 +000015021 (windows->backdrop.id != (Window) NULL))
15022 (void) XMapWindow(display,windows->image.id);
15023 /*
15024 Set our progress monitor and warning handlers.
15025 */
15026 if (warning_handler == (WarningHandler) NULL)
15027 {
15028 warning_handler=resource_info->display_warnings ?
15029 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
15030 warning_handler=resource_info->display_warnings ?
15031 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
15032 }
15033 /*
15034 Initialize Image and Magnify X images.
15035 */
15036 windows->image.x=0;
15037 windows->image.y=0;
15038 windows->magnify.shape=MagickFalse;
15039 width=(unsigned int) display_image->columns;
15040 height=(unsigned int) display_image->rows;
15041 if ((display_image->columns != width) || (display_image->rows != height))
15042 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
15043 display_image->filename);
15044 status=XMakeImage(display,resource_info,&windows->image,display_image,
cristy051718b2011-08-28 22:49:25 +000015045 width,height,exception);
anthony11d32022012-11-17 05:31:33 +000015046 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +000015047 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
15048 display_image->filename);
15049 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL,
cristy051718b2011-08-28 22:49:25 +000015050 windows->magnify.width,windows->magnify.height,exception);
anthony11d32022012-11-17 05:31:33 +000015051 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +000015052 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
15053 display_image->filename);
anthony11d32022012-11-17 05:31:33 +000015054 if( IfMagickTrue(windows->magnify.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000015055 (void) XMapRaised(display,windows->magnify.id);
anthony11d32022012-11-17 05:31:33 +000015056 if( IfMagickTrue(windows->pan.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000015057 (void) XMapRaised(display,windows->pan.id);
15058 windows->image.window_changes.width=(int) display_image->columns;
15059 windows->image.window_changes.height=(int) display_image->rows;
cristy051718b2011-08-28 22:49:25 +000015060 (void) XConfigureImage(display,resource_info,windows,display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015061 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
15062 (void) XSync(display,MagickFalse);
15063 /*
15064 Respond to events.
15065 */
15066 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L);
15067 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15068 update_time=0;
anthony11d32022012-11-17 05:31:33 +000015069 if( IfMagickTrue(resource_info->update) )
cristy3ed852e2009-09-05 21:47:34 +000015070 {
15071 MagickBooleanType
15072 status;
15073
15074 /*
15075 Determine when file data was last modified.
15076 */
15077 status=GetPathAttributes(display_image->filename,&attributes);
anthony11d32022012-11-17 05:31:33 +000015078 if( IfMagickTrue(status) )
cristy3ed852e2009-09-05 21:47:34 +000015079 update_time=attributes.st_mtime;
15080 }
15081 *state&=(~FormerImageState);
15082 *state&=(~MontageImageState);
15083 *state&=(~NextImageState);
15084 do
15085 {
15086 /*
15087 Handle a window event.
15088 */
anthony11d32022012-11-17 05:31:33 +000015089 if( IfMagickTrue(windows->image.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000015090 if ((display_image->delay != 0) || (resource_info->update != 0))
15091 {
15092 if (timer < time((time_t *) NULL))
15093 {
anthony11d32022012-11-17 05:31:33 +000015094 if( IfMagickFalse(resource_info->update) )
cristy3ed852e2009-09-05 21:47:34 +000015095 *state|=NextImageState | ExitState;
15096 else
15097 {
15098 MagickBooleanType
15099 status;
15100
15101 /*
15102 Determine if image file was modified.
15103 */
15104 status=GetPathAttributes(display_image->filename,&attributes);
anthony11d32022012-11-17 05:31:33 +000015105 if( IfMagickTrue(status) )
cristy3ed852e2009-09-05 21:47:34 +000015106 if (update_time != attributes.st_mtime)
15107 {
15108 /*
15109 Redisplay image.
15110 */
cristyb51dff52011-05-19 16:55:47 +000015111 (void) FormatLocaleString(
cristy3ed852e2009-09-05 21:47:34 +000015112 resource_info->image_info->filename,MaxTextExtent,
15113 "%s:%s",display_image->magick,
15114 display_image->filename);
cristy947cb4c2011-10-20 18:41:46 +000015115 nexus=ReadImage(resource_info->image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +000015116 if (nexus != (Image *) NULL)
15117 {
15118 nexus=DestroyImage(nexus);
15119 *state|=NextImageState | ExitState;
15120 }
15121 }
15122 delay=display_image->delay/MagickMax(
15123 display_image->ticks_per_second,1L);
15124 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15125 }
15126 }
15127 if (XEventsQueued(display,QueuedAfterFlush) == 0)
15128 {
15129 /*
15130 Do not block if delay > 0.
15131 */
15132 XDelay(display,SuspendTime << 2);
15133 continue;
15134 }
15135 }
15136 timestamp=time((time_t *) NULL);
15137 (void) XNextEvent(display,&event);
anthony11d32022012-11-17 05:31:33 +000015138 if( IfMagickFalse(windows->image.stasis) )
15139 windows->image.stasis=IsMagickTrue((time((time_t *) NULL)-timestamp) > 0);
15140 if( IfMagickFalse(windows->magnify.stasis) )
15141 windows->magnify.stasis=IsMagickTrue((time((time_t *) NULL)-timestamp) > 0);
cristy3ed852e2009-09-05 21:47:34 +000015142 if (event.xany.window == windows->command.id)
15143 {
15144 /*
15145 Select a command from the Command widget.
15146 */
15147 id=XCommandWidget(display,windows,CommandMenu,&event);
15148 if (id < 0)
15149 continue;
15150 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent);
15151 command_type=CommandMenus[id];
15152 if (id < MagickMenus)
15153 {
15154 /*
15155 Select a command from a pop-up menu.
15156 */
15157 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id],
15158 command);
15159 if (entry < 0)
15160 continue;
15161 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent);
15162 command_type=Commands[id][entry];
15163 }
15164 if (command_type != NullCommand)
15165 nexus=XMagickCommand(display,resource_info,windows,command_type,
cristy051718b2011-08-28 22:49:25 +000015166 &display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015167 continue;
15168 }
15169 switch (event.type)
15170 {
15171 case ButtonPress:
15172 {
anthony11d32022012-11-17 05:31:33 +000015173 if( IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000015174 (void) LogMagickEvent(X11Event,GetMagickModule(),
15175 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
15176 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15177 if ((event.xbutton.button == Button3) &&
15178 (event.xbutton.state & Mod1Mask))
15179 {
15180 /*
15181 Convert Alt-Button3 to Button2.
15182 */
15183 event.xbutton.button=Button2;
15184 event.xbutton.state&=(~Mod1Mask);
15185 }
15186 if (event.xbutton.window == windows->backdrop.id)
15187 {
15188 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent,
15189 event.xbutton.time);
15190 break;
15191 }
15192 if (event.xbutton.window == windows->image.id)
15193 {
15194 switch (event.xbutton.button)
15195 {
15196 case Button1:
15197 {
15198 if (resource_info->immutable)
15199 {
15200 /*
15201 Select a command from the Virtual menu.
15202 */
15203 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15204 command);
15205 if (entry >= 0)
15206 nexus=XMagickCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015207 VirtualCommands[entry],&display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015208 break;
15209 }
15210 /*
15211 Map/unmap Command widget.
15212 */
anthony11d32022012-11-17 05:31:33 +000015213 if( IfMagickTrue(windows->command.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000015214 (void) XWithdrawWindow(display,windows->command.id,
15215 windows->command.screen);
15216 else
15217 {
15218 (void) XCommandWidget(display,windows,CommandMenu,
15219 (XEvent *) NULL);
15220 (void) XMapRaised(display,windows->command.id);
15221 }
15222 break;
15223 }
15224 case Button2:
15225 {
15226 /*
15227 User pressed the image magnify button.
15228 */
15229 (void) XMagickCommand(display,resource_info,windows,ZoomCommand,
cristy051718b2011-08-28 22:49:25 +000015230 &display_image,exception);
cristy6710d842011-10-20 23:23:00 +000015231 XMagnifyImage(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000015232 break;
15233 }
15234 case Button3:
15235 {
15236 if (resource_info->immutable)
15237 {
15238 /*
15239 Select a command from the Virtual menu.
15240 */
15241 entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
15242 command);
15243 if (entry >= 0)
15244 nexus=XMagickCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015245 VirtualCommands[entry],&display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015246 break;
15247 }
15248 if (display_image->montage != (char *) NULL)
15249 {
15250 /*
15251 Open or delete a tile from a visual image directory.
15252 */
15253 nexus=XTileImage(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015254 display_image,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000015255 if (nexus != (Image *) NULL)
15256 *state|=MontageImageState | NextImageState | ExitState;
cristy49e2d862010-11-12 02:50:30 +000015257 vid_info.x=(short int) windows->image.x;
15258 vid_info.y=(short int) windows->image.y;
cristy3ed852e2009-09-05 21:47:34 +000015259 break;
15260 }
15261 /*
15262 Select a command from the Short Cuts menu.
15263 */
15264 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu,
15265 command);
15266 if (entry >= 0)
15267 nexus=XMagickCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015268 ShortCutsCommands[entry],&display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015269 break;
15270 }
15271 case Button4:
15272 {
15273 /*
15274 Wheel up.
15275 */
15276 XTranslateImage(display,windows,*image,XK_Up);
15277 break;
15278 }
15279 case Button5:
15280 {
15281 /*
15282 Wheel down.
15283 */
15284 XTranslateImage(display,windows,*image,XK_Down);
15285 break;
15286 }
15287 default:
15288 break;
15289 }
15290 break;
15291 }
15292 if (event.xbutton.window == windows->magnify.id)
15293 {
15294 int
15295 factor;
15296
15297 static const char
15298 *MagnifyMenu[] =
15299 {
15300 "2",
15301 "4",
15302 "5",
15303 "6",
15304 "7",
15305 "8",
15306 "9",
15307 "3",
15308 (char *) NULL,
15309 };
15310
15311 static KeySym
15312 MagnifyCommands[] =
15313 {
15314 XK_2,
15315 XK_4,
15316 XK_5,
15317 XK_6,
15318 XK_7,
15319 XK_8,
15320 XK_9,
15321 XK_3
15322 };
15323
15324 /*
15325 Select a magnify factor from the pop-up menu.
15326 */
15327 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command);
15328 if (factor >= 0)
cristy6710d842011-10-20 23:23:00 +000015329 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor],
15330 exception);
cristy3ed852e2009-09-05 21:47:34 +000015331 break;
15332 }
15333 if (event.xbutton.window == windows->pan.id)
15334 {
15335 switch (event.xbutton.button)
15336 {
15337 case Button4:
15338 {
15339 /*
15340 Wheel up.
15341 */
15342 XTranslateImage(display,windows,*image,XK_Up);
15343 break;
15344 }
15345 case Button5:
15346 {
15347 /*
15348 Wheel down.
15349 */
15350 XTranslateImage(display,windows,*image,XK_Down);
15351 break;
15352 }
15353 default:
15354 {
cristy6710d842011-10-20 23:23:00 +000015355 XPanImage(display,windows,&event,exception);
cristy3ed852e2009-09-05 21:47:34 +000015356 break;
15357 }
15358 }
15359 break;
15360 }
15361 delay=display_image->delay/MagickMax(display_image->ticks_per_second,
15362 1L);
15363 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15364 break;
15365 }
15366 case ButtonRelease:
15367 {
anthony11d32022012-11-17 05:31:33 +000015368 if( IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000015369 (void) LogMagickEvent(X11Event,GetMagickModule(),
15370 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
15371 event.xbutton.button,event.xbutton.x,event.xbutton.y);
15372 break;
15373 }
15374 case ClientMessage:
15375 {
anthony11d32022012-11-17 05:31:33 +000015376 if( IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000015377 (void) LogMagickEvent(X11Event,GetMagickModule(),
15378 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window,
cristyf2faecf2010-05-28 19:19:36 +000015379 event.xclient.message_type,event.xclient.format,(unsigned long)
cristy3ed852e2009-09-05 21:47:34 +000015380 event.xclient.data.l[0]);
15381 if (event.xclient.message_type == windows->im_protocols)
15382 {
cristyecd0ab52010-05-30 14:59:20 +000015383 if (*event.xclient.data.l == (long) windows->im_update_widget)
cristy3ed852e2009-09-05 21:47:34 +000015384 {
15385 (void) CloneString(&windows->command.name,MagickTitle);
15386 windows->command.data=MagickMenus;
15387 (void) XCommandWidget(display,windows,CommandMenu,
15388 (XEvent *) NULL);
15389 break;
15390 }
cristyecd0ab52010-05-30 14:59:20 +000015391 if (*event.xclient.data.l == (long) windows->im_update_colormap)
cristy3ed852e2009-09-05 21:47:34 +000015392 {
15393 /*
15394 Update graphic context and window colormap.
15395 */
15396 for (i=0; i < (int) number_windows; i++)
15397 {
15398 if (magick_windows[i]->id == windows->icon.id)
15399 continue;
15400 context_values.background=pixel->background_color.pixel;
15401 context_values.foreground=pixel->foreground_color.pixel;
15402 (void) XChangeGC(display,magick_windows[i]->annotate_context,
15403 context_mask,&context_values);
15404 (void) XChangeGC(display,magick_windows[i]->widget_context,
15405 context_mask,&context_values);
15406 context_values.background=pixel->foreground_color.pixel;
15407 context_values.foreground=pixel->background_color.pixel;
15408 context_values.plane_mask=context_values.background ^
15409 context_values.foreground;
15410 (void) XChangeGC(display,magick_windows[i]->highlight_context,
cristybb503372010-05-27 20:51:26 +000015411 (size_t) (context_mask | GCPlaneMask),
cristy3ed852e2009-09-05 21:47:34 +000015412 &context_values);
15413 magick_windows[i]->attributes.background_pixel=
15414 pixel->background_color.pixel;
15415 magick_windows[i]->attributes.border_pixel=
15416 pixel->border_color.pixel;
15417 magick_windows[i]->attributes.colormap=map_info->colormap;
15418 (void) XChangeWindowAttributes(display,magick_windows[i]->id,
cristy49e2d862010-11-12 02:50:30 +000015419 (unsigned long) magick_windows[i]->mask,
15420 &magick_windows[i]->attributes);
cristy3ed852e2009-09-05 21:47:34 +000015421 }
anthony11d32022012-11-17 05:31:33 +000015422 if( IfMagickTrue(windows->pan.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000015423 {
15424 (void) XSetWindowBackgroundPixmap(display,windows->pan.id,
15425 windows->pan.pixmap);
15426 (void) XClearWindow(display,windows->pan.id);
15427 XDrawPanRectangle(display,windows);
15428 }
15429 if (windows->backdrop.id != (Window) NULL)
15430 (void) XInstallColormap(display,map_info->colormap);
15431 break;
15432 }
cristyecd0ab52010-05-30 14:59:20 +000015433 if (*event.xclient.data.l == (long) windows->im_former_image)
cristy3ed852e2009-09-05 21:47:34 +000015434 {
15435 *state|=FormerImageState | ExitState;
15436 break;
15437 }
cristyecd0ab52010-05-30 14:59:20 +000015438 if (*event.xclient.data.l == (long) windows->im_next_image)
cristy3ed852e2009-09-05 21:47:34 +000015439 {
15440 *state|=NextImageState | ExitState;
15441 break;
15442 }
cristyecd0ab52010-05-30 14:59:20 +000015443 if (*event.xclient.data.l == (long) windows->im_retain_colors)
cristy3ed852e2009-09-05 21:47:34 +000015444 {
15445 *state|=RetainColorsState;
15446 break;
15447 }
cristyecd0ab52010-05-30 14:59:20 +000015448 if (*event.xclient.data.l == (long) windows->im_exit)
cristy3ed852e2009-09-05 21:47:34 +000015449 {
15450 *state|=ExitState;
15451 break;
15452 }
15453 break;
15454 }
15455 if (event.xclient.message_type == windows->dnd_protocols)
15456 {
15457 Atom
15458 selection,
15459 type;
15460
15461 int
15462 format,
15463 status;
15464
15465 unsigned char
15466 *data;
15467
cristyf2faecf2010-05-28 19:19:36 +000015468 unsigned long
cristy3ed852e2009-09-05 21:47:34 +000015469 after,
15470 length;
15471
15472 /*
15473 Display image named by the Drag-and-Drop selection.
15474 */
15475 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128))
15476 break;
15477 selection=XInternAtom(display,"DndSelection",MagickFalse);
cristyecd0ab52010-05-30 14:59:20 +000015478 status=XGetWindowProperty(display,root_window,selection,0L,(long)
cristy3ed852e2009-09-05 21:47:34 +000015479 MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format,
15480 &length,&after,&data);
15481 if ((status != Success) || (length == 0))
15482 break;
15483 if (*event.xclient.data.l == 2)
15484 {
15485 /*
15486 Offix DND.
15487 */
15488 (void) CopyMagickString(resource_info->image_info->filename,
15489 (char *) data,MaxTextExtent);
15490 }
15491 else
15492 {
15493 /*
15494 XDND.
15495 */
15496 if (strncmp((char *) data, "file:", 5) != 0)
15497 {
15498 (void) XFree((void *) data);
15499 break;
15500 }
15501 (void) CopyMagickString(resource_info->image_info->filename,
15502 ((char *) data)+5,MaxTextExtent);
15503 }
cristy947cb4c2011-10-20 18:41:46 +000015504 nexus=ReadImage(resource_info->image_info,exception);
15505 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +000015506 if (nexus != (Image *) NULL)
15507 *state|=NextImageState | ExitState;
15508 (void) XFree((void *) data);
15509 break;
15510 }
15511 /*
15512 If client window delete message, exit.
15513 */
15514 if (event.xclient.message_type != windows->wm_protocols)
15515 break;
cristyecd0ab52010-05-30 14:59:20 +000015516 if (*event.xclient.data.l != (long) windows->wm_delete_window)
cristy3ed852e2009-09-05 21:47:34 +000015517 break;
15518 (void) XWithdrawWindow(display,event.xclient.window,
15519 visual_info->screen);
15520 if (event.xclient.window == windows->image.id)
15521 {
15522 *state|=ExitState;
15523 break;
15524 }
15525 if (event.xclient.window == windows->pan.id)
15526 {
15527 /*
15528 Restore original image size when pan window is deleted.
15529 */
15530 windows->image.window_changes.width=windows->image.ximage->width;
15531 windows->image.window_changes.height=windows->image.ximage->height;
15532 (void) XConfigureImage(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015533 display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015534 }
15535 break;
15536 }
15537 case ConfigureNotify:
15538 {
anthony11d32022012-11-17 05:31:33 +000015539 if( IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000015540 (void) LogMagickEvent(X11Event,GetMagickModule(),
15541 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window,
15542 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x,
15543 event.xconfigure.y,event.xconfigure.send_event);
15544 if (event.xconfigure.window == windows->image.id)
15545 {
15546 /*
15547 Image window has a new configuration.
15548 */
15549 if (event.xconfigure.send_event != 0)
15550 {
15551 XWindowChanges
15552 window_changes;
15553
15554 /*
15555 Position the transient windows relative of the Image window.
15556 */
15557 if (windows->command.geometry == (char *) NULL)
anthony11d32022012-11-17 05:31:33 +000015558 if( IfMagickFalse(windows->command.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000015559 {
15560 windows->command.x=event.xconfigure.x-
15561 windows->command.width-25;
15562 windows->command.y=event.xconfigure.y;
15563 XConstrainWindowPosition(display,&windows->command);
15564 window_changes.x=windows->command.x;
15565 window_changes.y=windows->command.y;
15566 (void) XReconfigureWMWindow(display,windows->command.id,
15567 windows->command.screen,(unsigned int) (CWX | CWY),
15568 &window_changes);
15569 }
15570 if (windows->widget.geometry == (char *) NULL)
anthony11d32022012-11-17 05:31:33 +000015571 if( IfMagickFalse(windows->widget.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000015572 {
15573 windows->widget.x=event.xconfigure.x+
15574 event.xconfigure.width/10;
15575 windows->widget.y=event.xconfigure.y+
15576 event.xconfigure.height/10;
15577 XConstrainWindowPosition(display,&windows->widget);
15578 window_changes.x=windows->widget.x;
15579 window_changes.y=windows->widget.y;
15580 (void) XReconfigureWMWindow(display,windows->widget.id,
15581 windows->widget.screen,(unsigned int) (CWX | CWY),
15582 &window_changes);
15583 }
15584 if (windows->magnify.geometry == (char *) NULL)
anthony11d32022012-11-17 05:31:33 +000015585 if( IfMagickFalse(windows->magnify.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000015586 {
15587 windows->magnify.x=event.xconfigure.x+
15588 event.xconfigure.width+25;
15589 windows->magnify.y=event.xconfigure.y;
15590 XConstrainWindowPosition(display,&windows->magnify);
15591 window_changes.x=windows->magnify.x;
15592 window_changes.y=windows->magnify.y;
15593 (void) XReconfigureWMWindow(display,windows->magnify.id,
15594 windows->magnify.screen,(unsigned int) (CWX | CWY),
15595 &window_changes);
15596 }
15597 if (windows->pan.geometry == (char *) NULL)
anthony11d32022012-11-17 05:31:33 +000015598 if( IfMagickFalse(windows->pan.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000015599 {
15600 windows->pan.x=event.xconfigure.x+
15601 event.xconfigure.width+25;
15602 windows->pan.y=event.xconfigure.y+
15603 windows->magnify.height+50;
15604 XConstrainWindowPosition(display,&windows->pan);
15605 window_changes.x=windows->pan.x;
15606 window_changes.y=windows->pan.y;
15607 (void) XReconfigureWMWindow(display,windows->pan.id,
15608 windows->pan.screen,(unsigned int) (CWX | CWY),
15609 &window_changes);
15610 }
15611 }
cristyecd0ab52010-05-30 14:59:20 +000015612 if ((event.xconfigure.width == (int) windows->image.width) &&
15613 (event.xconfigure.height == (int) windows->image.height))
cristy3ed852e2009-09-05 21:47:34 +000015614 break;
15615 windows->image.width=(unsigned int) event.xconfigure.width;
15616 windows->image.height=(unsigned int) event.xconfigure.height;
15617 windows->image.x=0;
15618 windows->image.y=0;
15619 if (display_image->montage != (char *) NULL)
15620 {
15621 windows->image.x=vid_info.x;
15622 windows->image.y=vid_info.y;
15623 }
anthony11d32022012-11-17 05:31:33 +000015624 if( IfMagickTrue(windows->image.mapped) &&
15625 IfMagickTrue(windows->image.stasis) )
cristy34b9f452010-01-06 20:04:29 +000015626 {
15627 /*
15628 Update image window configuration.
15629 */
15630 windows->image.window_changes.width=event.xconfigure.width;
15631 windows->image.window_changes.height=event.xconfigure.height;
15632 (void) XConfigureImage(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015633 display_image,exception);
cristy34b9f452010-01-06 20:04:29 +000015634 }
cristy3ed852e2009-09-05 21:47:34 +000015635 /*
15636 Update pan window configuration.
15637 */
15638 if ((event.xconfigure.width < windows->image.ximage->width) ||
15639 (event.xconfigure.height < windows->image.ximage->height))
15640 {
15641 (void) XMapRaised(display,windows->pan.id);
15642 XDrawPanRectangle(display,windows);
15643 }
15644 else
anthony11d32022012-11-17 05:31:33 +000015645 if( IfMagickTrue(windows->pan.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000015646 (void) XWithdrawWindow(display,windows->pan.id,
15647 windows->pan.screen);
15648 break;
15649 }
15650 if (event.xconfigure.window == windows->magnify.id)
15651 {
15652 unsigned int
15653 magnify;
15654
15655 /*
15656 Magnify window has a new configuration.
15657 */
15658 windows->magnify.width=(unsigned int) event.xconfigure.width;
15659 windows->magnify.height=(unsigned int) event.xconfigure.height;
anthony11d32022012-11-17 05:31:33 +000015660 if( IfMagickFalse(windows->magnify.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000015661 break;
15662 magnify=1;
15663 while ((int) magnify <= event.xconfigure.width)
15664 magnify<<=1;
15665 while ((int) magnify <= event.xconfigure.height)
15666 magnify<<=1;
15667 magnify>>=1;
15668 if (((int) magnify != event.xconfigure.width) ||
15669 ((int) magnify != event.xconfigure.height))
15670 {
15671 window_changes.width=(int) magnify;
15672 window_changes.height=(int) magnify;
15673 (void) XReconfigureWMWindow(display,windows->magnify.id,
15674 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
15675 &window_changes);
15676 break;
15677 }
anthony11d32022012-11-17 05:31:33 +000015678 if( IfMagickTrue(windows->magnify.mapped) &&
15679 IfMagickTrue(windows->magnify.stasis) )
cristy3ed852e2009-09-05 21:47:34 +000015680 {
15681 status=XMakeImage(display,resource_info,&windows->magnify,
cristy051718b2011-08-28 22:49:25 +000015682 display_image,windows->magnify.width,windows->magnify.height,
15683 exception);
cristy6710d842011-10-20 23:23:00 +000015684 XMakeMagnifyImage(display,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +000015685 }
15686 break;
15687 }
anthony11d32022012-11-17 05:31:33 +000015688 if( IfMagickTrue(windows->magnify.mapped) &&
cristy3ed852e2009-09-05 21:47:34 +000015689 (event.xconfigure.window == windows->pan.id))
15690 {
15691 /*
15692 Pan icon window has a new configuration.
15693 */
15694 if (event.xconfigure.send_event != 0)
15695 {
15696 windows->pan.x=event.xconfigure.x;
15697 windows->pan.y=event.xconfigure.y;
15698 }
15699 windows->pan.width=(unsigned int) event.xconfigure.width;
15700 windows->pan.height=(unsigned int) event.xconfigure.height;
15701 break;
15702 }
15703 if (event.xconfigure.window == windows->icon.id)
15704 {
15705 /*
15706 Icon window has a new configuration.
15707 */
15708 windows->icon.width=(unsigned int) event.xconfigure.width;
15709 windows->icon.height=(unsigned int) event.xconfigure.height;
15710 break;
15711 }
15712 break;
15713 }
15714 case DestroyNotify:
15715 {
15716 /*
15717 Group leader has exited.
15718 */
anthony11d32022012-11-17 05:31:33 +000015719 if( IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000015720 (void) LogMagickEvent(X11Event,GetMagickModule(),
15721 "Destroy Notify: 0x%lx",event.xdestroywindow.window);
15722 if (event.xdestroywindow.window == windows->group_leader.id)
15723 {
15724 *state|=ExitState;
15725 break;
15726 }
15727 break;
15728 }
15729 case EnterNotify:
15730 {
15731 /*
15732 Selectively install colormap.
15733 */
15734 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15735 if (event.xcrossing.mode != NotifyUngrab)
15736 XInstallColormap(display,map_info->colormap);
15737 break;
15738 }
15739 case Expose:
15740 {
anthony11d32022012-11-17 05:31:33 +000015741 if( IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000015742 (void) LogMagickEvent(X11Event,GetMagickModule(),
15743 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window,
15744 event.xexpose.width,event.xexpose.height,event.xexpose.x,
15745 event.xexpose.y);
15746 /*
15747 Refresh windows that are now exposed.
15748 */
cristy6bee4042010-01-30 15:27:14 +000015749 if ((event.xexpose.window == windows->image.id) &&
anthony11d32022012-11-17 05:31:33 +000015750 IfMagickTrue(windows->image.mapped) )
cristy6bee4042010-01-30 15:27:14 +000015751 {
15752 XRefreshWindow(display,&windows->image,&event);
15753 delay=display_image->delay/MagickMax(
15754 display_image->ticks_per_second,1L);
15755 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15756 break;
15757 }
15758 if ((event.xexpose.window == windows->magnify.id) &&
anthony11d32022012-11-17 05:31:33 +000015759 IfMagickTrue(windows->magnify.mapped))
cristy6bee4042010-01-30 15:27:14 +000015760 {
cristy6710d842011-10-20 23:23:00 +000015761 XMakeMagnifyImage(display,windows,exception);
cristy6bee4042010-01-30 15:27:14 +000015762 break;
15763 }
cristy3ed852e2009-09-05 21:47:34 +000015764 if (event.xexpose.window == windows->pan.id)
cristy6bee4042010-01-30 15:27:14 +000015765 {
15766 XDrawPanRectangle(display,windows);
15767 break;
15768 }
cristy3ed852e2009-09-05 21:47:34 +000015769 if (event.xexpose.window == windows->icon.id)
cristy6bee4042010-01-30 15:27:14 +000015770 {
15771 XRefreshWindow(display,&windows->icon,&event);
15772 break;
15773 }
cristy3ed852e2009-09-05 21:47:34 +000015774 break;
15775 }
15776 case KeyPress:
15777 {
15778 int
15779 length;
15780
15781 /*
15782 Respond to a user key press.
15783 */
15784 length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
15785 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
15786 *(command+length)='\0';
anthony11d32022012-11-17 05:31:33 +000015787 if( IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000015788 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristyf2faecf2010-05-28 19:19:36 +000015789 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long)
cristy3ed852e2009-09-05 21:47:34 +000015790 key_symbol,command);
15791 if (event.xkey.window == windows->image.id)
15792 {
15793 command_type=XImageWindowCommand(display,resource_info,windows,
cristy051718b2011-08-28 22:49:25 +000015794 event.xkey.state,key_symbol,&display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015795 if (command_type != NullCommand)
15796 nexus=XMagickCommand(display,resource_info,windows,command_type,
cristy051718b2011-08-28 22:49:25 +000015797 &display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000015798 }
15799 if (event.xkey.window == windows->magnify.id)
cristy6710d842011-10-20 23:23:00 +000015800 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol,
15801 exception);
cristy3ed852e2009-09-05 21:47:34 +000015802 if (event.xkey.window == windows->pan.id)
15803 {
15804 if ((key_symbol == XK_q) || (key_symbol == XK_Escape))
15805 (void) XWithdrawWindow(display,windows->pan.id,
15806 windows->pan.screen);
15807 else
15808 if ((key_symbol == XK_F1) || (key_symbol == XK_Help))
15809 XTextViewWidget(display,resource_info,windows,MagickFalse,
15810 "Help Viewer - Image Pan",ImagePanHelp);
15811 else
15812 XTranslateImage(display,windows,*image,key_symbol);
15813 }
15814 delay=display_image->delay/MagickMax(
15815 display_image->ticks_per_second,1L);
15816 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
15817 break;
15818 }
15819 case KeyRelease:
15820 {
15821 /*
15822 Respond to a user key release.
15823 */
15824 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
15825 sizeof(command),&key_symbol,(XComposeStatus *) NULL);
anthony11d32022012-11-17 05:31:33 +000015826 if( IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000015827 (void) LogMagickEvent(X11Event,GetMagickModule(),
cristyf2faecf2010-05-28 19:19:36 +000015828 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command);
cristy3ed852e2009-09-05 21:47:34 +000015829 break;
15830 }
15831 case LeaveNotify:
15832 {
15833 /*
15834 Selectively uninstall colormap.
15835 */
15836 if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
15837 if (event.xcrossing.mode != NotifyUngrab)
15838 XUninstallColormap(display,map_info->colormap);
15839 break;
15840 }
15841 case MapNotify:
15842 {
anthony11d32022012-11-17 05:31:33 +000015843 if( IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000015844 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx",
15845 event.xmap.window);
15846 if (event.xmap.window == windows->backdrop.id)
15847 {
15848 (void) XSetInputFocus(display,event.xmap.window,RevertToParent,
15849 CurrentTime);
15850 windows->backdrop.mapped=MagickTrue;
15851 break;
15852 }
15853 if (event.xmap.window == windows->image.id)
15854 {
15855 if (windows->backdrop.id != (Window) NULL)
15856 (void) XInstallColormap(display,map_info->colormap);
15857 if (LocaleCompare(display_image->magick,"LOGO") == 0)
15858 {
15859 if (LocaleCompare(display_image->filename,"LOGO") == 0)
15860 nexus=XOpenImage(display,resource_info,windows,MagickFalse);
15861 }
15862 if (((int) windows->image.width < windows->image.ximage->width) ||
15863 ((int) windows->image.height < windows->image.ximage->height))
15864 (void) XMapRaised(display,windows->pan.id);
15865 windows->image.mapped=MagickTrue;
15866 break;
15867 }
15868 if (event.xmap.window == windows->magnify.id)
15869 {
cristy6710d842011-10-20 23:23:00 +000015870 XMakeMagnifyImage(display,windows,exception);
cristy3ed852e2009-09-05 21:47:34 +000015871 windows->magnify.mapped=MagickTrue;
15872 (void) XWithdrawWindow(display,windows->info.id,
15873 windows->info.screen);
15874 break;
15875 }
15876 if (event.xmap.window == windows->pan.id)
15877 {
cristy051718b2011-08-28 22:49:25 +000015878 XMakePanImage(display,resource_info,windows,display_image,
15879 exception);
cristy3ed852e2009-09-05 21:47:34 +000015880 windows->pan.mapped=MagickTrue;
15881 break;
15882 }
15883 if (event.xmap.window == windows->info.id)
15884 {
15885 windows->info.mapped=MagickTrue;
15886 break;
15887 }
15888 if (event.xmap.window == windows->icon.id)
15889 {
15890 MagickBooleanType
15891 taint;
15892
15893 /*
15894 Create an icon image.
15895 */
15896 taint=display_image->taint;
15897 XMakeStandardColormap(display,icon_visual,icon_resources,
cristy6710d842011-10-20 23:23:00 +000015898 display_image,icon_map,icon_pixel,exception);
cristy3ed852e2009-09-05 21:47:34 +000015899 (void) XMakeImage(display,icon_resources,&windows->icon,
cristy051718b2011-08-28 22:49:25 +000015900 display_image,windows->icon.width,windows->icon.height,
15901 exception);
cristy3ed852e2009-09-05 21:47:34 +000015902 display_image->taint=taint;
15903 (void) XSetWindowBackgroundPixmap(display,windows->icon.id,
15904 windows->icon.pixmap);
15905 (void) XClearWindow(display,windows->icon.id);
15906 (void) XWithdrawWindow(display,windows->info.id,
15907 windows->info.screen);
15908 windows->icon.mapped=MagickTrue;
15909 break;
15910 }
15911 if (event.xmap.window == windows->command.id)
15912 {
15913 windows->command.mapped=MagickTrue;
15914 break;
15915 }
15916 if (event.xmap.window == windows->popup.id)
15917 {
15918 windows->popup.mapped=MagickTrue;
15919 break;
15920 }
15921 if (event.xmap.window == windows->widget.id)
15922 {
15923 windows->widget.mapped=MagickTrue;
15924 break;
15925 }
15926 break;
15927 }
15928 case MappingNotify:
15929 {
15930 (void) XRefreshKeyboardMapping(&event.xmapping);
15931 break;
15932 }
15933 case NoExpose:
15934 break;
15935 case PropertyNotify:
15936 {
15937 Atom
15938 type;
15939
15940 int
15941 format,
15942 status;
15943
15944 unsigned char
15945 *data;
15946
cristyf2faecf2010-05-28 19:19:36 +000015947 unsigned long
cristy3ed852e2009-09-05 21:47:34 +000015948 after,
15949 length;
15950
anthony11d32022012-11-17 05:31:33 +000015951 if( IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000015952 (void) LogMagickEvent(X11Event,GetMagickModule(),
15953 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window,
15954 event.xproperty.atom,event.xproperty.state);
15955 if (event.xproperty.atom != windows->im_remote_command)
15956 break;
15957 /*
15958 Display image named by the remote command protocol.
15959 */
15960 status=XGetWindowProperty(display,event.xproperty.window,
cristyecd0ab52010-05-30 14:59:20 +000015961 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom)
cristy3ed852e2009-09-05 21:47:34 +000015962 AnyPropertyType,&type,&format,&length,&after,&data);
15963 if ((status != Success) || (length == 0))
15964 break;
15965 if (LocaleCompare((char *) data,"-quit") == 0)
15966 {
15967 XClientMessage(display,windows->image.id,windows->im_protocols,
15968 windows->im_exit,CurrentTime);
15969 (void) XFree((void *) data);
15970 break;
15971 }
15972 (void) CopyMagickString(resource_info->image_info->filename,
15973 (char *) data,MaxTextExtent);
15974 (void) XFree((void *) data);
cristy947cb4c2011-10-20 18:41:46 +000015975 nexus=ReadImage(resource_info->image_info,exception);
15976 CatchException(exception);
cristy3ed852e2009-09-05 21:47:34 +000015977 if (nexus != (Image *) NULL)
15978 *state|=NextImageState | ExitState;
15979 break;
15980 }
15981 case ReparentNotify:
15982 {
anthony11d32022012-11-17 05:31:33 +000015983 if( IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000015984 (void) LogMagickEvent(X11Event,GetMagickModule(),
15985 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent,
15986 event.xreparent.window);
15987 break;
15988 }
15989 case UnmapNotify:
15990 {
anthony11d32022012-11-17 05:31:33 +000015991 if( IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000015992 (void) LogMagickEvent(X11Event,GetMagickModule(),
15993 "Unmap Notify: 0x%lx",event.xunmap.window);
15994 if (event.xunmap.window == windows->backdrop.id)
15995 {
15996 windows->backdrop.mapped=MagickFalse;
15997 break;
15998 }
15999 if (event.xunmap.window == windows->image.id)
16000 {
16001 windows->image.mapped=MagickFalse;
16002 break;
16003 }
16004 if (event.xunmap.window == windows->magnify.id)
16005 {
16006 windows->magnify.mapped=MagickFalse;
16007 break;
16008 }
16009 if (event.xunmap.window == windows->pan.id)
16010 {
16011 windows->pan.mapped=MagickFalse;
16012 break;
16013 }
16014 if (event.xunmap.window == windows->info.id)
16015 {
16016 windows->info.mapped=MagickFalse;
16017 break;
16018 }
16019 if (event.xunmap.window == windows->icon.id)
16020 {
16021 if (map_info->colormap == icon_map->colormap)
16022 XConfigureImageColormap(display,resource_info,windows,
cristy6710d842011-10-20 23:23:00 +000016023 display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000016024 (void) XFreeStandardColormap(display,icon_visual,icon_map,
16025 icon_pixel);
16026 windows->icon.mapped=MagickFalse;
16027 break;
16028 }
16029 if (event.xunmap.window == windows->command.id)
16030 {
16031 windows->command.mapped=MagickFalse;
16032 break;
16033 }
16034 if (event.xunmap.window == windows->popup.id)
16035 {
16036 if (windows->backdrop.id != (Window) NULL)
16037 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
16038 CurrentTime);
16039 windows->popup.mapped=MagickFalse;
16040 break;
16041 }
16042 if (event.xunmap.window == windows->widget.id)
16043 {
16044 if (windows->backdrop.id != (Window) NULL)
16045 (void) XSetInputFocus(display,windows->image.id,RevertToParent,
16046 CurrentTime);
16047 windows->widget.mapped=MagickFalse;
16048 break;
16049 }
16050 break;
16051 }
16052 default:
16053 {
anthony11d32022012-11-17 05:31:33 +000016054 if( IfMagickTrue(display_image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000016055 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
16056 event.type);
16057 break;
16058 }
16059 }
16060 } while (!(*state & ExitState));
16061 if ((*state & ExitState) == 0)
16062 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand,
cristy051718b2011-08-28 22:49:25 +000016063 &display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000016064 else
anthony11d32022012-11-17 05:31:33 +000016065 if( IfMagickTrue(resource_info->confirm_edit) )
cristy3ed852e2009-09-05 21:47:34 +000016066 {
16067 /*
16068 Query user if image has changed.
16069 */
anthony11d32022012-11-17 05:31:33 +000016070 if( IfMagickFalse(resource_info->immutable) &&
16071 IfMagickTrue(display_image->taint))
cristy3ed852e2009-09-05 21:47:34 +000016072 {
16073 int
16074 status;
16075
16076 status=XConfirmWidget(display,windows,"Your image changed.",
16077 "Do you want to save it");
16078 if (status == 0)
16079 *state&=(~ExitState);
16080 else
16081 if (status > 0)
16082 (void) XMagickCommand(display,resource_info,windows,SaveCommand,
cristy051718b2011-08-28 22:49:25 +000016083 &display_image,exception);
cristy3ed852e2009-09-05 21:47:34 +000016084 }
16085 }
16086 if ((windows->visual_info->klass == GrayScale) ||
16087 (windows->visual_info->klass == PseudoColor) ||
16088 (windows->visual_info->klass == DirectColor))
16089 {
16090 /*
16091 Withdraw pan and Magnify window.
16092 */
anthony11d32022012-11-17 05:31:33 +000016093 if( IfMagickTrue(windows->info.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000016094 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
anthony11d32022012-11-17 05:31:33 +000016095 if( IfMagickTrue(windows->magnify.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000016096 (void) XWithdrawWindow(display,windows->magnify.id,
16097 windows->magnify.screen);
anthony11d32022012-11-17 05:31:33 +000016098 if( IfMagickTrue(windows->command.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000016099 (void) XWithdrawWindow(display,windows->command.id,
16100 windows->command.screen);
16101 }
anthony11d32022012-11-17 05:31:33 +000016102 if( IfMagickTrue(windows->pan.mapped) )
cristy3ed852e2009-09-05 21:47:34 +000016103 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen);
anthony11d32022012-11-17 05:31:33 +000016104 if( IfMagickFalse(resource_info->backdrop) )
cristy3ed852e2009-09-05 21:47:34 +000016105 if (windows->backdrop.mapped)
16106 {
16107 (void) XWithdrawWindow(display,windows->backdrop.id,
16108 windows->backdrop.screen);
16109 (void) XDestroyWindow(display,windows->backdrop.id);
16110 windows->backdrop.id=(Window) NULL;
16111 (void) XWithdrawWindow(display,windows->image.id,
16112 windows->image.screen);
16113 (void) XDestroyWindow(display,windows->image.id);
16114 windows->image.id=(Window) NULL;
16115 }
16116 XSetCursorState(display,windows,MagickTrue);
16117 XCheckRefreshWindows(display,windows);
16118 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0))
16119 *state&=(~ExitState);
16120 if (*state & ExitState)
16121 {
16122 /*
16123 Free Standard Colormap.
16124 */
16125 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel);
16126 if (resource_info->map_type == (char *) NULL)
16127 (void) XFreeStandardColormap(display,visual_info,map_info,pixel);
16128 /*
16129 Free X resources.
16130 */
16131 if (resource_info->copy_image != (Image *) NULL)
16132 {
16133 resource_info->copy_image=DestroyImage(resource_info->copy_image);
16134 resource_info->copy_image=NewImageList();
16135 }
16136 DestroyXResources();
16137 }
16138 (void) XSync(display,MagickFalse);
16139 /*
16140 Restore our progress monitor and warning handlers.
16141 */
16142 (void) SetErrorHandler(warning_handler);
16143 (void) SetWarningHandler(warning_handler);
16144 /*
16145 Change to home directory.
16146 */
cristy00976d82011-02-20 20:31:28 +000016147 directory=getcwd(working_directory,MaxTextExtent);
16148 (void) directory;
cristy3ed852e2009-09-05 21:47:34 +000016149 {
16150 int
16151 status;
16152
cristy8a5d7f42013-01-06 15:24:33 +000016153 if (*resource_info->home_directory == '\0')
16154 (void) CopyMagickString(resource_info->home_directory,".",MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +000016155 status=chdir(resource_info->home_directory);
16156 if (status == -1)
cristy947cb4c2011-10-20 18:41:46 +000016157 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
16158 "UnableToOpenFile","%s",resource_info->home_directory);
cristy3ed852e2009-09-05 21:47:34 +000016159 }
16160 *image=display_image;
16161 return(nexus);
16162}
16163#else
16164
16165/*
16166%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16167% %
16168% %
16169% %
16170+ D i s p l a y I m a g e s %
16171% %
16172% %
16173% %
16174%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16175%
16176% DisplayImages() displays an image sequence to any X window screen. It
16177% returns a value other than 0 if successful. Check the exception member
16178% of image to determine the reason for any failure.
16179%
16180% The format of the DisplayImages method is:
16181%
16182% MagickBooleanType DisplayImages(const ImageInfo *image_info,
cristy051718b2011-08-28 22:49:25 +000016183% Image *images,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000016184%
16185% A description of each parameter follows:
16186%
16187% o image_info: the image info.
16188%
16189% o image: the image.
16190%
cristy051718b2011-08-28 22:49:25 +000016191% o exception: return any errors or warnings in this structure.
16192%
cristy3ed852e2009-09-05 21:47:34 +000016193*/
16194MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
cristy051718b2011-08-28 22:49:25 +000016195 Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +000016196{
16197 assert(image_info != (const ImageInfo *) NULL);
16198 assert(image_info->signature == MagickSignature);
16199 assert(image != (Image *) NULL);
16200 assert(image->signature == MagickSignature);
anthony11d32022012-11-17 05:31:33 +000016201 if( IfMagickTrue(image->debug) )
cristy3ed852e2009-09-05 21:47:34 +000016202 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy051718b2011-08-28 22:49:25 +000016203 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
anthonye5b39652012-04-21 05:37:29 +000016204 "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image->filename);
cristy3ed852e2009-09-05 21:47:34 +000016205 return(MagickFalse);
16206}
16207
16208/*
16209%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16210% %
16211% %
16212% %
16213+ R e m o t e D i s p l a y C o m m a n d %
16214% %
16215% %
16216% %
16217%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16218%
16219% RemoteDisplayCommand() encourages a remote display program to display the
16220% specified image filename.
16221%
16222% The format of the RemoteDisplayCommand method is:
16223%
16224% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image,
16225% const char *window,const char *filename,ExceptionInfo *exception)
16226%
16227% A description of each parameter follows:
16228%
16229% o image_info: the image info.
16230%
16231% o window: Specifies the name or id of an X window.
16232%
16233% o filename: the name of the image filename to display.
16234%
16235% o exception: return any errors or warnings in this structure.
16236%
16237*/
16238MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
16239 const char *window,const char *filename,ExceptionInfo *exception)
16240{
16241 assert(image_info != (const ImageInfo *) NULL);
16242 assert(image_info->signature == MagickSignature);
16243 assert(filename != (char *) NULL);
16244 (void) window;
16245 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
16246 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
anthonye5b39652012-04-21 05:37:29 +000016247 "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image_info->filename);
cristy3ed852e2009-09-05 21:47:34 +000016248 return(MagickFalse);
16249}
16250#endif